agents-gitflow-guard 0.0.16 → 0.0.17

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 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 Antigravity.
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,7 +42,7 @@ 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.16
45
+ dsh plugin --profile web add agents-gitflow-guard@0.0.17
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).
@@ -312,7 +312,7 @@ The PR/MR target is resolved via `gh pr view` (GitHub) or `glab mr view` (GitLab
312
312
  **From the npm registry** — the standard path, already covered in [Quick Start](#quick-start--30-seconds-to-a-guarded-repo):
313
313
 
314
314
  ```bash
315
- dsh plugin --profile web add agents-gitflow-guard@0.0.16 # pin recommended, see note above
315
+ dsh plugin --profile web add agents-gitflow-guard@0.0.17 # pin recommended, see note above
316
316
  ```
317
317
 
318
318
  Then restart DSH. Upgrades are the same command, followed by another restart.
@@ -326,7 +326,7 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
326
326
 
327
327
  The package declares `dsh.bundle.patch`, so `dsh plugin add` automatically makes it a profile layer — no manual profile editing.
328
328
 
329
- **Standalone agent hooks** — the same guard inside those agents, no DSH required. 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:
329
+ **Standalone agent hooks** — the same guard inside those agents, no DSH required. This repo ships project configs at `.claude/settings.json` (Claude Code), `.codex/hooks.json` (Codex), `.opencode/hook/hooks.yaml` (OpenCode), `.agents/hooks.json` (Antigravity / Google) and `.pi/settings.json` + `.pi/extensions/gitflow-guard.ts` (Pi); any other repo adds its own:
330
330
 
331
331
  ```jsonc
332
332
  // Claude Code — .claude/settings.json
@@ -371,13 +371,26 @@ hooks:
371
371
  }
372
372
  ```
373
373
 
374
+ ```jsonc
375
+ // Pi — .pi/settings.json (extensions resolve relative to .pi)
376
+ { "extensions": ["extensions/gitflow-guard.ts"] }
377
+ ```
378
+
379
+ 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:
380
+
381
+ ```bash
382
+ npm i -D agents-gitflow-guard
383
+ mkdir -p .pi/extensions
384
+ cp node_modules/agents-gitflow-guard/pi/gitflow-guard.ts .pi/extensions/gitflow-guard.ts
385
+ ```
386
+
374
387
  **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
388
 
376
389
  - [Allowing and denying tool use (GitHub Docs)](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools)
377
390
  - [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
391
  - 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
392
 
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).
393
+ - 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
394
  - 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
395
  - Use an **absolute path** to the binary — hook subprocesses may not inherit your shell `PATH`. `${CLAUDE_PROJECT_DIR}/bin/gitflow-guard.mjs` (Claude Code), `node bin/gitflow-guard.mjs` (Codex, runs from the project working directory), or `$OPENCODE_PROJECT_DIR/bin/gitflow-guard.mjs` (OpenCode) or `node bin/gitflow-guard.mjs` (Antigravity, relative to the workspace `.agents/` dir) also work from a checkout.
383
396
  - Fully opt-in: the hook does nothing unless the repo has `gitflow-guard.config.json` with `enabled: true`.
@@ -494,12 +507,12 @@ npm install
494
507
  npm test # unit tests: classify / gate / config / cli / repo / platform / i18n / index / accuracy-audit
495
508
  npm run typecheck # tsc --noEmit, 0 errors
496
509
  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
510
+ npm run verify:matrix # continuous cross-agent regression: DSH logic + zh-locale regression + Claude Code / Codex / OpenCode / Antigravity hook wiring + Pi extension
498
511
  ```
499
512
 
500
513
  **Rule**: any logic change must pass a 0-error build + all green tests + a green `verify:matrix` before done.
501
514
 
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.)
515
+ **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
516
 
504
517
  ---
505
518
 
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,7 +41,7 @@
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.16
44
+ dsh plugin --profile web add agents-gitflow-guard@0.0.17
45
45
  ```
46
46
 
47
47
  > **版本坑**: 裸 `add` 装的是安装时刻的 `latest`——在 npm/pnpm 注册表缓存或镜像陈旧的机器上可能拿到旧版本。看到版本不对就锁版本。pnpm 打印的 peer 依赖 *警告* 属预期: DSH 启动时经共享模块回退提供 `@deepseek-ai/cordis` / `@deepseek-ai/dsh-tools`(插件正常工作)。
@@ -308,7 +308,7 @@ PR/MR 目标通过 `gh pr view`(GitHub)或 `glab mr view`(GitLab)解析;没有
308
308
  **从 npm registry**——标准路径,已在[快速开始](#快速开始30-秒用上)覆盖:
309
309
 
310
310
  ```bash
311
- dsh plugin --profile web add agents-gitflow-guard@0.0.16 # 建议锁版本, 见上文提示
311
+ dsh plugin --profile web add agents-gitflow-guard@0.0.17 # 建议锁版本, 见上文提示
312
312
  ```
313
313
 
314
314
  然后重启 DSH。升级用同一命令,再重启一次。
@@ -322,7 +322,7 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
322
322
 
323
323
  包自带 `dsh.bundle.patch` 声明,`dsh plugin add` 自动把它挂为 profile 层,无需手工编辑 profile。
324
324
 
325
- **各 agent 独立 hook**——同一守卫也能在这些 agent 里跑,不依赖 DSH。本仓库已自带 `.claude/settings.json`(Claude Code)、`.codex/hooks.json`(Codex)、`.opencode/hook/hooks.yaml`(OpenCode)和 `.agents/hooks.json`(Antigravity / Google);其他仓库加自己的 hooks:
325
+ **各 agent 独立 hook**——同一守卫也能在这些 agent 里跑,不依赖 DSH。本仓库已自带 `.claude/settings.json`(Claude Code)、`.codex/hooks.json`(Codex)、`.opencode/hook/hooks.yaml`(OpenCode)、`.agents/hooks.json`(Antigravity / Google)和 `.pi/settings.json` + `.pi/extensions/gitflow-guard.ts`(Pi);其他仓库加自己的 hooks:
326
326
 
327
327
  ```jsonc
328
328
  // Claude Code — .claude/settings.json
@@ -367,13 +367,26 @@ hooks:
367
367
  }
368
368
  ```
369
369
 
370
+ ```jsonc
371
+ // Pi — .pi/settings.json(extensions 路径相对 .pi 解析)
372
+ { "extensions": ["extensions/gitflow-guard.ts"] }
373
+ ```
374
+
375
+ Pi 以进程内扩展装载(没有 stdin payload,也没有子进程 hook)。把随包发布的入口装进项目、包留在 devDependencies:
376
+
377
+ ```bash
378
+ npm i -D agents-gitflow-guard
379
+ mkdir -p .pi/extensions
380
+ cp node_modules/agents-gitflow-guard/pi/gitflow-guard.ts .pi/extensions/gitflow-guard.ts
381
+ ```
382
+
370
383
  **GitHub Copilot —— 故意不提供 hook**。Copilot 自带这套守卫的原生能力: 工具级 **allow/deny/ask** 权限 + 项目 **rules**(`rules.json` + `AGENTS.md`)。对 Copilot 用户,直接引官方文档即可,不需要我们的插件:
371
384
 
372
385
  - [允许和拒绝工具使用(GitHub Docs)](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools)
373
386
  - [为 Copilot coding agent 添加自定义规则(GitHub Docs)](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-rules-for-the-copilot-coding-agent)
374
387
  - 可选: Copilot 也有官方 [hooks 系统](https://docs.github.com/en/copilot/reference/hooks-reference)(`preToolUse` → `permissionDecision:"deny"`),想要命令级拦截可以自己接。
375
388
 
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 值)。
389
+ - 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
390
  - 只需要**执行前事件**:守卫在命令执行*之前*拦截;没有特许可事后消费,因此无需执行后钩子。
378
391
  - 用**绝对路径**指向二进制——hook 子进程不一定继承你的 shell PATH。Claude Code 用 `${CLAUDE_PROJECT_DIR}/bin/gitflow-guard.mjs`,Codex 用 `node bin/gitflow-guard.mjs`,OpenCode 用 `$OPENCODE_PROJECT_DIR/bin/gitflow-guard.mjs`、Antigravity 用 `node bin/gitflow-guard.mjs`(相对 workspace `.agents/` 目录)也可以。
379
392
  - 完全 opt-in:仓库没有 `gitflow-guard.config.json`(或 `enabled` 非 true)时 hook 什么都不做。
@@ -490,12 +503,12 @@ npm install
490
503
  npm test # 单测: classify / gate / config / cli / repo / platform / i18n / index / accuracy-audit
491
504
  npm run typecheck # tsc --noEmit, 0 Error
492
505
  npm run build # tsdown → lib/(CLI 与插件共用)
493
- npm run verify:matrix # 连续复测矩阵: DSH 逻辑 + zh 文案回归 + Claude Code / Codex / OpenCode / Antigravity hook 编码
506
+ npm run verify:matrix # 连续复测矩阵: DSH 逻辑 + zh 文案回归 + Claude Code / Codex / OpenCode / Antigravity hook 编码 + Pi 扩展
494
507
  ```
495
508
 
496
509
  **铁律**:任何逻辑改动必须 0 Error 构建 + 单测全绿 + 连续复测矩阵(`verify:matrix`)全绿后才算完成。
497
510
 
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 为进程内插件不走 stdin-hook 清单,见该节例外说明。)
511
+ **接入新的 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
512
 
500
513
  ---
501
514
 
package/lib/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as classify, c as currentBranch, d as loadConfig, f as roleMatches, g as resolveLocale, i as formatDeny, l as findRepoRoot, m as makeT, o as stateDir, r as evaluateCommand, u as gitRunner } from "./src-p6q9dCIr.mjs";
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, h as registerLocale, i as formatDeny, n as apply, o as stateDir, p as MESSAGE_KEYS, r as evaluateCommand, s as userStateRoot, t as appendAudit } from "./src-p6q9dCIr.mjs";
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 { classify as _, name as a, currentBranch as c, loadConfig as d, roleMatches as f, resolveLocale as g, registerLocale as h, formatDeny as i, findRepoRoot as l, makeT as m, apply as n, stateDir as o, MESSAGE_KEYS as p, evaluateCommand as r, userStateRoot as s, appendAudit as t, gitRunner as u };
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.16",
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.17",
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()