write/edit/str_replace_editor 编辑前审批:改动落盘前展示红绿行级 diff,选择同意一次或拒绝,带设置页总开关。
安装
# npm 包(预构建)
dsh plugin --profile web add dsh-edit-approval
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:SiriLee/dsh-edit-approval
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
为 DeepSeek Harness 提供编辑前审批:在 write / edit / str_replace_editor 真正落盘之前,弹出红绿行级 diff——同意一次 / 拒绝,并可在 Settings → General 一键关闭。
状态:已发布 npm(
v0.1.8),经 GitHub Actions Trusted Publishing + Sigstore provenance 构建发布。目标为 web 配置档(dsh --profile web)。
目录
✨ 功能特性
| 特性 | 说明 |
|---|---|
| 写前审批 | 在 tools/pre-execute 拦截 write / edit / str_replace_editor,任何文件修改前先询问 |
| 红绿行级 diff | 按各工具语义计算行级 diff(新增 / 删除 / 上下文),审批面板逐行渲染,未变化部分折叠为 … |
| 同意一次 / 拒绝 | 两种操作,参照 Claude Code 的 edit approval 流程;拒绝会反馈给模型 |
| 总开关 | Settings → General 的「编辑前审批」开关,由 /approval-edit on|off|status host 命令支撑(同源) |
| 策略联动 | 尊重会话审批策略:ask 正常拦截,never(全权)直接放行 |
| 阈值控制 | minDiffLines、includeCreate、includeDelete 精细控制 |
📸 截图
| Settings → General 总开关 | 聊天中的 /approval-edit 命令及其参数 |
|---|---|
![]() |
![]() |
| 审批面板——红绿行级 diff |
|---|
![]() |
工作原理
插件监听 tools/pre-execute 瀑布(harness 在工具执行前运行的 seam),匹配注册工具名白名单:write、edit、str_replace_editor。对每个被拦截的调用:
- 解析目标文件:经
ctx.fs解析路径,沿用 fs 工具的会话 cwd 规则(相对路径含..时对 cwd 做规范化)。 - 读取当前内容并按工具参数重建拟写入内容,镜像各工具语义:
write— 全文;edit— 唯一替换(或replace_all);str_replace_editor—str_replace唯一替换、insert按行插入、create用file_text。
- 计算行级 LCS diff:先裁剪相等头/尾行,大文件里改 1 行仍是 1 行 diff;病态超大文件回退为粗粒度整文件替换。
- 返回
{ kind: 'ask', reason }:头部一行(工具名 · 文件 (操作): N insertions, M deletions)加 diff 文本。harness 自带的serviceAsk经ctx.approval路由到 Web 审批面板——host 端零 UI 改动。allowed-once继续执行、rejected拒绝调用;其余情况一律next()委托后续监听器。
浏览器端(dsh.client)把面板纯文本 headline 重建为红绿逐行块,注入一条 white-space: pre-wrap 补偿样式修复 headline 的 CSS 折叠,并注册 Settings → General 总开关。所有副作用收敛在单个 ctx.effect(插件卸载 / HMR 时完整清理),按动画帧合并的 MutationObserver 负责发现并增强审批面板。
与审批策略的联动
harness 的会话审批策略(ask / never)持续生效:
| 会话策略 | 插件行为 |
|---|---|
ask(如 workspace-write 预设) |
正常拦截并弹出审批面板 |
never(如 danger-full-access 预设) |
直接放行——编辑不再询问,由沙箱继续约束 |
在 never 下,插件发出的每个 ask 都会被审批服务确定性转为拒绝,导致全权会话里所有编辑被静默拦截。因此插件停止询问、交由沙箱兜底。插件绝不扩大权限,也不改变沙箱模式。
📦 安装
已发布 npm——优先走 registry 直装;安装后重启 dsh web(--profile web)生效。
方式 A:registry 直装(推荐)
dsh plugin --profile web add dsh-edit-approval
方式 B:本地 checkout(作者 / 贡献者)
cd dsh-edit-approval
npm install # devDeps 全部来自 npm registry,无需本机 harness checkout
npm run build # tsc 全量构建,含 .d.ts
dsh plugin --profile web add /path/to/dsh-edit-approval # link 安装
方式 C:GitHub(建议固定 commit 保证可复现)
dsh plugin --profile web add github:SiriLee/dsh-edit-approval#<commit-sha>
首次会失败:pnpm 默认阻止 git 依赖执行构建脚本。按 CLI 提示把 allowBuilds 键写入 profile 的 pnpm-workspace.yaml(如 $DSH_HOME/profiles/web/pnpm-workspace.yaml),重试即可。之后 pnpm 会自动运行插件的 prepare(全量构建)并安装到 profile 内。
方式 D:tarball(离线 / 自建 registry)
npm pack # 生成 dsh-edit-approval-<version>.tgz
dsh plugin --profile web add ./dsh-edit-approval-<version>.tgz
npm pack 会运行 prepare,tarball 内始终包含完整预构建 lib/(含 .d.ts)与 LICENSE;dsh plugin add 不再运行任何构建脚本。
配置
运行时配置统一在 edit-approval 设置命名空间,层级为schema 默认值 < cordis 行 config < 用户设置页(持久化)。cordis 行默认不带 config;profile patch 只需重写要改的键即可覆盖部署默认值:
# profile 的 cordis.patch.yml
- id: dsh-edit-approval
name: dsh-edit-approval
config:
minDiffLines: 2
includeCreate: false
| 键 | 默认 | 说明 |
|---|---|---|
enabled |
true |
总开关(用户可关) |
tools |
['write','edit','str_replace_editor'] |
拦截白名单(注册工具名) |
minDiffLines |
0 |
变更行数至少达到此值才询问;更小的改动静默放行 |
includeCreate |
true |
新建文件是否询问 |
includeDelete |
true |
清空/删除文件是否询问 |
行为细节与限制
- 只拦截写类工具;
bash/pwsh命令内的文件修改不在范围内。 - diff 以
+/-行标记呈现——只读预览,非交互式逐行选择;不支持「部分应用」。 - 工具自身会失败的情形不询问、放行由工具报错:
str_replace_editor create命中已存在文件、old_str/old_string非唯一或不存在。空old_string的edit预览与工具行为有偏差(视为 not-found 放行),偏差方向安全,不会误拦截。 - 按钮文案按
navigator.language而非ctx.locale——自包含 bundle 的有意简化。 - 注意注册工具名是
str_replace_editor(下划线),与 npm 包名@deepseek-ai/dsh-tool-str-replace-editor不同。
明确不包含
- 编辑后审查 / 回滚——由社区 dsh-change-review 覆盖。
- 快捷键(Enter 审批 / Esc 拒绝)——已拆分为独立插件。
- 权限档位扩展——由社区 dsh-auto-approval-plugin 覆盖。
兼容性
- Node.js
^22.19.0 || >=24.0.0。 - DeepSeek Harness web 配置档(
dsh --profile web);@deepseek-ai/*peer 包由 harness 运行时提供。
[!WARNING] 本项目与 DSH 均处于 developer preview。可复现环境请固定精确版本,并留意上文的行为说明。
开发
npm install # devDeps 来自 npm registry
npm run typecheck # tsc 双编译面(host + client)
npm test # vitest:diff / guard 单测 + 真实 cordis 集成测试(46 用例)
npm run build # 全量构建:tsc → lib/(含 .d.ts)+ lib/client.js bundle
npm run build:portable # 可选:轻量 esbuild 构建,不做类型检查
node scripts/verify-host.mjs # 对 BUILT host 产物做端到端验证
prepare 生命周期运行全量构建,因此 git 安装与 npm pack/npm publish 始终得到完整的 lib/(含 .d.ts)与 LICENSE。
发布
发版走 GitHub Actions Trusted Publishing(OIDC,无需存储 NPM_TOKEN)。详见 docs/npm-trusted-publishing-guide.md。
npm version patch && git push origin main --tags # 触发 .github/workflows/publish.yml
workflow 会校验 tag 与 package.json 版本一致,执行 typecheck + 测试 + 全量构建 + 产物验证,以 Sigstore provenance 发布并创建 GitHub Release。CI(.github/workflows/ci.yml)在每次 push / PR 上运行同样的检查。发布步骤幂等——版本已在 npm 则跳过。
目录结构
src/index.ts host 插件:tools/pre-execute 拦截 + /approval-edit 命令 + settings
src/diff.ts 行级 diff(纯函数:LCS、头尾裁剪、渲染、统计)
src/guard.ts 决策逻辑(纯函数:工具匹配、阈值、create/delete、ask/放行)
src/client/index.ts client 插件:红绿 diff 渲染 + 总开关 + 生命周期
src/client/settings-row.tsx Settings → General 开关行
tests/ vitest 套件(diff / guard / 集成)
scripts/ 构建与产物验证
cordis.patch.yml bundle patch(挂载 host 插件行)
package.json dsh.bundle + dsh.client 声明、peerDependencies
License
链接
同类插件
superdesigndev/treg★ 454
给 Agent 的工具目录:按「要做的事」检索约 2,600 个外部接口(SEO 与 SERP、外链、社交、人物与公司信息补全、广告库、抓取),查看参数与单次调用价格后直接调用,凭据由服务端注入。附带技能,MCP 行在未设置 TREG_TOKEN 前保持禁用。
zhaoolee/notes★ 146
将 DSH 对话导出为锤子便签风格 PNG,或在配置的账号工作区中新建和更新 Markdown 便签。
taxueseek/argo★ 98
专为 agent 打造的搜索工具:多语言,覆盖中文/英文/学术/代码/购物/金融/新闻/百科。
omdsh-dev/dsh-data-agent★ 52
让 AI 帮你连数据库、写 SQL。
geml-spec/geml#integrations/dsh-plugin★ 24
按块寻址的文档读写:MCP server 提供 geml_get / geml_set / geml_check 等工具,Agent 只取回或改写 Markdown、GEML 文档中的某一个块,而不是整篇文件。另带 GEML 写作技能,以及把项目调用图构建为 GEML codemap 并浏览的代码图谱技能。
omdsh-dev/dsh-custom-tool★ 24
用 Monaco 编辑器创建和管理沙箱化的自定义 JavaScript 工具。


