Windows 跨盘符路径下 isolated-git-guard 误判所有非 C 盘项目为隔离子会话(contains 的 relative 跨盘符缺陷)
环境
- Windows 10/11(项目位于非 C 盘,如
E:\;用户数据目录在默认的C:\Users\<user>\.local\share\mimocode) - compose / compose-next 工作流会话
现象
在位于非 C 盘的 git 仓库里,compose 工作流的 Workspace 步骤执行普通命令:
git worktree add .worktrees/<slug> -b <branch>被 isolated-git-guard 错误拦截,报错:
Blocked in an isolated child session: git worktree add .worktrees/<slug> -b <branch>
Reason: `git worktree add` mutates the shared worktree registry.
your worktree: E:\...(用户项目目录本身,并非 app-managed 隔离 worktree)
your branch: developgit merge、git checkout <其他分支> 等同样被拦。凡是项目不在 Global.Path.data 所在盘符(默认 C 盘),guard 都会对普通会话(orchestrator 主会话)错误生效;C 盘项目不受影响。
根因
isIsolatedWorktree()(packages/opencode/src/tool/isolated-git-guard.ts)用 AppFileSystem.contains(<data>/worktree, 会话目录) 判断当前会话是否运行在 app-managed 隔离 worktree 中。而 contains() 的实现:
export function contains(parent: string, child: string) {
return !relative(parent, child).startsWith("..")
}path.relative() 在 Windows 上跨盘符时无法相对化,会返回目标的绝对路径(如 relative("C:\\a", "E:\\b") → "E:\\b"),它不以 ".." 开头,于是 contains() 对任意跨盘符路径对都返回 true(误判"包含"):
PS> path.win32.relative('C:\Users\\\x\.local\share\mimocode\worktree', 'E:\Work\repo')
E:\Work\repo # 不以 ".." 开头 → contains 误判 true因此 guard 把 C 盘数据目录与 E 盘项目判为"包含"关系,进而把所有非数据盘项目的普通会话误判为隔离子会话并开启跨分支 git 命令拦截。报错信息中的 your worktree 显示用户项目目录(而非 <data>/worktree/<projectID>/<name>)是识别此 bug 的关键特征。
影响面
两份同款实现均受影响:packages/shared/src/filesystem.ts 与 packages/opencode/src/util/filesystem.ts。
除 guard 误拦截外,contains() 的全部调用点都会受此影响,例如 external-directory.ts 的信任根判断此前会放行跨盘符写入、静默绕过外部目录权限询问。
另注:同文件的孪生函数 overlaps() 存在同样的跨盘符缺陷(overlaps("C:/a", "D:/b") 误判为 true),目前未发现生产调用方,建议一并修复。
修复方案
跨盘符(及任何无法相对化的情形)判定为不包含:
export function contains(parent: string, child: string) {
const rel = relative(parent, child)
return !isAbsolute(rel) && !rel.startsWith("..")
}这与仓库内已有的正确用法一致(如 workflow/workspace.ts、session/instruction.ts 等处的 !startsWith("..") && !isAbsolute 模式)。posix 语义下 relative() 永不返回绝对路径,行为完全不变。
回归测试用合成 win32 路径(C:/data/worktree vs D:/projects/app)在 Linux/Windows 双平台结果一致,无需平台条件跳过。
Source: XiaomiMiMo/MiMo-Code