agents-gitflow-guard 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -14
- package/README.zh.md +41 -14
- package/lib/cli.mjs +1 -1
- package/lib/index.d.mts +44 -1
- package/lib/index.mjs +2 -2
- package/lib/{src-p6q9dCIr.mjs → src-BQYC4N6b.mjs} +48 -1
- package/package.json +6 -2
- package/pi/gitflow-guard.ts +11 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Are you tired of agents skipping your GitFlow?**
|
|
4
4
|
|
|
5
|
-
A configurable branch-role guard for AI coding agents — [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH), Claude Code, Codex, OpenCode, and
|
|
5
|
+
A configurable branch-role guard for AI coding agents — [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH), Claude Code, Codex, OpenCode, Antigravity, and Pi.
|
|
6
6
|
You define your own branches —
|
|
7
7
|
**integration** (features merge in via PR/MR), **preview** (env endpoints), **production**, **archive** — each with its own update rules. Agents can't skip the flow, and sensitive merges stay in your hands.
|
|
8
8
|
|
|
@@ -42,11 +42,13 @@ You define your own branches —
|
|
|
42
42
|
# installs the latest release
|
|
43
43
|
dsh plugin --profile web add agents-gitflow-guard
|
|
44
44
|
# ...or pin an exact known-good version (recommended; also bypasses stale registry caches)
|
|
45
|
-
dsh plugin --profile web add agents-gitflow-guard@0.0.
|
|
45
|
+
dsh plugin --profile web add agents-gitflow-guard@0.0.18
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
> **Version gotcha**: a bare `add` resolves whatever `latest` is at install time — on machines behind a stale npm/pnpm registry cache or mirror it may install an old version. If the installed version looks wrong, pin it explicitly. The peer-dependency *warning* pnpm may print is expected: DSH supplies `@deepseek-ai/cordis` / `@deepseek-ai/dsh-tools` through its shared profile module fallback at startup (the plugin works normally).
|
|
49
49
|
|
|
50
|
+
Using another agent? The same npm package also serves Claude Code, Codex, OpenCode, Antigravity, and Pi — see the per-agent install table in [Installation in detail](#installation-in-detail).
|
|
51
|
+
|
|
50
52
|
**Step 2 — configure**, create `gitflow-guard.config.json` in your **project root**:
|
|
51
53
|
|
|
52
54
|
```jsonc
|
|
@@ -307,12 +309,18 @@ The PR/MR target is resolved via `gh pr view` (GitHub) or `glab mr view` (GitLab
|
|
|
307
309
|
---
|
|
308
310
|
## Installation in detail
|
|
309
311
|
|
|
310
|
-
**Prerequisite**:
|
|
312
|
+
**Prerequisite**: **Node.js ≥ 22** on your `PATH` (the package `engines` floor and the lowest CI matrix tier). Every client consumes the **same npm package** `agents-gitflow-guard` — only the mounting step differs.
|
|
313
|
+
|
|
314
|
+
| Agent | Install command | After that |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| DSH | `dsh plugin --profile web add agents-gitflow-guard@0.0.18` | restart DSH — the plugin auto-mounts as a profile layer |
|
|
317
|
+
| Claude Code · Codex · OpenCode · Antigravity | `npm i -g agents-gitflow-guard@0.0.18` | wire a hook to the `gitflow-guard` binary (below) |
|
|
318
|
+
| Pi | `npm i -D agents-gitflow-guard@0.0.18` | copy `pi/gitflow-guard.ts` into `.pi/extensions/` (below) |
|
|
311
319
|
|
|
312
|
-
**
|
|
320
|
+
**DSH — in-process plugin** (the standard path, already covered in [Quick Start](#quick-start--30-seconds-to-a-guarded-repo)):
|
|
313
321
|
|
|
314
322
|
```bash
|
|
315
|
-
dsh plugin --profile web add agents-gitflow-guard@0.0.
|
|
323
|
+
dsh plugin --profile web add agents-gitflow-guard@0.0.18 # pin recommended, see note above
|
|
316
324
|
```
|
|
317
325
|
|
|
318
326
|
Then restart DSH. Upgrades are the same command, followed by another restart.
|
|
@@ -326,14 +334,20 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
|
|
|
326
334
|
|
|
327
335
|
The package declares `dsh.bundle.patch`, so `dsh plugin add` automatically makes it a profile layer — no manual profile editing.
|
|
328
336
|
|
|
329
|
-
**Standalone agent hooks** —
|
|
337
|
+
**Standalone agent hooks** — Claude Code / Codex / OpenCode / Antigravity, no DSH required. Install the CLI once, then reference the `gitflow-guard` binary in each hook config:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npm i -g agents-gitflow-guard@0.0.18 # provides the `gitflow-guard` binary
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
This repo ships project configs at `.claude/settings.json` (Claude Code), `.codex/hooks.json` (Codex), `.opencode/hook/hooks.yaml` (OpenCode) and `.agents/hooks.json` (Antigravity / Google); any other repo adds its own:
|
|
330
344
|
|
|
331
345
|
```jsonc
|
|
332
346
|
// Claude Code — .claude/settings.json
|
|
333
347
|
{
|
|
334
348
|
"hooks": {
|
|
335
349
|
"PreToolUse": [
|
|
336
|
-
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "
|
|
350
|
+
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "gitflow-guard check --platform claude" }] }
|
|
337
351
|
]
|
|
338
352
|
}
|
|
339
353
|
}
|
|
@@ -344,7 +358,7 @@ The package declares `dsh.bundle.patch`, so `dsh plugin add` automatically makes
|
|
|
344
358
|
{
|
|
345
359
|
"hooks": {
|
|
346
360
|
"PreToolUse": [
|
|
347
|
-
{ "matcher": "^Bash$", "hooks": [{ "type": "command", "command": "
|
|
361
|
+
{ "matcher": "^Bash$", "hooks": [{ "type": "command", "command": "gitflow-guard check --platform codex" }] }
|
|
348
362
|
]
|
|
349
363
|
}
|
|
350
364
|
}
|
|
@@ -357,7 +371,7 @@ hooks:
|
|
|
357
371
|
event: tool.before.bash
|
|
358
372
|
actions:
|
|
359
373
|
- bash: |
|
|
360
|
-
|
|
374
|
+
gitflow-guard check --platform opencode
|
|
361
375
|
```
|
|
362
376
|
|
|
363
377
|
```json
|
|
@@ -365,21 +379,34 @@ hooks:
|
|
|
365
379
|
{
|
|
366
380
|
"gitflow-guard": {
|
|
367
381
|
"PreToolUse": [
|
|
368
|
-
{ "matcher": "run_command", "hooks": [ { "type": "command", "command": "
|
|
382
|
+
{ "matcher": "run_command", "hooks": [ { "type": "command", "command": "gitflow-guard check --platform antigravity" } ] }
|
|
369
383
|
]
|
|
370
384
|
}
|
|
371
385
|
}
|
|
372
386
|
```
|
|
373
387
|
|
|
388
|
+
```jsonc
|
|
389
|
+
// Pi — .pi/settings.json (extensions resolve relative to .pi)
|
|
390
|
+
{ "extensions": ["extensions/gitflow-guard.ts"] }
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Pi loads extensions in-process (no stdin payload, no subprocess hook). Install the shipped entry point into the project and keep the package in devDependencies:
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
npm i -D agents-gitflow-guard@0.0.18
|
|
397
|
+
mkdir -p .pi/extensions
|
|
398
|
+
cp node_modules/agents-gitflow-guard/pi/gitflow-guard.ts .pi/extensions/gitflow-guard.ts
|
|
399
|
+
```
|
|
400
|
+
|
|
374
401
|
**GitHub Copilot — deliberately no hook here.** Copilot ships its own guardrails for exactly this job: per-tool **allow/deny/ask** permissions and project **rules** (`rules.json` + `AGENTS.md`). Point Copilot users at the official docs instead of a plugin hook:
|
|
375
402
|
|
|
376
403
|
- [Allowing and denying tool use (GitHub Docs)](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools)
|
|
377
404
|
- [Adding custom rules for the Copilot coding agent (GitHub Docs)](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-rules-for-the-copilot-coding-agent)
|
|
378
405
|
- Optional: Copilot also has a [hooks system](https://docs.github.com/en/copilot/reference/hooks-reference) (`preToolUse` → `permissionDecision:"deny"`) if you want command-level interception.
|
|
379
406
|
|
|
380
|
-
- The hook reads the payload on stdin and answers with that platform's protocol: Claude Code / OpenCode → `exit 2` (stderr is the reason + "next step" hint); Codex → JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}` on stdout; Antigravity → JSON `{"decision":"deny","reason":...}` on stdout with `exit 0` (Antigravity requires exit 0 and rejects `hookSpecificOutput` / non-allow values).
|
|
407
|
+
- The hook reads the payload on stdin and answers with that platform's protocol: Claude Code / OpenCode → `exit 2` (stderr is the reason + "next step" hint); Codex → JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}` on stdout; Antigravity → JSON `{"decision":"deny","reason":...}` on stdout with `exit 0` (Antigravity requires exit 0 and rejects `hookSpecificOutput` / non-allow values). Pi has no stdin protocol: the in-process extension listens to the official `tool_call` event and denies via its return value `{ block: true, reason }` (the CLI subprocess only speaks the internal exit-2 contract).
|
|
381
408
|
- Only the pre-tool event is needed: the guard blocks *before* the command runs. There is no permit to consume afterwards, so no post-tool hooks are required.
|
|
382
|
-
-
|
|
409
|
+
- The examples above call the globally-installed `gitflow-guard` (`npm i -g`). If a hook subprocess can't see it on its `PATH`, point at the full binary path from `npm bin -g` — hook subprocesses may not inherit your interactive shell `PATH`. The `bin/gitflow-guard.mjs` paths in this repo's shipped configs only work from a checkout.
|
|
383
410
|
- Fully opt-in: the hook does nothing unless the repo has `gitflow-guard.config.json` with `enabled: true`.
|
|
384
411
|
|
|
385
412
|
---
|
|
@@ -494,12 +521,12 @@ npm install
|
|
|
494
521
|
npm test # unit tests: classify / gate / config / cli / repo / platform / i18n / index / accuracy-audit
|
|
495
522
|
npm run typecheck # tsc --noEmit, 0 errors
|
|
496
523
|
npm run build # tsdown → lib/ (CLI and plugin share the build)
|
|
497
|
-
npm run verify:matrix # continuous cross-agent regression: DSH logic + zh-locale regression + Claude Code / Codex / OpenCode / Antigravity hook wiring
|
|
524
|
+
npm run verify:matrix # continuous cross-agent regression: DSH logic + zh-locale regression + Claude Code / Codex / OpenCode / Antigravity hook wiring + Pi extension
|
|
498
525
|
```
|
|
499
526
|
|
|
500
527
|
**Rule**: any logic change must pass a 0-error build + all green tests + a green `verify:matrix` before done.
|
|
501
528
|
|
|
502
|
-
**Adding a new agent client** (e.g. Cursor / Windsurf): all of these must change in one commit — `src/platform.ts` (+tests, `HookPlatform` union), a repo hook config beside `.claude/settings.json` / `.codex/hooks.json`, `.agents/hooks/references/<tool>.md`, `scripts/verify-matrix.mjs`, the README hook section and the top tagline, `package.json` description/keywords, and `CHANGELOG`. Done only when `npm run verify:matrix` is green. (Same checklist in [AGENTS.md](AGENTS.md) §8.)
|
|
529
|
+
**Adding a new agent client** (e.g. Cursor / Windsurf): all of these must change in one commit — `src/platform.ts` (+tests, `HookPlatform` union), a repo hook config beside `.claude/settings.json` / `.codex/hooks.json`, `.agents/hooks/references/<tool>.md`, `scripts/verify-matrix.mjs`, the README hook section and the top tagline, `package.json` description/keywords, and `CHANGELOG`. Done only when `npm run verify:matrix` is green. (Same checklist in [AGENTS.md](AGENTS.md) §8; DSH and Pi are in-process clients covered by the exceptions noted there.)
|
|
503
530
|
|
|
504
531
|
---
|
|
505
532
|
|
package/README.zh.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **有没有受够了 agent 跳过你的合入流程?**
|
|
4
4
|
|
|
5
|
-
一个可自由配置分支角色的流程守卫,为 AI 编码 agent 而生——[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)、Claude Code、Codex、OpenCode、Antigravity。
|
|
5
|
+
一个可自由配置分支角色的流程守卫,为 AI 编码 agent 而生——[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)、Claude Code、Codex、OpenCode、Antigravity、Pi。
|
|
6
6
|
你自己定义分支——**集成分支**(feature 经 PR/MR 合入)、**预览分支**(环境终点)、**生产分支**、**归档分支**——每个角色各自配规则。agent 无法跳过流程,敏感合并始终留在你手上。
|
|
7
7
|
|
|
8
8
|
[English](README.md) · [许可证](LICENSE)
|
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
# 安装最新版
|
|
42
42
|
dsh plugin --profile web add agents-gitflow-guard
|
|
43
43
|
# ...或锁定已知良好版本(推荐; 同时绕开 registry 陈旧缓存)
|
|
44
|
-
dsh plugin --profile web add agents-gitflow-guard@0.0.
|
|
44
|
+
dsh plugin --profile web add agents-gitflow-guard@0.0.18
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
> **版本坑**: 裸 `add` 装的是安装时刻的 `latest`——在 npm/pnpm 注册表缓存或镜像陈旧的机器上可能拿到旧版本。看到版本不对就锁版本。pnpm 打印的 peer 依赖 *警告* 属预期: DSH 启动时经共享模块回退提供 `@deepseek-ai/cordis` / `@deepseek-ai/dsh-tools`(插件正常工作)。
|
|
48
48
|
|
|
49
|
+
用的是别的 agent? 同一个 npm 包也适用于 Claude Code / Codex / OpenCode / Antigravity / Pi——见[安装详解](#安装详解)的逐客户端安装表。
|
|
50
|
+
|
|
49
51
|
**第 2 步——配置**,在**项目根目录**创建 `gitflow-guard.config.json`:
|
|
50
52
|
|
|
51
53
|
```jsonc
|
|
@@ -303,12 +305,18 @@ PR/MR 目标通过 `gh pr view`(GitHub)或 `glab mr view`(GitLab)解析;没有
|
|
|
303
305
|
---
|
|
304
306
|
## 安装详解
|
|
305
307
|
|
|
306
|
-
|
|
308
|
+
**前置**:`PATH` 上有 **Node.js ≥ 22**(与包 `engines` 及 CI 矩阵最低档一致)。所有客户端都吃**同一个 npm 包** `agents-gitflow-guard`——只有挂载步骤不同。
|
|
309
|
+
|
|
310
|
+
| 客户端 | 安装命令 | 装完再做什么 |
|
|
311
|
+
|---|---|---|
|
|
312
|
+
| DSH | `dsh plugin --profile web add agents-gitflow-guard@0.0.18` | 重启 DSH——插件自动挂为 profile 层 |
|
|
313
|
+
| Claude Code · Codex · OpenCode · Antigravity | `npm i -g agents-gitflow-guard@0.0.18` | 在各自 hook 配置里指向 `gitflow-guard` 二进制(见下) |
|
|
314
|
+
| Pi | `npm i -D agents-gitflow-guard@0.0.18` | 把 `pi/gitflow-guard.ts` 拷进 `.pi/extensions/`(见下) |
|
|
307
315
|
|
|
308
|
-
|
|
316
|
+
**DSH —— 进程内插件**(标准路径,已在[快速开始](#快速开始30-秒用上)覆盖):
|
|
309
317
|
|
|
310
318
|
```bash
|
|
311
|
-
dsh plugin --profile web add agents-gitflow-guard@0.0.
|
|
319
|
+
dsh plugin --profile web add agents-gitflow-guard@0.0.18 # 建议锁版本, 见上文提示
|
|
312
320
|
```
|
|
313
321
|
|
|
314
322
|
然后重启 DSH。升级用同一命令,再重启一次。
|
|
@@ -322,14 +330,20 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
|
|
|
322
330
|
|
|
323
331
|
包自带 `dsh.bundle.patch` 声明,`dsh plugin add` 自动把它挂为 profile 层,无需手工编辑 profile。
|
|
324
332
|
|
|
325
|
-
**各 agent 独立 hook
|
|
333
|
+
**各 agent 独立 hook**——Claude Code / Codex / OpenCode / Antigravity,不依赖 DSH。全局装一次 CLI,然后引用 `gitflow-guard` 二进制:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
npm i -g agents-gitflow-guard@0.0.18 # 提供 `gitflow-guard` 二进制
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
本仓库已自带 `.claude/settings.json`(Claude Code)、`.codex/hooks.json`(Codex)、`.opencode/hook/hooks.yaml`(OpenCode)和 `.agents/hooks.json`(Antigravity / Google);其他仓库加自己的 hooks:
|
|
326
340
|
|
|
327
341
|
```jsonc
|
|
328
342
|
// Claude Code — .claude/settings.json
|
|
329
343
|
{
|
|
330
344
|
"hooks": {
|
|
331
345
|
"PreToolUse": [
|
|
332
|
-
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "
|
|
346
|
+
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "gitflow-guard check --platform claude" }] }
|
|
333
347
|
]
|
|
334
348
|
}
|
|
335
349
|
}
|
|
@@ -340,7 +354,7 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
|
|
|
340
354
|
{
|
|
341
355
|
"hooks": {
|
|
342
356
|
"PreToolUse": [
|
|
343
|
-
{ "matcher": "^Bash$", "hooks": [{ "type": "command", "command": "
|
|
357
|
+
{ "matcher": "^Bash$", "hooks": [{ "type": "command", "command": "gitflow-guard check --platform codex" }] }
|
|
344
358
|
]
|
|
345
359
|
}
|
|
346
360
|
}
|
|
@@ -353,7 +367,7 @@ hooks:
|
|
|
353
367
|
event: tool.before.bash
|
|
354
368
|
actions:
|
|
355
369
|
- bash: |
|
|
356
|
-
|
|
370
|
+
gitflow-guard check --platform opencode
|
|
357
371
|
```
|
|
358
372
|
|
|
359
373
|
```json
|
|
@@ -361,21 +375,34 @@ hooks:
|
|
|
361
375
|
{
|
|
362
376
|
"gitflow-guard": {
|
|
363
377
|
"PreToolUse": [
|
|
364
|
-
{ "matcher": "run_command", "hooks": [ { "type": "command", "command": "
|
|
378
|
+
{ "matcher": "run_command", "hooks": [ { "type": "command", "command": "gitflow-guard check --platform antigravity" } ] }
|
|
365
379
|
]
|
|
366
380
|
}
|
|
367
381
|
}
|
|
368
382
|
```
|
|
369
383
|
|
|
384
|
+
```jsonc
|
|
385
|
+
// Pi — .pi/settings.json(extensions 路径相对 .pi 解析)
|
|
386
|
+
{ "extensions": ["extensions/gitflow-guard.ts"] }
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Pi 以进程内扩展装载(没有 stdin payload,也没有子进程 hook)。把随包发布的入口装进项目、包留在 devDependencies:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
npm i -D agents-gitflow-guard@0.0.18
|
|
393
|
+
mkdir -p .pi/extensions
|
|
394
|
+
cp node_modules/agents-gitflow-guard/pi/gitflow-guard.ts .pi/extensions/gitflow-guard.ts
|
|
395
|
+
```
|
|
396
|
+
|
|
370
397
|
**GitHub Copilot —— 故意不提供 hook**。Copilot 自带这套守卫的原生能力: 工具级 **allow/deny/ask** 权限 + 项目 **rules**(`rules.json` + `AGENTS.md`)。对 Copilot 用户,直接引官方文档即可,不需要我们的插件:
|
|
371
398
|
|
|
372
399
|
- [允许和拒绝工具使用(GitHub Docs)](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools)
|
|
373
400
|
- [为 Copilot coding agent 添加自定义规则(GitHub Docs)](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-rules-for-the-copilot-coding-agent)
|
|
374
401
|
- 可选: Copilot 也有官方 [hooks 系统](https://docs.github.com/en/copilot/reference/hooks-reference)(`preToolUse` → `permissionDecision:"deny"`),想要命令级拦截可以自己接。
|
|
375
402
|
|
|
376
|
-
- hook 读 stdin payload,按**各平台协议**作答:Claude Code / OpenCode → `exit 2`(stderr 展示原因 + "下一步"提示);Codex → stdout 输出 JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}`;Antigravity → stdout 输出 `{"decision":"deny","reason":...}` 且 **exit 0**(Antigravity 要求 exit 0,拒绝 hookSpecificOutput/非 allow 值)。
|
|
403
|
+
- hook 读 stdin payload,按**各平台协议**作答:Claude Code / OpenCode → `exit 2`(stderr 展示原因 + "下一步"提示);Codex → stdout 输出 JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}`;Antigravity → stdout 输出 `{"decision":"deny","reason":...}` 且 **exit 0**(Antigravity 要求 exit 0,拒绝 hookSpecificOutput/非 allow 值)。Pi 没有 stdin 协议:进程内扩展监听官方 `tool_call` 事件,经返回值 `{ block: true, reason }` 拒绝(守卫 CLI 子进程只承载内部 exit-2 契约)。
|
|
377
404
|
- 只需要**执行前事件**:守卫在命令执行*之前*拦截;没有特许可事后消费,因此无需执行后钩子。
|
|
378
|
-
-
|
|
405
|
+
- 上面示例调的是全局安装的 `gitflow-guard`(`npm i -g`)。若 hook 子进程在它的 `PATH` 里找不到,就指向 `npm bin -g` 给出的完整二进制路径——hook 子进程不一定继承你交互 shell 的 PATH。本仓库自带配置里的 `bin/gitflow-guard.mjs` 路径只对 checkout 贡献者有效。
|
|
379
406
|
- 完全 opt-in:仓库没有 `gitflow-guard.config.json`(或 `enabled` 非 true)时 hook 什么都不做。
|
|
380
407
|
|
|
381
408
|
---
|
|
@@ -490,12 +517,12 @@ npm install
|
|
|
490
517
|
npm test # 单测: classify / gate / config / cli / repo / platform / i18n / index / accuracy-audit
|
|
491
518
|
npm run typecheck # tsc --noEmit, 0 Error
|
|
492
519
|
npm run build # tsdown → lib/(CLI 与插件共用)
|
|
493
|
-
npm run verify:matrix # 连续复测矩阵: DSH 逻辑 + zh 文案回归 + Claude Code / Codex / OpenCode / Antigravity hook 编码
|
|
520
|
+
npm run verify:matrix # 连续复测矩阵: DSH 逻辑 + zh 文案回归 + Claude Code / Codex / OpenCode / Antigravity hook 编码 + Pi 扩展
|
|
494
521
|
```
|
|
495
522
|
|
|
496
523
|
**铁律**:任何逻辑改动必须 0 Error 构建 + 单测全绿 + 连续复测矩阵(`verify:matrix`)全绿后才算完成。
|
|
497
524
|
|
|
498
|
-
**接入新的 agent 客户端**(如 Cursor / Windsurf):以下各项必须在同一个 commit 内完成——`src/platform.ts`(含测试与 `HookPlatform` 联合类型)、`.claude/settings.json` / `.codex/hooks.json` 旁新增一份仓库级 hook 配置、`.agents/hooks/references/<tool>.md`、`scripts/verify-matrix.mjs`、README 双语 hook 段与开头宣传语、`package.json` 的 description/keywords,以及 `CHANGELOG`。`npm run verify:matrix` 全绿才算完成。(同一清单见 [AGENTS.md](AGENTS.md) §8;DSH
|
|
525
|
+
**接入新的 agent 客户端**(如 Cursor / Windsurf):以下各项必须在同一个 commit 内完成——`src/platform.ts`(含测试与 `HookPlatform` 联合类型)、`.claude/settings.json` / `.codex/hooks.json` 旁新增一份仓库级 hook 配置、`.agents/hooks/references/<tool>.md`、`scripts/verify-matrix.mjs`、README 双语 hook 段与开头宣传语、`package.json` 的 description/keywords,以及 `CHANGELOG`。`npm run verify:matrix` 全绿才算完成。(同一清单见 [AGENTS.md](AGENTS.md) §8;DSH 与 Pi 为进程内接入,见该节例外说明。)
|
|
499
526
|
|
|
500
527
|
---
|
|
501
528
|
|
package/lib/cli.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { _ as resolveLocale, d as gitRunner, f as loadConfig, h as makeT, i as formatDeny, l as currentBranch, o as stateDir, p as roleMatches, r as evaluateCommand, u as findRepoRoot, v as classify } from "./src-BQYC4N6b.mjs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
//#region src/platform.ts
|
package/lib/index.d.mts
CHANGED
|
@@ -18,6 +18,49 @@ declare const MESSAGE_KEYS: readonly string[];
|
|
|
18
18
|
*/
|
|
19
19
|
declare function registerLocale(name: string, dict: Dict): void;
|
|
20
20
|
//#endregion
|
|
21
|
+
//#region src/pi.d.ts
|
|
22
|
+
/** Pi 官方 tool_call 事件(只读提取, 与官方 ExtensionAPI 的 ToolCallEvent 对齐) */
|
|
23
|
+
interface PiToolCallEvent {
|
|
24
|
+
toolName: string;
|
|
25
|
+
input?: {
|
|
26
|
+
command?: unknown;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Pi 扩展上下文最小面(官方 ExtensionContext 的 cwd/hasUI 子集) */
|
|
30
|
+
interface PiExtensionContext {
|
|
31
|
+
cwd: string;
|
|
32
|
+
hasUI?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** tool_call 拦截返回值: { block: true, reason } 即拒绝(官方 tool_call 协议) */
|
|
35
|
+
interface PiBlock {
|
|
36
|
+
block: true;
|
|
37
|
+
reason: string;
|
|
38
|
+
}
|
|
39
|
+
type PiToolCallResult = PiBlock | undefined;
|
|
40
|
+
type PiToolCallHandler = (event: PiToolCallEvent, ctx: PiExtensionContext) => Promise<PiToolCallResult> | PiToolCallResult;
|
|
41
|
+
interface PiExtensionAPI {
|
|
42
|
+
on(event: 'tool_call', handler: PiToolCallHandler): void;
|
|
43
|
+
}
|
|
44
|
+
/** 命令执行结果(适配器与守卫 CLI 的进程间契约: 借用 claude 编码 exit 2 + stderr) */
|
|
45
|
+
interface PiRunResult {
|
|
46
|
+
code: number;
|
|
47
|
+
stdout: string;
|
|
48
|
+
stderr: string;
|
|
49
|
+
}
|
|
50
|
+
interface PiExtensionOptions {
|
|
51
|
+
/** 拦截哪些工具的命令文本(默认 bash / powershell, 与 DSH 插件 toolNames 同口径) */
|
|
52
|
+
toolNames?: string[];
|
|
53
|
+
/** 守卫 CLI 可执行(默认 GITFLOW_GUARD_BIN 环境变量 → gitflow-guard); 可为 [node, path] 形式 */
|
|
54
|
+
bin?: string | string[];
|
|
55
|
+
/** 命令执行器(测试注入; 默认真实 execFile) */
|
|
56
|
+
run?: (argv: string[], cwd: string) => Promise<PiRunResult>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 创建 Pi 扩展入口: 返回函数形态与官方扩展默认导出一致(default export (pi) => void)。
|
|
60
|
+
* 监听 tool_call → 提取 bash/powershell 的 command → 守卫 CLI 门禁 → deny 映射为 { block, reason }。
|
|
61
|
+
*/
|
|
62
|
+
declare function createPiExtension(opts?: PiExtensionOptions): (pi: PiExtensionAPI) => void;
|
|
63
|
+
//#endregion
|
|
21
64
|
//#region src/index.d.ts
|
|
22
65
|
declare const name = "gitflow-guard";
|
|
23
66
|
interface PluginConfig {
|
|
@@ -73,4 +116,4 @@ declare function evaluateCommand(command: string, opts: EvaluateOptions): Promis
|
|
|
73
116
|
declare function formatDeny(locale: Locale, why: string, next: string): string;
|
|
74
117
|
declare function apply(ctx: Context, pluginConfig?: PluginConfig): void;
|
|
75
118
|
//#endregion
|
|
76
|
-
export { AuditEntry, type Dict, EvaluateOptions, EvaluateResult, MESSAGE_KEYS, PluginConfig, appendAudit, apply, evaluateCommand, formatDeny, name, registerLocale, stateDir, userStateRoot };
|
|
119
|
+
export { AuditEntry, type Dict, EvaluateOptions, EvaluateResult, MESSAGE_KEYS, type PiExtensionAPI, type PiExtensionContext, type PiExtensionOptions, type PiToolCallEvent, type PiToolCallResult, PluginConfig, appendAudit, apply, createPiExtension, evaluateCommand, formatDeny, name, registerLocale, stateDir, userStateRoot };
|
package/lib/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as name,
|
|
2
|
-
export { MESSAGE_KEYS, appendAudit, apply, evaluateCommand, formatDeny, name, registerLocale, stateDir, userStateRoot };
|
|
1
|
+
import { a as name, c as createPiExtension, g as registerLocale, i as formatDeny, m as MESSAGE_KEYS, n as apply, o as stateDir, r as evaluateCommand, s as userStateRoot, t as appendAudit } from "./src-BQYC4N6b.mjs";
|
|
2
|
+
export { MESSAGE_KEYS, appendAudit, apply, createPiExtension, evaluateCommand, formatDeny, name, registerLocale, stateDir, userStateRoot };
|
|
@@ -1122,6 +1122,53 @@ function resolvePrTarget(info, config) {
|
|
|
1122
1122
|
};
|
|
1123
1123
|
}
|
|
1124
1124
|
//#endregion
|
|
1125
|
+
//#region src/pi.ts
|
|
1126
|
+
const GITISH = /\b(?:git|gh|glab)\b|gitflow-guard/;
|
|
1127
|
+
function execFileResult(cmd, args, cwd) {
|
|
1128
|
+
return new Promise((resolve) => {
|
|
1129
|
+
execFile(cmd, args, { cwd }, (err, stdout, stderr) => {
|
|
1130
|
+
const e = err;
|
|
1131
|
+
resolve({
|
|
1132
|
+
code: e && typeof e.code === "number" ? e.code : e ? -1 : 0,
|
|
1133
|
+
stdout: String(stdout ?? ""),
|
|
1134
|
+
stderr: String(stderr ?? "")
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* 创建 Pi 扩展入口: 返回函数形态与官方扩展默认导出一致(default export (pi) => void)。
|
|
1141
|
+
* 监听 tool_call → 提取 bash/powershell 的 command → 守卫 CLI 门禁 → deny 映射为 { block, reason }。
|
|
1142
|
+
*/
|
|
1143
|
+
function createPiExtension(opts = {}) {
|
|
1144
|
+
const toolNames = new Set(opts.toolNames ?? ["bash", "powershell"]);
|
|
1145
|
+
const bin = opts.bin ?? process.env.GITFLOW_GUARD_BIN ?? "gitflow-guard";
|
|
1146
|
+
const run = opts.run ?? ((argv, cwd) => execFileResult(Array.isArray(bin) ? bin[0] : bin, [...Array.isArray(bin) ? bin.slice(1) : [], ...argv], cwd));
|
|
1147
|
+
return (pi) => {
|
|
1148
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
1149
|
+
try {
|
|
1150
|
+
if (!toolNames.has(event.toolName)) return void 0;
|
|
1151
|
+
const command = typeof event.input?.command === "string" ? event.input.command : "";
|
|
1152
|
+
if (!command || !GITISH.test(command)) return void 0;
|
|
1153
|
+
const res = await run([
|
|
1154
|
+
"check",
|
|
1155
|
+
"--platform",
|
|
1156
|
+
"claude",
|
|
1157
|
+
"--command",
|
|
1158
|
+
command
|
|
1159
|
+
], ctx.cwd);
|
|
1160
|
+
if (res.code === 2) return {
|
|
1161
|
+
block: true,
|
|
1162
|
+
reason: res.stderr.trim() || "blocked by gitflow-guard"
|
|
1163
|
+
};
|
|
1164
|
+
return;
|
|
1165
|
+
} catch {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
});
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
//#endregion
|
|
1125
1172
|
//#region src/index.ts
|
|
1126
1173
|
const name = "gitflow-guard";
|
|
1127
1174
|
/**
|
|
@@ -1291,4 +1338,4 @@ function apply(ctx, pluginConfig = {}) {
|
|
|
1291
1338
|
});
|
|
1292
1339
|
}
|
|
1293
1340
|
//#endregion
|
|
1294
|
-
export {
|
|
1341
|
+
export { resolveLocale as _, name as a, createPiExtension as c, gitRunner as d, loadConfig as f, registerLocale as g, makeT as h, formatDeny as i, currentBranch as l, MESSAGE_KEYS as m, apply as n, stateDir as o, roleMatches as p, evaluateCommand as r, userStateRoot as s, appendAudit as t, findRepoRoot as u, classify as v };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agents-gitflow-guard",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A configurable branch-role guard for AI coding agents (DSH / Claude Code / Codex / OpenCode / Antigravity) — integration/preview/production/archive, each with its own update rules",
|
|
3
|
+
"version": "0.0.18",
|
|
4
|
+
"description": "A configurable branch-role guard for AI coding agents (DSH / Claude Code / Codex / OpenCode / Antigravity / Pi) — integration/preview/production/archive, each with its own update rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"lib",
|
|
19
19
|
"bin",
|
|
20
20
|
"patch.yml",
|
|
21
|
+
"pi",
|
|
21
22
|
"README.md",
|
|
22
23
|
"README.zh.md"
|
|
23
24
|
],
|
|
@@ -32,6 +33,9 @@
|
|
|
32
33
|
"codex",
|
|
33
34
|
"opencode",
|
|
34
35
|
"antigravity",
|
|
36
|
+
"pi",
|
|
37
|
+
"pi-agent",
|
|
38
|
+
"pi-extension",
|
|
35
39
|
"plugin",
|
|
36
40
|
"hook",
|
|
37
41
|
"gitflow",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Pi 扩展入口(随包发布, 可复制): 拦截 bash/powershell 的 git 系命令, 经守卫 CLI 门禁后
|
|
2
|
+
// 以官方 tool_call 协议 { block: true, reason } 拒绝。协议见仓库 .agents/hooks/references/pi.md。
|
|
3
|
+
//
|
|
4
|
+
// 用法(推荐): 复制本文件到 <project>/.pi/extensions/gitflow-guard.ts, 项目 devDependencies
|
|
5
|
+
// 安装 agents-gitflow-guard(jiti 从扩展所在项目解析裸导入); 仓库再配 .pi/settings.json:
|
|
6
|
+
// { "extensions": ["extensions/gitflow-guard.ts"] }
|
|
7
|
+
//
|
|
8
|
+
// 也可以不复制: 手写一行 wrapper 后放任意位置并绝对路径登记进 extensions。
|
|
9
|
+
import { createPiExtension } from 'agents-gitflow-guard'
|
|
10
|
+
|
|
11
|
+
export default createPiExtension()
|