dsh-hashline-edittool

toolstested: passnpmMIT

Hash-anchored file tools for DeepSeek Harness: the read, edit, write and grep tools are replaced by versions where every line is addressed by a variable-length content anchor instead of a line number, and the plugin also registers delete, rename, undo_last_edit, ast_grep, ast_edit, lsp and format. E

下载量 / Downloads
2,216
依赖体积 / node_modules
70.92 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-hashline-edittool

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

<h1 align="center">dsh-hashline-edittool</h1>

<p align="center">

<img src="docs/images/cards.png" alt="hashline 卡片:读 / diff / grep / LSP / 设置" width="760">

</p>

<p align="center">

<strong>DeepSeek Harness 的行锚定编辑工具<br>

每一行都有一个变长内容锚点 —— 不写行号、不回抄旧代码,更省 token,把上下文留给真正的工作。</strong>

</p>

<p align="center">

<a href="README.md">English</a> ·

<strong>简体中文</strong>

</p>

<p align="center">

<a href="#快速开始">快速开始</a> •

<a href="#锚点契约">锚点契约</a> •

<a href="#工具">工具</a> •

<a href="#设置">设置</a> •

<a href="#错误码">错误码</a> •

<a href="#架构">架构</a> •

<a href="#致谢">致谢</a>

</p>

<p align="center">

<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="MIT License">

<img src="https://img.shields.io/badge/DeepSeek_Harness-Plugin-blueviolet.svg" alt="DeepSeek Harness Plugin">

<img src="https://img.shields.io/npm/v/dsh-hashline-edittool" alt="npm version">

<img src="https://img.shields.io/github/stars/hyperion2144/dsh-hashline-edittool?style=social" alt="GitHub Stars">

<a href="https://dsh-plugin.org/plugins/hyperion2144/dsh-hashline-edittool"><img src="https://dsh-plugin.org/badges/listed.svg" alt="Listed on dsh-plugin.org"></a>

</p>


它是什么

一个 DeepSeek Harness 插件:用哈希锚定版本替换内置的

read / edit / grep 工具,并在此基础上提供 delete、rename、undo_last_edit、ast_grep、ast_edit、

apply_patch 和 lsp 工具:

  • 每一行都携带内容锚点 —— 变长 Base62 标记(前 3,844 行只需 2 个字符,随文件规模

才会增长)。模型按标记编辑,永远不需要回抄要替换的代码。

  • 编辑会对照模型实际看到的内容做校验。 每个锚点都逐行校验:必须仍然存活、它绑定的那一行

必须仍持铸锚时的内容、且它必须在本会话的 served 集合里。行在会话期间被改动会被拒 ——

而拒绝信息会回显失效行并附带真锚点、可直接使用(reject-and-serve)。文件校验和变化是

重映射信号而不是拒绝理由,所以别的会话改了别的行,永远不会让你的锚点失效。

  • 同一工作区内锚点跨会话共享。 在一个会话里读过文件,另一个会话可以直接改,不必重读:

锚点是每工作区的身份,而「这一行能不能写」按会话回答。若另一个会话替换了你手里那一行,

你会拿到拒绝与该行当前的锚点 —— 而不是静默写到别处。

  • 每个文件一个原子批次。 同一 edit 调用里的所有锚点都对照原始快照解析,因此每一项都用原始锚点。

单个文件内的编辑 all-or-nothing:一条失败即拒绝该文件的批次([E_BATCH_ABORT])、该文件什么都不写;

文件之间互不牵连 —— 多文件调用逐文件上报部分成功,每个失败各自带错误码。

  • 一切皆卡片。 随包的 client 插件从结构化 presentationMeta 在 dsh web UI 渲染

读 / diff / grep / 撤销 / 写入 / 结构 / LSP 卡片 —— 模型文本与 UI 永远不需要靠字符串

解析达成一致。

