agents-gitflow-guard 0.0.4 → 0.0.5

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, and Codex.
5
+ A configurable branch-role guard for AI coding agents — [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH), Claude Code, Codex, and OpenCode.
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
 
@@ -309,7 +309,7 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
309
309
 
310
310
  The package declares `dsh.bundle.patch`, so `dsh plugin add` automatically makes it a profile layer — no manual profile editing.
311
311
 
312
- **Claude Code / Codex hooks** — the same guard inside those agents, no DSH required. This repo ships project configs at `.claude/settings.json` (Claude Code) and `.codex/hooks.json` (Codex); any other repo adds its own:
312
+ **Claude Code / Codex / OpenCode 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) and `.opencode/hook/hooks.yaml` (OpenCode); any other repo adds its own:
313
313
 
314
314
  ```jsonc
315
315
  // Claude Code — .claude/settings.json
@@ -333,9 +333,19 @@ The package declares `dsh.bundle.patch`, so `dsh plugin add` automatically makes
333
333
  }
334
334
  ```
335
335
 
336
- - The hook reads the payload on stdin and answers with that platform's protocol: Claude Code → `exit 2` (stderr is the reason + "next step" hint); Codex → JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}` on stdout (Codex also accepts the legacy `{"decision":"block","reason":...}` shape, which `--platform antigravity` uses).
337
- - Only `PreToolUse` is needed: the guard blocks *before* the command runs. There is no permit to consume afterwards, so no `PostToolUse` hooks are required.
338
- - Use an **absolute path** to the binary — hook subprocesses may not inherit your shell `PATH`. `${CLAUDE_PROJECT_DIR}/bin/gitflow-guard.mjs` (Claude Code) or `node bin/gitflow-guard.mjs` (Codex, runs from the project working directory) also work from a checkout.
336
+ ```yaml
337
+ # OpenCode .opencode/hook/hooks.yaml
338
+ hooks:
339
+ - id: gitflow-guard
340
+ event: tool.before.bash
341
+ actions:
342
+ - bash: |
343
+ node "$OPENCODE_PROJECT_DIR/bin/gitflow-guard.mjs" check --platform opencode
344
+ ```
345
+
346
+ - 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 (Codex also accepts the legacy `{"decision":"block","reason":...}` shape, which `--platform antigravity` uses).
347
+ - 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.
348
+ - 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) also work from a checkout.
339
349
  - Fully opt-in: the hook does nothing unless the repo has `gitflow-guard.config.json` with `enabled: true`.
340
350
 
341
351
  ---
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。
5
+ 一个可自由配置分支角色的流程守卫,为 AI 编码 agent 而生——[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)、Claude Code、Codex、OpenCode
6
6
  你自己定义分支——**集成分支**(feature 经 PR/MR 合入)、**预览分支**(环境终点)、**生产分支**、**归档分支**——每个角色各自配规则。agent 无法跳过流程,敏感合并始终留在你手上。
7
7
 
8
8
  [English](README.md) · [许可证](LICENSE)
@@ -306,7 +306,7 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
306
306
 
307
307
  包自带 `dsh.bundle.patch` 声明,`dsh plugin add` 自动把它挂为 profile 层,无需手工编辑 profile。
308
308
 
309
- **Claude Code / Codex hook**——同一守卫也能在这些 agent 里跑,不依赖 DSH。本仓库已自带 `.claude/settings.json`(Claude Code)和 `.codex/hooks.json`(Codex);其他仓库加自己的 hooks:
309
+ **Claude Code / Codex / OpenCode hook**——同一守卫也能在这些 agent 里跑,不依赖 DSH。本仓库已自带 `.claude/settings.json`(Claude Code)、`.codex/hooks.json`(Codex)和 `.opencode/hook/hooks.yaml`(OpenCode);其他仓库加自己的 hooks:
310
310
 
311
311
  ```jsonc
312
312
  // Claude Code — .claude/settings.json
@@ -330,9 +330,19 @@ dsh plugin --profile web add file:/path/to/agents-gitflow-guard
330
330
  }
331
331
  ```
