DeepSeek Harness 插件

BOWLUNA/dsh-zcode-git

Star 数 ★ 0 分类 Git 与代码评审 收录于 2026-09-22

给 DeepSeek Harness 智能体用的结构化 Git 工具:status、diff、log、branch、commit 与 stash。输出由十项 `git -c` 覆盖钉死,因此用户的 pager、颜色或 quotepath 设置无法改变智能体读到的东西;每次调用都是 argv 数组,任何 shell 都不解析参数;写入动作走 harness 的审批服务,没有装审批服务时拒绝执行而不是放行。

安装

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:BOWLUNA/dsh-zcode-git

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWEDERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yamlallowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

English | 中文

给 DeepSeek Harness 智能体用的一等公民 Git 工具

DSH 本身没有任何 git 工具,模型只能通过 bash 手搓命令。这个插件注册六个结构化工具, 并解决 bash 路线的三个根本问题:

bash 的问题 本插件的做法
输出形态随用户配置变化(color.uicore.pagercore.quotepathdiff.externalstatus.relativePaths、alias) 每次调用都钉死这些配置,并解析 porcelain / NUL / %x1f 等机器可读格式
git commit -m "..." 要同时活过 cmd.exe、PowerShell 与 POSIX sh —— 三者转义规则不同,且都不会「碰巧」保住 %PATH%$(...) 或换行 构造 argv 数组:参数根本不经过任何 shell
bash 里,git statusgit push --force 权限一样大 读操作与写操作分开,写操作走 harness 的审批服务

环境要求

  • DeepSeek Harness >=0.1.5-rc.2 <0.1.6-0 || >=0.1.6-alpha.1 <0.2.0-0 —— 同一范围也声明在 engines.dsh
  • Node >=20,harness 自带的那份运行时即满足
  • PATH 上有一个 git 二进制

安装

dsh plugin --profile web add dsh-zcode-git

包自带 patch 声明,profile 的 bundles 会自动更新。装完重启 Harness —— bundle 层在启动时读取。

手工挂载:

# cordis.patch.yml
- insert:
    - id: tool-git
      name: dsh-zcode-git

工具清单

工具 类型 作用
git_status 分支、upstream、ahead/behind,以及 staged / modified / conflicted / untracked / ignored 五类清单
git_diff 逐文件行数统计 + unified diff,可用 pathsstagedcontextLines 收窄
git_log 提交记录,返回 {hash, shortHash, author, date, subject}limit 限流,paths / revision 过滤
git_branch 读 + 写 list / create / switch / delete;写操作需审批
git_commit 可选先 paths 暂存,再提交 message;需审批
git_stash 读 + 写 list / push / pop / apply / drop;写操作需审批

所有工具都接受可选的 path 指定仓库目录,默认取会话工作目录,相对值按会话目录解析。

状态码

git_status 输出 git 自己的两列码 —— 先索引态、后工作区态,所以 .M 是未暂存的改动, M. 是已暂存的改动。同时也会把词形(index / worktree 字段)返回给偏好的调用方。

安全边界

绝不经过 shell。 每次调用都走 ctx.subprocess.spawnargv 数组。Harness 的另一个接缝 ctx.shell 收的是一整行命令字符串,用它就等于把每个参数重新交给 shell 解析 —— 而不存在一套同时对 cmd.exe、PowerShell 和 POSIX sh 正确的转义(cmd.exe 在双引号内部 依然展开 %VAR%)。所以参数干脆不进 shell。含 "`$(...)%PATH%、换行、 中文的提交信息会逐字节原样存入仓库。

输出被钉死。 以下配置在每次调用时强制覆盖(紧跟在 git 之后),因为每一项都会改变本插件 所解析的字节:

color.ui=false              core.pager=cat
core.quotepath=false        status.relativePaths=false
log.showSignature=false     log.date=default
diff.noprefix=false         diff.mnemonicPrefix=false
diff.external=              advice.detachedHead=false

行为类配置则刻意不覆盖user.nameuser.emailcore.autocrlf、hooks、 core.sshCommand 是用户的意图,不是噪声。子进程环境额外注入 GIT_TERMINAL_PROMPT=0, 让需要凭据的操作立即失败而不是卡在一个没人能回答的提示上;以及 GIT_OPTIONAL_LOCKS=0, 让读操作不会因为别的窗口占着 index.lock 而失败。

