将代码评审变成一道硬性闸门:确定性严重级别规则、LLM 辅助发现、团队批准法定人数与合规审计追踪,未通过前禁止合并。
安装
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:JohnXu22786/review-gate
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
一个将代码评审变成硬门禁的 DeepSeek Harness (dsh) bundle(插件)。
与只读的评审/差异查看器不同,review-gate 真正闭环:生成分级评审项、以确定性规则
放行或拦截合并、要求团队审批达到法定人数、并留存可审计的合规报备记录——同时接入
ctx.tools 与独立的 CLI(供 CI/hook 使用)。
它填补的空白:生态中现有评审插件只能查看差异并添加批注,缺少把评审作为门禁的 能力。review-gate 让评审成为合并/PR 之前必须通过的检查点。
git diff ──► run ──► 评审项(severe/warning/suggestion)
│ 确定性规则 (不依赖模型)
▼
gate ──► blocked / passed
│
▼
团队审批法定人数 ──► approved ⇢ 解锁合并
│
▼
合规报备(时间 / 人 / 结论 / 规则版本)
功能
- 评审会话 — 审查工作区、暂存区、单个提交或任意
base..head范围。评审项按severe/warning/suggestion分级,逐文件/hunk 产出,来源包括:- 确定性静态规则(对新增行做正则匹配,绝不依赖模型),以及
- LLM 辅助评审项(可选)。模型只会新增评审项,永远不能绕过任何阈值。
- 门禁规则 — 可配置阈值(
severe = 0、warning ≤ N、suggestion 不限、 人工确认清单)。通过/拦截的判定由确定性规则基于已固化轮次 (评审项 + 确认 + 投票)计算——完全可复现,绝非模型判断。自动门禁不过,任何 审批都无法解锁合并。 - 团队审批流 —
approve/request_changes/reject,可配置法定人数 (N 个不同的审批)。按评审人后写覆盖;重新评审(新轮次)会使旧的审批**与旧的 确认(acknowledgement)**一并失效。 - 合规报备 — 每次评审、投票、确认、导出都追加到不可变的审计日志(时间、操作者、 结论、规则版本),并可导出为 JSON 或 Markdown 报告。
- 与 CI 协作 — 每个工具与 CLI 命令都输出机器可读 JSON 与正确的退出码
(
gate-check在未通过前以非零退出),可直接接入 GitHub Action / hook / 分支保护。 - 教训库 — 可选:失败经验可沉淀为可复用静态规则(见“配置”)。
- 工具链 — dsh 工具
review_run、review_status、review_approve、review_request_changes、review_reject、review_acknowledge、gate_check、review_export;以及独立review-gateCLI。
工作原理(简述)
会话 由(稳定的仓库标识, 差异范围)确定,因此提交的记录在任何检出/CI 机器上 都保持同一标识。基于差异 + 规则 + 策略的确定性 指纹 标识被评审内容;内容未变时 复用该轮(幂等),绝不重复写入审计。
评审项具有基于内容生成的稳定 id,因此确认(acknowledge)与人工确认清单可在 内容完全相同的重复评审之间保持一致。新轮次(内容或策略变化)需要重新确认。
门禁 综合自动规则与审批状态得出唯一状态:
状态 含义 open已创建,尚未评审(无轮次) blocked自动门禁未通过,或存在 request_changes/rejectpassed自动门禁通过,等待审批 approved自动门禁通过 且 达到法定人数、无拦截 —— 解锁合并 持久化 为 JSON 文件存储:按会话做原子化读-改-写(进程内互斥 + 临时写/fsync/重命名)、跨进程锁文件、以及只追加的
audit.jsonl。
目录结构
review-gate/
├── package.json # dsh.bundle.patch → cordis.patch.yml
├── cordis.patch.yml # 挂载插件行的补丁
├── tsconfig[.test].json
├── src/
│ ├── types.ts # 核心领域类型
│ ├── config.ts # 配置、默认值、校验、规则
│ ├── git/diff.ts # unified diff 解析(纯函数)
│ ├── git/runner.ts # git 交互(可注入执行器)
│ ├── analyzers/static.ts # 确定性正则分析器
│ ├── analyzers/llm.ts # 可选 LLM 评审器(惰性解析 ctx.llm)
│ ├── gate/engine.ts # 确定性自动门禁
│ ├── approval/flow.ts # 投票、法定人数、后写覆盖
│ ├── service/evaluate.ts # 门禁+审批综合判定
│ ├── service/reviewGate.ts # 门面 / 公开 API
│ ├── store/ # 持久化 + 内存存储、文件锁
│ ├── audit/report.ts # 合规报告渲染
│ ├── dsh/ # dsh 适配器(工具、LLM 网关、入口)
│ ├── cli.ts # 独立 CLI
│ └── index.ts # 编程式 API 导出
├── test/ # node:test 测试套件(61 项)
├── examples/
│ ├── review-gate.config.json # 完整带注释配置
│ └── github-action.yml # CI 门禁工作流
├── README.md / README.zh.md
└── LICENSE
快速开始
独立 CLI 与编程式 API 需要 Node.js ≥ 18;作为 dsh bundle 运行时,harness 本身 要求
^22.19.0 || >=24.0.0(以 harness 安装文档为准)。git须在PATH中且 目标目录为 git 工作区。
安装
npm install -g review-gate # 面向任意 git 仓库的独立 CLI
或作为 dsh bundle 安装(见下文)。
使用 CLI
# 在某个 git 仓库内
review-gate run --json # 评审工作区相对 HEAD 的差异
review-gate status --json
review-gate gate-check --mode merge # 仅当可合并时退出码为 0
本地构建与测试:
npm install
npm run build # → dist/
npm test # 构建 dist-test/ 并运行 node --test
node dist/cli.js run # 或:npm run cli -- run
作为 dsh bundle 接入
review-gate 遵循 dsh bundle 规范:
// package.json
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
cordis.patch.yml 向 profile 层插入 review-gate 一行;部署时可覆盖其 config
(补丁按整行替换,需写全所有字段)。像其他 bundle 一样安装:
dsh plugin --profile <name> add ./review-gate
dsh --profile <name> --patch ./review-gate/cordis.patch.yml
插件导出 name / inject / apply(ctx, config),并在 ctx.tools 上注册工具
(见“dsh 工具”)。LLM 辅助评审在 config.llm.enabled 开启后,于调用时惰性解析
ctx.llm,可自动发现后挂载的模型层;模型层不可用时写入 llm.warn 审计事件并继续——
静态规则的评审项仍然主导门禁。
配置
在 <repo>/.review-gate.config.json(CLI 读取)和/或插件行 config 中放置:
{
"cwd": "/绝对/路径/仓库",
"store": { "root": ".review-gate", "repoId": "github.com/acme/repo" },
"gate": {
"severe": 0,
"warning": 0,
"suggestion": -1,
"requiredAcknowledge": []
},
"approvals": { "required": 2 },
"llm": { "enabled": false },
"onEmptyDiff": "pass",
"maxFindings": 500,
"rules": { /* 自定义静态规则,叠加在内置规则之上 */ }
}
运行 review-gate init 可生成示例文件。详见 examples/review-gate.config.json。
store.repoId 固定用于键控会话的稳定标识,使已提交的记录在每个检出与 CI 上都可读。
未设置时按 remote.origin.url、git toplevel、工作目录依次推导——见“与 CI 协作”。
LLM 辅助评审默认关闭。开启需设 llm.enabled,并在部署未路由默认 provider/model
时设置 llm.provider 与 llm.model。LLM 评审项同样由确定性阈值计数;模型不可用时
运行照常完成。
门禁阈值(-1 = 不限):
| 字段 | 默认 | 含义 |
|---|---|---|
gate.severe |
0 |
允许的最大未确认 severe 评审项数 |
gate.warning |
0 |
允许的最大未确认 warning 数 |
gate.suggestion |
-1 |
默认不拦截 suggestion |
gate.requiredAcknowledge |
[] |
必须显式确认的评审项 id;标记 "severe" 表示“所有 severe 都必须确认” |
确认(acknowledge)评审项 会将其移出失败集合,且始终留痕:
review-gate acknowledge <id> --reason "已登记 CR-77"。
内置规则(src/config.ts::defaultRules):todo、debugger、console-log、
hardcoded-secret、long-line、merge-markers。每条含 pattern、severity、
message、可选的 files 路径正则与 suggestion。在 rules 下新增/覆盖即可把
历史失败沉淀为规则——匹配数量由 maxFindings 封顶。
空差异 — “空”指 git 完全没有报告任何变更。纯二进制、纯重命名或仅改模式的变化
属于真实差异:不产生逐行评审项,但仍需审批达到法定人数。onEmptyDiff: "pass"
(默认)放行真正空差异;"fail" 则要求显式评审:会插入一个必须确认的 severe
评审项,以此表达“没有改动仍需签核”的策略。
dsh 工具
| 工具 | 用途 |
|---|---|
review_run |
评审当前差异 / 提交 / 范围 |
review_status |
当前评审项、状态、审批进度 |
review_approve |
为法定人数 +1(自动门禁不过时无效) |
review_request_changes |
拦截直至重新评审 |
review_reject |
拦截直至重新评审 |
review_acknowledge |
带原因确认某个评审项(留痕) |
gate_check |
确定性判定,机器可读 JSON,gate/merge 两种模式 |
review_export |
导出合规报告(JSON / Markdown) |
每个工具都返回 JSON 值(CI 可消费)并为模型渲染可读摘要。也可用编程式 API:
import { ReviewGate, JsonFileStore, GitRunner, resolveConfig } from 'review-gate/core'
const config = resolveConfig({ cwd: '/path/to/repo' })
const gate = new ReviewGate({
config,
store: new JsonFileStore({ root: config.store.root }),
git: new GitRunner({ cwd: config.cwd }),
})
const { verdict } = await gate.run({ scope: { kind: 'range', base: 'main', head: 'feature' } })
const check = await gate.gateCheck({ mode: 'merge' })
CLI 参考
review-gate <command> [scope] [options]
run | status | approve | reject | request-changes | acknowledge
gate-check | export | audit | init | version
Scope: working | staged | commit:<ref> | range:<base>..<head> (默认 working)
--dir <path> 要评审的仓库 --config <file>
--force 内容未变也强制新一轮 --mode gate|merge
--reviewer <r> --comment <text> --reason <text>
--format json|markdown(export) --out <file>
--actor <label> --json
gate-check 即 CI hook:输出 JSON,--mode gate 下当状态为 passed/approved
时退出 0;--mode merge 下仅当 approved 时退出 0。其余命令成功退出 0、
操作被拒绝退出 1、用法/配置错误退出 2。
与 CI 协作
门禁状态与审计记录存放在 <repo>/.review-gate/。由于会话以稳定仓库标识为键
(store.repoId,或由远程 URL 推导),在一个检出里记录的内容,可以在同一仓库的
任何其他检出(含 CI)中读取。
两种部署模型:
- 提交记录(推荐用于拦合并) — 评审人在其检出中创建并更新评审状态与审批,然后
提交
.review-gate/到仓库。CI 只需检出并校验:review-gate gate-check --mode merge仅在自动阈值 与 审批法定人数都满足时 退出0。examples/github-action.yml给出了这种分支保护任务的示例。 - 流水线自管 — 由 harness / CLI 作为评审方,直接在与合并门禁相同的环境中写状态。
重要:同一门禁在处处都使用一致的 scope——评审人审批所用的差异范围,必须与 CI
校验的是同一个(默认 working)。gate-check 本身从不改动状态,可安全地从 hook
反复调用。
设计说明 / 取舍
- 确定性门禁:通过/拦截的判定是“轮次内已存评审项 + 确认 + 投票”的纯函数。 模型输出只能贡献评审项——永远不能绕过阈值——且轮次一旦持久化,任何重读都会得到 完全一致的结论。
- 幂等:内容未变时重复
review_run复用轮次;相同投票/确认是空操作;gate_check从不改动状态。 - 并发:按会话键串行(进程内互斥 + 带陈旧锁打破与归属令牌的跨进程锁文件); 写入采用临时文件+fsync+原子重命名,崩溃不损坏文档;审计只追加。
- 范围边界:组合(
--cc)合并差异不做逐行评审(记录为占位文件)。空差异由onEmptyDiff决定。评审项数量由maxFindings封顶。 - 教训库 刻意做成配置驱动(加一条规则),而非自动变更的子系统——确定性、可审计。
安全
- 门禁只读仓库(
git diff/git show),绝不修改工作区。 - 评审项中的敏感信息:
hardcoded-secret规则会把匹配行写入评审项/报告;请限制 记录文件的读取范围,高安全仓库应使用更严格规则。 - 这是评审/合规辅助,不是授权边界。只要能写存储就能改审批;请保护好
.review-gate/。
测试
npm test 运行 node:test 套件:git/diff 解析器、静态分析器、门禁引擎、
审批流、JSON 存储(并发 + 持久化 + 锁)、评审运行器 E2E(含空差异 + LLM 兜底 +
轮次作用域 + 稳定标识)、幂等性、报告、配置校验、dsh 工具注册表,以及针对真实临时
git 仓库的完整 CLI 往返。
许可证
MIT — 见 LICENSE。
链接
同类插件
yjh051108/dsh-routing-suite★ 7018
一个仓库三件套:DSH 插件包的运行时注入器(注入、热重载、卸载、开发侧挂区一键转正、路由自愈,外带设置页插件管理:列出、卸载、拖入文件夹内化)、任务感知的思维模式路由 agent 预设(router-standard / router-spec / router-react)、以及分级两级任务协议(commit_star / lock_stage / revise_do / edit_plan / mark_task / redteam_verdict 六个工具,任务状态落盘)。注入器实现直接在库内,安装的是它自己的行为而不是一份依赖清单。
strukto-ai/mirage#dsh★ 3681
把文件系统与 bash 提供者换成 mirage 虚拟工作区:文件工具与 shell 命令作用于挂载的资源(RAM、S3、Redis、Slack、Gmail、Notion、Postgres)而非宿主磁盘,支持按挂载点设置读/写/执行模式、按命令选择沙箱(进程内 monty、pyodide、quickjs;远程 docker、e2b、daytona),并可在虚拟终端中安装 CLI(git、gh、slack、linear、ntn、gws,或自行注册的程序树)作为命令头词。
hust-open-atom-club/oh-dsh★ 322
社区发行版:TUI、桌面端与 Web UI 统一体验,分层安装、一步到位。
weijiafu14/pi2dsh★ 212
Pi Host ABI 兼容引擎:装一次之后,npm 上的 Pi 扩展原包经 `dsh plugin add <pi-package>` 直接作为 DSH 原生插件挂载。已在官方 DSH 上端到端验证 pi-mcp-adapter(完整 MCP 管理面:OAuth、resources、prompts、MCP Apps、elicitation、sampling)、@tintinweb/pi-subagents、pi-code、pi-hermes-memory、pi-background-tasks;`pi2dsh inspect` 在安装前报告一个包的兼容情况。
Fishquito7/dsh-skill-mcp-panel★ 194
在 DSH Web 设置中管理技能与 MCP 服务器:技能卡片热启停、工作区作用域、分组、批量迁移与拖拽导入,以及 stdio/HTTP MCP 增删改查、连接测试、密钥脱敏,并附带统一 dsh-panel 命令行。
lire1131/dsh-undo-savepoint★ 179
DSH 撤销/回退系统:配置变更自动存档,一键撤销/恢复/回退到任意版本,支持 WebUI 与离线 CLI/GUI 工具(DSH 启动失败也能救)。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。