前言¶
DeepSeek Harness(DSH)在本地改文件时,会用 fs-local 记录的版本 token 做乐观并发校验。token 由 dev:ino:size:mtimeNs:ctimeNs 拼成;只要写入后 token 与下一次 edit / write 前读到的不一致,就会报 FS_STALE_VERSION,并出现类似「file changed since it was read — re-read the file, then retry」的提示。
在 macOS 上,Spotlight(mds)、TCC 等常在不改内容的前提下写入 com.apple.macl、com.apple.provenance 等扩展属性,观测上往往只刷新 ctime,inode、size、mtime 不变。写入后立刻被 DSH 记下的 token,几毫秒到两秒内就可能因 ctime 跳变而对不上,下一次编辑被误拦。表现上像「每次改完都必须先 read 一遍」,容易误判成工具用法问题。上游讨论见 deepseek-harness #3111。
下面介绍社区插件 dsh-fs-ctime-guard(维护者 wx-yss,目录分类 admin-security),在 intent 层对「仅 ctime 变化」做有条件放行,减轻上述误报。
这是什么¶
dsh-fs-ctime-guard 是 DSH 的 Cordis 插件包(npm 名 dsh-fs-ctime-guard,当前资料中版本 0.1.2,MIT 许可证)。它不修改 DSH 安装目录,通过 bundle patch 挂到 fs/edit-intent 与 fs/write-intent 瀑布最外层(prepend),在 DSH 原有 fs-observation-policy 判定之前介入。
定位一句话:让文件版本守卫在除 ctime 外其余字段未变时,不把纯元数据噪声当成内容冲突。
核心功能¶
插件在每次 edit / write(含 str_replace_editor 等走同一 intent 的路径)上的流程如下:
- 先
await next(),拿到 DSH 原有守卫的判定; - 对当前路径再
stat一次; - 若守卫认为 stale,且当前 stat 与 token 对比后只有 ctime 段不同 → 用当前版本覆盖守卫版本,放行;
- 若 mtime、size、inode、设备变化,文件不存在,版本串不符合
dev:ino:size:mtimeNs:ctimeNs五段十进制协议,或 stat 失败、用户取消等 → 原样返回原有判定,不额外放宽。
瀑布顺序(资料原文示意):
edit/write 工具
│
fs/edit-intent 瀑布
├─ fs-ctime-guard(prepend) ← 本插件
├─ fs-observation-policy ← DSH 原有守卫
└─ fallback
fs/write-intent 同样注册,因此 write 覆盖写入也会应用同一套「只忽略 ctime」逻辑。
安装与启用¶
插件随 DSH 的 profile bundle 安装,资料中的官方命令为:
dsh plugin --profile web add dsh-fs-ctime-guard
ds
dsh plugin add 会把包写入 profile 的 dsh.profile.bundles,重启 DSH 进程(ds)后生效。
本地开发可用 link 安装(路径换成你的 clone 目录):
dsh plugin --profile web add link:/path/to/dsh-fs-ctime-guard
ds
卸载:
dsh plugin --profile web remove dsh-fs-ctime-guard
ds
安装前建议自行查看 GitHub 仓库 源码与 MIT 许可证;插件以当前 DSH 进程权限运行,与其它 DSH 插件相同。
验证与测试¶
维护者在 README 中给出两类测试命令:
npm test # 16 个单元测试
npm run test:integration # 真实 cordis + dsh-fs-local + fs-observation-policy
集成测试覆盖要点包括:修复前仅 chmod 改 ctime 时 edit 会报 FS_STALE_VERSION;修复后同场景可通过;真实内容变更仍会报 stale;write 在忽略 ctime 噪声的同时仍拒绝真实修改。集成测试默认从 ~/.npm/_npx 发现 DSH,也可用环境变量 DSH_NPX_ROOT 指定 node_modules;找不到安装时会跳过(退出码 0),不宜当作发布门禁。
适用场景与注意¶
适合谁: 主要在 macOS 上用 DSH 做本地文件编辑,且频繁遇到写入后立刻 FS_STALE_VERSION、被迫 read 再试的场景(尤其 ~/Documents 等易被 Spotlight 触达的路径)。
务必接受的取舍(资料中的「边界与已知弱化」):
- 放行依据是「除 ctime 外四字段相同」,不等于内容一定相同。若另一进程同尺寸原地改写并用
utimes精确恢复 mtime,token 可能只差 ctime,插件会放行,edit/write可能基于过期视图写入。这与上游 #3111 方案 1 的取舍一致,集成测试中有「已知弱化」用例固定该行为。 chmod、ACL、属主、部分有语义的 xattr 变化也可能只动 ctime,插件会放行;DSH 原生写入本就不覆盖这些语义。- DSH 写入并非跨进程原子 CAS;intent 判定与 provider 之间仍有窗口,ctime 若在两次 stat 间再变,仍可能偶发一次 stale,重新 read 即可。
prepend注册顺序在 HMR/重载后建议回归;依赖当前fs-local版本串格式,格式或 provider 变化时插件会保守退回严格判定。- 上游若在 #3111 落地等价修复,可直接卸载本插件。
当前维护者选择(README 记载 2026-10-31):默认同时放宽 edit 与 write;若日后只想保留 edit 放宽,可改 bundle 不再注册 fs/write-intent。
参考链接¶
- 社区目录:skillhub.cn/plugins/wx-yss/dsh-fs-ctime-guard
- 源码与说明:github.com/wx-yss/dsh-fs-ctime-guard
- npm:dsh-fs-ctime-guard
DSH 生态强调「一切皆插件」;SkillHub 等社区目录为独立站点,与 DeepSeek / 幻方无官方从属关系。本插件属于 admin-security 分类,用于在明确接受弱化前提下,减少 macOS ctime 元数据噪声带来的误报。