dsh-better-edit:用内容哈希锚定 DSH 的文件读写与编辑

前言

在 DeepSeek Harness(DSH)里跑编码 Agent,文件编辑往往是 token 消耗和出错的重灾区。常见的 str_replace 或按行号定位,要求模型在输出里逐字复述要被替换的旧代码——这部分是输出 token,计费通常是输入的约 5–6 倍。上方多插入一行,下方行号整体偏移,改错行的风险随之上升,且工具侧往往缺少「这段范围是否就是模型刚才看到的内容」的校验。

下面介绍 dsh-better-edit(维护者 Rianico)。它为 DSH 提供基于内容哈希(hashline)的 readeditundo_last_edit 工具:每行分配一个 3 字符哈希作为地址,编辑时只传起止哈希和替换文本,不回显旧内容;范围在写入前对照模型已读状态校验,过期或未见行直接拒绝并回传新锚点。项目采用 MIT 许可证,npm 当前版本为 0.4.0,GitHub 约 15 stars。

这是什么

dsh-better-edit 是 DSH 的客户端插件,分类为「客户端」。它通过 cordis.patch.yml 挂载到 DSH 运行时,在 agent/session-start 时将 hashline 版 read/edit 注册到 agent 作用域,从而替换 preset 内置的同名工具,并保留内置 write

与按行号或全文搜索替换不同,hashline 把每一行当作内容寻址:哈希由行内容推导,上方编辑不会使下方未改动行的锚点失效。插件在 SkillHub 社区目录(skillhub.cn/plugins/Rianico/dsh-better-edit)可检索;该目录为独立社区站点,与 DeepSeek / 幻方无官方从属关系。

核心功能

三个工具

工具 作用
read HASH│内容 返回文件,支持 offset(1 起始)、limit 分页
edit remove_from / remove_to 哈希范围替换;同文件最多 32 条编辑原子批量
undo_last_edit 撤销指定路径的上一次 hashline 编辑,重启后仍可用

read 展示过的行、diff 回显行、拒绝并回传(reject-and-serve)的行,都计入「已提供」状态。edit 写入前逐行校验:从未展示的行触发 [E_RANGE_UNSERVED],磁盘内容与锚点不一致触发 [E_RANGE_STALE],批次中任一项失败则整批不写([E_BATCH_ABORT])。

相对 str_replace 的差异

README 中的对比要点如下,均来自项目文档与可复现基准,而非第三方案例:

  • 编辑调用不回显被替换文本,只传两个 3 字符哈希加新内容
  • 锚点为内容地址,连续编辑时未改动行哈希保持有效,diff 输出带新锚点,通常不必每次改完都 read
  • 范围与模型所见逐行核对;错锚点、过期内容在写入前硬拒绝,并回传带新哈希的当前行供重试
  • 对 ASCII 空白变化有一定容忍(如 prettierblack 介入后锚点仍可解析);字符串字面量内的空白不在此列

项目在固定 103 行语料、12 次编辑的 token 基准中报告:相对 str_replace,hashline edit 输出 token 约省 31%(多行范围 29–47%);同一外部漂移重构任务中,工具调用约 3 次 vs 6 次(对比 OMP 封装,方法说明)。确定性正确性电池为 23/23。本地可运行 npm run benchmark 复现计数部分。

存储与撤销

哈希快照、已提供状态、撤销历史默认存放在 central 模式:

$DSH_HOME/plugins/dsh-better-edit/runtime/<name>-<hash8>/hash-store.sqlite

DB 为可丢弃缓存,删除后下次 read 会按文件内容重建哈希。撤销默认 TTL 7 天(undo_ttl_s: 604800-1 为永久)。

安装与启用

环境要求:Node ^22.19.0 || >=24.0.0(DSH 要求,存储依赖 node:sqlite);已有一个 dsh profile。

任选一种安装方式:

npx @deepseek-ai/dsh plugin --profile web add github:Rianico/dsh-better-edit   # 从 GitHub
npx @deepseek-ai/dsh plugin --profile web add dsh-better-edit                   # 从 npm
npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-better-edit          # 从本地源码

无需额外配置。该 profile 的下一次会话即加载 hashline 工具。验证插件层是否生效:

dsh --profile <name> --dump-config   # 输出中应出现 "# == dsh-better-edit" 层

可选配置写在 $DSH_HOME/plugins/dsh-better-edit/config.yaml,例如存储位置、撤销 TTL、central 清理策略。环境变量 DSH_BETTER_EDIT_STORE_DIRDSH_BETTER_EDIT_AUTO_GITIGNORE 可覆盖 yaml。首次启动时若文件不存在,插件会生成带注释的默认配置,不覆盖已有文件。

典型用法

读取:每行带哈希前缀

read 返回的每一行,行首哈希即该行地址:

ve7│function hello() {
szJ│  console.log("world");
kQm│}

编辑:按哈希范围定位

下面示例把 szJ 这一行替换为新内容:

{
  "path": "src/main.ts",
  "edits": [["szJ", "szJ", "  console.log('hi');"]]
}

工具返回 diff,并附带新锚点,便于链式编辑:

- szJ │   console.log("world");
+ a3m │   console.log('hi');
  kQm │ }

同一文件可一次提交多条编辑,全部成功才写入:

{
  "path": "src/main.ts",
  "edits": [
    ["a1b", "a1b", "new line 1\n"],
    ["c3d", "c3d", "new line 2"]
  ]
}

撤销

对刚改过的文件调用 undo_last_edit,传入 { "path": "src/main.ts" }。仅当磁盘内容与上次编辑后快照一致时生效;若中间被外部修改,返回 [E_UNDO_STALE]

适用场景与注意

适合:

  • 长会话中的结构性改动,需要连续多次编辑且不能落错行
  • 希望减少编辑相关输出 token、降低 str_replace 式复述成本
  • 文件可能在编辑间隙被格式化工具或外部进程改动,需要过期检测而非静默覆盖

不太适合:

  • 单行微调(token 节省接近持平,README 有说明)
  • 新建文件(继续用内置 write;插件会在 write 后自动 read 以建立锚点)

安装前请注意:

  • 插件以当前 dsh 进程权限读写工作区与 $DSH_HOME 下的存储,安装前应阅读 源码MIT 许可证
  • DSH 仍处于开发者预览阶段,插件 README 注明当前针对特定 dsh 版本接线,升级 DSH 后宜重新核对兼容性
  • 基准数字衡量的是请求负载 token,未完全建模转录失败重试等真实会话成本;正确性优势需结合具体工作流评估

链接

若你已在 DSH 里反复遇到行号漂移或 str_replace 复述出错,可以先按上文命令装入 profile,用 readedit → 看 diff 新锚点走一遍最小闭环,再决定是否用于日常 Agent 会话。

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

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

小夜