@sabaiway/agent-workflow-kit 1.47.0 → 1.49.0

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +2 -2
  3. package/SKILL.md +1 -1
  4. package/bridges/antigravity-cli-bridge/SKILL.md +1 -1
  5. package/bridges/antigravity-cli-bridge/bin/agy-review.sh +21 -3
  6. package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +3 -2
  7. package/bridges/antigravity-cli-bridge/bin/agy.sh +20 -2
  8. package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +3 -2
  9. package/bridges/antigravity-cli-bridge/capability.json +1 -1
  10. package/bridges/codex-cli-bridge/SKILL.md +1 -1
  11. package/bridges/codex-cli-bridge/bin/codex-exec.sh +20 -2
  12. package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +3 -2
  13. package/bridges/codex-cli-bridge/bin/codex-review.sh +21 -3
  14. package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +3 -2
  15. package/bridges/codex-cli-bridge/capability.json +1 -1
  16. package/capability.json +1 -1
  17. package/package.json +1 -1
  18. package/references/agents/changelog-skeleton.md +1 -0
  19. package/references/agents/gate-triage.md +1 -0
  20. package/references/agents/mechanical-sweep.md +1 -0
  21. package/references/hooks/gate-approve.mjs +120 -18
  22. package/references/modes/hook.md +6 -1
  23. package/references/modes/recommendations.md +8 -6
  24. package/references/modes/setup.md +7 -2
  25. package/references/modes/upgrade.md +9 -9
  26. package/references/modes/velocity.md +4 -2
  27. package/tools/ack-write.mjs +186 -0
  28. package/tools/doc-parity.mjs +14 -0
  29. package/tools/fs-safe.mjs +28 -5
  30. package/tools/gate-hook.mjs +193 -4
  31. package/tools/recommendations.mjs +171 -17
  32. package/tools/setup-backends.mjs +48 -3
  33. package/tools/velocity-profile.mjs +13 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,75 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
4
4
  is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
5
5
  every `migrations/<version>-<slug>.md` newer than it, in semver order.
6
6
 
7
+ ## 1.49.0 — Honesty/robustness bundle: refresh EROFS stated skip · settings integer-overflow parity (AD-056)
8
+
9
+ A small **honesty/robustness** release (kit MINOR carrying the two bridge PATCH bumps in-tarball —
10
+ codex-cli-bridge 2.7.1 + antigravity-cli-bridge 2.6.1; engine 1.17.0 / memory 2.3.0 unchanged; lineage
11
+ head stays `2.0.0`). Two kit/bridge fixes ship here (a third, repo-only dispatcher fix, rides the same
12
+ commit); all three share one theme: **a blocked environment must produce a STATED degrade, never a
13
+ false red — and a real failure stays loud.**
14
+
15
+ - **Refresh under a read-only skills dir is a stated skip, not a false failure.** Under the harness
16
+ session sandbox `~/.claude/skills` is read-only, yet `--refresh-placed` re-syncs even at the current
17
+ version (repair-on-rerun). That write EROFSed into the generic catch → *"could not refresh — … recover
18
+ with setup"*, though both versions were already current AND `setup` hits the same read-only dir. It now
19
+ reports a new **`skipped-readonly`** outcome (exit 0): it names the current version, states the re-sync
20
+ was skipped/incomplete, and names the read-only cause — never claiming a re-sync ran or file integrity
21
+ (a partial copy may precede the block). Only a read-only-class write failure at the copy-write boundary,
22
+ at an equal version, degrades; a read-side / source-side / `linkWrappers` / real-I/O failure, or a
23
+ version-**behind** refresh, stays a loud *could not refresh* (its recovery pointing at a writable
24
+ rerun). The opt-in `setup` placement lane keeps its loud failure. Any drift persists until a writable
25
+ rerun (converge-on-re-run).
26
+ - **Settings integer validation is now shell↔JS exact (Issue-012, Resolved).** The four bridge wrappers'
27
+ shared `aw_settings_valid` integer arms did `(( 10#$v … ))`, which wraps modulo 2^64 on a 19+ digit
28
+ string — the shell **accepted** `18446744073709551916` (2^64+300) while the kit's `settingValueValid`
29
+ (safe-integer) **rejected** it. A shared overflow-safe `aw_int_in_range` helper (byte-identical across
30
+ all four wrappers) strips leading zeros then rejects on a digit count exceeding the max's — never
31
+ running arithmetic on a huge string. A leading-zero **in-range** value (e.g. `000…086400`) still
32
+ passes on both sides; the value is pinned by a new behavioral shell↔JS parity test.
33
+
34
+ ## 1.48.0 — Family-owned neutral ack store + read-prompt-economy hook lane (AD-055, the CLAUDE-CODE-HARNESS-FRICTION cluster)
35
+
36
+ A **feature** release (kit-only — engine 1.17.0, memory 2.3.0, bridges 2.7.0/2.6.0 unchanged) that
37
+ closes two sibling defects where the kit fought the Claude Code host surface. Both land under one ADR
38
+ (AD-055), two commit-anchored segments.
39
+
40
+ - **Part I — the neutral ack store relocates off the host settings schema.** The `sandbox-lane`
41
+ upgrade recommendation converged by writing `agentWorkflow.sandboxLaneAck` into
42
+ `.claude/settings.local.json` — an advertised apply path a Claude Code host blocks twice (the
43
+ Edit-tool settings validator rejects the unknown key; the command sandbox EROFS-denies
44
+ `.claude/settings*.json`). The neutral fingerprint acknowledgement now lives in a **family-owned
45
+ `docs/ai/acks.json`** no host validator guards, written by a new consent-gated **ack writer**
46
+ (`tools/ack-write.mjs`); the legacy settings-scope key is still read for one deprecation window
47
+ (until the next MAJOR). The recommendation's apply line is an executable writer one-liner again.
48
+ - **Part II — the read-prompt-economy hook lane kills read-side Bash prompts at the source.** A
49
+ Claude Code prefix allow rule can never match a `;`/`&&`/`|` COMPOUND even when every segment is
50
+ seeded, so routine read compounds still prompt. The placed gate hook gains an **opt-in read-lane**
51
+ (rung c): with `docs/ai/lanes.json` set to `{ "readLane": true }` (read live per call, fail-closed),
52
+ a command whose every separator-split segment is a plain frozen read-only core command with **zero
53
+ shell metaprogramming** is auto-approved — a conservative closed-world allow bounded by the audited
54
+ core (a standalone opt-in grant). `lanes.json` is a **separate** kit-owned file — `gates.json`, its
55
+ validators and the byte-mirrored template stay untouched. The residual guard (settings-allowed
56
+ singles) additionally trips the bash-5.3 funsub openers, a backslash-newline line-continuation
57
+ splice, and a de-spliced re-scan of quote/backslash/bracket/brace `--output` reconstruction.
58
+ - **`gate-hook --read-lane`** is the consent-gated writer for `lanes.json`: it verifies the placed
59
+ hook is byte-current **and** wired **and** at the deployment stamp head before enabling (a pre-1.48
60
+ hook never reads `lanes.json`), refusing a stale/unwired hook with the delete-to-reseed recovery
61
+ (absolute paths). The upgrade Recommendations advisor surfaces the **read-lane offer** once the hook
62
+ is placed+wired (RISK_NOTED, with a consent-moment posture note; ATTENTION variants when the placed
63
+ hook is stale or missing — no silent dark lane).
64
+ - **Canon honesty.** `velocity.md` (read-side invocation shape), `hook.md` (rung c + `lanes.json` +
65
+ the currency check + delete-to-reseed), the three cheap-agent templates (they grant no Bash — a
66
+ missing `Grep`/`Glob` falls back to the Read tool; a harness-forced Bash read stays plain-single),
67
+ and the README hook row.
68
+
69
+ Reviewed by the codex + agy council across three rounds (agy SHIP ×3; every fixable fold red-first);
70
+ the surviving word-construction-on-a-single major is a documented inherent-layer-residual — a
71
+ string-based residual guard cannot close every shell reconstruction of a write flag without a full
72
+ shell parser or an over-ASK that would defeat the read-prompt-economy goal (rung b is a trust-posture
73
+ convenience, not a sandbox). Dogfooded live on this host: the read-lane currency guard passed on the
74
+ re-placed 1.48 hook and wrote `lanes.json`.
75
+
7
76
  ## 1.47.0 — REPORT-FACTS train: live-fact report contract · batched ledger writer · version-sync wrapper lane · sandbox-lanes canon & bridge contract twins (AD-054)
