dsh-hardlink-publish-fallback:在不支持硬链接的卷上补全新文件写入

前言

在 DeepSeek Harness(DSH)里,智能体通过 write 工具在工作区创建或更新文件。Windows 上 @deepseek-ai/dsh-fs-local 对新文件的发布路径会使用硬链接:把暂存目录里的临时文件硬链到目标路径,同时充当「不覆盖已存在文件」的守卫。若工作区落在 exFAT、FAT32(常见 U 盘、移动硬盘)或部分不支持硬链接的网络共享上,该 link 调用会被拒绝;Node 往往把错误报成 EISDIR,而不是更直观的 ENOTSUP/EPERM。结果是:新建文件每次都会失败,而更新已有文件仍走 rename/ReplaceFileW,看起来「能改不能建」,排查成本高。下面介绍社区插件 dsh-hardlink-publish-fallback 如何在不改默认行为的前提下,仅在识别到这类硬链接发布失败时做一次性兜底。

这是什么

dsh-hardlink-publish-fallback 由维护者 Mushroomcowisheggs 发布,仓库见 GitHub,目录页见 SkillHub。它以 DSH bundle 形式注入配置层(cordis.patch.yml),在 write 因「卷不支持硬链接发布」而失败时,在严格检测通过后改用卷已支持的 rename 路径完成新建(与更新文件时相同的路径),并记录与正常成功写入一致的 observation。未触发该失败签名的写入完全不受影响。

背景:失败长什么样

在不支持硬链接的卷上,典型错误类似:

cannot write "<workspace>\<file>": EISDIR: illegal operation on a directory,
  link '<workspace>\.<file>.<pid>.<uuid>.tmpdir\<file>.tmp' -> '<workspace>\<file>'

调用方「仅在目标不存在时创建」的意图从未被满足,因此在该工作区上所有新建尝试都会永久失败。同一类卷通常也不支持符号链接;dsh-app-boot 的 healProfilesModuleFallback 会在组合时用符号链接把安装链到 profile,因此 DSH_HOME 不能放在无符号链接能力的文件系统上——本插件不解决 profile 无法启动的问题,只解决 write 新建文件的硬链接发布失败。

核心功能

插件行为可概括为四步(资料中的设计说明):

  1. 先让真实的 write 原样执行。
  2. 仅当失败消息同时带有 .tmpdir 暂存标记和 link 动词、且属于 FS_IO_ERROR 的硬链接发布特征时,再次确认目标仍不存在,然后用无「禁止替换」守卫的 intent-free 写入完成发布(rename 路径)。
  3. 写入成功后记录与正常 write 相同的 observation。
  4. 兜底链路中任一步失败,则向调用方返回原始错误,不掩盖其它问题。

检测是严格的:无关的 EISDIR(例如目标是目录、路径组件错误)不会被拦截。默认行为不被修改——成功的写入不会进入兜底,也不会替换已有服务或覆盖已有配置行。

安装与启用

从 GitHub 安装时建议固定 tag 或 commit;不指定 ref 时,pnpm 会随默认分支当前指向变化,后续推送可能静默改变本机实际运行的代码:

dsh plugin --profile web add "github:Mushroomcowisheggs/dsh-hardlink-publish-fallback#v0.1.0"

# 更强:固定 40 位 commit
dsh plugin --profile web add "github:Mushroomcowisheggs/dsh-hardlink-publish-fallback#<40-char-sha>"

该包为纯 JavaScript,无 prepare/构建脚本,一般不需要在 profile 的 pnpm-workspace.yaml 里为 allowBuilds 单独授权(若未来版本增加构建步骤,则需按 DSH 文档处理 git 依赖构建)。

从本地目录或 tarball 安装时,路径务必用双引号包住(Windows 下未加引号时 \d、\t 等会被当作转义):

dsh plugin --profile web add "<path-to-checkout>"
pnpm pack
dsh plugin --profile web add "<path-to-checkout>\dsh-hardlink-publish-fallback-0.1.0.tgz"

dsh plugin add 会因包内声明的 dsh.bundle 自动把 bundle 追加到 profile 的 dsh.profile.bundles。

验证是否加载:

dsh --profile web --dump-config          # 查找 "# == dsh-hardlink-publish-fallback"

典型用法与验证

在受影响的卷上打开工作区,让智能体创建一个新文件。未装插件时应出现上文 EISDIR/link 错误;安装并加载后,应像常一样报告 Created file。维护者在固定 exFAT 卷、从发布 tag 安装的场景下确认过:新建文件、在需先建目录的路径下新建、对同一文件连续第二次写入且无中间 read、以及无暂存残留;经本插件创建的文件 observation 与正常写入一致,后续行为与其它文件相同。

仓库内可用以下命令跑行为测试(无需真实 exFAT 卷):

npm test          # 或: node test/plugin.test.mjs

适用场景与注意

适合谁: 在 exFAT/FAT32 或可移动介质、部分网络共享上跑 DSH,且主要痛点是 agent write 无法新建文件、但编辑已有文件正常时,可在对应 profile 安装本插件作为运行时 workaround。

范围与限制(以 README 为准):

  • 只修复新建;更新与 edit 本就不走硬链接路径,插件不拦截。
  • 逻辑按失败签名识别,不限于 Windows;任何拒绝 link() 且错误形态相同的 POSIX 文件系统也可能受益。
  • 不能靠本插件在 Windows 盘符根目录直接新建文件:writeFileAtomic 在根上 mkdir 会 EPERM,属于另一缺陷;请写到子目录。
  • 不能替代上游修复 dsh-fs-local 发布逻辑;详细分析见仓库内 DEFECT-REPORT.md。
  • 兜底前会再次检查目标不存在,与原始 writeText 一样存在有限的 TOCTOU 窗口;仍保留「不静默覆盖竞态创建者」的语义。

安全与信任: 插件随当前 DSH 进程权限运行,会介入文件写入路径。安装前请阅读 源码与 MIT 许可证,自行评估是否纳入 profile。SkillHub 等为社区目录,与 DeepSeek / 幻方无官方从属关系;DSH 生态强调「一切皆插件」,选用第三方 bundle 需自行 pinning 与审计。

结尾

dsh-hardlink-publish-fallback 针对「不支持硬链接发布的新文件 write」做窄范围兜底:默认路径不变,仅在识别到硬链接失败且目标仍缺失时改用 rename 完成创建。若你的工作区常落在 exFAT 等卷上,可固定版本安装并在 --dump-config 中确认 bundle 已加载。更多信息见 SkillHub 目录页 与 GitHub 仓库。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