332
332
 
333
- - hook 读 stdin payload,按**各平台协议**作答:Claude Code → `exit 2`(stderr 展示原因 + "下一步"提示);Codex → stdout 输出 JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}`(Codex 也兼容旧的 `{"decision":"block","reason":...}` 形状,`--platform antigravity` 用的就是它)。
334
- - 只需要 `PreToolUse`:守卫在命令执行*之前*拦截;没有特许可事后消费,因此无需 `PostToolUse` 钩子。
335
- - 用**绝对路径**指向二进制——hook 子进程不一定继承你的 shell PATH。Claude Code 用 `${CLAUDE_PROJECT_DIR}/bin/gitflow-guard.mjs`,Codex 用 `node bin/gitflow-guard.mjs`(在项目目录执行)也可以。
333
+ ```yaml
334
+ # OpenCode .opencode/hook/hooks.yaml
335
+ hooks:
336
+ - id: gitflow-guard
337
+ event: tool.before.bash
338
+ actions:
339
+ - bash: |
340
+ node "$OPENCODE_PROJECT_DIR/bin/gitflow-guard.mjs" check --platform opencode
341
+ ```
342
+
343
+ - hook 读 stdin payload,按**各平台协议**作答:Claude Code / OpenCode → `exit 2`(stderr 展示原因 + "下一步"提示);Codex → stdout 输出 JSON `{"hookSpecificOutput":{"permissionDecision":"deny",...}}`(Codex 也兼容旧的 `{"decision":"block","reason":...}` 形状,`--platform antigravity` 用的就是它)。
344
+ - 只需要**执行前事件**:守卫在命令执行*之前*拦截;没有特许可事后消费,因此无需执行后钩子。
345
+ - 用**绝对路径**指向二进制——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`(均在项目目录执行)也可以。
336
346
  - 完全 opt-in:仓库没有 `gitflow-guard.config.json`(或 `enabled` 非 true)时 hook 什么都不做。
337
347
 
338
348
  ---