PTC preset 下同样成立:run_code 子调用携带同一份 presentationMeta,渲染同一张卡片(#353)。

以单个 npm 包(dsh-hashline-edittool)交付:宿主插件 + web 卡片插件 + prompt sections,

由一个 bundle patch 挂载。

亮点

自渲染卡片。 随包 client 插件自带 React 组件——HashlineReadRow、HashlineEditRow、HashlineGrepRow(文件 tab + 命中高亮)、HashlineUndoRow、HashlineWriteRow、HashlineAstGrepRow、HashlineAstEditRow、HashlineLspRow——直接注册进 dsh web UI 的插槽。每张卡片从工具的结构化 presentationMeta 渲染,锚点 gutter、diff 行、高亮 span 全部原生绘制:没有通用工具输出卡,没有字符串互解,不改上游 web。

卡片界面跟随读者。 五类卡片(read / grep / diff / LSP / error)默认自动换行,卡片标题上的按钮可一键切回横向滚动(#373)。卡片文字跟随 DSH 的界面语言(zh/en,其它语言回落英文):文案收在插件自有的 hashline.card 词表里,宿主过 wire 发的是稳定 key,不是拼好的句子(#372、#375)。

动态长度锚点。 锚点不是定宽哈希。分配最短优先:2 个字符覆盖前 3,844 行,只有文件真需要时才长出新层(上限 62⁸ 行,实际不可达)。全数字编码被跳过,标记永远不会与行号混淆;冲突在分配时探测消解;会话内编辑后幸存的行保持原锚点——分配/释放走统一生命周期门,重写与外部变更按行对齐继承。

AST + LSP 双语义后端。 ast_grep / ast_edit 通过沙箱化的 tree-sitter worker 回答「语法在哪里匹配」,配精选语法目录(SHA-256 校验下载、安装/卸载路由)与长文件的可编辑折叠大纲。lsp 工具通过每语言一个的真实语言服务器回答「这个符号是什么」——按需启动,与 dsh 自带 lsp 服务共享——起不了服务器时降级启发式后端。两者都会 serve 自己的行,结构与语义结果可直接编辑。没人用的语言服务器会在 lsp.idle_timeout_ms(默认五分钟)后被回收,下次用到再重新拉起——一个抱着大仓库索引的 TypeScript 服务器,不该整场会话都常驻。启动失败的语言服务器会在退避窗口(首次 5 秒、指数翻倍、上限 1 分钟,成功后计数清零)过后在下一次使用时重试;lsp 工具的 warm 操作可跳过退避立即重拉,status 操作只读查询各已启动语言的服务器状态(#318)。

写入即诊断(自动诊断)。 编辑/写入落盘后,插件以写入前的文本为基线通知语言服务器,拉取诊断并按写入文件逐一投递——短窗口内联胶囊挂在卡片下方(严重度着色),未竟部分在模型下一步自然边界异步补投;JSON 信封与 text 模式双通道可达。lsp.auto_diagnostics 一键关闭。

语言服务器格式化。 format 工具把活交给服务器的格式化器——缩进优先取项目 .editorconfig(format.editorconfig 默认为开),否则按文件自身的缩进步长推断(4 空格的深层文件仍是 4 空格,见 #336)。format.auto 是三态开关(#315):off(默认)绝不背着工具悄悄格式化;full 在每次真正改了内容的 write/edit/ast_edit 后格式化整个文件;range 只格式化本次调用改到的行——仅当服务器不支持局部格式化且 format.fallback_full_file 开启时才回退整文件(否则该次自动格式化静默跳过,而显式带 range 调用 format 工具会以 E_FORMAT_UNSUPPORTED 明确拒绝、绝不擅自猜测)。只用已就绪的服务器(绝不为此冷启动)、每文件 2s 预算、请求失败记一条 warning + skipped 段。卡片在主 diff 之下渲染格式化自己的段——header 打头([auto-format: server · mode · requested → applied · n lines changed · k in main diff · r restored · u unserved])——并且不重复主 diff 已展示的内容:主 diff 已有的行只计入 header 计数、不再画第二遍(#312);被格式化器改回编辑前原文的行只定位、不引用——每段连续行折叠成一条 @@ ~start,count @@ scope 定位行加一句 restored 摘要(#315);本会话从未 serve 过的行不带锚点:格式化器的改动只展示一次,但只有 serve 过的行才能按锚点再编辑。

写后回显。 write 写后回显多少是用户的决定(write.preview,#354)。diff(默认)把覆盖渲染成与所有编辑工具同一套统一 diff——--- path / +++ path、@@ … @@ scope() 段头、context_lines 上下文行,+ 行与上下文行的锚点立即可用;新建没有 before 侧,仍走回读式全文。full 保留整文件自动回读预览。confirmation 只回一行(Wrote <path> (update).)且不 serve 任何东西:没有文件窗口、没有 resume 令牌、没有锚点——卡片仍画 diff,但 gutter 只有行号。JSON 输出同构:diff 回与 edit 相同的 marker-keyed diff 字典,confirmation 回 {path, operation}。

插件自渲染的设置面板。 随包的 HashlineSettingsCard 是 web 端完整设置 UI:分隔符、输出格式、上下文行数、行号(模型侧标记形态,默认关)、require_line_content、AST 总开关与按语言开关、命名 LSP 服务器、自动诊断、语言服务器空闲回收窗口。改完提交即生效——不用碰 YAML。

处处热切换。 提交的设置改动下一次工具调用即生效——输出格式、分隔符、上下文行数、AST/LSP 开关(已实测:会话中途切换 output_format,模型收到的内容立即改变)。影响面最大的开关也有处理:切换 require_line_content 会销毁并重挂 edit 工具的 schema,模型下一步就看到新的 { anchor, line } 参数集——全程无需重启。

快速开始

npx @deepseek-ai/dsh plugin --profile web add github:hyperion2144/dsh-hashline-edittool   # 从 github
npx @deepseek-ai/dsh plugin --profile web add dsh-hashline-edittool                       # 从 npm
npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-hashline-edittool              # 本地检出

该 profile 的下一个会话即装即用。验证层已挂载:

dsh --profile <name> --dump-config   # 会出现 "# == dsh-hashline-edittool" 层

要求 ·

Node · ^22.19.0 \ · \ · >=24.0.0(dsh 的要求;存储使用 node:sqlite)

Profile · 一个 dsh profile(首次使用 dsh plugin 会自动初始化)

后端 · 支持沙箱 / 远程文件系统(写入走 ctx.fs)

锚点契约

标记

  • 锚点是变长 Base62 标记,每行唯一(内容相同的行拿到不同的锚点 —— 锚点是行身份,

不是可以猜的内容哈希)。全数字的编码会被跳过,所以标记永远不会是纯数字。

  • 标记写作 <anchor> 或 <anchor>:<line>;line 只是位置提示 —— 锚点才是权威,

提示与锚点不一致只给警告([E_LINE_HINT]),不是错误。旧的 `<line>:<anchor>

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::30,最后更新 2026-11-04

Links

GitHub · Homepage · npm

Same category