Files
deepseek-harness/.agents/notes/implemented/bug-fix/2026-08-12-unlink-stale-profile-fallback-links.zh.md
T

2.1 KiB

Agent Note: 用 unlink 删除过期的 profile 回退链接而非 rmSync

Status: implemented

English | 中文

问题

healProfilesModuleFallback 在安装位置迁移时会把 $DSH_HOME/profiles/node_modules 中的条目重新指向新目标,而 Windows 主机上这些条目是 junction。ensureSymlink 原先用 rmSync(link) 删除过期条目,但 Node 在删除时把 junction 当作目录处理:不带 recursivermSync 会抛 ERR_FS_EISDIR,于是从迁移后的安装或第二个 worktree 启动时,每次都会在应用引导前崩溃。replaces a wrong symlink 单元测试在 Windows 上正好在该删除调用处复现了这一崩溃。

决策

ensureSymlink 改用 unlinkSync(link) 删除过期链接。unlink 在所有平台上都只删除重解析点或符号链接本身、绝不进入目标目录,从而保住该函数“真实目录永远不会被删除”的大声失败保证。profile-plugin-bundles 决策继续拥有回退目录的双锚点解析;本 note 只拥有“用哪个删除原语”这一决定。

考虑过的替代方案

rmSync(link, { recursive: true }) Node 24 上它只删 junction、不跟随目标,但 recursive 会在 lstat 守卫与删除之间链接被替换成真实目录时静默删除该目录,削弱守卫存在所依据的大声失败契约。

rmdirSync(link) Windows 上同样能删 junction,但它读起来像“删目录”,而 unlinkSync 才是仓库现有的 junction 清理惯例。

无条件删除并重建所有条目。 正确,但每次启动都翻动未变化的链接,并扩大并发修复的竞态窗口。

后果

Windows 启动现在可以修复迁移后的安装或第二个 checkout,而不是以 ERR_FS_EISDIR 崩溃;POSIX 行为不变,因为 unlinkSync 同样能 unlink 普通符号链接。现有的 replaces a wrong symlink 测试在 Windows 上从复现崩溃变为通过。两个并发 healer 删除同一过期链接时,第二次删除仍会以 ENOENT 浮现,与原先的 rmSync 实现一致。