8
77
 
9
78
  A **feature** release (ships with engine 1.17.0, memory 2.3.0, bridges 2.7.0/2.6.0 bundled) that
package/README.md CHANGED
@@ -240,12 +240,12 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
240
240
  | `/agent-workflow-kit grounding` | any time | **grounded-review facts assembler** — mechanizes populating `agy-review --facts @f`: slices your entry-point's **Hard Constraints** section verbatim (exactly one match, else a loud stop) and/or a plan's decision-bearing sections (`## Approach` + `## Verification` required, `## Decisions (locked)` when present; duplicates stop), under the same byte budget the agy wrapper enforces (minus `--reserve-bytes` for the artifact share), with a loud tail-trim on overflow. `--autonomy` (AD-044) appends the COMPUTED effective autonomy policy from the git-top `docs/ai/autonomy.json` (every red-line + per-activity level, stated source line; absent file → the computed defaults ARE the policy, exit 0; a malformed policy fails CLOSED, exit 1). `--ledger-summary` (AD-049) appends a COMPUTED review-ledger digest for the single in-flight segment (rounds · origins · classifications · verdicts · overrides — unrelated loops excluded), so the reviewer sees the loop's own history without hand-copying. Prints to stdout; `--out` writes **one scratch file only** — system-temp outside the repo ($TMPDIR / /tmp, rewritable) or a **fresh** gitignored in-repo path (create-only, exclusive write; an existing in-repo file, even gitignored, is refused — the `.env` clobber class); tracked, not-ignored-in-repo, other outside-repo, and symlink/non-regular destinations are all refused. Never commits, never runs a subscription CLI. |
