Skip to content

Commit 515b257

Browse files
committed
fix: canonicalize MCP watcher paths on Windows
1 parent bc54841 commit 515b257

4 files changed

Lines changed: 12 additions & 3 deletions

File tree

‎changelogs/releases/v1.20.4.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
## 变更
88

99
- MCP supervisor 保持客户端已协商的 tools/prompts 契约;worker 重启时复核候选,schema 漂移给出明确重启错误。共享 JSONL reader 拒绝超大帧后继续接收合法请求。
10+
- MCP 文件监听使用实际物理目录,避免 Windows 短路径或 junction 别名触发原生监听断言并使 supervisor 退出。
1011
- 修正文件 inventory 截断、损坏 layout marker 的静默回退、正文或否定表述被误判为关闭,以及事务恢复的物理路径校验。
1112
- ContextRead bootstrap 复核 runtime/capability/catalog 身份,保留已消费的冲突记录;SkillRoute、文档和网站同步当前 87 Skill、84 active、3 gray。
1213
- 修复 managed validation 的短 lease 续租,按 task/shard owner 精确 CAS 更新并保持原 hard deadline;过期、撤销、换代和冲突 authority 仍拒绝。

‎mcp/hot-reload-supervisor.cjs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ function watchTree (root, onChange) {
8686
const watchers = []
8787
const attach = (directory, recursive) => {
8888
try {
89-
const watcher = fs.watch(directory, { recursive }, () => onChange())
89+
// Windows notifications use the physical long path. A short-name or
90+
// junction alias can otherwise trigger an uncatchable libuv assertion.
91+
const watchDirectory = path.normalize(fs.realpathSync.native(directory))
92+
const watcher = fs.watch(watchDirectory, { recursive }, () => onChange())
9093
watcher.on('error', () => onChange())
9194
watchers.push(watcher)
9295
return true

‎public-site/data/public-product-projection.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schemaVersion": "PublicProductProjectionV2",
3-
"generatedAt": "2026-10-10T16:48:17.854Z",
3+
"generatedAt": "2026-10-10T16:55:25.722Z",
44
"release": {
55
"version": "1.20.4"
66
},

‎scripts/test-mcp-hot-reload-supervisor.js‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ async function main () {
7575
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'devcodex-mcp-hot-reload-'))
7676
const baseRoot = path.join(tempRoot, 'managed')
7777
const sourceRoot = path.join(tempRoot, 'source')
78+
const sourceAlias = path.join(tempRoot, 'source-alias')
7879
const mcpRoot = path.join(sourceRoot, 'mcp')
7980
let child
8081
try {
@@ -91,6 +92,9 @@ async function main () {
9192
fs.rmSync(path.join(sourceRoot, '.git'), { recursive: true, force: true })
9293
fs.writeFileSync(path.join(sourceRoot, '.git'), 'gitdir: ../.git/worktrees/fixture\n')
9394
assert.strictEqual(validLiveSourceRoot(sourceRoot, 'profile'), true)
95+
fs.symlinkSync(sourceRoot, sourceAlias, process.platform === 'win32' ? 'junction' : 'dir')
96+
assert.strictEqual(validLiveSourceRoot(sourceAlias, 'profile'), true)
97+
assert.strictEqual(fs.realpathSync.native(sourceAlias), fs.realpathSync.native(sourceRoot))
9498
const supervisor = path.join(baseRoot, 'mcp-hot-reload-supervisor.cjs')
9599
fs.copyFileSync(path.join(ROOT, 'mcp', 'hot-reload-supervisor.cjs'), supervisor)
96100
fs.writeFileSync(path.join(baseRoot, 'global-host-receipt.json'), `${JSON.stringify({
@@ -101,7 +105,7 @@ async function main () {
101105
runtimeSource: {
102106
schemaVersion: 'McpRuntimeSourceV1',
103107
mode: 'live-source-checkout',
104-
sourceRoot
108+
sourceRoot: sourceAlias
105109
},
106110
updatedAt: new Date().toISOString()
107111
})}\n`)
@@ -202,6 +206,7 @@ async function main () {
202206
newWorkerPid: second.pid,
203207
implementationHotReload: 'PASS',
204208
schemaChangeFallback: 'PASS',
209+
physicalWatchPath: 'PASS',
205210
result: 'PASS'
206211
}))
207212
} finally {

0 commit comments

Comments
 (0)