dsh-plugin-code-quality
Verified@hope_phenom/dsh-plugin-code-quality · v0.1.1 · MIT
DeepSeek Harness plugin adding two code-quality commands as user-invocable skills: /simplify (behavior-preserving cleanups over the current diff) and /code-review (multi-angle bug hunt with an independent verifier pass), plus /review as an alias.
Install
dsh plugin add @hope_phenom/dsh-plugin-code-quality Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dsh-plugin-code-quality
一个 DeepSeek Harness 插件,在 / 菜单里加上两个代码质量命令:
| 命令 | 作用 | 谁能调用 |
|---|---|---|
/simplify [目标] |
对你改动过的代码做不改变行为的清理:复用已存在的辅助函数、去掉多余的复杂度、削减浪费的工作、把做错层次的改动挪回去。不是找 bug。 | 你 和 模型 |
/code-review [级别] [--fix] [目标] |
用多个相互独立的审查角度在 diff 里找真实正确性缺陷,每条候选都先经独立验证再上报,存活下来的按严重度排序。 | 仅你 |
/review … |
/code-review 的别名,行为与指令完全相同。 |
仅你 |
两个命令沿用主流代码审查工具已经收敛的设计,并按 DSH 的工具、指令文件布局与 subagent 模型做了适配。
安装
dsh plugin --profile <你的 profile> add @hope_phenom/dsh-plugin-code-quality
然后重启该 profile(或让 HMR 接管),在输入框敲 / —— simplify、code-review、review 会出现在 skills 分组下。
本地开发联调:
dsh plugin --profile <你的 profile> add F:\path\to\dsh-plugin-code-quality
前置条件
- DSH 组合了
@deepseek-ai/dsh-skill与@deepseek-ai/dsh-client-ui-skill。两者都在随包发布的 standard preset 里,原装安装即有。 - Node.js ≥ 20。
- 本插件没有任何依赖,也没有 peer 依赖——它不 import 任何 DSH 包,只通过宿主传入的
ctx对象与宿主交互。
用法
/simplify
/simplify # 清理自上游分支以来的全部改动
/simplify src/parser.ts # 只看某个路径
/simplify 421 # 改成审查某个 PR,而不是本地 diff
范围解析顺序:你指定的目标 → git diff '@{upstream}...HEAD' → main...HEAD(退到 origin/main、master)→ HEAD~1。工作区未提交的改动与未跟踪文件也会纳入,因为这个命令最有用的时机是提交之前。如果什么都没改,它会直说并停下。
四个独立审查者看同一个 diff——Reuse(复用)、Simplification(简化)、Efficiency(效率)、Altitude(层次)。一条发现只有在能给出具体替换方案时才算数:该调用的现成辅助函数、更简单的写法、更省的替代方案、或者特例该收敛进哪个通用机制。填不出这一栏的发现会在到达你之前就被丢掉。
存活下来的发现去重后直接应用。凡是会改变预期行为、或需要改动 diff 之外代码的,一律跳过并如实说明跳过原因,而不是跟你辩论。
/code-review
/code-review # 默认级别的均衡审查
/code-review high # 更多角度、更高上报上限、倾向召回的验证
/code-review max --fix # 最宽的扫描,然后应用发现
/code-review high src/parser.ts # 级别 + 目标
级别词是模型从你自己的消息里读出来的——没有参数解析器,因为这个命令是以指令形式下发的。
| 级别 | 正确性角度 | 清理角度 | 每个 finder 候选上限 | 上报上限 | 验证倾向 |
|---|---|---|---|---|---|
low |
3 | 0 | 4 | 5 | 只保留 CONFIRMED |
medium(默认) |
5 | 2 | 6 | 8 | 均衡 |
high |
6 | 4 | 8 | 12 | 保留 PLAUSIBLE |
max |
6 | 4 + 补漏 | 8 | 20 | 保留 PLAUSIBLE |
共定义六个正确性角度,由级别决定跑几个——low 跑三个、medium 跑五个、high 与 max 跑全部六个:
| id | 角度 | 它问的问题 |
|---|---|---|
| C1 | 逐行 hunk 扫描 | 是什么输入、状态、时序或平台会让这一行产生错误结果?(含被改动函数里未改动的那几行) |
| C2 | 被删除行为审计 | 被删掉或替换的每一行原先保证了什么不变式?新代码在哪里重新建立它? |
| C3 | 跨文件契约追踪 | 这次改动是否通过新的前置条件、返回值形状、抛错路径或时序要求打断了某个调用方? |
| C4 | 语言与框架陷阱 | 这次 diff 里真实出现的语言/框架,踩中了哪个经典陷阱? |
| C5 | 异步、并发与资源生命周期 | 竞态、漏掉的 await、启动了却没人等的活儿、错误路径跳过清理、活得比属主还久的监听器。 |
| C6 | 错误路径与边界 | 空集合、零与负数、null、多字节文本、溢出、超时、部分写入、超大载荷。 |
每条候选随后交给一个独立验证者,它的指令是尝试反驳这条候选,并必须回答 CONFIRMED / PLAUSIBLE / REFUTED。在 high 与 max 下,最后还有一个补漏审查者拿到已验证清单,只找清单上没有的东西。当上报上限需要削减时,正确性发现优先于清理、层次与规范类发现。
输出是每条发现一行:
src/parser.ts:118 —— 重试循环在循环体内重置了 `attempts`;持续 503 会无限重试
如果没有任何发现通过验证,它会用一行如实说明,而不是把报告灌水。--fix 会在上报之后应用存活的发现;不加这个参数,命令永远不会改文件。
实现方式
插件没有客户端一半,没有工具、没有服务、没有 HTTP 路由。lib/index.js 只做一件事:
export const name = 'dsh-plugin-code-quality'
export const inject = ['skills']
export function apply(ctx) {
for (const skill of SKILLS) ctx.skills.register(skill)
}
为什么用 skill 而不是 ctx.commands
DSH 给插件两条加 / 命令的路,它们并不等价:
ctx.commands.register()发布的是宿主命令。它的 handler 直接对 agent 生效,默认不产生任何模型消息——想让模型干活的命令必须自己伪造一条用户消息提交上去。ctx.skills.register()且userInvocable: true发布的是 skill。composer 把你的消息原样送出(连/simplify这个 token 一起),宿主在 pre-step 边界把 skill 正文作为<skill_content>指令块追加进去。
后者正好是这两个命令需要的载体:它们的内容本身就是一份指令文档,你输入的目标文本能完整到达,也不需要伪造一条"假装是你"的消息。
调用策略
simplify 注册为 { modelInvocable: true, userInvocable: true },所以模型在自己的 skill 目录里也看得到、可以主动调用——"做一次不改变行为的清理"是 agent 自己判断需要时完全可以做的事。
code-review 与 review 注册为 { modelInvocable: false, userInvocable: true }。它们从不进入模型的目录,也无法被模型自行触发;/ 菜单是它们唯一的入口,DSH 会在菜单里把它们标成"仅限用户"。
/review 是第二次注册,不是指针
@deepseek-ai/dsh-skill 的运行时注册只以 name 为键,没有别名字段(DSH 的本地化命令别名只存在于宿主命令,且靠一方 definitionId 定位)。因此 /review 注册为它自己的 skill,但按引用共享 code-review 的正文,两者不可能漂移。代价是 / 菜单里多一行。
设计说明
这两个命令沿用了一套代码审查工具已经大致收敛的做法:把审查拆成若干相互独立的角度,让任何单次扫描都不必样样精通;每条候选在上报之前都要过一遍独立验证;上报数量设上限,免得一堆边缘发现把真正的问题埋掉。
在此基础上,这里有几处是超出该做法的:
- 角度。 除了常见的逐行、被删除行为、跨文件三个角度,还加入了
C5(异步、并发与资源生命周期)与C6(错误路径与边界)——这两类承载的真实缺陷量很大,而泛泛的扫描容易略过。 - 扇出工具。 审查者以
subagent子代理运行,并钉死run_in_background: false。DSH 的 standard preset 把该工具配置成continuable,不钉的话它会返回一个 id、逼父级去轮询,而不是在同一个 step 里交回一整轮发现。所有 finder 调用在同一条消息里发出,以并发执行。 - 努力级别。 DSH 的 skill 正文是静态的,没有宿主 API 可以选级别,因此级别由模型从你的消息里解析,对照上表。
- 指令文件。 DSH 加载
$DSH_HOME/AGENTS.md,以及按目录组成的项目链AGENTS.md与其AGENTS.local.md叠加层。这条链通常会自动注入,因此规范类角度只在没注入时才去直接读文件。 - 范围。 审查只针对你的本地 diff,报告留在对话里。不会往 PR 上发评论,也不会发布到别处。
非官方社区项目,MIT 许可证,无商业目的。
开发
npm test # node --test:skill 契约、插件接线、提示词合规
npm run verify # 同样检查的可读 PASS/FAIL 报告
test/prompts.test.js 是 docs/PORT-SPEC.md §7 的执行点:任何正文丢掉 subagent 扇出契约、少了某个判定标签、开始自行输出 prompt 框架、混入厂商名、或超出字数预算,都会让构建失败。