241
241
  | `/agent-workflow-kit review-ledger` | any time | **review-round ledger** — turns the review-loop stop rule into a **computed** signal: record each plan-execution review round, its triage, and any recorded **overrides** (`oracle-change` lifts named tampered test files; `red-proof` waives the observed-red proof for exactly one `testId`; v4 adds **`size-cap`** — the exact sanctioned magnitude for a surface over the diff cap, segment-scoped — all loud, durable, auditable waivers, never silent) into a JSONL ledger inside the git dir (never committable), and read the stop decision (`converged > resolved-residual > triage-required > continue`) from the records — never from a remembered rule. **Since v4 every record carries `base` = the HEAD commit and the whole loop is SEGMENT-scoped (AD-048):** round numbering, the caps, and every tooth reset ONLY at a gated commit — a multiphase plan records fully while round 4 within one segment stays refused; `gate-run` records (minted by `gates --record`) make gates-before-review a computed precondition; the triage class **`refuted`** is the honest phantom-finding lane (grounds mandatory); `--telemetry` renders counts-only gate-efficacy data across all loops and both ledgers. `--status` replaces the hand-composed per-round tally; `record --from-receipts` (AD-049) DRAFTS the `backends[]` from the current-fingerprint receipts (verdict per backend, counts from the supplied findings) instead of hand-composing them — a recipe-named backend with no receipt is a loud stop; a **`batch`** verb applies an ordered list of record/classify/override ops in ONE writer call (the prompt-economy lane — the whole envelope is validated structurally first with zero writes, then ops apply sequentially and fail-fast; prior ops stay recorded, append-only); `--check` is a fail-closed gate exit code for `docs/ai/gates.json` (by hand or via the consent-gated seeder). A `fixable-bug` triage **requires its red→green `testId`** (v1..v3 records stay valid on read — old records never enter a segment). The writer refuses a round (past the hard-max, while a triage is pending, or lacking a grounded review receipt) and refuses an override outside its single in-flight loop. Honest residual: records are forgeable — self-discipline, not a security boundary. Never commits, never runs a subscription CLI. |
242
242
  | `/agent-workflow-kit fold-completeness` | any time | **fold-completeness gate** — attests the review loop's folded fixes were proven the HONEST way (no fix theater): the runner executes your suite ONCE under `NODE_V8_COVERAGE`, checks every changed executable line is **executed**, probes every bound `testId` N times (`AW_FOLD_RERUNS`), records content hashes, and scans the test surface for tamper; the `--red` verb observes a test FAILING on the pre-fold tree — **BEFORE the fix** — and mints an **observed-red receipt**. The read-only checker (`--status` / `--check`) then requires, per bound test: the receipt, receipt-precedes-run order, N/N-green probes, and content **custody** (the green test is byte-identical to the one seen failing) — the receipt+custody half waivable for exactly one `testId` by a recorded `red-proof` override; mixed/timed-out probes are QUARANTINE (never converted, no override); **v3 records carry `base` and the proof is segment-scoped (AD-048)** — a committed phase's custody obligations close with its commit, and a receipt never crosses a commit boundary; tampered pre-existing test files fail closed unless covered by a recorded `oracle-change` override. Honest residuals: coverage proves **execution, not assertion**, and records are forgeable — self-discipline, not a security boundary. v1 scope is JS/V8 (pluggable via `AW_FOLD_BOUND_CMD`): changed TS/JSX fails closed, docs/config changes are listed but never block, and **no mutation testing ships**. Wire the gate by hand — the consent-gated seeder deliberately does not offer it yet (JS-only hold). Never commits, never runs a subscription CLI. |
