Repository navigation
Releases: FeatureAgents/AgentsGitFlowController
Releases · FeatureAgents/AgentsGitFlowController
Release list
v0.1.8
- fix(dsh): judge a git command in the directory it actually runs in — the DSH adapter resolved the repository and current branch from the session directory (
exec.agent.session.header.cwd) only, so abash/pwshcall that ran elsewhere was judged against the wrong checkout: from a session rooted onmain,git merge developwithworkdirset to a feature worktree,cd <worktree> && git merge developandgit -C <worktree> merge developwere refused as "Merging into archive branch(main)", and the reverse (session on a feature worktree, command aimed at themaincheckout) was allowed;apply()now starts from the tool'sworkdir(orcwd) argument, applies leadingcd/pushdsteps and the gated git command's-Coptions (new pureresolveSegmentCwdsinsrc/classify.ts, see the next entry for the per-segment rules), and falls back to the session directory's repository when the resolved directory is not inside one; covered bytests/classify.spec.tsand a real-git main checkout + linked worktree suite intests/index.spec.ts—— DSH 适配层按命令实际运行的目录判定:此前仓库与当前分支只取会话目录(exec.agent.session.header.cwd),在别处运行的bash/pwsh调用会按错误的检出判定——会话停在main时,workdir指向 feature worktree 的git merge develop、cd <worktree> && git merge develop与git -C <worktree> merge develop被误拒为「合并进归档分支 main」,反向(会话在 feature worktree、命令打到main检出)则被放行;现apply()以工具的workdir(兼容cwd)参数为起点,依次应用前导cd/pushd与受门禁 git 段的-C(新增纯函数src/classify.ts的resolveSegmentCwds,逐段规则见下一条),推演出的目录不在任何仓库内时回落到会话目录的仓库;由tests/classify.spec.ts与tests/index.spec.ts的真实 git 主检出 + linked worktree 用例覆盖。 - fix(dsh): judge every gated segment in its own directory — the first fix resolved one directory (the first gated git segment's
-C) and judged the whole command against it, so a later segment that runs elsewhere was never judged where it really runs: from a session on a feature worktree,git -C <archive checkout> merge develop && git push origin feature/xwas allowed, and so weregit push origin feature/wt && git -C <archive checkout> merge developand, from a session on the archive checkout,git -C <worktree> merge develop && git merge develop; a step that cannot be resolved statically (cd $VAR,cd ~,cd -,popd, globs,git -C "$D", a subshell or command group) used to fall back to the starting directory, which letcd $VAR && git merge developthrough from a feature worktree;resolveSegmentCwds(replacesresolveCommandCwd) now derives the directory of each gated segment separately (workdir/cwd→ leadingcd/pushd→ that segment's owngit -C), andapply()denies the command (audited, in the repository's configured locale, and only when a candidate repository has the guard enabled — otherwise it passes through as before) when the gated segments resolve to different directories or when any gated segment's directory cannot be determined statically, and otherwise judges all of them in the one shared directory; a step that cannot be resolved only matters when a gated segment follows it (git merge develop && cd $VARis still judged as before). Out of scope, unchanged:cdscoping inside command groups and subshells, directories inside wrappers (env/sudo/sh -c/command/builtin) and nested contexts ($(...), backticks, shell keywords such asthen/do),--git-dir/--work-tree/GIT_DIRredirection, allowing different subdirectories of one repository, and unifying the command-line hook channels (tracked separately) —— 受门禁段各自按其实际运行的目录判定:上一条修复只推演一个目录(首个受门禁 git 段的-C)并拿它判定整条命令,后面在别处运行的段从未按真实目录判定——会话在功能工作树时,git -C <归档检出> merge develop && git push origin feature/x、git push origin feature/wt && git -C <归档检出> merge develop被放行,会话在归档检出时git -C <工作树> merge develop && git merge develop同样被放行;无法静态确定的步骤(cd $VAR、cd ~、cd -、popd、通配符、git -C "$D"、子 shell 与命令组)此前回落到起点目录,使功能工作树会话里的cd $VAR && git merge develop被放行;现resolveSegmentCwds(取代resolveCommandCwd)为每个受门禁段分别推演目录(workdir/cwd→ 前导cd/pushd→ 该段自身的git -C),apply()在各受门禁段目录不一致、或任一受门禁段的目录无法静态确定时拒绝整条命令(写审计、按仓库配置的语言出文案,且仅当候选仓库中有启用守卫的仓库时才拒绝,否则与此前一样放行),全部一致时按这一个共同目录判定;无法静态确定的步骤只有其后仍有受门禁段时才触发拒绝(git merge develop && cd $VAR判定不变)。本次不做、行为不变:命令组与子 shell 内cd的作用域推演、包装器(env/sudo/sh -c/command/builtin)内部与嵌套语境($(...)、反引号、then/do等 shell 关键字)里的目录、--git-dir/--work-tree/GIT_DIR重定向、同一仓库内不同子目录的跨目录放行、命令行钩子通道的统一(另开议题);由tests/classify.spec.ts与tests/index.spec.ts的真实 git 主检出 + linked worktree 用例覆盖(双向不一致 / 同目录不误伤 / 无法确定即拒绝)。
v0.1.7
- fix(cli,docs): use the published package name in
npxcommands and exposeagents-gitflow-guardinpackage.json#bin— the first-screen demo snippet across all 11 READMEs,cli.demo.wireinsrc/i18n.ts(en/zh), anddocs/assets/demo.svgpreviously invokednpx gitflow-guard ..., which only worked on machines where the CLI was already onPATHand failed with404 Not Foundfrom the npm registry on any fresh machine (while leaving the unclaimedgitflow-guardpackage name open to squatting);package.json#binnow exposes bothgitflow-guardandagents-gitflow-guardpointing tobin/gitflow-guard.mjs, everynpxcommand in the 11 READMEs,src/i18n.tsand the regenerateddocs/assets/demo.svgnow usesnpx agents-gitflow-guard ..., andtests/doc-consistency.spec.tsplustests/cli.spec.tsguard against barenpx gitflow-guardregressions —— 修复npx首屏命令使用未注册包名的问题并在package.json#bin同步暴露agents-gitflow-guard:此前 11 语言 README 首屏演示代码、src/i18n.ts(中英双语cli.demo.wire)与docs/assets/demo.svg均写npx gitflow-guard ...,仅在已全局安装使gitflow-guard位于PATH的机器上能运行,未安装的新用户执行即报 npm404 Not Found(且未注册包名gitflow-guard存在被第三方抢注的风险);现package.json#bin同时暴露gitflow-guard与agents-gitflow-guard指向bin/gitflow-guard.mjs,11 语言 README、src/i18n.ts与重新生成的docs/assets/demo.svg统一改为npx agents-gitflow-guard ...,并由tests/doc-consistency.spec.ts与tests/cli.spec.ts机械拦截回退。
v0.1.6
- test(docs): harden the 11-language README checker —
scripts/check-readme-equality.mjsnow resolves every TOC anchor against the real headings, requires the TOC order to match the document's H2 order, and requires every H2 to be listed; heading/TOC parsing is one shared, fence-aware, CRLF-tolerant source (collectHeadings/collectTocItems), and the slug model matchesgithub-slugger(no trim, so a heading ending in " ?" keeps its trailing hyphen). The old checker only counted TOC items, so the two real drifts below passed silently —— 11 语 README 校验器加严:scripts/check-readme-equality.mjs现会校验每个 TOC 锚点都能解析到真实标题、TOC 顺序必须与正文 H2 顺序一致、且每个 H2 必须列入 TOC;标题/TOC 解析合并为唯一事实源(围栏感知、容忍 CRLF),slug 规则对齐 github-slugger(不 trim,标题尾部“空格+标点”保留尾部连字符)。旧校验只数 TOC 条数,下面两处真实漂移因此长期漏检。 - fix(docs): repair four misleading client links in all 11 READMEs — Pi pointed at a 404 (
github.com/mariozechner/pi→pi.dev), ZCode's domain now redirects to an unrelated promo page (zcode.ai→zcode.z.ai, the official site), Antigravity pointed at a GitHub organization page (github.com/google-deepmind→antigravity.google), and OpenCode at its legacy repository (github.com/opencode-ai/opencode→opencode.ai) —— 修正 11 语 README 的四个误导外链:Pi 原本指向 404(github.com/mariozechner/pi→pi.dev);ZCode 原域名已跳转到无关推广页(zcode.ai→ 官方站zcode.z.ai);Antigravity 原本指向 GitHub 组织主页(github.com/google-deepmind→antigravity.google);OpenCode 原本指向旧仓库(github.com/opencode-ai/opencode→opencode.ai)。 - fix(docs): repair the French TOC anchor and reorder every TOC to document order —
#voyez-le-à-loeuvre--une-démo-live-de-30-secondesnever resolved (a ligature was missing from the slug), and all 11 TOCs still listed the demo section third although 0.1.2 moved that section to the first screen. Three duplicated paragraphs are dropped at the same time: thewirerecap in the hook-mechanism section, the FAQ config-error example that repeats the configuration reference, and the FAQ coffee line that repeats the Support section —— 修复法语 TOC 锚点并让 11 语目录顺序与正文一致:#voyez-le-à-loeuvre--…因漏字符从未解析成功;11 语目录也都仍把演示段排在第三位,而 0.1.2 已把它移到首屏。同时删除三处重复段落:钩子机制段的wire复述、FAQ 里与配置参考重复的配置错误示例、以及 FAQ 里与 Support 段重复的咖啡句。
v0.1.5
- fix(pi): start the guard as
node <bundled runner>by default —createPiExtension()used to default to the baregitflow-guardcommand, which Windows cannot start without a shell (extension-less npm shim or.cmd), so the spawn error was swallowed by the fail-open path and the extension silently stopped guarding (verified on Windows 2026-10-06);resolvePiBin()now returns[process.execPath, resolveRunnerPath()],GITFLOW_GUARD_BINstill overrides it, and the verification matrix asserts the default and runs a real CLI round-trip without injectingbin/run—— Pi 扩展默认执行器改为node <随包 runner>:此前默认走 PATH 上的gitflow-guard,而 Windows 不带 shell 无法启动无扩展名 shim 或.cmd,spawn 失败被降级路径吞掉,守卫静默失效(2026-10-06 Windows 实测);现resolvePiBin()返回[process.execPath, resolveRunnerPath()],GITFLOW_GUARD_BIN仍可覆盖,复测矩阵改为不注入bin/run直接验证默认执行器并实弹跑一次真实 CLI。 - docs(pi): document user-level wiring — the 11 READMEs, the Pi protocol reference, the
wire --client piguidance and the shipped extension header now describe the user-level install (~/.pi/agent/extensions/+~/.pi/agent/settings.json+ the package installed inside~/.pi/agent, PowerShell junction on Windows) and state that no PATH entry or global npm install is needed —— Pi 用户级接线补进文档:11 语言 README、Pi 协议参考、wire --client pi引导与随包扩展头部说明均补上用户级安装三条(~/.pi/agent/extensions/+~/.pi/agent/settings.json+ 在~/.pi/agent内安装本包;Windows 用 PowerShell junction),并写明不依赖 PATH 与全局 npm 安装。 - docs: drop the remaining section signs in source comments and test names (17 occurrences) — the same replacement as 0.1.4, applied to
.ts/.mjscomments and the dogfood extension header; the only remaining"§"is the literal one quoted in the 0.1.4 changelog entry itself —— 补清源码注释与测试名里的章节符号(17 处):与 0.1.4 同一替换规则,覆盖.ts/.mjs注释与 dogfood 扩展头部;现在唯一剩下的"§"是 0.1.4 条目里描述本次清理时引用的那个字面符号。
v0.1.4
- docs(agents): add a project scope section (AGENTS.md, section 9) — one place that states what the project does (gate correctness, truthful documentation, real usability of the supported clients including Windows, tests green) and what it explicitly does not do (new client integrations, CI-side hard gating, cross-machine audit synchronization, remote policy fetching, filesystem interception, an MCP interception layer, a Copilot plugin, more README languages), plus a two-question rule for any new capability;
docs/design.mdsection 2 remains the authoritative full text —— AGENTS.md 新增第 9 节「项目范围(做什么 / 不做什么)」:一处写明做什么(门禁正确性、文档如实、已支持客户端含 Windows 的真实可用、测试全绿)与明确不做的事(新客户端接入、CI 侧硬门禁、跨机器审计同步、远程策略拉取、文件系统拦截、MCP 拦截层、Copilot 插件、新增语言文档),并给出新增能力的两问决策规则;权威全文仍是docs/design.md第 2 节。 - docs: replace every "§" section sign with plain references (72 occurrences across AGENTS.md, CHANGELOG.md, the 11 READMEs,
docs/design.md,docs/e2e/README.mdand five skill files) — English files now say "section N", Chinese files say "第 N 节"; no meaning changed —— 全库清理「§」章节符号(72 处,覆盖 AGENTS.md、CHANGELOG.md、11 个 README、docs/design.md、docs/e2e/README.md与 5 个技能文件):英文改为 "section N",中文改为「第 N 节」,语义不变。
v0.1.3
- docs(readme): replace the stale roadmap with an honest scope statement — the Roadmap section no longer lists "new agent integrations", "cross-machine audit aggregation", "workflow presets" or "CI hard-gating" as future work; it now states the project's direction (correctness and real-world validation of the existing gate first) and what it deliberately does not plan (new agent integrations, CI-side hard gating, cross-machine audit synchronization, remote policy fetching), so the public page no longer advertises capabilities the project has decided against —— README 路线图改为诚实的范围声明:不再把"更多 Agent 平台接入 / 跨机器审计汇总 / 场景化流程预设 / CI 硬门禁"列为未来计划,改为写明项目方向(先把现有门禁的正确性与真实验证做好)与明确不计划的事项(新 Agent 平台接入、CI 侧硬门禁、跨机器审计同步、远程策略拉取),公开页面不再宣传已被否决的能力。
- docs(readme): align the Development section's structure counts with the structure checker (45 headings / 7 tables / 18 TOC items) —— 开发段的结构数字与结构校验器对齐(45 标题 / 7 表格 / 18 TOC 项)。
v0.1.2
- docs(readme): move the "See it work — a 30-second live demo" section above the fold — the demo section (animated SVG + one-command reproduction) now sits right after the badges and before the Table of Contents in all 11 language READMEs, instead of after the Why section where it took two screens of scrolling to reach; structure moved verbatim, checker constants unchanged (still 45 headings / 7 tables / 21 code blocks / 18 TOC anchors) —— README demo 段上移到首屏:"看它干活——30 秒真机演示"段(动画 SVG + 一条命令复现)从 Why 段之后移到徽章之下、目录之上,11 语言同步;此前要滚两三屏才能看到,现在打开首页即见;结构原样平移,校验器常量不变(仍为 45 标题 / 7 表格 / 21 代码块 / 18 TOC 锚点)。
v0.1.1
- feat(cli): add
gitflow-guard demo— a 30-second live demo that builds a throwaway real-git sandbox repo, runs three real scenes through the sameevaluateCommandcore the agent hooks call (1 allow, 2 denials with the actual why/next), then deletes the sandbox; audit state is redirected inside the sandbox viaGITFLOW_GUARD_STATE_ROOTfor the run, so nothing is left in the user's home or state directories;--cast <file>emits the run as a JSONL event stream; usage text updated in both locales —— 新增gitflow-guard demo:30 秒真机演示——在一次性沙箱仓库里用与 agent hook 完全同一的evaluateCommand核心跑三个真实场景(1 放行、2 拦截,拦截附真实 why/next),退出即删;演示期间经GITFLOW_GUARD_STATE_ROOT把审计状态根指进沙箱,用户主目录与状态目录零残留;--cast <文件>把本次运行落成 JSONL 事件流;双语文案与 usage 同步更新。 - feat(demo-svg): add
scripts/generate-demo-svg.mjs(dev-only, not shipped) that renders thedemo --castJSONL into a SMIL animated SVG (dark terminal, per-event frames, strict escaping, fails loudly on malformed input);docs/assets/demo.svgis generated from a real demo run and embedded in all 11 READMEs —— 新增scripts/generate-demo-svg.mjs(仅仓库内工具,不随包发布):把demo --cast的 JSONL 渲染成 SMIL 动画 SVG(暗色终端、逐事件成帧、严格转义、坏输入响亮失败);docs/assets/demo.svg由真实 demo 运行生成,内嵌进全部 11 语言 README。 - docs(readme): keep claims honest — the intro line and the "Why" section no longer claim agents "can't skip the flow" or call the guard a "hard mechanism"; they now say routine flow violations are blocked before they run with why/next guidance, and that a determined agent can still evade a text-layer guard (linking the existing honest-limits section); a new "See it work — a 30-second live demo" section embeds the generated demo SVG and the one-command reproduction in all 11 languages, with TOC updated (45 headings / 7 tables / 21 code blocks / 18 TOC anchors, checker constants updated accordingly) —— 文档表述诚实化:引言行与 "Why" 段不再宣称 agent "无法跳过流程"、不再称守卫为"硬机制";改为"常规流程违规在执行前被拦截并给出 why/next 引导,存心的 agent 仍可绕过文本层守卫"(链向既有诚实边界段);新增"看它干活——30 秒真机演示"段,内嵌生成的演示 SVG 与一条命令复现,11 语言同步,TOC 更新(45 标题 / 7 表格 / 21 代码块 / 18 TOC 锚点,校验器常量随之更新)。
v0.1.0
v0.0.50
- fix(gate): enforce
mergeByconsistently across all four roles — PR merge checks previously readmergeByonly on production, denied archive merges unconditionally, and ignoredmergeByon integration/preview entirely;decidePrMergenow readsmergeByfor every role with dedicated i18n guidance, keeping each role's established default (integration/preview=anyone,production/archive=user). Behavior change to note: archive merges are no longer denied unconditionally — they are denied unless the archive role explicitly setsmergeBy: "anyone"—— 四角色统一按mergeBy判定:此前 PR 合并检查只对生产分支读取mergeBy、对归档分支无条件拒绝、对集成分支与预览分支完全忽略该配置;现decidePrMerge对四个角色统一读取mergeBy并给出对应国际化提示,各角色沿用既有默认(integration/preview=anyone,production/archive=user)。需注意的行为变化:归档分支不再是"一律拒绝",而是"除显式配置mergeBy: "anyone"外均拒绝"。 - fix(config,gate): strictly anchor
featurePattern—featurePatternregex previously lacked start/end boundary anchors, allowing spoofed branch names likemalicious/feature/footo pass as valid feature branches; default pattern and pattern matching now enforce strict boundary anchors (^(?:...)$) —— 严格首尾锚定featurePattern正则:此前分支角色判断未对featurePattern实施首尾锚定,导致带有前缀的伪装分支名(如malicious/feature/foo)被误判为合法 feature 分支;现默认正则与匹配层均严格约束^(?:...)$。 - fix(platform): identify Cursor payloads when
cursor_versionis omitted — CursorbeforeShellExecutionand top-level{ command, cwd }payloads lackingcursor_versionwere previously misclassified as Claude Code, resulting inexit 2client crashes instead of structuredexit 0with permission JSON;detectPlatformnow inspects top-level command attributes and Cursor hook lifecycle events to reliably identify Cursor and return the standard{ permission: "deny", ... }JSON payload —— 完善 Cursor 平台识别机制:部分 Cursor 事件未携带cursor_version特征导致被误判为 Claude Code 并返回exit 2报错;现通过顶层命令结构与生命周期事件精准识别 Cursor,拦截时严格遵循exit 0与结构化 JSON 拒绝协议。 - fix(wire): preserve JSONC comments and existing hooks during wire and unwire — reading/writing JSON configuration previously discarded comments via standard
JSON.parse/JSON.stringify, and unwiring blanket-deleted entire hook matcher blocks;wirenow usescomment-jsonso comments survive a rewrite (the file is re-serialized with a uniform 2-space indent), and filtering is fine-grained: only the guard's own hook entries are removed, while sibling hooks, pre-existing empty entries, and non-object entries are left intact; unwiringantigravitykeeps the top-level key whenever user-authored content remains in it, except when the guard command sits outside every event array, in which case the key is removed as a whole (legacy migration semantics) —— 保留 JSONC 注释并实现细粒度 Hook 卸载:接线层引入comment-json读写用户配置文件,注释在重写后保留(文件统一以 2 空格缩进重新序列化);卸载只摘除守卫自身的 hook 条目,同 matcher 下的用户自定义 Hook、用户原有的空条目与非对象条目均原样保留;antigravity 卸载时若顶层键内仍有用户自建内容则保留该键,仅当守卫命令落在所有事件数组之外时才整键移除(沿用历史迁移语义)。 - fix(pi): block instead of failing open when the guard subprocess is timed out — the extension's own 10s subprocess timeout raced the guard's internal 10s git budget and killed it first, so a slow git turned into "allow"; the outer timeout is now 45s (above the guard's worst-case budget), a timeout kill is reported as
timedOutand mapped to{ block: true }, andkillSignal: SIGKILLguarantees the kill cannot be ignored —— Pi 扩展超时改为阻断:此前扩展自身的 10s 子进程超时与守卫内部 10s 的 git 预算同量级且先到,慢 git 会被杀成"放行";现外层超时提高到 45s(高于守卫最坏预算),超时被杀标记为timedOut并映射为{ block: true },killSignal: SIGKILL保证杀进程不可被忽略。 - fix(repo): guarantee the 5s/10s runner timeouts actually fire —
execFileused the default SIGTERM, so a child process ignoring that signal kept the guard hanging forever; the git/gh/glab runners now kill with SIGKILL —— 保证 5s/10s 熔断真正生效:execFile原先使用默认 SIGTERM,忽略该信号的子进程会让守卫永久挂起;现 git/gh/glab 三个 runner 一律用 SIGKILL 终结。 - fix(index,cli): keep non-git commands out of the timeout path and audit timeout denials — the DSH plugin probed the repository before knowing whether the command was git-related, so a hung git denied unrelated commands such as
npm test, and timeout denials were not recorded at all; the plugin now has the same classify fast path as the CLI, and timeout denials are written toaudit.jsonlwhenever a repository root is known (afindRepoRoottimeout has no repository to attribute to and is reported on stderr instead) —— DSH 插件此前在判断命令是否 git 相关之前就探测仓库,git 卡死会连带拒绝npm test这类无关命令,且超时拒绝不留痕;现插件与 CLI 采用同一 classify 快路径,超时拒绝在能定位到仓库根时写入audit.jsonl(findRepoRoot自身超时时没有可归属的仓库,改为在 stderr 报告)。 - test(matrix): count skipped cases as failures — the decision matrix silently skipped rows whose sandbox branch was missing, so a broken sandbox could shrink coverage without turning the run red; skips are now reported and counted into FAIL —— 矩阵把跳过计为失败:此前沙箱缺分支的行会被静默跳过,沙箱损坏会悄悄缩小覆盖而不变红;现跳过会被报告并计入 FAIL。
- chore(package): ship third-party notices for bundled code —
comment-json,esprimaandarray-timsortare inlined intolib/, so their licenses now travel with the package (THIRD-PARTY-NOTICES.md) —— 随包附第三方声明:comment-json、esprima、array-timsort被内联进lib/,其许可文本随包分发(THIRD-PARTY-NOTICES.md)。 - fix(repo,pi): add timeout control for external CLI and git runner child processes —
ghandglabCLI calls previously lacked timeout bounds and could hang indefinitely on network failure or auth prompts; runners now enforce a 5-second timeout for external CLIs and a 10-second timeout for git/pi child processes —— 外部子进程增加超时熔断:gh/glab等外部 CLI 子进程增加 5 秒超时保护,本地git与 Pi 扩展增加 10 秒超时,防止网络卡顿或鉴权挂死导致守卫进程永久阻塞。 - fix(repo,gate): fail closed when worktree status query fails —
getWorktreeStatuspreviously caught git failures (e.g.index.locklocks) and returned a clean status, allowing dirty worktrees to bypass clean-worktree gates; it now returnsnullon failure, and worktree gates fail closed by rejecting sensitive operations when worktree status cannot be determined —— 修复工作区状态查询失败时的假干净漏洞:getWorktreeStatus在 git 报错时不再虚假返回干净状态,改为返回null;门禁在工作区状态不可知时遵循安全失败(fail-closed)原则坚决阻断。 - ci(release): run
test:git-matrixandtest:realflowin release verification — the 169-case git decision matrix and realflow E2E tests are now executed within the release workflow verification suite before tagging and publishing —— 发布流水线补充 Git 决策矩阵与真机流回归:在发版校验阶段加入test:git-matrix与test:realflow,防止缺陷版本流入发布环节。 - test(pi): enforce strict branch assertions in
test-pi-extension.sh— post-state branch immutability checks previously used|| echowhich masked failures and reported PASS even if a branch was illegally moved; the script now tracks assertion failures and exits with a non-zero exit code on failure —— 严密 Pi 扩展测试断言:移除屏蔽非零退出码的容错逻辑,分支被篡改时立即输出错误并中断退出。 - fix(wire): keep user data intact during fine-grained filtering — the filtering introduced in this batch silently deleted non-object array entries and user-authored empty entries on every wire/unwire; filtering now recycles only the entries that became empty because the guard's own command was removed,
antigravityunwiring walks every event array under its top-level key, and the key is kept whenever user-authored content remains in it —— 修复本批引入的非破坏性回归:细粒度过滤会在每次 wire/unwire 时静默删除数组中的非对象条目与用户原有的空条目;现仅回收"因摘除守卫自身命令而变空"的条目,antigravity 卸载遍历顶层键内所有事件数组,且键内仍有用户内容时保留该键。 - fix(repo,gate,cli): fail closed when a git query times out — the 5s/10s timeouts added in this batch funneled "killed by timeout" into the same bucket as ordinary failures, so branch/upstream lookups that timed out degraded to “unprotected” and allowed the command; runners now surface
timedOut, repo helpers raiseRunnerTimeoutError, and the gate, DSH plugin and CLIcheckpaths all deny with a dedicated message instead of failing open —— git 查询超时改为保守拒绝:本批新增的 5s/10s 超时把"超时被杀"与普通失败混在一起,分支/上游查询一旦超时会静默降级为"不受保护"而放行;现 runner 显式暴露timedOut,仓库查询抛RunnerTimeoutError,门禁、DSH 插件与 CLIcheck三条路径均以专属文案拒绝,不再 fail-open。 - test(matrix): stop counting guard crashes as legitimate allows —
scripts/test-git-matrix.shmapped every exit code other than 2 toallow, so an internal crash (exit 1) could masquerade as a real allow; only 0 (allow) and 2 (deny) are protocol results now, and anything else is counted as FAIL —— 矩阵不再把守卫崩溃记成放行:此前check()把所有非 2 退出码都记为 allow,守卫内部崩溃(exit 1)会被伪装成合法放行;现只有 0(放行)与 2(拦截)属协议内结果,其余一律计 FAIL 并单列计数。 - test(matrix): cover platform auto-detection — the verification matrix always passed
--platform, so the new Cursor heuristics had no end-to-end coverage; the Cursor block now also runsgitflow-guard checkwithout--platformand asserts the{"permission":"deny"}payload for a payload withoutcursor_version—— 矩阵补自动判别覆盖:此前验证矩阵恒传--platform,新的 Cursor 启发式没有端到端兜底;现 Cursor 区块额外以不带--platform的方式实弹断言无cursor_version的 payload 仍返回 Cursor 拒绝协议。 - ci(release): provide the E2E git identity per step — the release workflow wrote a global git identity into the runner (
git config --global), leaking into every later git invocation of the job; the two E2E suites now receive identity through step-level environment variables —— 发布工作流不再写全局 git 配置:此前用git config --global给 runner 写入全局身份,会波及该作业后续所有 git 调用;现改为步骤级环境变量,仅对两个 E2E 套件生效。 - docs(readme): document whole-string anchoring of
featurePattern— patterns are compiled as^(?:…)$, so prefix/substring-style patterns no longer match and prefix spoofing (malicious/feature/x) is rejected; the regex-safety bullet says so in all 11 languages, anddocs/design.mdrecords the rule with its anti-spoofing rationale —— 11 语言 README 与docs/design.md补记featurePattern整串锚定语义:模式按^(?:…)$编译,前缀/子串式写法会失配,前缀伪装(malicious/feature/x)不再被认作 feature 分支。 - test(wire,repo,gate,platform,cli): close the coverage gaps found in review — non-object and pre-existing empty hook entries survive wire+unwire, an entry mixing user and guard commands unwires to the user command only (codex/zcode),
antigravitymulti-event unwire keeps user content, a real 50 ms timeout boundary plusRunnerTimeoutErrorpr...