写操作需审批。 git_commit,以及 git_branch / git_stash 的写入动作,都会在 执行前调用 ctx.approval.request()如果 profile 没有装审批服务,写操作会被拒绝而不是放行 —— 「静默无保护的 git commit」正是本插件要消除的东西。只有在你明确接受这一点时, 才把 requireApprovalForWrites 设为 false

路径先校验。 绝对路径、.. 穿越、UNC 路径、驱动器相对形式(C:foo)、 NTFS 备用数据流、Windows 保留设备名、控制字符,都在任何进程启动之前被拒绝。 git 自己也会拦大部分,但先校验能给出精确消息,并让明显敌意的输入连进程都不进。

刻意不提供: pushfetchpullresetcleanrebaseremote、config 写入。 在 bash 里这些至少还躺在一行人类能读的命令里;做成工具就变成「一次调用摧毁工作区、 只靠一个提示框把关」。fetch 与 push 还牵涉凭据与主机密钥处理,值得单独设计,而不是在这里加个复选框。

配置

默认 含义
timeoutMs 30000 单次调用超时
maxDiffLines 500 默认补丁行数上限(钳制在 10–5000)
maxLogEntries 50 git_log 默认条数(钳制在 1–500)
requireApprovalForWrites true 写操作是否需要审批

patch 条目是整键替换而非深合并,所以要把想保留的键写全:

- insert:
    - id: tool-git
      name: dsh-zcode-git
      config:
        timeoutMs: 60000
        requireApprovalForWrites: true

开发

npm test          # node --test

95 个测试,除 harness 的 peer 包外零依赖,分六层:

  • test/parse.test.js —— 纯解析器,喂录制的 git 输出
  • test/validate.test.js —— 路径、提交信息、分支名、revision 校验
  • test/exec.test.js —— spawn spec,喂记录用的假实现
  • test/tools.test.js —— 工具行为,喂假 subprocess 服务
  • test/e2e.test.js —— 真实 git 二进制 + 真实临时仓库
  • test/schema.test.js —— 与 harness、provider 的 schema 兼容性

给后来写 DSH 工具插件的人

本插件里有四处设计,是因为「显而易见的做法」会失败,而且都不是在出错的地方报错

ctx.tools.register() 不编译任何东西。 它只校验 output.schema,然后原样存下定义。 parameters 的作者 DSL 不会被转换 —— 所以直接注册原始定义对象,等于把一个没有顶层 type 的裸属性 map 送给模型 provider,整个请求被拒。必须包一层: ctx.tools.register(defineTool(definition))。而且 provider 只报字母序第一个工具的名字, 于是错误指向一个本身没问题的工具。

parametersoutput.schema 用的是两套 DSL。 parameters 是扁平属性 map ({ path: { type: "string" } });output.schema 是裸 JSON Schema ({ type: "object", properties: { ... } })。把后者交给 parameters 会抛 parameters.type must be a value schema object;把前者交给 output.schema 会抛 schema.type must be string/…

③ schema 关键字对版本敏感。 property 内的 required: true 在 dsh-tools 0.1.5-rc.2 上被接受、在 0.1.6-alpha.2 上被拒绝(UNSUPPORTED_SCHEMA);顶层 required: [...] 数组 两边都拒绝。工具 schema 里出现 enum 会让某个 provider 拒绝整个 function schema,报 must be a JSON Schema of 'type: "object"', got 'type: null'。所以本插件一个都不用, 而是在代码里强制同样的约束 —— 顺带得到了更好的错误消息: unsupported action "x"; expected one of list, create, switch, delete

④ 返回值必须与 schema 严格一致。 在 schema 声明为 string 的位置放 null, 会让这一轮以 INVALID_TOOL_OUTPUT 失败,而此时 git 已经执行成功了。 没有值就省略字段,不要送 null

⑤ 渲染器在工作已完成之后运行。 渲染器读了 execute 从未返回的字段,会在 harness 内部抛错, 把一次本来成功的调用变成失败的一轮。test/tools.test.js 之所以要拿每个工具的输出驱动它自己的 渲染器,就是为这个。

许可

MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。