243
- | `/agent-workflow-kit recommendations` | any time (every `upgrade` ends with it) | **read-only deployment advisor** (AD-044) — computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, OS sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe) and renders **verdict-first**: one composed verdict line (does anything need attention?), then each item as **{severity · what · one-line benefit · the exact consent-gated apply one-liner}**. The agent PRESENTS the section in the user's conversational language — every fact and count, nothing added or dropped; commands, paths, hosts and rule strings byte-exact; raw tool block on request — and runs EXACTLY the rendered one-liners only on your yes, surfacing each item's posture note first. Renders **present-even-when-empty** (`no recommendations — flow optimal.`); a failed probe degrades to a stated skip line. Registry strings are fact-true frozen one-line data (posture/risk notes live in the mode doc at the consent moment); the sandbox-lane item is **HAND-APPLY** — the kit never seeds `sandbox.network.allowedDomains` / `filesystem.allowWrite` (the recipe is documented per bridge in `capability.json` `networkHosts` + `writableDirs`; convergence is a neutral fingerprint acknowledgement, never a security key). `--cwd` is required (the target project is explicit); never writes, never commits, never runs a subscription CLI. |
243
+ | `/agent-workflow-kit recommendations` | any time (every `upgrade` ends with it) | **read-only deployment advisor** (AD-044) — computes what in THIS deployment is configured sub-optimally (allowlist not seeded, autonomy render drifted, OS sandbox unavailable, gates undeclared, bridge friction, sandbox-mask clutter, an unacknowledged sandbox recipe) and renders **verdict-first**: one composed verdict line (does anything need attention?), then each item as **{severity · what · one-line benefit · an optional `recipe:` line (sandbox-lane only) · the exact consent-gated apply one-liner}**. The agent PRESENTS the section in the user's conversational language — every fact and count, nothing added or dropped; commands, paths, hosts and rule strings byte-exact; raw tool block on request — and runs EXACTLY the rendered one-liners only on your yes, surfacing each item's posture note first. Renders **present-even-when-empty** (`no recommendations — flow optimal.`); a failed probe degrades to a stated skip line. Registry strings are fact-true frozen one-line data (posture/risk notes live in the mode doc at the consent moment); the kit never seeds `sandbox.network.allowedDomains` / `filesystem.allowWrite` (**HAND-APPLY** territory), and the sandbox-lane item's convergence is a neutral fingerprint acknowledgement recorded by a consent-gated ack writer into `docs/ai/acks.json` — never a security key (the recipe is documented per bridge in `capability.json` `networkHosts` + `writableDirs`). `--cwd` is required (the target project is explicit); never writes, never commits, never runs a subscription CLI. |
244
244
  | `/agent-workflow-kit doc-parity` | any time | **read-only doc-parity lint** (AD-049) — kills the doc-drift class where a mode-contract doc silently lags a code constant (a `--check` doc still reading `300` after the diff cap moved to `400`): a **closed, exported registry** binds each live constant (review caps, schema versions, the ledger's own class/scope vocabulary, and the autonomy-doctor EXIT/status/trusted-dir contract) to the exact token its `references/modes/*.md` contract must carry, and asserts the CURRENT value renders into every bound file — a drifted doc, an unreadable file, or an absent token **fails closed**. The values are sourced from the live imports (never re-typed), so the lint can't itself go stale; adding a binding is adding a checked entry (closed-world, edit-safe). `--check` is a gate exit code for `docs/ai/gates.json`. Never writes, never commits, never runs a subscription CLI. |
245
245
  | `/agent-workflow-kit uninstall` | opt-in, any time | **guarded teardown** — the inverse of `init` / `setup`. Removes only what's **provably ours** (managed skill dirs + bridge wrappers; in a project, the hidden-mode git-ignore block it added + the pre-commit hook it installed); **never deletes** your `docs/ai` / `AGENTS.md` (prints the exact `rm` to run by hand) or your `.claude/settings.json` (prints an **edit** — remove the attribution key, review any velocity `permissions.*` — never an `rm`). Always `--dry-run` first; preflight-then-mutate; never commits. |
246
246
  | `/agent-workflow-kit velocity` | Claude Code · opt-in | **onboarding velocity profile** — seeds a fixed, audited **read-only** allowlist into `.claude/settings.json` so routine read-only commands stop idling on approval prompts while you're away; opt-in `acceptEdits`; plus a **read-only advisory** of likely project gate commands to add by hand. Writes **only** `.claude/settings.json` — **never** allowlists commit/push/publish, never writes `settings.local.json`, never commits. A seeded entry is a **trust posture, not a sandbox** (a runtime residual remains at the settings level — its guard ships as the opt-in `hook` command); a direct commit/push/publish still asks. `--dry-run` first. |
247
247
  | `/agent-workflow-kit agents` | Claude Code · opt-in | **cheap-lane subagents** — places bundled subagent definitions (`.claude/agents/`) pinned to a **cheap model** (haiku, low effort, read-only tools) for mechanical work: extraction sweeps, changelog fact-skeletons, gate-failure triage. Judgment, review, and real code stay on your main lane — these vehicles only extract and draft, and their output is verified. Preview by default (`--apply` writes); an existing customized file is **preserved, never overwritten**; never touches `settings*.json`, never commits. |
248
- | `/agent-workflow-kit hook` | Claude Code · opt-in | **gate-approval hook** — places a self-contained PreToolUse hook (`.claude/hooks/`) and wires it into `.claude/settings.json`: a Bash command **byte-identical** to a gate you declared in `docs/ai/gates.json` (run from the project root) is auto-approved — no prompt, no idle; a seeded read-only command carrying a runtime residual (output redirection, command substitution, `--output` writes) now **asks** even where an allow rule would have silently passed it (proven live — hook `ask` overrides an allow rule). Exact matches only, never patterns; never `deny`; a broken `gates.json` only disables auto-approval, never the guard. Preview by default; never writes `settings.local.json`; never commits. |
248
+ | `/agent-workflow-kit hook` | Claude Code · opt-in | **gate-approval hook** — places a self-contained PreToolUse hook (`.claude/hooks/`) and wires it into `.claude/settings.json`: a Bash command **byte-identical** to a gate you declared in `docs/ai/gates.json` (run from the project root) is auto-approved — no prompt, no idle; a seeded read-only command carrying a runtime residual (output redirection, command substitution, `--output` writes) now **asks** even where an allow rule would have silently passed it (proven live — hook `ask` overrides an allow rule). Exact matches only, never patterns; never `deny`; a broken `gates.json` only disables auto-approval, never the guard. An opt-in **read-lane** (`--read-lane` → `docs/ai/lanes.json`, a **separate** file from `gates.json`) additionally auto-approves *compounds* of seeded read-only commands carrying no shell metaprogramming; `--apply --read-lane` verifies the placed hook is current first (delete-to-reseed otherwise). Preview by default; never writes `settings.local.json`; never commits. |
249
249
  | `/agent-workflow-kit bridge-settings` | opt-in, any time | **host-level bridge settings** — read or change the bridges' `KEY=VALUE` config file (`${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf`), the **one place a knob survives kit upgrades** (it lives outside every kit tree; a refresh never touches it, and now states loudly if it ever overwrote a local edit). First knobs: the **codex Fast tier** (`CODEX_SERVICE_TIER=priority` — ~1.5× speed at a **2.5× credit rate**, quality-neutral, default off — a consented spend), the codex/agy hard timeouts, the review byte cap, the oversized-review add-dir toggle. Allowed keys + value rules come from the bundled bridge manifests; **model/effort are never settable** (the quality guard is untouched). **Previews by default**; refuses an unknown key, an out-of-range value, or a duplicate-carrying file; writes atomically (symlink/TOCTOU-safe). Never commits, never runs a subscription CLI. |
250
250
  | `/agent-workflow-kit autonomy-doctor` | opt-in, any time | **guarded sandbox provisioner "doctor"** — can this machine run the Claude sandbox, and (only with your consent) fix it: macOS Seatbelt built-in / Linux+WSL2 needs `bwrap`+`socat` / native Windows → WSL2. Flagless = **FS-only preview** (the diagnosis, the exact absolute-path command it WOULD run, the exact `--apply <pm>:<pkgs>` consent tuple — runs nothing, never claims ready); `--verify` runs the unprivileged proof (a `bwrap` user-namespace smoke + `socat -V`) — the **only** source of a Linux "ready (verified)" claim; `--apply <pm>:<pkgs>` is the consent-gated privileged install (the tuple must equal the previewed plan; everything executed resolves to absolute paths inside `/usr/bin:/bin:/usr/sbin:/sbin`; the exact command is re-printed immediately before execution), then verifies. Honest loud degrades (unknown PM, untrusted location, nested-sandbox INDETERMINATE, root-unproven) and a stated restart step. Sits **outside every velocity auto-approve tier**; never auto-runs, never writes repo files, never commits. |
251
251
 
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: agent-workflow-kit
3
3
  description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
4
4
  disable-model-invocation: true
5
5
  metadata:
6
- version: '1.47.0'
6
+ version: '1.49.0'
7
7
  ---
8
8
 
9
9
  # agent-workflow-kit
@@ -2,7 +2,7 @@
2
2
  name: antigravity-cli-bridge
3
3
  description: Delegate work to Google's Antigravity CLI (`agy`) — the successor to Gemini CLI — to reach Gemini, Claude, and GPT-OSS models under a Google AI Pro/Ultra subscription from the terminal. Use when the user wants to run a headless `agy` prompt, hand a focused task or second-opinion review to `agy`, install or authenticate Antigravity CLI, check or economise its quota/models, bridge project context into `agy`, set up a second delegated-execution backend beside Codex, or troubleshoot `agy` flags, models, auth, conversations, or its no-JSON headless behaviour.
4
4
  metadata:
5
- version: '2.6.0'
5
+ version: '2.6.1'
6
6
  ---
7
7
 
8
8
  # antigravity-cli-bridge
@@ -132,12 +132,22 @@ aw_settings_known() {
132
132
  *) return 1 ;;
133
133
  esac
134
134
  }
