@sabaiway/agent-workflow-kit 5.1.0 → 5.3.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.
- package/CHANGELOG.md +95 -0
- package/SKILL.md +13 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +14 -3
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +220 -30
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +264 -8
- package/bridges/antigravity-cli-bridge/bin/agy.sh +12 -2
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +18 -0
- package/bridges/antigravity-cli-bridge/capability.json +19 -13
- package/bridges/antigravity-cli-bridge/references/driving-agy.md +3 -2
- package/bridges/codex-cli-bridge/SKILL.md +17 -7
- package/bridges/codex-cli-bridge/bin/codex-exec.sh +156 -36
- package/bridges/codex-cli-bridge/bin/codex-exec.test.mjs +228 -4
- package/bridges/codex-cli-bridge/bin/codex-review.sh +205 -34
- package/bridges/codex-cli-bridge/bin/codex-review.test.mjs +276 -5
- package/bridges/codex-cli-bridge/capability.json +10 -7
- package/bridges/codex-cli-bridge/references/driving-codex.md +7 -5
- package/bridges/codex-cli-bridge/references/sandbox-and-flags.md +26 -12
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/flow-writer.md +37 -0
- package/references/modes/gates.md +4 -4
- package/references/modes/procedures.md +4 -2
- package/references/modes/receipt-deadline.md +16 -0
- package/references/modes/review-state.md +1 -1
- package/references/modes/set-flow.md +22 -0
- package/references/scripts/archive-decisions.mjs +340 -15
- package/references/scripts/archive-decisions.test.mjs +522 -2
- package/tools/cheap-agents.mjs +8 -2
- package/tools/commands.mjs +24 -2
- package/tools/commit-guard.mjs +44 -9
- package/tools/core-evidence.mjs +25 -22
- package/tools/detect-backends.mjs +33 -11
- package/tools/dispatch-record.mjs +926 -0
- package/tools/doc-parity.mjs +21 -6
- package/tools/flow-check.mjs +842 -0
- package/tools/flow-record.mjs +795 -0
- package/tools/flow-store-read.mjs +114 -0
- package/tools/flow-store.mjs +1178 -0
- package/tools/flow-writer.mjs +1265 -0
- package/tools/fs-read-nofollow.mjs +128 -0
- package/tools/gates-declaration.mjs +184 -0
- package/tools/gates-init.mjs +59 -17
- package/tools/orchestration-config.mjs +87 -10
- package/tools/orchestration-write.mjs +3 -3
- package/tools/plan-files.mjs +35 -0
- package/tools/procedures.mjs +75 -11
- package/tools/receipt-deadline.mjs +242 -0
- package/tools/recipes.mjs +21 -0
- package/tools/repo-lex.mjs +22 -0
- package/tools/review-state.mjs +240 -80
- package/tools/run-gates.mjs +361 -139
- package/tools/set-flow.mjs +465 -0
- package/tools/velocity-profile.mjs +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,101 @@ 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
|
+
## 5.3.0 — a check must speak where it is built to speak: the two silent checks (AD-088)
|
|
8
|
+
|
|
9
|
+
**Two shipped checks stayed SILENT at exactly the point they exist to speak** — one a GATE that
|
|
10
|
+
refuses and blocks a commit, one a WARNING that never changes an exit status. They were one
|
|
11
|
+
sentence, so they ship together.
|
|
12
|
+
|
|
13
|
+
- **The `flow-check` gate stops demanding the receipt its own run will write.** A red final on the
|
|
14
|
+
current base was cleared only through a LATER completed retry — but `run-gates` appends the final
|
|
15
|
+
receipt only after every gate has run, so the in-matrix `flow-check` could never see the receipt
|
|
16
|
+
its OWN run would write, and each `--final` on an unchanged base minted red N+1. No number of
|
|
17
|
+
rerun-causes converged; the only exit was a hook bypass. The `#65` rung is now consumer-aware, the
|
|
18
|
+
same lane split the flow→final comparison already applies one arm away: on the `gate` lane a
|
|
19
|
+
current-base red is
|
|
20
|
+
ALSO answered by a provable IN-PROGRESS retry — an authoritative `rerun-cause` naming its attempt
|
|
21
|
+
and binding the current fingerprint, a `final-start` at that fingerprint ordered strictly after
|
|
22
|
+
that red whose attempt has no completed final, and that fingerprint correlating to exactly ONE
|
|
23
|
+
base, the current one. Inside a real final run the conjunction holds by construction; a standalone
|
|
24
|
+
check on a quiet tree still refuses.
|
|
25
|
+
- **`commit-guard` is unchanged.** It keeps the strict completed-retry demand, so the commit
|
|
26
|
+
boundary still sees a real receipt. The rung's own `consumer` defaults to that strict lane, the
|
|
27
|
+
relaxation is opt-in by EXACT match, and a tree whose fingerprint is unresolvable or ambiguously
|
|
28
|
+
base-correlated never relaxes.
|
|
29
|
+
- **The interrupted-run residual is stated, not papered over.** An interrupted final run leaves the
|
|
30
|
+
same record shape with no live run behind it, so a standalone `flow-check --check` reads PASS in
|
|
31
|
+
that window. It authorizes nothing — the commit boundary refuses that shape twice over,
|
|
32
|
+
independently — and the rung's own source comment says so, pinned end to end by a fixture that
|
|
33
|
+
asserts all three conditions at once.
|
|
34
|
+
- **The bundled `codex-cli-bridge` mirror moves to 3.4.0** — its nested-sandbox scan now runs on
|
|
35
|
+
every completed run, not only a failed one, so a delegated run that SURVIVES the failure and exits
|
|
36
|
+
0 is no longer silent about it. On a successful run, it warns when the scanner recognises the
|
|
37
|
+
expected per-item shape — both tokens inside the `aggregated_output` of ONE `command_execution`
|
|
38
|
+
with a proven failure. The heuristic is biased toward under-firing on ambiguous or schema-drifted
|
|
39
|
+
input: field reordering stops the match, and only the first matching item on a line is judged.
|
|
40
|
+
The exit status deliberately stays 0 there — a heuristic scan must never gain the power to refuse
|
|
41
|
+
real work.
|
|
42
|
+
|
|
43
|
+
Evidence: an end-to-end fixture drives a caused red at the current tree through ONE real
|
|
44
|
+
`run-gates --final` to a GREEN newest-authoritative final and a passing `commit-guard --check` — the
|
|
45
|
+
test that would have failed before this release.
|
|
46
|
+
|
|
47
|
+
## 5.2.0 — the flow machinery ships whole: recorded subset budgets, flow-bound finals, the round arms, and the dogfooded pipeline (AD-086)
|
|
48
|
+
|
|
49
|
+
**Everything the flow series built after 5.1.0 lands as one wave** — the record vocabulary, the
|
|
50
|
+
fd-custody store, chain identity + `flow-check`, `set-flow` arming, receipt-deadline + wrapper
|
|
51
|
+
finding manifests, and this release's closing moves. The flow schema (`schema: 1`) was never
|
|
52
|
+
published before, so every schema move below arrives migration-free.
|
|
53
|
+
|
|
54
|
+
- **`--pre-review` under an ARMED flow is a RECORDED lane** (new store-global `subset-attempt`
|
|
55
|
+
kind): every subset run appends an attempt with a lock-computed monotone `attemptIndex`; the
|
|
56
|
+
run producing the SECOND red at a key completes, records it, and exits red printing the
|
|
57
|
+
diagnosis rule; a third attempt requires a recorded, byte-distinct `--diagnosis`; past three
|
|
58
|
+
reds only a recorded fresh-eyes consult verdict reopens the key — every stop is self-servable,
|
|
59
|
+
never a wait-for-a-human. A `pregateExclude` change opens a fresh counting context (new
|
|
60
|
+
`subsetDigest`), and an unarmed repo's `--pre-review` stays byte-unchanged (characterized).
|
|
61
|
+
- **`run-gates --final` binds the flow store to the release decision** (AD-086 D10): the minted
|
|
62
|
+
`final` carries an OPTIONAL `evidenceHashes.flow` — the owner-scoped projection hash — with
|
|
63
|
+
projection movement under the run an `integrityFailure`; `commit-guard` (its lane only, after
|
|
64
|
+
the dead-green selection) refuses a green final whose hash no longer matches the live
|
|
65
|
+
projection, and an armed flow whose latest green final LACKS the field fails closed naming the
|
|
66
|
+
fresh-`--final` remedy. No `EVIDENCE_SCHEMA_VERSION` bump: the released 5.1.0 validator accepts
|
|
67
|
+
a flow-bearing final (proven against `4b08ace` worktree bytes, both directions).
|
|
68
|
+
- **The writer's round machinery arms**: `round-open` (pre-dispatch mint — per-backend watermark
|
|
69
|
+
+ fresh nonce, printed as pasteable dispatch + `receipt-deadline` lines) · `round-land`
|
|
70
|
+
(arrival binding — receipt/manifest digests computed FROM the files; foreign, ambiguous,
|
|
71
|
+
malformed, or symlinked artifacts refuse) · per-finding `--dispose` ledgers ·
|
|
72
|
+
`freeze`/`unfreeze`/`converged` with completeness walks · `internal-attestation` refusing
|
|
73
|
+
while any in-flight plan lacks an adopted chain. Caps (3 rounds/cycle, 1 unfreeze, the
|
|
74
|
+
redesign valve) enforce at the arms; an over-cap mint requires a recorded `--justification`.
|
|
75
|
+
- **SECURITY — the receipts reader no longer follows symlinks** (new `fs-read-nofollow` leaf): a
|
|
76
|
+
symlinked/FIFO/directory receipts path surfaces as a loud `readError` through all four
|
|
77
|
+
consumers (review-state, core-evidence summary, flow-writer, flow-check) instead of content or
|
|
78
|
+
an empty success. The 5.1.0 reader read straight through a symlink — this is the one behavior
|
|
79
|
+
change for a conceivable existing loop, and the documented `AW_REVIEW_RECEIPTS` regular-file
|
|
80
|
+
lane is untouched (suite-pinned), so it ships as a flagged security fix, not an API break.
|
|
81
|
+
- **Bridge bumps ride the kit mirrors** — codex-cli-bridge **3.3.0** · antigravity-cli-bridge
|
|
82
|
+
**5.1.0**: an additive `--nonce <n>` flag on both review wrappers — the plain-argument lane
|
|
83
|
+
onto the existing `AW_REVIEW_NONCE` seam for hosts whose dispatch policy has no env-prefix
|
|
84
|
+
form (one seam: a disagreeing flag+env pair refuses pre-spend; a nonce-less run adds no nonce
|
|
85
|
+
field and mints no manifest — the `wrapperVersion` field every receipt carries moves with the
|
|
86
|
+
release), and a manifest-mint FAILURE whose temp unlink also fails now names the orphan
|
|
87
|
+
path on both failure codes.
|
|
88
|
+
- **Smaller rungs**: the veteran-store arming fence (#65 — arming a store with pre-flow red
|
|
89
|
+
finals no longer bricks `flow-check`; reds scope to the earliest own adoption instant,
|
|
90
|
+
fail-closed edges) · mixed declared+undeclared delta forks name the undeclared path ·
|
|
91
|
+
`velocity-profile` credential floor null-guards an unparseable harness version (was
|
|
92
|
+
fail-open via `null >= 0`) · `set-flow` empty/duplicate `pregateExclude` ids exit 2 at parse
|
|
93
|
+
time · the read surface's import closure is pinned write-free and acyclic
|
|
94
|
+
(`read-graph-purity.test.mjs`) · suite file-URL paths go through `fileURLToPath` (Windows).
|
|
95
|
+
- **The pipeline is dogfooded end to end**: a permanent hermetic tracked-`docs/ai` fixture
|
|
96
|
+
(`flow-dogfood.integration.test.mjs`) drives the REAL CLIs through set-flow → adoption →
|
|
97
|
+
subset-attempts → two nonce-bound rounds → bookkeeping-delta + refresh → freeze/converged →
|
|
98
|
+
`--final` with `evidenceHashes.flow` → guard PASS → the D10 post-final-append refusal — plus
|
|
99
|
+
the second-red stop pair and the foreign-worktree advisory lane. This repo itself released
|
|
100
|
+
under the armed flow.
|
|
101
|
+
|
|
7
102
|
## 5.1.0 — the config learns to carry the flow block before anything writes one (AD-085)
|
|
8
103
|
|
|
9
104
|
**Upgrade this before any flow feature arrives — that ordering IS the release.** The shared
|
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: '5.
|
|
6
|
+
version: '5.3.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -131,6 +131,14 @@ writer — read `${CLAUDE_SKILL_DIR}/references/modes/set-recipe.md` before acti
|
|
|
131
131
|
|
|
132
132
|
writer — read `${CLAUDE_SKILL_DIR}/references/modes/set-autonomy.md` before acting.
|
|
133
133
|
|
|
134
|
+
### Mode: set-flow
|
|
135
|
+
|
|
136
|
+
writer — read `${CLAUDE_SKILL_DIR}/references/modes/set-flow.md` before acting.
|
|
137
|
+
|
|
138
|
+
### Mode: flow-writer
|
|
139
|
+
|
|
140
|
+
writer — read `${CLAUDE_SKILL_DIR}/references/modes/flow-writer.md` before acting.
|
|
141
|
+
|
|
134
142
|
### Mode: autonomy-doctor
|
|
135
143
|
|
|
136
144
|
guarded — read `${CLAUDE_SKILL_DIR}/references/modes/autonomy-doctor.md` before acting.
|
|
@@ -171,6 +179,10 @@ guarded — read `${CLAUDE_SKILL_DIR}/references/modes/bridge-settings.md` befor
|
|
|
171
179
|
|
|
172
180
|
read-only — read `${CLAUDE_SKILL_DIR}/references/modes/review-state.md` before acting.
|
|
173
181
|
|
|
182
|
+
### Mode: receipt-deadline
|
|
183
|
+
|
|
184
|
+
read-only — read `${CLAUDE_SKILL_DIR}/references/modes/receipt-deadline.md` before acting.
|
|
185
|
+
|
|
174
186
|
### Mode: grounding
|
|
175
187
|
|
|
176
188
|
writer — read `${CLAUDE_SKILL_DIR}/references/modes/grounding.md` before acting.
|
|
@@ -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: '5.
|
|
5
|
+
version: '5.1.0'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# antigravity-cli-bridge
|
|
@@ -140,8 +140,19 @@ session error. One stderr banner states the actual posture (`review posture: mod
|
|
|
140
140
|
and the receipt records the same `posture {model}`; an attesting review with `AGY_MODEL` explicitly
|
|
141
141
|
emptied refuses pre-spend (`AGY_PROBE=1` exempt), and control bytes in a model string refuse
|
|
142
142
|
pre-spend in every mode. The `timeout=` field is **banner-only** (exactly the duration `agy-run`
|
|
143
|
-
hands to `timeout(1)
|
|
144
|
-
banner verbatim** when labeling a
|
|
143
|
+
hands to `timeout(1)`; without a capping binary `agy-review` fails CLOSED pre-spend) —
|
|
144
|
+
informational, never a receipt field. **Quote the posture banner verbatim** when labeling a
|
|
145
|
+
dispatch.
|
|
146
|
+
|
|
147
|
+
**Flow dispatch nonce (`AW_REVIEW_NONCE`, unset by default):** under the safe grammar
|
|
148
|
+
`[A-Za-z0-9._-]{1,64}` (anything else refuses pre-spend), a successful review first mints the
|
|
149
|
+
finding MANIFEST `agent-workflow-finding-manifest-agy-<nonce>.json` beside the receipts file —
|
|
150
|
+
atomic, no-clobber, ORDERED before the receipt append; a failed mint EXCLUDES the receipt, so a
|
|
151
|
+
nonce-supplied dispatch never lands a receipt without its readable manifest. Nonce-less runs add
|
|
152
|
+
no nonce field and mint nothing (the `wrapperVersion` field every receipt carries moves with each
|
|
153
|
+
release). `agy-review … --nonce <n>` is the plain-argument equivalent
|
|
154
|
+
(one seam; flag and a non-empty env must agree, a disagreeing pair refuses pre-spend) — the lane
|
|
155
|
+
for hosts whose dispatch policy has no env-prefix form.
|
|
145
156
|
|
|
146
157
|
Frontier default `Gemini 3.1 Pro (High)`; **any** model is allowed (a sub-frontier one earns a
|
|
147
158
|
silenceable `AGY_PROBE=1` advisory). An oversized `code` review is **DELIVERED, not refused**: the
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
# arms nothing; an oversized CODE review is delivered as a chunked feed
|
|
47
47
|
# AW_REVIEW_RECEIPTS override the review-receipt file (default: <git dir>/
|
|
48
48
|
# agent-workflow-review-receipts.jsonl — see the --help Receipt block)
|
|
49
|
+
# AW_REVIEW_NONCE the dispatch nonce (safe grammar [A-Za-z0-9._-]{1,64}) — when supplied,
|
|
50
|
+
# a successful review first mints the finding manifest beside the receipt;
|
|
51
|
+
# the --nonce <n> flag is its plain-argument equivalent (one seam — a
|
|
52
|
+
# disagreeing flag+env pair refuses pre-spend)
|
|
49
53
|
set -euo pipefail
|
|
50
54
|
|
|
51
55
|
# --- --help / -h (pre-preflight: no agy, no login, no git tree needed) ---------
|
|
@@ -57,15 +61,16 @@ case "${1:-}" in
|
|
|
57
61
|
agy-review — grounded read-only ADVISORY review by Google's Antigravity CLI (agy; subscription-only).
|
|
58
62
|
|
|
59
63
|
Usage:
|
|
60
|
-
agy-review code [--facts @f] [--ungrounded] [--decided @f] [--focus "…"] [extra focus…]
|
|
61
|
-
agy-review plan <plan-file> [--facts @f] [--decided @f] [--focus "…"]
|
|
62
|
-
agy-review diff <diff-file> [--facts @f] [--decided @f] [--focus "…"]
|
|
64
|
+
agy-review code [--facts @f] [--ungrounded] [--decided @f] [--focus "…"] [--nonce <n>] [extra focus…]
|
|
65
|
+
agy-review plan <plan-file> [--facts @f] [--decided @f] [--focus "…"] [--nonce <n>]
|
|
66
|
+
agy-review diff <diff-file> [--facts @f] [--decided @f] [--focus "…"] [--nonce <n>]
|
|
63
67
|
|
|
64
68
|
Flags:
|
|
65
69
|
--facts @f — verified facts the review runs AGAINST (code mode REQUIRES a non-empty payload; plan/diff warn loudly when omitted)
|
|
66
70
|
--ungrounded — deliberately ungrounded CODE review, a throwaway opinion (code mode only, contradicts --facts; the receipt records grounded:false and never attests)
|
|
67
71
|
--decided @f — already-decided / already-addressed list; do NOT re-raise (anti-circling; the round-2 payload)
|
|
68
72
|
--focus "…" — extra focus (repeatable; code mode also takes trailing focus words)
|
|
73
|
+
--nonce <n> — the flow dispatch nonce, the plain-argument lane onto the AW_REVIEW_NONCE seam (one seam: flag and a non-empty env must agree; a disagreeing pair refuses pre-spend)
|
|
69
74
|
|
|
70
75
|
Grounding:
|
|
71
76
|
grounded review — agy reads NOTHING by default, an ungrounded review GUESSES:
|
|
@@ -78,15 +83,16 @@ Notes:
|
|
|
78
83
|
pre-dispatch host-diff: before the FIRST dispatch of this bridge, diff its declared networkHosts
|
|
79
84
|
against the live sandbox allow-list — a missing host is surfaced to the maintainer BEFORE
|
|
80
85
|
dispatching, never fired into a known prompt
|
|
81
|
-
the review posture banner appends a banner-only timeout=<duration
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
the review posture banner appends a banner-only timeout=<duration> field — exactly the duration
|
|
87
|
+
agy-run hands to timeout(1); the hard-timeout preflight fails CLOSED when no timeout/gtimeout
|
|
88
|
+
binary exists (the wrapper refuses by name before any CLI run, so an uncapped review run can no
|
|
89
|
+
longer happen), and the field never enters the receipt posture or the D5 banner↔receipt parity
|
|
84
90
|
quote the posture banner verbatim when labeling this dispatch — the banner is the machine-stated
|
|
85
91
|
posture; a prose re-type drifts
|
|
86
92
|
|
|
87
93
|
Round-2 / resume:
|
|
88
|
-
agy-review --continue [--decided @f] [--focus "…"]
|
|
89
|
-
agy-review --conversation <id> [--decided @f] [--focus "…"]
|
|
94
|
+
agy-review --continue [--decided @f] [--focus "…"] [--nonce <n>]
|
|
95
|
+
agy-review --conversation <id> [--decided @f] [--focus "…"] [--nonce <n>]
|
|
90
96
|
(a continuation sends a small delta — agy holds the artifact server-side; --facts is invalid on a continuation)
|
|
91
97
|
|
|
92
98
|
Receipt:
|
|
@@ -116,7 +122,17 @@ Receipt:
|
|
|
116
122
|
particular value; absent by construction on plan/diff/continuation receipts, which carry no change
|
|
117
123
|
set; a run whose output carries NO recognized '### Verdict' section — empty
|
|
118
124
|
output included — exits 4 with NO receipt (D4: a FAILED review to RE-RUN, never a fatal session
|
|
119
|
-
error);
|
|
125
|
+
error); when the dispatch nonce seam is supplied — the AW_REVIEW_NONCE environment value or
|
|
126
|
+
its plain-argument equivalent --nonce <n> (one seam: the flag assigns the same value;
|
|
127
|
+
supplying both with different values refuses pre-spend) — under the safe grammar
|
|
128
|
+
[A-Za-z0-9._-]{1,64} (anything else refuses pre-spend), the wrapper first mints the finding
|
|
129
|
+
MANIFEST {schema, backend, nonce, fingerprint, findings} beside the receipts file
|
|
130
|
+
(agent-workflow-finding-manifest-<backend>-<nonce>.json; atomic, no-clobber — a byte-identical
|
|
131
|
+
rewrite is an idempotent no-op, different bytes refuse loudly) ORDERED before the receipt
|
|
132
|
+
append — a failed manifest write EXCLUDES the receipt append, so a nonce-supplied dispatch can
|
|
133
|
+
never land a receipt without its readable manifest; a nonce-less invocation adds NO nonce field
|
|
134
|
+
and mints NO finding manifest (the existing wrapperVersion field still changes with each bridge
|
|
135
|
+
release); a write failure warns, never fails the review
|
|
120
136
|
|
|
121
137
|
Settings file (KEY=VALUE, parsed never sourced; env wins over file, file wins over built-in default):
|
|
122
138
|
${XDG_CONFIG_HOME:-~/.config}/agent-workflow/bridge-settings.conf
|
|
@@ -257,8 +273,9 @@ aw_apply_settings
|
|
|
257
273
|
|
|
258
274
|
# --- Effective-timeout resolver (D5 banner honesty; AD-061) --------------------
|
|
259
275
|
# ONE rule, both bridges: the posture banner prints EXACTLY the duration handed to timeout(1) —
|
|
260
|
-
# an integer-seconds value rendered with the `s` suffix, a duration string verbatim
|
|
261
|
-
#
|
|
276
|
+
# an integer-seconds value rendered with the `s` suffix, a duration string verbatim; without a
|
|
277
|
+
# capping binary the EXEC wrappers print `timeout=uncapped` and run, while the REVIEW wrappers
|
|
278
|
+
# refuse pre-spend (fail-closed preflight) — never a fabricated number.
|
|
262
279
|
# The EFFECTIVE value (env included — closing the aw_settings_valid env bypass) is validated by
|
|
263
280
|
# the same per-key rule as the settings file, plus a 7-digit integer-part bound (overflow); an
|
|
264
281
|
# invalid value warns + falls back to the built-in default — a typo never silently masquerades
|
|
@@ -309,7 +326,7 @@ DEFAULT_AGY_REVIEW_MODEL="Gemini 3.1 Pro (High)"
|
|
|
309
326
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
310
327
|
# version (drift-guarded by agy-review.test.mjs against capability.json).
|
|
311
328
|
AW_RECEIPT_BACKEND="agy"
|
|
312
|
-
AW_BRIDGE_VERSION="5.
|
|
329
|
+
AW_BRIDGE_VERSION="5.1.0"
|
|
313
330
|
# `-` not `:-` so an EXPLICIT empty AGY_MODEL= survives (drop --model, use settings.json — agy.sh:52).
|
|
314
331
|
AGY_MODEL="${AGY_MODEL-$DEFAULT_AGY_REVIEW_MODEL}"
|
|
315
332
|
# D5 control-byte screen — IMMEDIATELY after resolution, BEFORE the off-frontier advisory (or any
|
|
@@ -343,6 +360,14 @@ AGY_PROBE="${AGY_PROBE:-0}"
|
|
|
343
360
|
# review-state gate rejects it — a guards-relaxed review must never attest a tree.
|
|
344
361
|
REVIEW_PROBE=false
|
|
345
362
|
if [[ "$AGY_PROBE" == "1" ]]; then REVIEW_PROBE=true; fi
|
|
363
|
+
# The dispatch nonce seam (flow-orchestration Decision 2/P5): validated pre-spend under the SAFE
|
|
364
|
+
# grammar — a nonce that would escape the derived manifest name refuses before any CLI run. The
|
|
365
|
+
# bracket expression ENUMERATES the ASCII set (no ranges): a range like A-Z is locale-collation-
|
|
366
|
+
# dependent and could admit a non-ASCII nonce the kit's JS reader then refuses.
|
|
367
|
+
if [[ -n "${AW_REVIEW_NONCE:-}" && ! "${AW_REVIEW_NONCE}" =~ ^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-]{1,64}$ ]]; then
|
|
368
|
+
echo "error: AW_REVIEW_NONCE fails the safe nonce grammar ([A-Za-z0-9._-]{1,64}) — the derived manifest name would be unsafe; fix the nonce and re-run." >&2
|
|
369
|
+
exit 2
|
|
370
|
+
fi
|
|
346
371
|
# RETIRED (D3), not removed: the key stays RECOGNIZED by the shared settings registry so an existing
|
|
347
372
|
# settings line never starts warning as unknown — but it arms NOTHING. The `--add-dir` offload told
|
|
348
373
|
# agy to read a staging file; headless agy AUTO-DENIES its own read_file tool, so that lane could
|
|
@@ -442,6 +467,19 @@ if ! command -v agy >/dev/null 2>&1; then
|
|
|
442
467
|
echo "error: 'agy' (Antigravity CLI) not found on PATH. See this skill's setup/README.md." >&2
|
|
443
468
|
exit 127
|
|
444
469
|
fi
|
|
470
|
+
# The hard-timeout cap is a TWO-STAGE guarantee (flow-orchestration #26): (1) THIS parent
|
|
471
|
+
# preflight fails CLOSED without a capping binary — an uncapped review run is refused before any
|
|
472
|
+
# CLI spend; (2) the agy-run child re-resolves the binary at dispatch time, so the exported seam
|
|
473
|
+
# below makes ITS missing-binary lane refuse too — a delete-between race can never silently void
|
|
474
|
+
# the cap. The banner uses the parent-resolved path; the child's mandatory recheck is the seam's.
|
|
475
|
+
aw_review_timeout_bin="$(aw_resolve_timeout_bin)"
|
|
476
|
+
if [[ -z "$aw_review_timeout_bin" ]]; then
|
|
477
|
+
echo "error: no 'timeout'/'gtimeout' binary on PATH — the hard-timeout preflight fails CLOSED:" >&2
|
|
478
|
+
echo " an uncapped review run is refused before any CLI spend. Install coreutils (timeout;" >&2
|
|
479
|
+
echo " on macOS: brew install coreutils for gtimeout), then re-run." >&2
|
|
480
|
+
exit 127
|
|
481
|
+
fi
|
|
482
|
+
export AGY_REQUIRE_TIMEOUT_BIN=1
|
|
445
483
|
# Delegate execution to agy-run (the single home of the timeout + subscription + byte-ceiling guards);
|
|
446
484
|
# fall back to the sibling agy.sh on a fresh checkout / hermetic test where agy-run is not yet linked.
|
|
447
485
|
if command -v agy-run >/dev/null 2>&1; then
|
|
@@ -449,6 +487,16 @@ if command -v agy-run >/dev/null 2>&1; then
|
|
|
449
487
|
else
|
|
450
488
|
AGY_RUN="$HERE/agy.sh"
|
|
451
489
|
fi
|
|
490
|
+
# The seam is a guarantee only when the RESOLVED child honors it: a stale installed agy-run that
|
|
491
|
+
# never reads AGY_REQUIRE_TIMEOUT_BIN would keep its uncapped lane past the parent preflight —
|
|
492
|
+
# refuse loudly and name the refresh recovery instead of dispatching on a hope.
|
|
493
|
+
aw_child_path="$(command -v "$AGY_RUN" 2>/dev/null || printf '%s' "$AGY_RUN")"
|
|
494
|
+
if ! grep -q "AGY_REQUIRE_TIMEOUT_BIN" "$aw_child_path" 2>/dev/null; then
|
|
495
|
+
echo "error: the resolved agy-run child ($aw_child_path) does not honor the AGY_REQUIRE_TIMEOUT_BIN seam —" >&2
|
|
496
|
+
echo " a stale bridge install could run uncapped past the parent preflight. Refresh the placed" >&2
|
|
497
|
+
echo " bridges (/agent-workflow-kit setup --refresh-placed), then re-run." >&2
|
|
498
|
+
exit 127
|
|
499
|
+
fi
|
|
452
500
|
|
|
453
501
|
# --- Model policy (advisory, NOT a gate) -------------------------------------
|
|
454
502
|
is_frontier=0
|
|
@@ -689,7 +737,104 @@ posture_json() {
|
|
|
689
737
|
fi
|
|
690
738
|
}
|
|
691
739
|
|
|
692
|
-
#
|
|
740
|
+
# write_finding_manifest <receipts-path> <fingerprint|""> <findings-file> — the wrapper-minted
|
|
741
|
+
# finding MANIFEST (flow-orchestration Decision 2 / P5 / P24-25), minted ONLY when the dispatch
|
|
742
|
+
# nonce seam AW_REVIEW_NONCE is supplied: {schema, backend, nonce, fingerprint, findings} lands
|
|
743
|
+
# beside the receipts file under the {backend, nonce}-derived name. The write is ATOMIC (temp +
|
|
744
|
+
# hard-link publish) and NO-CLOBBER: a byte-identical re-write is an idempotent no-op, different
|
|
745
|
+
# bytes refuse loudly. Returns non-zero on ANY failure — the caller then EXCLUDES the receipt
|
|
746
|
+
# append, so a nonce-supplied dispatch can never land a receipt without its readable manifest.
|
|
747
|
+
# A nonce-less invocation returns 0 untouched (no nonce field, no manifest — the receipt
|
|
748
|
+
# otherwise proceeds unchanged).
|
|
749
|
+
write_finding_manifest() {
|
|
750
|
+
local receipts="$1" fingerprint="$2" findings_file="$3" nonce="${AW_REVIEW_NONCE:-}"
|
|
751
|
+
[[ -n "$nonce" ]] || return 0
|
|
752
|
+
if [[ ! "$nonce" =~ ^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-]{1,64}$ ]]; then
|
|
753
|
+
echo "error: AW_REVIEW_NONCE fails the safe nonce grammar ([A-Za-z0-9._-]{1,64}) — the derived manifest name would be unsafe; NO manifest was written." >&2
|
|
754
|
+
return 1
|
|
755
|
+
fi
|
|
756
|
+
if [[ -z "$findings_file" || ! -f "$findings_file" ]]; then
|
|
757
|
+
echo "error: no captured findings file to mint the manifest from — NO manifest was written." >&2
|
|
758
|
+
return 1
|
|
759
|
+
fi
|
|
760
|
+
local manifest mint_rc
|
|
761
|
+
manifest="$(dirname -- "$receipts")/agent-workflow-finding-manifest-${AW_RECEIPT_BACKEND}-${nonce}.json"
|
|
762
|
+
# The WHOLE mint core rides ONE node script (a family floor; the verdict parse already leans on
|
|
763
|
+
# it): FATAL UTF-8 compose (BOM kept — invalid bytes refuse rather than silently mutate the
|
|
764
|
+
# digest domain), an UNPREDICTABLE sibling temp opened with "wx" (O_CREAT|O_EXCL — a planted
|
|
765
|
+
# node at the name refuses, and ONLY a temp we provably created is ever unlinked), a hard-link
|
|
766
|
+
# publish (atomic no-clobber), and an EEXIST loser judged through ONE O_NOFOLLOW|O_NONBLOCK
|
|
767
|
+
# descriptor whose fstat must say REGULAR before the same-fd byte compare — no TOCTOU window,
|
|
768
|
+
# no symlink read-through, no FIFO hang. Exit: 0 minted or byte-identical no-op; 3 different
|
|
769
|
+
# bytes or a non-regular/symlink manifest; 5 minted-but-temp-left (SUCCESS with the orphan path
|
|
770
|
+
# on stdout — the caller warns loudly, never silently); 1 unreadable/non-UTF-8 findings or an
|
|
771
|
+
# fs failure.
|
|
772
|
+
local mint_out
|
|
773
|
+
mint_out="$( umask 077; node -e '
|
|
774
|
+
const fs = require("node:fs");
|
|
775
|
+
const { join, dirname, basename } = require("node:path");
|
|
776
|
+
const { randomBytes } = require("node:crypto");
|
|
777
|
+
const [file, backend, nonce, fingerprint, manifest] = process.argv.slice(1);
|
|
778
|
+
let code = 1;
|
|
779
|
+
let tmp = null;
|
|
780
|
+
try {
|
|
781
|
+
const findings = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(fs.readFileSync(file));
|
|
782
|
+
const bytes = Buffer.from(`${JSON.stringify({ schema: 1, backend, nonce, fingerprint: fingerprint || null, findings })}\n`);
|
|
783
|
+
const candidate = join(dirname(manifest), `.${basename(manifest)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
|
|
784
|
+
const fd = fs.openSync(candidate, "wx", 0o600);
|
|
785
|
+
tmp = candidate;
|
|
786
|
+
try {
|
|
787
|
+
fs.writeFileSync(fd, bytes);
|
|
788
|
+
} finally {
|
|
789
|
+
fs.closeSync(fd);
|
|
790
|
+
}
|
|
791
|
+
try {
|
|
792
|
+
fs.linkSync(tmp, manifest);
|
|
793
|
+
code = 0;
|
|
794
|
+
} catch (err) {
|
|
795
|
+
if (err && err.code === "EEXIST") {
|
|
796
|
+
try {
|
|
797
|
+
const mfd = fs.openSync(manifest, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
798
|
+
try {
|
|
799
|
+
code = !fs.fstatSync(mfd).isFile() ? 3 : fs.readFileSync(mfd).equals(bytes) ? 0 : 3;
|
|
800
|
+
} finally {
|
|
801
|
+
fs.closeSync(mfd);
|
|
802
|
+
}
|
|
803
|
+
} catch {
|
|
804
|
+
code = 3;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
} catch {
|
|
809
|
+
code = 1;
|
|
810
|
+
}
|
|
811
|
+
if (tmp !== null) { try { fs.unlinkSync(tmp); } catch { if (code === 0) code = 5; process.stdout.write(tmp); } }
|
|
812
|
+
process.exit(code);
|
|
813
|
+
' "$findings_file" "$AW_RECEIPT_BACKEND" "$nonce" "$fingerprint" "$manifest" 2>/dev/null )"
|
|
814
|
+
mint_rc=$?
|
|
815
|
+
if [[ $mint_rc -eq 5 ]]; then
|
|
816
|
+
echo "warning: the finding manifest was minted, but its temporary sibling could not be removed —" >&2
|
|
817
|
+
echo " orphan left at: ${mint_out} — remove it by hand (the manifest and the receipt are intact)." >&2
|
|
818
|
+
return 0
|
|
819
|
+
fi
|
|
820
|
+
if [[ $mint_rc -eq 3 ]]; then
|
|
821
|
+
echo "error: the finding manifest $manifest already exists with DIFFERENT bytes or is not a regular file — no-clobber refuses loudly (one dispatch identity, one manifest)." >&2
|
|
822
|
+
if [[ -n "$mint_out" ]]; then
|
|
823
|
+
echo " orphan left at: ${mint_out} — its temporary sibling could not be removed either; remove it by hand." >&2
|
|
824
|
+
fi
|
|
825
|
+
return 1
|
|
826
|
+
fi
|
|
827
|
+
if [[ $mint_rc -ne 0 ]]; then
|
|
828
|
+
echo "error: could not compose or write the finding manifest (unreadable or non-UTF-8 findings, or an fs failure) — NO manifest was written." >&2
|
|
829
|
+
if [[ -n "$mint_out" ]]; then
|
|
830
|
+
echo " orphan left at: ${mint_out} — its temporary sibling could not be removed either; remove it by hand." >&2
|
|
831
|
+
fi
|
|
832
|
+
return 1
|
|
833
|
+
fi
|
|
834
|
+
return 0
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
# write_review_receipt <artifact|""> <fresh: true|false> <fingerprint|""> <verdict> <grounded: true|false> <factsHash|""> [probe: true|false] [delivery|""] [findings-file]
|
|
693
838
|
# Appends ONE receipt line (the AD-038 fixture shape) as a side effect of a SUCCESSFUL review —
|
|
694
839
|
# to $AW_REVIEW_RECEIPTS when set, else <git dir>/agent-workflow-review-receipts.jsonl (inside the
|
|
695
840
|
# git dir by construction, so it is never committable). Fail-safe: every failure here warns loudly
|
|
@@ -699,8 +844,10 @@ posture_json() {
|
|
|
699
844
|
# marker is written ALWAYS, true or false: the receipt SELF-DECLARES, so the gate reads the fact
|
|
700
845
|
# itself instead of inferring it from this wrapper's version (which bumps in a different release
|
|
701
846
|
# phase). Silence is not a declaration — an unmarked receipt is untrustworthy and the gate rejects it.
|
|
847
|
+
# The 9th argument feeds the finding-manifest mint: on a nonce-supplied dispatch the manifest is
|
|
848
|
+
# minted FIRST (atomic, no-clobber, ORDERED) and a failed mint EXCLUDES the receipt append.
|
|
702
849
|
write_review_receipt() {
|
|
703
|
-
local artifact="$1" fresh="$2" fingerprint="$3" verdict="$4" grounded="$5" facts_hash="$6" probe="${7:-false}" delivery="${8:-}"
|
|
850
|
+
local artifact="$1" fresh="$2" fingerprint="$3" verdict="$4" grounded="$5" facts_hash="$6" probe="${7:-false}" delivery="${8:-}" findings_file="${9:-}"
|
|
704
851
|
local receipts="${AW_REVIEW_RECEIPTS:-}"
|
|
705
852
|
if [[ -z "$receipts" ]]; then
|
|
706
853
|
local receipt_git_dir
|
|
@@ -710,13 +857,24 @@ write_review_receipt() {
|
|
|
710
857
|
fi
|
|
711
858
|
receipts="$receipt_git_dir/agent-workflow-review-receipts.jsonl"
|
|
712
859
|
fi
|
|
713
|
-
|
|
860
|
+
if ! write_finding_manifest "$receipts" "$fingerprint" "$findings_file"; then
|
|
861
|
+
echo "warning: the finding manifest could not be minted — the receipt append is EXCLUDED (a" >&2
|
|
862
|
+
echo " nonce-supplied dispatch never lands a receipt without its readable manifest);" >&2
|
|
863
|
+
echo " the review itself succeeded — re-run it to mint the pair." >&2
|
|
864
|
+
return 0
|
|
865
|
+
fi
|
|
866
|
+
# A nonce-SUPPLIED dispatch stamps its nonce into the receipt too (the flow round-land matcher
|
|
867
|
+
# requires exact {backend, nonce} equality — dispatch identity end-to-end); the nonce is
|
|
868
|
+
# grammar-safe by the pre-spend check, and a nonce-less receipt stays BYTE-EXACT (the frozen
|
|
869
|
+
# compatibility floor).
|
|
870
|
+
local line probe_field=',"probe":false' delivery_field="" nonce_field=""
|
|
714
871
|
if [[ "$probe" == "true" ]]; then probe_field=',"probe":true'; fi
|
|
715
872
|
if [[ -n "$delivery" ]]; then delivery_field=",\"delivery\":\"$delivery\""; fi
|
|
716
|
-
|
|
873
|
+
if [[ -n "${AW_REVIEW_NONCE:-}" ]]; then nonce_field=",\"nonce\":\"${AW_REVIEW_NONCE}\""; fi
|
|
874
|
+
line="$(printf '{"schema":1,"artifact":%s,"fresh":%s,"fingerprint":%s,"backend":"%s","verdict":"%s","grounded":%s,"factsHash":%s,"wrapperVersion":"%s","timestamp":"%s"%s,"posture":%s%s%s}' \
|
|
717
875
|
"$(receipt_json_scalar "$artifact")" "$fresh" "$(receipt_json_scalar "$fingerprint")" \
|
|
718
876
|
"$AW_RECEIPT_BACKEND" "$verdict" "$grounded" "$(receipt_json_scalar "$facts_hash")" \
|
|
719
|
-
"$AW_BRIDGE_VERSION" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$probe_field" "$(posture_json)" "$delivery_field")"
|
|
877
|
+
"$AW_BRIDGE_VERSION" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$probe_field" "$(posture_json)" "$delivery_field" "$nonce_field")"
|
|
720
878
|
if ! printf '%s\n' "$line" >>"$receipts" 2>/dev/null; then
|
|
721
879
|
echo "warning: could not append the review receipt to $receipts — the review itself succeeded;" >&2
|
|
722
880
|
echo " the review-state gate will read the current tree as un-receipted." >&2
|
|
@@ -1158,11 +1316,11 @@ case "${1:-}" in
|
|
|
1158
1316
|
esac
|
|
1159
1317
|
|
|
1160
1318
|
usage() {
|
|
1161
|
-
echo "usage: $0 code [--facts @f] [--ungrounded] [--decided @f] [--focus \"…\"] [extra focus…]" >&2
|
|
1162
|
-
echo " $0 plan <plan-file> [--facts @f] [--decided @f] [--focus \"…\"]" >&2
|
|
1163
|
-
echo " $0 diff <diff-file> [--facts @f] [--decided @f] [--focus \"…\"]" >&2
|
|
1164
|
-
echo " $0 --continue [--decided @f] [--focus \"…\"]" >&2
|
|
1165
|
-
echo " $0 --conversation <id> [--decided @f] [--focus \"…\"]" >&2
|
|
1319
|
+
echo "usage: $0 code [--facts @f] [--ungrounded] [--decided @f] [--focus \"…\"] [--nonce <n>] [extra focus…]" >&2
|
|
1320
|
+
echo " $0 plan <plan-file> [--facts @f] [--decided @f] [--focus \"…\"] [--nonce <n>]" >&2
|
|
1321
|
+
echo " $0 diff <diff-file> [--facts @f] [--decided @f] [--focus \"…\"] [--nonce <n>]" >&2
|
|
1322
|
+
echo " $0 --continue [--decided @f] [--focus \"…\"] [--nonce <n>]" >&2
|
|
1323
|
+
echo " $0 --conversation <id> [--decided @f] [--focus \"…\"] [--nonce <n>]" >&2
|
|
1166
1324
|
}
|
|
1167
1325
|
|
|
1168
1326
|
# --- Mode dispatch (non-resume) ----------------------------------------------
|
|
@@ -1203,6 +1361,8 @@ fi
|
|
|
1203
1361
|
FACTS_RAW=""
|
|
1204
1362
|
DECIDED_RAW=""
|
|
1205
1363
|
UNGROUNDED=0
|
|
1364
|
+
NONCE_FLAG=""
|
|
1365
|
+
NONCE_FLAG_SET=0
|
|
1206
1366
|
FOCUS_PARTS=()
|
|
1207
1367
|
# A value-taking flag must be followed by a real value — never end-of-args and never another flag.
|
|
1208
1368
|
# Otherwise `agy-review code --facts --focus x` would silently take "--focus" as the facts and spend a
|
|
@@ -1231,6 +1391,20 @@ while [[ $# -gt 0 ]]; do
|
|
|
1231
1391
|
need_value "$1" "${2:-}"; DECIDED_RAW="$2"; shift 2 ;;
|
|
1232
1392
|
--focus)
|
|
1233
1393
|
need_value "$1" "${2:-}"; FOCUS_PARTS+=("$2"); shift 2 ;;
|
|
1394
|
+
--nonce)
|
|
1395
|
+
# Not need_value: the nonce's CLOSED grammar admits leading-dash values and validates
|
|
1396
|
+
# deterministically below — the next argument is taken unconditionally (only end-of-args
|
|
1397
|
+
# refuses here), and presence rides its own flag so an EMPTY value still hits the grammar
|
|
1398
|
+
# screen and a duplicate after it still refuses.
|
|
1399
|
+
if [[ $# -lt 2 ]]; then
|
|
1400
|
+
echo "error: --nonce needs a value; got '<end of args>'." >&2
|
|
1401
|
+
exit 2
|
|
1402
|
+
fi
|
|
1403
|
+
if [[ "$NONCE_FLAG_SET" == "1" ]]; then
|
|
1404
|
+
echo "error: duplicate --nonce — one dispatch carries one nonce." >&2
|
|
1405
|
+
exit 2
|
|
1406
|
+
fi
|
|
1407
|
+
NONCE_FLAG="$2"; NONCE_FLAG_SET=1; shift 2 ;;
|
|
1234
1408
|
--)
|
|
1235
1409
|
echo "error: this wrapper OWNS the review posture — no '--' passthrough. The only escapes are" >&2
|
|
1236
1410
|
echo " AGY_PROBE=1 (off-frontier model). An oversized code review is a chunked feed, not a flag." >&2
|
|
@@ -1252,6 +1426,23 @@ done
|
|
|
1252
1426
|
# Merge --focus values and trailing focus words, in parse order, into ONE focus block.
|
|
1253
1427
|
FOCUS="${FOCUS_PARTS[*]:-}"
|
|
1254
1428
|
|
|
1429
|
+
# --nonce rides the EXISTING AW_REVIEW_NONCE seam (flow FLOW-NONCE-DISPATCH-LANE): the
|
|
1430
|
+
# plain-argument lane for hosts whose dispatch policy has no env-prefix form. The flag and a
|
|
1431
|
+
# non-empty env value must AGREE — two disagreeing sources would mint an ambiguous dispatch
|
|
1432
|
+
# identity (fail closed). Grammar screen identical to the env screen above (enumerated ASCII —
|
|
1433
|
+
# locale-independent), pre-spend.
|
|
1434
|
+
if [[ "$NONCE_FLAG_SET" == "1" ]]; then
|
|
1435
|
+
if [[ ! "$NONCE_FLAG" =~ ^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-]{1,64}$ ]]; then
|
|
1436
|
+
echo "error: --nonce fails the safe nonce grammar ([A-Za-z0-9._-]{1,64}) — the derived manifest name would be unsafe; fix the nonce and re-run." >&2
|
|
1437
|
+
exit 2
|
|
1438
|
+
fi
|
|
1439
|
+
if [[ -n "${AW_REVIEW_NONCE:-}" && "${AW_REVIEW_NONCE}" != "$NONCE_FLAG" ]]; then
|
|
1440
|
+
echo "error: --nonce disagrees with the AW_REVIEW_NONCE environment value — one dispatch carries one nonce; drop one source and re-run." >&2
|
|
1441
|
+
exit 2
|
|
1442
|
+
fi
|
|
1443
|
+
AW_REVIEW_NONCE="$NONCE_FLAG"
|
|
1444
|
+
fi
|
|
1445
|
+
|
|
1255
1446
|
# --ungrounded closed grammar (D4): code-mode only, and an explicit contradiction with --facts refuses.
|
|
1256
1447
|
if [[ "$UNGROUNDED" == "1" ]]; then
|
|
1257
1448
|
if [[ -n "$FACTS_RAW" ]]; then
|
|
@@ -1607,12 +1798,11 @@ if [[ -z "$AGY_MODEL" && -z "$resume_mode" && "$REVIEW_PROBE" != "true" && "$REV
|
|
|
1607
1798
|
exit 2
|
|
1608
1799
|
fi
|
|
1609
1800
|
# The timeout field is BANNER-ONLY (AD-061): it prints exactly the duration agy-run hands to
|
|
1610
|
-
# timeout(1)
|
|
1611
|
-
#
|
|
1612
|
-
#
|
|
1613
|
-
#
|
|
1614
|
-
|
|
1615
|
-
aw_timeout_banner="$(aw_timeout_label "$aw_banner_timeout_bin" "$AGY_HARD_TIMEOUT")"
|
|
1801
|
+
# timeout(1) and never enters the receipt posture. The banner uses the PARENT-preflight-resolved
|
|
1802
|
+
# path (builtin type -P, absolute); the child re-resolves at dispatch under the exported
|
|
1803
|
+
# AGY_REQUIRE_TIMEOUT_BIN seam, whose missing-binary lane refuses — so an uncapped review
|
|
1804
|
+
# dispatch cannot exist on either stage.
|
|
1805
|
+
aw_timeout_banner="$(aw_timeout_label "$aw_review_timeout_bin" "$AGY_HARD_TIMEOUT")"
|
|
1616
1806
|
echo "review posture: model=${AGY_MODEL:-<agy settings default>} timeout=$aw_timeout_banner" >&2
|
|
1617
1807
|
|
|
1618
1808
|
# --- Execute via agy-run (single home of timeout + subscription + byte ceiling) ---
|
|
@@ -1673,7 +1863,7 @@ if [[ $rc -eq 0 ]]; then
|
|
|
1673
1863
|
# A continuation never re-embeds the current artifact (agy holds the ORIGINAL round server-side;
|
|
1674
1864
|
# --facts is rejected above), so it cannot attest the folded tree: fresh:false, artifact /
|
|
1675
1865
|
# fingerprint / factsHash null, grounded false — informational-only, ignored by the state gate.
|
|
1676
|
-
write_review_receipt "" false "" "$verdict" false "" "$REVIEW_PROBE"
|
|
1866
|
+
write_review_receipt "" false "" "$verdict" false "" "$REVIEW_PROBE" "" "$review_out_file"
|
|
1677
1867
|
echo "notice: a continuation receipt is fresh:false (informational-only) — only a fresh grounded run" >&2
|
|
1678
1868
|
echo " (agy-review code --facts @f) mints a receipt that satisfies the review-state gate." >&2
|
|
1679
1869
|
else
|
|
@@ -1683,7 +1873,7 @@ if [[ $rc -eq 0 ]]; then
|
|
|
1683
1873
|
grounded=true
|
|
1684
1874
|
facts_hash="$(printf '%s' "$FACTS_CONTENT" | sha256_stdin || true)"
|
|
1685
1875
|
fi
|
|
1686
|
-
write_review_receipt "$REVIEW_ARTIFACT" true "$REVIEW_FINGERPRINT" "$verdict" "$grounded" "$facts_hash" "$REVIEW_PROBE" "$REVIEW_DELIVERY"
|
|
1876
|
+
write_review_receipt "$REVIEW_ARTIFACT" true "$REVIEW_FINGERPRINT" "$verdict" "$grounded" "$facts_hash" "$REVIEW_PROBE" "$REVIEW_DELIVERY" "$review_out_file"
|
|
1687
1877
|
fi
|
|
1688
1878
|
fi
|
|
1689
1879
|
exit $rc
|