package/lib/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as findRepoRoot, d as resolveLocale, f as loadConfig, i as formatDeny, l as gitRunner, m as classify, o as stateDir, p as roleMatches, r as evaluateCommand, s as currentBranch, u as makeT } from "./src-LvZrsHEn.mjs";
1
+ import { c as findRepoRoot, d as resolveLocale, f as loadConfig, i as formatDeny, l as gitRunner, m as classify, o as stateDir, p as roleMatches, r as evaluateCommand, s as currentBranch, u as makeT } from "./src-2TtpUFC9.mjs";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  //#region src/platform.ts
@@ -30,6 +30,9 @@ function extractHookPayload(raw, platform = "auto") {
30
30
  if (plat === "claude" || plat === "codex") {
31
31
  command = str(j.tool_input?.command);
32
32
  cwd = str(j.cwd);
33
+ } else if (plat === "opencode") {
34
+ command = str(j.tool_args?.command) || str(j.tool_args?.cmd);
35
+ cwd = str(j.cwd);
33
36
  } else if (plat === "copilot") {
34
37
  command = str(j.tool_input?.command) || str(j.toolArgs?.command);
35
38
  cwd = str(j.cwd);
@@ -45,12 +48,13 @@ function extractHookPayload(raw, platform = "auto") {
45
48
  event: eventFrom(j.hook_event_name)
46
49
  };
47
50
  }
48
- /** 按 payload 判别平台: 非空 turn_id→codex, toolCall→antigravity, 其余→claude */
51
+ /** 按 payload 判别平台: 非空 turn_id→codex, toolCall→antigravity, tool_args→opencode, 其余→claude */
49
52
  function detectPlatform(raw) {
50
53
  const j = parseRaw(raw);
51
54
  if (!j) return "claude";
52
55
  if (j.turn_id) return "codex";
53
56
  if (j.toolCall) return "antigravity";
57
+ if (j.tool_args) return "opencode";
54
58
  return "claude";
55
59
  }
56
60
  /** deny 编码: 各平台的拦截协议(exit 码 + stdout/stderr) */
@@ -60,6 +64,10 @@ function encodeDeny(platform, reason) {
60
64
  exitCode: 2,
61
65
  stderr: reason
62
66
  };
67
+ case "opencode": return {
68
+ exitCode: 2,
69
+ stderr: reason
70
+ };
63
71
  case "codex": return {
64
72
  exitCode: 0,
65
73
  stdout: JSON.stringify({ hookSpecificOutput: {
package/lib/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as name, i as formatDeny, n as apply, o as stateDir, r as evaluateCommand, t as appendAudit } from "./src-LvZrsHEn.mjs";
1
+ import { a as name, i as formatDeny, n as apply, o as stateDir, r as evaluateCommand, t as appendAudit } from "./src-2TtpUFC9.mjs";
2
2
  export { appendAudit, apply, evaluateCommand, formatDeny, name, stateDir };
@@ -418,13 +418,13 @@ const en = {
418
418
  Usage:
419
419
  gitflow-guard status [--repo <path>]
420
420
  gitflow-guard audit [--lines <count>] [--repo <path>]
421
- gitflow-guard check [--platform <claude|auto>] [--command "<cmd>"] [--repo <path>]
421
+ gitflow-guard check [--platform <auto|claude|codex|opencode|antigravity>] [--command "<cmd>"] [--repo <path>]
422
422
  gitflow-guard --help
423
423
 
424
424
  Notes:
425
425
  status/audit are read-only; the agent can self-inspect.
426
- check reads the hook payload on stdin (exit 0 = allow / 2 = block) and is meant for
427
- pre/post hooks of agents such as Claude Code.`
426
+ check reads the hook payload on stdin (platform-specific protocol: claude/opencode exit 2,
427
+ codex/antigravity JSON on stdout) and is meant for pre/post hooks of AI agents.`
428
428
  };
429
429
  const zh = {
430
430
  "role.integration": () => "集成分支",
@@ -488,12 +488,13 @@ const zh = {
488
488
  用法:
489
489
  gitflow-guard status [--repo <路径>]
490
490
  gitflow-guard audit [--lines <数量>] [--repo <路径>]
491
- gitflow-guard check [--platform <claude|auto>] [--command "<cmd>"] [--repo <路径>]
491
+ gitflow-guard check [--platform <auto|claude|codex|opencode|antigravity>] [--command "<cmd>"] [--repo <路径>]
492
492
  gitflow-guard --help
493
493
 
494
494
  说明:
495
495
  status/audit 只读, agent 可自查。
496
- check 读 stdin hook payload 做门禁(exit 0=放行 / 2=拦截), 供 Claude Code 等 agent 的 pre/post hook 调用。`
496
+ check 读 stdin hook payload 做门禁(平台协议: claude/opencode exit 2, codex/antigravity stdout JSON),
497
+ 供 Claude Code / Codex / OpenCode 等 agent 的 pre/post hook 调用。`
497
498
  };
498
499
  const MESSAGE_KEYS = Object.keys(en);
499
500
  /** key 合法性与 en/zh 双字典完整性检查(开发期一次) */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agents-gitflow-guard",
3
- "version": "0.0.4",
4
- "description": "A configurable branch-role guard for AI coding agents (DSH / Claude Code / Codex) — integration/preview/production/archive, each with its own update rules",
3
+ "version": "0.0.5",
4
+ "description": "A configurable branch-role guard for AI coding agents (DSH / Claude Code / Codex / OpenCode) — integration/preview/production/archive, each with its own update rules",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "lib/index.mjs",
@@ -28,6 +28,7 @@
28
28
  "deepseek-harness",
29
29
  "claude-code",
30
30
  "codex",
31
+ "opencode",
31
32
  "plugin",
32
33
  "hook",
33
34
  "gitflow",