135
+ aw_int_in_range() {
136
+ # All-digits $1 vs [min,max] WITHOUT 64-bit wrap (Issue-012): strip leading zeros, then a longer
137
+ # digit count than max's is unconditionally out of range — never do the arithmetic on a huge string.
138
+ # A leading-zero in-range value still passes (its stripped count is small); all-zeros collapses to
139
+ # "0" (below min>=1). Mirrors the JS settingValueValid safe-integer bound, verified by parity test.
140
+ local n="${1#"${1%%[!0]*}"}" min="$2" max="$3"
141
+ n="${n:-0}"
142
+ (( ${#n} > ${#max} )) && return 1
143
+ (( n >= min && n <= max ))
144
+ }
135
145
  aw_settings_valid() {
136
146
  local k="$1" v="$2" int_re='^[0-9]+$' dur_re='^[0-9]+(\.[0-9]+)?[smhd]$' zero_re='^0+(\.0+)?[smhd]$'
137
147
  case "$k" in
138
148
  CODEX_SERVICE_TIER) [[ "$v" == "priority" ]] ;;
139
- CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 86400 )) ;;
140
- CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 100000000 )) ;;
149
+ CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 86400 ;;
150
+ CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
141
151
  AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
142
152
  AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
143
153
  *) return 1 ;;
@@ -189,6 +199,14 @@ aw_apply_settings() {
189
199
  fi
190
200
  continue
191
201
  fi
202
+ # Normalize an all-digit (integer) value to DECIMAL before export: a leading-zero value the integer
203
+ # arms legitimately accept (000…086400 == 86400) would otherwise read as OCTAL in downstream Bash
204
+ # arithmetic ("value too great for base"). Strip leading zeros, floor "0"; enum/duration (non-digit)
205
+ # and boolean 0/1 are unaffected.
206
+ if [[ "$value" =~ ^[0-9]+$ ]]; then
207
+ value="${value#"${value%%[!0]*}"}"
208
+ value="${value:-0}"
209
+ fi
192
210
  export "$key=$value"
193
211
  done
194
212
  return 0
@@ -199,7 +217,7 @@ DEFAULT_AGY_REVIEW_MODEL="Gemini 3.1 Pro (High)"
199
217
  # Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
200
218
  # version (drift-guarded by agy-review.test.mjs against capability.json).
201
219
  AW_RECEIPT_BACKEND="agy"
202
- AW_BRIDGE_VERSION="2.6.0"
220
+ AW_BRIDGE_VERSION="2.6.1"
203
221
  # `-` not `:-` so an EXPLICIT empty AGY_MODEL= survives (drop --model, use settings.json — agy.sh:52).
204
222
  AGY_MODEL="${AGY_MODEL-$DEFAULT_AGY_REVIEW_MODEL}"
205
223
  # Frontier review models. ANY model is allowed; a sub-frontier one only earns a soft, silenceable warning.
@@ -994,8 +994,9 @@ describe('agy-review.sh — settings surface ⟷ manifest (D6, manifest-pinned)'
994
994
  assert.ok(arm, `no validation arm for ${s.key}`);
995
995
  if (s.kind === 'enum') for (const v of s.values) assert.ok(arm[1].includes(`"${v}"`), `${s.key}: enum value '${v}' not pinned`);
996
996
  if (s.kind === 'integer') {
997
- assert.match(arm[1], new RegExp(`>= ${s.min}\\b`), `${s.key}: min ${s.min} not pinned`);
998
- assert.match(arm[1], new RegExp(`<= ${s.max}\\b`), `${s.key}: max ${s.max} not pinned`);
997
+ // Issue-012 refactor: min/max are pinned as the aw_int_in_range helper's positional bounds
998
+ // (`aw_int_in_range "$v" <min> <max>`) the overflow-safe range check replaced raw arithmetic.
999
+ assert.match(arm[1], new RegExp(`aw_int_in_range "\\$v" ${s.min} ${s.max}\\b`), `${s.key}: min/max ${s.min}/${s.max} not pinned as the aw_int_in_range bounds`);
999
1000
  }
1000
1001
  if (s.kind === 'boolean') assert.ok(arm[1].includes('"0"') && arm[1].includes('"1"'), `${s.key}: boolean 0/1 not pinned`);
1001
1002
  if (s.kind === 'duration') {
@@ -99,12 +99,22 @@ aw_settings_known() {
99
99
  *) return 1 ;;
100
100
  esac
101
101
  }
102
+ aw_int_in_range() {
103
+ # All-digits $1 vs [min,max] WITHOUT 64-bit wrap (Issue-012): strip leading zeros, then a longer
104
+ # digit count than max's is unconditionally out of range — never do the arithmetic on a huge string.
105
+ # A leading-zero in-range value still passes (its stripped count is small); all-zeros collapses to
106
+ # "0" (below min>=1). Mirrors the JS settingValueValid safe-integer bound, verified by parity test.
107
+ local n="${1#"${1%%[!0]*}"}" min="$2" max="$3"
108
+ n="${n:-0}"
109
+ (( ${#n} > ${#max} )) && return 1
110
+ (( n >= min && n <= max ))
111
+ }
102
112
  aw_settings_valid() {
103
113
  local k="$1" v="$2" int_re='^[0-9]+$' dur_re='^[0-9]+(\.[0-9]+)?[smhd]$' zero_re='^0+(\.0+)?[smhd]$'
104
114
  case "$k" in
105
115
  CODEX_SERVICE_TIER) [[ "$v" == "priority" ]] ;;
106
- CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 86400 )) ;;
107
- CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 100000000 )) ;;
116
+ CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 86400 ;;
117
+ CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
108
118
  AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
109
119
  AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
110
120
  *) return 1 ;;
