# review-gate 一个将代码评审变成**硬门禁**的 **DeepSeek Harness (dsh) bundle(插件)**。 与只读的评审/差异查看器不同,review-gate 真正闭环:生成分级评审项、以确定性规则 放行或拦截合并、要求团队审批达到法定人数、并留存可审计的合规报备记录——同时接入 `ctx.tools` 与独立的 CLI(供 CI/hook 使用)。 它填补的空白:生态中现有评审插件只能查看差异并添加批注,缺少**把评审作为门禁**的 能力。review-gate 让评审成为合并/PR 之前必须通过的检查点。 ``` git diff ──► run ──► 评审项(severe/warning/suggestion) │ 确定性规则 (不依赖模型) ▼ gate ──► blocked / passed │ ▼ 团队审批法定人数 ──► approved ⇢ 解锁合并 │ ▼ 合规报备(时间 / 人 / 结论 / 规则版本) ``` --- ## 功能 1. **评审会话** — 审查工作区、暂存区、单个提交或任意 `base..head` 范围。评审项按 `severe` / `warning` / `suggestion` 分级,逐文件/hunk 产出,来源包括: - **确定性静态规则**(对新增行做正则匹配,绝不依赖模型),以及 - **LLM 辅助评审项**(可选)。模型只会*新增评审项*,永远不能绕过任何阈值。 2. **门禁规则** — 可配置阈值(`severe = 0`、`warning ≤ N`、suggestion 不限、 人工确认清单)。通过/拦截的判定由**确定性规则**基于已固化轮次 (评审项 + 确认 + 投票)计算——完全可复现,绝非模型判断。自动门禁不过,任何 审批都无法解锁合并。 3. **团队审批流** — `approve` / `request_changes` / `reject`,可配置法定人数 (N 个不同的审批)。按评审人后写覆盖;重新评审(新轮次)会使旧的审批**与旧的 确认(acknowledgement)**一并失效。 4. **合规报备** — 每次评审、投票、确认、导出都追加到不可变的审计日志(时间、操作者、 结论、规则版本),并可导出为 JSON 或 Markdown 报告。 5. **与 CI 协作** — 每个工具与 CLI 命令都输出机器可读 JSON 与正确的退出码 (`gate-check` 在未通过前以非零退出),可直接接入 GitHub Action / hook / 分支保护。 6. **教训库** — 可选:失败经验可沉淀为可复用静态规则(见“配置”)。 7. **工具链** — dsh 工具 `review_run`、`review_status`、`review_approve`、 `review_request_changes`、`review_reject`、`review_acknowledge`、`gate_check`、 `review_export`;以及独立 `review-gate` CLI。 --- ## 工作原理(简述) - **会话** 由(稳定的仓库标识, 差异范围)确定,因此提交的记录在任何检出/CI 机器上 都保持同一标识。基于差异 + 规则 + 策略的确定性 **指纹** 标识被评审内容;内容未变时 复用该轮(幂等),绝不重复写入审计。 - 评审项具有**基于内容生成的稳定 id**,因此确认(acknowledge)与人工确认清单可在 内容完全相同的重复评审之间保持一致。*新轮次*(内容或策略变化)需要重新确认。 - **门禁** 综合自动规则与审批状态得出唯一状态: | 状态 | 含义 | | --- | --- | | `open` | 已创建,尚未评审(无轮次) | | `blocked` | 自动门禁未通过,或存在 `request_changes`/`reject` | | `passed` | 自动门禁通过,等待审批 | | `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 工作区。 ### 安装 ```sh npm install -g review-gate # 面向任意 git 仓库的独立 CLI ``` 或作为 dsh bundle 安装(见下文)。 ### 使用 CLI ```sh # 在某个 git 仓库内 review-gate run --json # 评审工作区相对 HEAD 的差异 review-gate status --json review-gate gate-check --mode merge # 仅当可合并时退出码为 0 ``` 本地构建与测试: ```sh 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 规范: ```js // package.json "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } ``` `cordis.patch.yml` 向 profile 层插入 `review-gate` 一行;部署时可覆盖其 `config` (补丁按整行替换,需写全所有字段)。像其他 bundle 一样安装: ```sh dsh plugin --profile add ./review-gate dsh --profile --patch ./review-gate/cordis.patch.yml ``` 插件导出 `name` / `inject` / `apply(ctx, config)`,并在 `ctx.tools` 上注册工具 (见“dsh 工具”)。LLM 辅助评审在 `config.llm.enabled` 开启后,于调用时惰性解析 `ctx.llm`,可自动发现后挂载的模型层;模型层不可用时写入 `llm.warn` 审计事件并继续—— 静态规则的评审项仍然主导门禁。 ### 配置 在 `/.review-gate.config.json`(CLI 读取)和/或插件行 `config` 中放置: ```json { "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 --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: ```ts 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 [scope] [options] run | status | approve | reject | request-changes | acknowledge gate-check | export | audit | init | version Scope: working | staged | commit: | range:.. (默认 working) --dir 要评审的仓库 --config --force 内容未变也强制新一轮 --mode gate|merge --reviewer --comment --reason --format json|markdown(export) --out --actor