@@ -156,6 +166,14 @@ aw_apply_settings() {
156
166
  fi
157
167
  continue
158
168
  fi
169
+ # Normalize an all-digit (integer) value to DECIMAL before export: a leading-zero value the integer
170
+ # arms legitimately accept (000…086400 == 86400) would otherwise read as OCTAL in downstream Bash
171
+ # arithmetic ("value too great for base"). Strip leading zeros, floor "0"; enum/duration (non-digit)
172
+ # and boolean 0/1 are unaffected.
173
+ if [[ "$value" =~ ^[0-9]+$ ]]; then
174
+ value="${value#"${value%%[!0]*}"}"
175
+ value="${value:-0}"
176
+ fi
159
177
  export "$key=$value"
160
178
  done
161
179
  return 0
@@ -443,8 +443,9 @@ describe('agy.sh — settings surface ⟷ manifest (D6, manifest-pinned)', () =>
443
443
  assert.ok(arm, `no validation arm for ${s.key}`);
444
444
  if (s.kind === 'enum') for (const v of s.values) assert.ok(arm[1].includes(`"${v}"`), `${s.key}: enum value '${v}' not pinned`);
445
445
  if (s.kind === 'integer') {
446
- assert.match(arm[1], new RegExp(`>= ${s.min}\\b`), `${s.key}: min ${s.min} not pinned`);
447
- assert.match(arm[1], new RegExp(`<= ${s.max}\\b`), `${s.key}: max ${s.max} not pinned`);
446
+ // Issue-012 refactor: min/max are pinned as the aw_int_in_range helper's positional bounds
447
+ // (`aw_int_in_range "$v" <min> <max>`) the overflow-safe range check replaced raw arithmetic.
448
+ assert.match(arm[1], new RegExp(`aw_int_in_range "\\$v" ${s.min} ${s.max}\\b`), `${s.key}: min/max ${s.min}/${s.max} not pinned as the aw_int_in_range bounds`);
448
449
  }
449
450
  if (s.kind === 'boolean') assert.ok(arm[1].includes('"0"') && arm[1].includes('"1"'), `${s.key}: boolean 0/1 not pinned`);
450
451
  if (s.kind === 'duration') {
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "antigravity-cli-bridge",
5
5
  "kind": "execution-backend",
6
- "version": "2.6.0",
6
+ "version": "2.6.1",
7
7
  "provides": ["review", "probe"],
8
8
  "roles": {
9
9
  "review": {
@@ -2,7 +2,7 @@
2
2
  name: codex-cli-bridge
3
3
  description: Delegate work to the OpenAI Codex CLI (`codex`) under a ChatGPT subscription — run plan/instruction EXECUTION in a sandboxed workspace, or get a read-only ADVISORY review of a plan or working-tree diff — as a second delegated-execution backend beside Antigravity. Use when the user wants to hand a bounded coding task or plan to `codex exec`, get a second-opinion review from codex, install or authenticate Codex CLI, understand its sandbox/network/approval policy, drive codex efficiently from the main agent (exec vs review, resume, the commit boundary), bridge project context (`AGENTS.md`) into codex, or troubleshoot codex flags, models, auth, or its no-TTY headless behaviour.
4
4
  metadata:
5
- version: '2.7.0'
5
+ version: '2.7.1'
6
6
  ---
7
7
 
8
8
  # codex-cli-bridge
@@ -112,12 +112,22 @@ aw_settings_known() {
112
112
  *) return 1 ;;
113
113
  esac
114
114
  }
115
+ aw_int_in_range() {
116
+ # All-digits $1 vs [min,max] WITHOUT 64-bit wrap (Issue-012): strip leading zeros, then a longer
117
+ # digit count than max's is unconditionally out of range — never do the arithmetic on a huge string.
118
+ # A leading-zero in-range value still passes (its stripped count is small); all-zeros collapses to
119
+ # "0" (below min>=1). Mirrors the JS settingValueValid safe-integer bound, verified by parity test.
120
+ local n="${1#"${1%%[!0]*}"}" min="$2" max="$3"
121
+ n="${n:-0}"
122
+ (( ${#n} > ${#max} )) && return 1
123
+ (( n >= min && n <= max ))
124
+ }
115
125
  aw_settings_valid() {
116
126
  local k="$1" v="$2" int_re='^[0-9]+$' dur_re='^[0-9]+(\.[0-9]+)?[smhd]$' zero_re='^0+(\.0+)?[smhd]$'
117
127
  case "$k" in
118
128
  CODEX_SERVICE_TIER) [[ "$v" == "priority" ]] ;;
119
- CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 86400 )) ;;
120
- CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 100000000 )) ;;
129
+ CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 86400 ;;
130
+ CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
121
131
  AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
122
132
  AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
123
133
  *) return 1 ;;
@@ -169,6 +179,14 @@ aw_apply_settings() {
169
179
  fi
170
180
  continue
171
181
  fi
182
+ # Normalize an all-digit (integer) value to DECIMAL before export: a leading-zero value the integer
183
+ # arms legitimately accept (000…086400 == 86400) would otherwise read as OCTAL in downstream Bash
184
+ # arithmetic ("value too great for base"). Strip leading zeros, floor "0"; enum/duration (non-digit)
185
+ # and boolean 0/1 are unaffected.
186
+ if [[ "$value" =~ ^[0-9]+$ ]]; then
187
+ value="${value#"${value%%[!0]*}"}"
188
+ value="${value:-0}"
189
+ fi
172
190
  export "$key=$value"
173
191
  done
174
192
  return 0
@@ -1080,8 +1080,9 @@ describe('codex-exec.sh — settings surface ⟷ manifest (D6, manifest-pinned)'
1080
1080
  assert.ok(arm, `no validation arm for ${s.key}`);
1081
1081
  if (s.kind === 'enum') for (const v of s.values) assert.ok(arm[1].includes(`"${v}"`), `${s.key}: enum value '${v}' not pinned`);
1082
1082
  if (s.kind === 'integer') {
1083
- assert.match(arm[1], new RegExp(`>= ${s.min}\\b`), `${s.key}: min ${s.min} not pinned`);
1084
- assert.match(arm[1], new RegExp(`<= ${s.max}\\b`), `${s.key}: max ${s.max} not pinned`);
1083
+ // Issue-012 refactor: min/max are pinned as the aw_int_in_range helper's positional bounds
1084
+ // (`aw_int_in_range "$v" <min> <max>`) the overflow-safe range check replaced raw arithmetic.
1085
+ assert.match(arm[1], new RegExp(`aw_int_in_range "\\$v" ${s.min} ${s.max}\\b`), `${s.key}: min/max ${s.min}/${s.max} not pinned as the aw_int_in_range bounds`);
1085
1086
  }
1086
1087
  if (s.kind === 'boolean') assert.ok(arm[1].includes('"0"') && arm[1].includes('"1"'), `${s.key}: boolean 0/1 not pinned`);
1087
1088
  if (s.kind === 'duration') {
@@ -104,12 +104,22 @@ aw_settings_known() {
104
104
  *) return 1 ;;
105
105
  esac
106
106
  }
107
+ aw_int_in_range() {
108
+ # All-digits $1 vs [min,max] WITHOUT 64-bit wrap (Issue-012): strip leading zeros, then a longer
109
+ # digit count than max's is unconditionally out of range — never do the arithmetic on a huge string.
110
+ # A leading-zero in-range value still passes (its stripped count is small); all-zeros collapses to
111
+ # "0" (below min>=1). Mirrors the JS settingValueValid safe-integer bound, verified by parity test.
112
+ local n="${1#"${1%%[!0]*}"}" min="$2" max="$3"
113
+ n="${n:-0}"
114
+ (( ${#n} > ${#max} )) && return 1
115
+ (( n >= min && n <= max ))
116
+ }
107
117
  aw_settings_valid() {
108
118
  local k="$1" v="$2" int_re='^[0-9]+$' dur_re='^[0-9]+(\.[0-9]+)?[smhd]$' zero_re='^0+(\.0+)?[smhd]$'
109
119
  case "$k" in
110
120
  CODEX_SERVICE_TIER) [[ "$v" == "priority" ]] ;;
111
- CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 86400 )) ;;
112
- CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && (( 10#$v >= 1 && 10#$v <= 100000000 )) ;;
121
+ CODEX_HARD_TIMEOUT) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 86400 ;;
122
+ CODEX_REVIEW_MAX_TOTAL_BYTES) [[ "$v" =~ $int_re ]] && aw_int_in_range "$v" 1 100000000 ;;
113
123
  AGY_HARD_TIMEOUT) [[ "$v" =~ $dur_re && ! "$v" =~ $zero_re ]] ;;
114
124
  AGY_REVIEW_ALLOW_ADDDIR) [[ "$v" == "0" || "$v" == "1" ]] ;;
115
125
  *) return 1 ;;
@@ -161,6 +171,14 @@ aw_apply_settings() {
161
171
  fi
162
172
  continue
163
173
  fi
174
+ # Normalize an all-digit (integer) value to DECIMAL before export: a leading-zero value the integer
175
+ # arms legitimately accept (000…086400 == 86400) would otherwise read as OCTAL in downstream Bash
176
+ # arithmetic ("value too great for base"). Strip leading zeros, floor "0"; enum/duration (non-digit)
177
+ # and boolean 0/1 are unaffected.
178
+ if [[ "$value" =~ ^[0-9]+$ ]]; then
179
+ value="${value#"${value%%[!0]*}"}"
180
+ value="${value:-0}"
181
+ fi
164
182
  export "$key=$value"
165
183
  done
166
184
  return 0
@@ -172,7 +190,7 @@ DEFAULT_CODEX_EFFORT="xhigh"
172
190
  # Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
173
191
  # version (drift-guarded by codex-review.test.mjs against capability.json).
174
192
  AW_RECEIPT_BACKEND="codex"
175
- AW_BRIDGE_VERSION="2.7.0"
193
+ AW_BRIDGE_VERSION="2.7.1"
176
194
  CODEX_MODEL="${CODEX_MODEL:-$DEFAULT_CODEX_MODEL}"
177
195
  CODEX_EFFORT="${CODEX_EFFORT:-$DEFAULT_CODEX_EFFORT}"
178
196
  # Generous hard cap for a slow xhigh review (subscription latency varies).
@@ -1020,8 +1020,9 @@ describe('codex-review.sh — settings surface ⟷ manifest (D6, manifest-pinned
1020
1020
  assert.ok(arm, `no validation arm for ${s.key}`);
1021
1021
  if (s.kind === 'enum') for (const v of s.values) assert.ok(arm[1].includes(`"${v}"`), `${s.key}: enum value '${v}' not pinned`);
1022
1022
  if (s.kind === 'integer') {
1023
- assert.match(arm[1], new RegExp(`>= ${s.min}\\b`), `${s.key}: min ${s.min} not pinned`);
1024
- assert.match(arm[1], new RegExp(`<= ${s.max}\\b`), `${s.key}: max ${s.max} not pinned`);
1023
+ // Issue-012 refactor: min/max are pinned as the aw_int_in_range helper's positional bounds
1024
+ // (`aw_int_in_range "$v" <min> <max>`) the overflow-safe range check replaced raw arithmetic.
1025
+ assert.match(arm[1], new RegExp(`aw_int_in_range "\\$v" ${s.min} ${s.max}\\b`), `${s.key}: min/max ${s.min}/${s.max} not pinned as the aw_int_in_range bounds`);
1025
1026
  }
1026
1027
  if (s.kind === 'boolean') assert.ok(arm[1].includes('"0"') && arm[1].includes('"1"'), `${s.key}: boolean 0/1 not pinned`);
1027
1028
  if (s.kind === 'duration') {
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "codex-cli-bridge",
5
5
  "kind": "execution-backend",
6
- "version": "2.7.0",
6
+ "version": "2.7.1",
7
7
  "provides": ["execute", "review"],
8
8
  "roles": {
9
9
  "execute": {
package/capability.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "schema": 1,
4
4
  "name": "agent-workflow-kit",
5
5
  "kind": "composition-root",
6
- "version": "1.47.0",
6
+ "version": "1.49.0",
7
7
  "provides": [],
8
8
  "roles": {},
9
9
  "detect": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sabaiway/agent-workflow-kit",
3
- "version": "1.47.0",
3
+ "version": "1.49.0",
4
4
  "description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -21,3 +21,4 @@ Rules:
21
21
  - Mark anything uncertain as `VERIFY:` rather than asserting it.
22
22
  - No superlatives, no persuasion, no summary paragraph — that is the frontier's red-line work.
23
23
  - Read-only: you never modify files.
24
+ - Tooling note: this vehicle grants `Read`/`Grep`/`Glob` only — **no `Bash`**. If a harness omits `Grep`/`Glob`, fall back to the `Read` tool (whole-file reads), never a shelled-out command. Should a harness nonetheless route your reads through `Bash`, keep each one a **plain single read-only command** (`grep …`, `ls …`, `cat …`) — never a `;`/`&&`/`|` chain, never `node -e`; where the maintainer enabled the opt-in **read-lane** (`docs/ai/lanes.json`), the gate hook keeps those seeded-read-only Bash reads promptless (it fires on subagent Bash too).
@@ -21,3 +21,4 @@ Rules:
21
21
  - Output: one section per failing gate, ordered as the run reported them. No fix suggestions,
22
22
  no root-cause speculation beyond the failure class, no code.
23
23
  - Read-only: you never modify files, never re-run commands.
24
+ - Tooling note: this vehicle grants `Read`/`Grep`/`Glob` only — **no `Bash`**. If a harness omits `Grep`/`Glob`, fall back to the `Read` tool (whole-file reads), never a shelled-out command. Should a harness nonetheless route your reads through `Bash`, keep each one a **plain single read-only command** (`grep …`, `ls …`, `cat …`) — never a `;`/`&&`/`|` chain, never `node -e`; where the maintainer enabled the opt-in **read-lane** (`docs/ai/lanes.json`), the gate hook keeps those seeded-read-only Bash reads promptless (it fires on subagent Bash too).
@@ -18,3 +18,4 @@ Rules:
18
18
  - Output format: the structure the prompt asks for (list / table / JSON). No preamble, no
19
19
  commentary, no recommendations — the orchestrator applies judgment, you supply facts.
20
20
  - Read-only: you never modify files, never run commands, never propose edits.
21
+ - Tooling note: this vehicle grants `Read`/`Grep`/`Glob` only — **no `Bash`**. If a harness omits `Grep`/`Glob`, fall back to the `Read` tool (whole-file reads), never a shelled-out command. Should a harness nonetheless route your reads through `Bash`, keep each one a **plain single read-only command** (`grep …`, `ls …`, `cat …`) — never a `;`/`&&`/`|` chain, never `node -e`; where the maintainer enabled the opt-in **read-lane** (`docs/ai/lanes.json`), the gate hook keeps those seeded-read-only Bash reads promptless (it fires on subagent Bash too).