@sabaiway/agent-workflow-kit 5.7.0 → 5.8.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 +32 -0
- package/README.md +1 -1
- package/SKILL.md +1 -1
- package/bridges/antigravity-cli-bridge/SKILL.md +26 -17
- package/bridges/antigravity-cli-bridge/bin/agy-review.sh +6 -5
- package/bridges/antigravity-cli-bridge/bin/agy-review.test.mjs +13 -4
- package/bridges/antigravity-cli-bridge/bin/agy.sh +7 -4
- package/bridges/antigravity-cli-bridge/bin/agy.test.mjs +24 -0
- package/bridges/antigravity-cli-bridge/capability.json +3 -3
- package/bridges/antigravity-cli-bridge/references/driving-agy.md +9 -8
- package/bridges/antigravity-cli-bridge/references/models-and-flags.md +31 -14
- package/bridges/antigravity-cli-bridge/setup/README.md +4 -3
- package/capability.json +1 -1
- package/package.json +1 -1
- package/references/modes/grounding.md +4 -3
- package/tools/grounding.mjs +105 -16
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,38 @@ 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.8.0 — the bundled agy bridge speaks the catalog the installed CLI actually serves, and grounding stops needing a shell (AD-095; antigravity-cli-bridge 5.2.0)
|
|
8
|
+
|
|
9
|
+
**A model display string is matched exactly, so a stale one is not a documentation bug — it is a
|
|
10
|
+
dispatch that refuses before it spends anything.** The bundled agy bridge had been describing a
|
|
11
|
+
catalog captured from CLI v1.0.13 while the installed binary moved to 1.1.13. The user-facing
|
|
12
|
+
catalog tables and every default pin now carry bytes read off `agy models` on the live binary,
|
|
13
|
+
which also turned up a `Gemini 3.6 Flash` family no announcement mentioned and confirmed 3.5 Flash
|
|
14
|
+
is still served. (The wrapper's own header comment stays a compact family inventory and now says
|
|
15
|
+
so, pointing at `agy models` for the exact strings.)
|
|
16
|
+
|
|
17
|
+
- **`Gemini 3.7 Flash (High)` is the bridge default for both roles** — `agy-run` and `agy-review` —
|
|
18
|
+
and joins the review wrapper's frontier set, so a council review on it stays advisory-silent.
|
|
19
|
+
Asserting frontier grade for the review lane was the maintainer's explicit call, not a default
|
|
20
|
+
that drifted. Any model remains selectable through `AGY_MODEL`; the sub-frontier advisory is
|
|
21
|
+
still a silenceable warning, never a gate.
|
|
22
|
+
- **The catalog lists every served row individually.** The 3.6 and 3.5 families are enumerated
|
|
23
|
+
Low/Medium/High rather than collapsed into `(Low|Medium|High)` — a collapsed row reads as a
|
|
24
|
+
display string that does not exist, and pasting it fails.
|
|
25
|
+
- **The reference stops overclaiming the wrapper's output.** v1.1.13 adds `--output-format
|
|
26
|
+
json|stream-json`, `--json-schema`, `--effort` and `--mode`; the wrapper adopts none of them, so
|
|
27
|
+
the docs now say text-DEFAULT and state plainly that raw passthrough JSON rides without
|
|
28
|
+
first-class parsing or validation. The old "no JSON output mode" sentence had become false.
|
|
29
|
+
- **`grounding.mjs --extra <text|@file>` merges orchestrator facts inside the tool.** Appending
|
|
30
|
+
live judgment facts to an emitted facts payload had been a shell append four times running; it is
|
|
31
|
+
now an input. Extras append byte-verbatim after the mechanical sections. The read surface is
|
|
32
|
+
deliberately narrow and fail-closed: an `@file` must sit inside a PROVEN work tree (a successful
|
|
33
|
+
`git rev-parse --show-toplevel` — never a `cwd` fallback) or the system temp surface, never
|
|
34
|
+
inside the git dir including a linked worktree's `.git` gitfile, and it is read through the kit's
|
|
35
|
+
no-follow descriptor door so a FIFO cannot block the assembler and a symlink leaf cannot
|
|
36
|
+
substitute its target. Git location variables (`GIT_DIR`, `GIT_WORK_TREE`, …) are scrubbed before
|
|
37
|
+
every git query, so an ambient override cannot prove a foreign tree.
|
|
38
|
+
|
|
7
39
|
## 5.7.0 — what the kit emits is now something a test executed, a claim it proved, or a command you can run (AD-092 + AD-093 + AD-094; memory 4.3.0)
|
|
8
40
|
|
|
9
41
|
**Three feedback plans, one release.** A live upgrade session on a deployed TypeScript project
|
package/README.md
CHANGED
|
@@ -237,7 +237,7 @@ file), or run the guarded `/agent-workflow-kit uninstall`.
|
|
|
237
237
|
| `/agent-workflow-kit set-recipe` | any time | **config writer** for `docs/ai/orchestration.json`: tell the agent your preference in plain language and it maps it to explicit `--set <activity>.<slot>=<recipe>` / `--unset` ops; the kit validates, **previews by default**, and writes only on `--write` (deployment-gated, atomic, symlink/TOCTOU-safe), resolving the effective recipe vs live readiness. Writes **only** that file — **never runs a backend, never commits**; hand-editing stays fully supported. |
|
|
238
238
|
| `/agent-workflow-kit review-state` | any time | **read-only review-receipt checker** — makes "reviewed ≠ shipped" detectable: the bridge review wrappers append a receipt per successful review (into a file inside the git dir — never committable); this checks that every backend your configured `plan-execution.review` recipe names holds a **fresh, grounded receipt for the current uncommitted tree** (any later edit moves the fingerprint and stales the receipt; a review continuation never re-attests a folded tree). `--check` gives a gate exit code to declare in `docs/ai/gates.json` **by hand or via the consent-gated seeder** (preview → your explicit yes; never without consent). `--await [--timeout <s>]` (AD-049) BLOCKS until every recipe-named backend has receipted the current tree — the durable completion signal is the receipt, never a process event — so you wait for the bridges instead of hand-polling. Never writes, never commits, never runs a subscription CLI; it spawns read-only `git` queries to fingerprint the tree — and `git commit --no-verify` stays possible (discipline, not a sandbox). |
|
|
239
239
|
| `/agent-workflow-kit sandbox-masks` | any time | **cosmetic exclude lane for sandbox device masks** — an OS sandbox (Claude Code) injects character-device masks into the work tree as untracked `git status` noise; the review domain already ignores them **by construction** (never-committable untracked classes — char/block devices, FIFOs, sockets — are excluded from the fingerprint, the assembled review payload, and the clean checks). This mode hides them from `git status` too: flagless = read-only probe (derives the CURRENT mask set from the unfiltered walk + lstat — never a frozen list — and revalidates fenced entries, loudly flagging one that became a real path); `--apply` = consent-gated FULL-BLOCK replace of its own fenced block in `git rev-parse --git-path info/exclude` (stale masks drop by construction; `--clear` always means REMOVE the block — it takes precedence over the derivation). Writes ONLY its fence — never `.gitignore`, never global config; symlinked/non-regular exclude paths and malformed fences fail closed. Watch note: a real file at an excluded path is silently skipped by bulk staging (`git add -A`/`git add .`) — delete the stale line first; the probe flags exactly this case. |
|
|
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). 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. |
|
|
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). `--extra <text|@file>` (repeatable) appends your own facts **byte-verbatim** after the mechanical sections, so the merge is a tool input rather than a shell append — an `@file` must sit inside the proven git work tree (never the git dir) or the system temp surface, and is read through a no-follow descriptor (a FIFO cannot block it, a symlink leaf cannot substitute its target). 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 core-evidence` | any time | **the ONE loop-evidence writer** (strip-the-kit) — every core evidence record lands in a single append-only JSONL store inside the git dir (never committable; versioned schema, latest-per-key supersession, byte-identical duplicates refused, malformed lines fail every reader closed). `red-proof "<file>#<pattern>"` declares an observed-red **BEFORE a bugfix** (N/N red runs + content custody + base + the pre-fix fingerprint; green/mixed/timeout are DISTINGUISHED refusals — nothing written); `degrade --backend --reason` is the ONLY escape for an unavailable review backend (per-tree, never all backends); `summary` renders the whole loop state statelessly (gate result · per-backend verdicts · red-proofs · degrades) — no ledger, no rounds, nothing remembered. Honest residual: records are forgeable — self-discipline, not a security boundary. Never commits, never runs a subscription CLI. |
|
|
242
242
|
| `/agent-workflow-kit coverage-check` | any time | **the final-run checker** (D3(c)+(d)) — **certifies coverage ONLY inside the `--final` run that owns the lcov** (ownership is exclusive by CONVENTION over the fixed path, not enforced — a concurrent writer to it is a stated residual, queued as LCOV-EXCLUSIVE-OWNERSHIP): an artifact on disk proves nothing about the tree it came from, so a standalone run prints its findings and states `attested=no` / `NO VERDICT` rather than a PASS (an lcov that predates an edit would otherwise certify a line the suite never executed). `attested=` claims a verdict was ISSUED, pass or fail — a run over uncovered lines still reads `attested=yes` and still exits 1, and a run whose coverage arm never executed (no lcov) reads `attested=no` even inside `--final`, because nothing was read and nothing is certified. The runner passes a nonce whose one-way commitment over `{nonce, fingerprint, base}` is the `final-start.attempt` it recorded; a context describing another tree, or matching no recorded attempt, is a REFUSAL, never a verdict. Findings are unchanged — reads the lcov the declared `unit-tests` gate produced at the FIXED git-dir path and fails on any uncovered CHANGED executable Node line (listed `file:line`; a changed file absent from the map is a file-level red; out-of-domain/unsupported files are LISTED — the claim narrowed honestly); VERIFIES every current-base red-proof declaration (bound test exists · custody hash unchanged · green N/N now · pre-fix fingerprint differs); prints `lcov-sha256=<hex|none>` of the exact bytes it consumed — the sha the `--final` receipt binds and re-hashes. An absent lcov is a LOUD `skipped-no-lcov`; a symlinked path is a refusal. `--check` is the gate exit code — declare it as the LAST gate (`run-gates --final` refuses otherwise). Read-only. |
|
|
243
243
|
| `/agent-workflow-kit commit-guard` | any time | **the read-only pre-commit guard** (D10) — makes the commit capture the whole current working tree, so «verified» and «about to be committed» are the same bytes (the receipt itself has a stated residual — see the mode doc). FIRST it refuses an **INDEX that lags the verified working tree** (the gates and the fingerprint describe the WORKING tree while `git commit` takes the INDEX alone, and the fingerprint cannot tell them apart — so a lagging index used to ship a strict subset of what was verified): unstaged tracked paths or reviewable untracked-not-ignored paths, named up to a bounded cap with the remainder stated, a dirty tracked **submodule** named separately with its own recovery, and fail-closed on an undecidable probe. This deliberately blocks a partial commit. Then it binds the LATEST completed `run-gates --final` receipt to the EXACT current tree: refuses on a missing/red/stale receipt, fingerprint drift under the run, a dangling later attempt, declaration content drift, evidence-hash or lcov drift, or unsatisfied review obligations (the same review-state decision, recomputed over a sanitized env — forged out-of-repo stores never satisfy). Re-runs NO gate or test. Wire it into `.git/hooks/pre-commit` (the installer writes the RESOLVED invocation). `git commit --no-verify` stays the stated residual. |
|
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.8.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: antigravity-cli-bridge
|
|
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
|
|
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 headless behaviour.
|
|
4
4
|
metadata:
|
|
5
|
-
version: '5.
|
|
5
|
+
version: '5.2.0'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# antigravity-cli-bridge
|
|
@@ -53,16 +53,22 @@ keep probes short (see *How the main agent drives agy*).
|
|
|
53
53
|
## Models
|
|
54
54
|
|
|
55
55
|
Pass the **exact display string** to `--model` (or set `AGY_MODEL`). The wrapper defaults to
|
|
56
|
-
`Gemini 3.
|
|
57
|
-
list wins.
|
|
56
|
+
`Gemini 3.7 Flash (High)`. Run `agy models` for the live list — if it differs from this table, the
|
|
57
|
+
live list wins.
|
|
58
58
|
|
|
59
59
|
| Model string | Use it for |
|
|
60
60
|
|---|---|
|
|
61
|
-
| `Gemini 3.
|
|
62
|
-
| `Gemini 3.
|
|
63
|
-
| `Gemini 3.
|
|
61
|
+
| `Gemini 3.7 Flash (Low)` | cheapest; reachability checks, smoke tests, simple transforms |
|
|
62
|
+
| `Gemini 3.7 Flash (Medium)` | cheap probes, context-reachability checks, quick summaries |
|
|
63
|
+
| `Gemini 3.7 Flash (High)` | wrapper + review default; asserted frontier-grade (fork (a)) |
|
|
64
|
+
| `Gemini 3.6 Flash (Low)` | previous Flash generation, still served — prefer 3.7 |
|
|
65
|
+
| `Gemini 3.6 Flash (Medium)` | previous Flash generation, still served — prefer 3.7 |
|
|
66
|
+
| `Gemini 3.6 Flash (High)` | previous Flash generation, still served — prefer 3.7 |
|
|
67
|
+
| `Gemini 3.5 Flash (Low)` | older Flash generation, still served — prefer 3.7 |
|
|
68
|
+
| `Gemini 3.5 Flash (Medium)` | older Flash generation, still served — prefer 3.7 |
|
|
69
|
+
| `Gemini 3.5 Flash (High)` | older Flash generation, still served — prefer 3.7 |
|
|
64
70
|
| `Gemini 3.1 Pro (Low)` | cheaper Pro pass for medium reasoning |
|
|
65
|
-
| `Gemini 3.1 Pro (High)` |
|
|
71
|
+
| `Gemini 3.1 Pro (High)` | hard reasoning, plan critique, architecture review (slower, deeper) |
|
|
66
72
|
| `Claude Sonnet 4.6 (Thinking)` | a Claude second opinion through the same subscription |
|
|
67
73
|
| `Claude Opus 4.6 (Thinking)` | strongest Claude reasoning available via `agy` |
|
|
68
74
|
| `GPT-OSS 120B (Medium)` | an open-weights cross-check / diversity pass |
|
|
@@ -89,10 +95,12 @@ AGY_HARD_TIMEOUT=8m agy-run "..." # hard wall-clock cap via timeout(
|
|
|
89
95
|
agy-run "..." -- --add-dir . # passthrough agy flags (never a permission widener)
|
|
90
96
|
```
|
|
91
97
|
|
|
92
|
-
`agy` is **headless-only** here (`-p`/`--print`)
|
|
93
|
-
|
|
98
|
+
`agy` is **headless-only** here (`-p`/`--print`); v1.1.13 adds `--output-format json|stream-json`,
|
|
99
|
+
and text stays the wrapper default — JSON can ride passthrough (`-- --output-format json`) but with
|
|
100
|
+
no first-class parsing/validation (adoption is a backlog item). If you need structure, ask
|
|
101
|
+
for Markdown with explicit headings and validate it
|
|
94
102
|
yourself. Wrapper inputs: first argument is the prompt (`text`, `-` for stdin, or `@file`);
|
|
95
|
-
`AGY_MODEL` (default `Gemini 3.
|
|
103
|
+
`AGY_MODEL` (default `Gemini 3.7 Flash (High)`); `AGY_TIMEOUT` → `--print-timeout` (default `5m`);
|
|
96
104
|
`AGY_HARD_TIMEOUT` → hard `timeout(1)` wall-clock cap (default = `AGY_TIMEOUT`); extra `agy` flags
|
|
97
105
|
after `--`. Full detail: [`references/models-and-flags.md`](references/models-and-flags.md).
|
|
98
106
|
|
|
@@ -154,7 +162,7 @@ release). `agy-review … --nonce <n>` is the plain-argument equivalent
|
|
|
154
162
|
(one seam; flag and a non-empty env must agree, a disagreeing pair refuses pre-spend) — the lane
|
|
155
163
|
for hosts whose dispatch policy has no env-prefix form.
|
|
156
164
|
|
|
157
|
-
Frontier default `Gemini 3.
|
|
165
|
+
Frontier default `Gemini 3.7 Flash (High)`; **any** model is allowed (a sub-frontier one earns a
|
|
158
166
|
silenceable `AGY_PROBE=1` advisory). An oversized `code` review is **DELIVERED, not refused**: the
|
|
159
167
|
change set is cut into under-cap parts, fed over continuation turns and reviewed in a final turn, and
|
|
160
168
|
the answer must reproduce a line the wrapper picked from each part — a missing or wrong echo is a
|
|
@@ -190,9 +198,9 @@ without an explicit `--add-dir`, so ground a review **self-contained** via `agy-
|
|
|
190
198
|
rather than relying on `agy` to read the change set. Re-runnable from a project root (use a cheap model):
|
|
191
199
|
|
|
192
200
|
```bash
|
|
193
|
-
AGY_MODEL="Gemini 3.
|
|
201
|
+
AGY_MODEL="Gemini 3.7 Flash (Low)" agy-run \
|
|
194
202
|
"Read the cwd context file and state the dialogue language plus one Hard Constraint, in two lines."
|
|
195
|
-
AGY_MODEL="Gemini 3.
|
|
203
|
+
AGY_MODEL="Gemini 3.7 Flash (Low)" agy-run \
|
|
196
204
|
"Without me pointing you at any file, name a project-specific skill under .agents/skills/ here and cite its path."
|
|
197
205
|
```
|
|
198
206
|
|
|
@@ -241,15 +249,16 @@ checklist, prompt templates, output handling). Essentials:
|
|
|
241
249
|
- Subdirectory `CLAUDE.md` files are **not** auto-loaded by `agy` (only the cwd context file +
|
|
242
250
|
`.agents/skills/`). Put cross-cutting rules in the root context file, or include local rules in the
|
|
243
251
|
prompt when they matter.
|
|
244
|
-
- **
|
|
245
|
-
|
|
252
|
+
- **Text is the wrapper default** — the CLI's 1.1.x `--output-format json|stream-json` can ride
|
|
253
|
+
passthrough but with no first-class parsing/validation (adoption is backlog) — and there is
|
|
254
|
+
**no `agy inspect`**: no machine-readable introspection.
|
|
246
255
|
- Model names must match the `agy models` display strings **exactly**.
|
|
247
256
|
- **Quota is finite.** Heavy use of Pro/Claude models can exhaust the subscription; prefer Flash for
|
|
248
257
|
cheap work.
|
|
249
258
|
- **A run can't hang forever.** The wrapper caps `agy` with `timeout(1)` (`AGY_HARD_TIMEOUT`,
|
|
250
259
|
default = `AGY_TIMEOUT`) because `agy`'s own `--print-timeout` is **not** a reliable wall-clock
|
|
251
260
|
kill (a run was seen surviving 32 min past a 10m `--print-timeout`). A heavy `--add-dir` agentic
|
|
252
|
-
prompt on
|
|
261
|
+
prompt on a slow model (e.g. `Gemini 3.1 Pro (High)`) can run unbounded — prefer a faster model or
|
|
253
262
|
a **self-contained prompt** (no `--add-dir`); an "exceeded the hard cap" error is the guard firing.
|
|
254
263
|
- `agy` output is plain text and may be incomplete or out of date — treat it as advisory until the
|
|
255
264
|
main agent verifies it.
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
# agy-review --conversation <id> [--decided @f] [--focus "…"] # resume a specific conversation
|
|
36
36
|
#
|
|
37
37
|
# Environment (every optional var has an explicit default so a no-env run is safe under set -u):
|
|
38
|
-
# AGY_MODEL default "Gemini 3.
|
|
38
|
+
# AGY_MODEL default "Gemini 3.7 Flash (High)"; ANY model allowed (advisory warn off-frontier).
|
|
39
39
|
# Set empty (AGY_MODEL=) to drop --model and use agy's settings.json.
|
|
40
40
|
# AGY_HARD_TIMEOUT default 30m (duration string; the timeout(1) hard cap via agy-run)
|
|
41
41
|
# AGY_TIMEOUT default = AGY_HARD_TIMEOUT (agy's soft --print-timeout)
|
|
@@ -322,11 +322,11 @@ aw_resolve_timeout_bin() {
|
|
|
322
322
|
printf '%s' "$bin"
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
DEFAULT_AGY_REVIEW_MODEL="Gemini 3.
|
|
325
|
+
DEFAULT_AGY_REVIEW_MODEL="Gemini 3.7 Flash (High)"
|
|
326
326
|
# Review-receipt identity (AD-038). AW_BRIDGE_VERSION mirrors this bridge's SKILL.md/capability.json
|
|
327
327
|
# version (drift-guarded by agy-review.test.mjs against capability.json).
|
|
328
328
|
AW_RECEIPT_BACKEND="agy"
|
|
329
|
-
AW_BRIDGE_VERSION="5.
|
|
329
|
+
AW_BRIDGE_VERSION="5.2.0" # aw-version-anchor
|
|
330
330
|
# `-` not `:-` so an EXPLICIT empty AGY_MODEL= survives (drop --model, use settings.json — agy.sh:52).
|
|
331
331
|
AGY_MODEL="${AGY_MODEL-$DEFAULT_AGY_REVIEW_MODEL}"
|
|
332
332
|
# D5 control-byte screen — IMMEDIATELY after resolution, BEFORE the off-frontier advisory (or any
|
|
@@ -335,8 +335,9 @@ if [[ "$AGY_MODEL" == *[$'\x01'-$'\x1f'$'\x7f']* ]]; then
|
|
|
335
335
|
echo "error: AGY_MODEL contains control bytes — fix the setting (env or bridge-settings.conf) and re-run." >&2
|
|
336
336
|
exit 2
|
|
337
337
|
fi
|
|
338
|
-
# Frontier review models. ANY model is allowed; a sub-frontier one only earns a soft, silenceable
|
|
339
|
-
|
|
338
|
+
# Frontier review models. ANY model is allowed; a sub-frontier one only earns a soft, silenceable
|
|
339
|
+
# warning. Gemini 3.7 Flash (High) is asserted frontier-grade (fork (a), maintainer 2026-08-14).
|
|
340
|
+
FRONTIER_SET=("Gemini 3.7 Flash (High)" "Gemini 3.1 Pro (High)" "Claude Opus 4.6 (Thinking)" "Claude Sonnet 4.6 (Thinking)")
|
|
340
341
|
|
|
341
342
|
# Duration-string timeouts (NOT codex's bare seconds): agy-run forwards a duration to --print-timeout,
|
|
342
343
|
# and the timeout(1) hard cap is a duration too — never numerically compared, so 30m vs 2h is fine.
|
|
@@ -285,7 +285,16 @@ describe('agy-review.sh — model policy advisory (1)', () => {
|
|
|
285
285
|
rmSync(sb.home, { recursive: true, force: true });
|
|
286
286
|
assert.equal(r.status, 0, r.stderr);
|
|
287
287
|
assert.doesNotMatch(r.stderr, /non-frontier model/);
|
|
288
|
-
assert.match(r.argv, /Gemini 3\.
|
|
288
|
+
assert.match(r.argv, /Gemini 3\.7 Flash \(High\)/, 'the frontier default reaches agy');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('an explicit Gemini 3.7 Flash (High) is FRONTIER — no advisory (fork (a), maintainer 2026-08-14)', () => {
|
|
292
|
+
const sb = makeSandbox();
|
|
293
|
+
const r = run(sb, { args: ['code', '--facts', 'a tiny fact'], env: { AGY_MODEL: 'Gemini 3.7 Flash (High)' } });
|
|
294
|
+
rmSync(sb.home, { recursive: true, force: true });
|
|
295
|
+
assert.equal(r.status, 0, r.stderr);
|
|
296
|
+
assert.doesNotMatch(r.stderr, /non-frontier model/, 'a FRONTIER_SET member never warns');
|
|
297
|
+
assert.match(r.argv, /Gemini 3\.7 Flash \(High\)/);
|
|
289
298
|
});
|
|
290
299
|
});
|
|
291
300
|
|
|
@@ -2444,8 +2453,8 @@ describe('agy-review.sh — dispatch-posture labeling (D5)', () => {
|
|
|
2444
2453
|
const receipts = readReceipts(sb.repo);
|
|
2445
2454
|
rmSync(sb.home, { recursive: true, force: true });
|
|
2446
2455
|
assert.equal(r.status, 0, r.stderr);
|
|
2447
|
-
assert.match(r.stderr, /review posture: model=Gemini 3\.
|
|
2448
|
-
assert.deepEqual(receipts[0].posture, { model: 'Gemini 3.
|
|
2456
|
+
assert.match(r.stderr, /review posture: model=Gemini 3\.7 Flash \(High\)/, 'the banner states the actual run posture');
|
|
2457
|
+
assert.deepEqual(receipts[0].posture, { model: 'Gemini 3.7 Flash (High)' }, 'banner ↔ receipt parity');
|
|
2449
2458
|
assert.deepEqual(Object.keys(receipts[0]), Object.keys(RECEIPT_FIXTURE), 'fixture key set + order');
|
|
2450
2459
|
});
|
|
2451
2460
|
|
|
@@ -2498,7 +2507,7 @@ describe('agy-review.sh — dispatch-posture labeling (D5)', () => {
|
|
|
2498
2507
|
const receipts = readReceipts(sb.repo);
|
|
2499
2508
|
rmSync(sb.home, { recursive: true, force: true });
|
|
2500
2509
|
assert.equal(r.status, 0, r.stderr);
|
|
2501
|
-
assert.match(r.stderr, /^review posture: model=Gemini 3\.
|
|
2510
|
+
assert.match(r.stderr, /^review posture: model=Gemini 3\.7 Flash \(High\) timeout=30m$/m);
|
|
2502
2511
|
assert.deepEqual(Object.keys(receipts[0].posture), ['model'], 'timeout never enters the receipt posture');
|
|
2503
2512
|
});
|
|
2504
2513
|
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
# policy (no plan contract, no auto-approve, no workspace edits) — that is left
|
|
18
18
|
# to whatever flow we design later, which can opt in via passthrough flags.
|
|
19
19
|
#
|
|
20
|
-
#
|
|
20
|
+
# Model families (compact inventory only; run `agy models` for exact display strings, then pass
|
|
21
|
+
# one via AGY_MODEL):
|
|
22
|
+
# Gemini 3.7 Flash (Low|Medium|High), Gemini 3.6 Flash (Low|Medium|High),
|
|
21
23
|
# Gemini 3.5 Flash (Low|Medium|High), Gemini 3.1 Pro (Low|High),
|
|
22
24
|
# Claude Sonnet 4.6 (Thinking), Claude Opus 4.6 (Thinking), GPT-OSS 120B (Medium)
|
|
23
25
|
#
|
|
@@ -237,8 +239,9 @@ if ! command -v agy >/dev/null 2>&1; then
|
|
|
237
239
|
exit 127
|
|
238
240
|
fi
|
|
239
241
|
|
|
240
|
-
# `-` (empty) => skip --model and let agy use settings.json; default to
|
|
241
|
-
|
|
242
|
+
# `-` (empty) => skip --model and let agy use settings.json; default to Flash (High) — asserted
|
|
243
|
+
# frontier-grade (fork (a), maintainer 2026-08-14).
|
|
244
|
+
AGY_MODEL="${AGY_MODEL-Gemini 3.7 Flash (High)}"
|
|
242
245
|
AGY_TIMEOUT="${AGY_TIMEOUT:-5m}"
|
|
243
246
|
AGY_TIMEOUT="$(aw_effective_timeout AGY_TIMEOUT 5m)"
|
|
244
247
|
# Hard wall-clock cap (defaults to AGY_TIMEOUT). agy's own --print-timeout is NOT a reliable
|
|
@@ -355,7 +358,7 @@ set -e
|
|
|
355
358
|
if [[ $rc -eq 124 || $rc -eq 137 ]]; then
|
|
356
359
|
echo "error: agy exceeded the hard cap AGY_HARD_TIMEOUT=$AGY_HARD_TIMEOUT and was terminated." >&2
|
|
357
360
|
echo " This usually means a heavy '--add-dir' agentic run, or the slowest model looping." >&2
|
|
358
|
-
echo " Retry with a faster model (e.g. AGY_MODEL='Gemini 3.
|
|
361
|
+
echo " Retry with a faster model (e.g. AGY_MODEL='Gemini 3.7 Flash (Low)') or a" >&2
|
|
359
362
|
echo " self-contained prompt without --add-dir. Raise AGY_HARD_TIMEOUT only if the run is healthy." >&2
|
|
360
363
|
fi
|
|
361
364
|
exit $rc
|
|
@@ -447,6 +447,30 @@ describe('agy.sh — bridge settings file (bridges 2.3.0)', { concurrency: true
|
|
|
447
447
|
});
|
|
448
448
|
});
|
|
449
449
|
|
|
450
|
+
// ── the wrapper's OWN default model (fork (a), round-1 council F3) ────────────────
|
|
451
|
+
describe('agy.sh — default model pin', () => {
|
|
452
|
+
it('absent AGY_MODEL → the stub argv carries --model Gemini 3.7 Flash (High)', () => {
|
|
453
|
+
const home = makeSandbox(ARGV_STUB);
|
|
454
|
+
const argvFile = join(home, 'argv.txt');
|
|
455
|
+
const r = runWrapper(home, { AGY_STUB_ARGV: argvFile });
|
|
456
|
+
const argv = readFileSync(argvFile, 'utf8');
|
|
457
|
+
rmSync(home, { recursive: true, force: true });
|
|
458
|
+
assert.equal(r.status, 0, r.stderr);
|
|
459
|
+
assert.match(argv, /^--model$/m, 'the default run passes --model');
|
|
460
|
+
assert.match(argv, /^Gemini 3\.7 Flash \(High\)$/m, 'the wrapper default is the probed display string');
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it("explicit AGY_MODEL='' drops --model entirely (settings.json takes over)", () => {
|
|
464
|
+
const home = makeSandbox(ARGV_STUB);
|
|
465
|
+
const argvFile = join(home, 'argv.txt');
|
|
466
|
+
const r = runWrapper(home, { AGY_MODEL: '', AGY_STUB_ARGV: argvFile });
|
|
467
|
+
const argv = readFileSync(argvFile, 'utf8');
|
|
468
|
+
rmSync(home, { recursive: true, force: true });
|
|
469
|
+
assert.equal(r.status, 0, r.stderr);
|
|
470
|
+
assert.doesNotMatch(argv, /^--model$/m, 'an explicit empty model never emits --model');
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
|
|
450
474
|
// ── settings surface ⟷ manifest (drift guard, D6) ────────────────────────────────
|
|
451
475
|
// agy-run's --help stays candidate-C (not contract-pinned), but its SETTINGS surface
|
|
452
476
|
// is manifest-pinned like the other three wrappers: the Settings help section and the
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"schema": 1,
|
|
4
4
|
"name": "antigravity-cli-bridge",
|
|
5
5
|
"kind": "execution-backend",
|
|
6
|
-
"version": "5.
|
|
6
|
+
"version": "5.2.0",
|
|
7
7
|
"provides": ["review", "probe"],
|
|
8
|
-
"posture": { "model": "Gemini 3.
|
|
8
|
+
"posture": { "model": "Gemini 3.7 Flash (High)" },
|
|
9
9
|
"roles": {
|
|
10
10
|
"review": {
|
|
11
11
|
"cmd": "agy-review",
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
],
|
|
181
181
|
"guardrails": [
|
|
182
182
|
{ "value": "subscription-only — every *_API_KEY env var is unset before the run", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
183
|
-
{ "value": "any model is selectable via AGY_MODEL; the default is Gemini 3.
|
|
183
|
+
{ "value": "any model is selectable via AGY_MODEL; the default is Gemini 3.7 Flash (High)", "enforcement": "advisory", "source": "bin/agy.sh" },
|
|
184
184
|
{ "value": "hard wall-clock cap AGY_HARD_TIMEOUT (built-in default 5m)", "enforcement": "enforced", "condition": "only while timeout(1)/gtimeout is on PATH — otherwise the wrapper warns and runs uncapped", "source": "capability.json settings.AGY_HARD_TIMEOUT" },
|
|
185
185
|
{ "value": "the prompt rides a single argv — over AGY_MAX_PROMPT_BYTES (120000) the run refuses", "enforcement": "enforced", "source": "bin/agy.sh" },
|
|
186
186
|
{ "value": "no review posture, no grounding, no receipt — the reply is raw model output", "enforcement": "advisory", "source": "bin/agy.sh" }
|
|
@@ -18,13 +18,14 @@ edits, verification, and final judgment.
|
|
|
18
18
|
|
|
19
19
|
| Task | Model |
|
|
20
20
|
|---|---|
|
|
21
|
-
| Reachability / smoke / "is it wired?" | `Gemini 3.
|
|
22
|
-
| Cheap probes, summaries | `Gemini 3.
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
| Same reasoning, lower quota cost | `Gemini 3.1 Pro (Low)` |
|
|
21
|
+
| Reachability / smoke / "is it wired?" | `Gemini 3.7 Flash (Low)` |
|
|
22
|
+
| Cheap probes, summaries | `Gemini 3.7 Flash (Medium)` |
|
|
23
|
+
| Review, reasoning, careful drafting | `Gemini 3.7 Flash (High)` (wrapper default; asserted frontier-grade) |
|
|
24
|
+
| Slower, deeper reasoning pass | `Gemini 3.1 Pro (High)` |
|
|
25
|
+
| Same Pro reasoning, lower quota cost | `Gemini 3.1 Pro (Low)` |
|
|
26
26
|
| A different engine's opinion | `Claude Sonnet 4.6 (Thinking)`, `Claude Opus 4.6 (Thinking)`, or `GPT-OSS 120B (Medium)` |
|
|
27
27
|
|
|
28
|
+
The 3.6 / 3.5 Flash families remain served — prefer 3.7 (newest generation at the same tiers).
|
|
28
29
|
Don't reach for Pro by reflex — Flash answers most reachability/probe questions for a fraction of the
|
|
29
30
|
quota.
|
|
30
31
|
|
|
@@ -94,7 +95,7 @@ What it does for you, and what YOU must supply:
|
|
|
94
95
|
`AGY_REVIEW_ALLOW_ADDDIR` is **RETIRED** (recognized, arms nothing): headless `agy` auto-denies its
|
|
95
96
|
own `read_file`, so the offload it armed could return a confident fabrication with no way to tell.
|
|
96
97
|
The kit never grants that permission — the feed exists so none is needed.
|
|
97
|
-
- **Model:** frontier default `Gemini 3.
|
|
98
|
+
- **Model:** frontier default `Gemini 3.7 Flash (High)`; any model is allowed (a sub-frontier one earns a
|
|
98
99
|
silenceable `AGY_PROBE=1` advisory). The service can still **stall on large/substantive prompts**
|
|
99
100
|
(Issue-001) — keep reviews **focused**; the hard timeout is the guard.
|
|
100
101
|
- **Posture banner — quote it verbatim.** Every review states its ACTUAL posture on ONE stderr line
|
|
@@ -127,9 +128,9 @@ Probe **reachability** from a project root (cheap model) — this is the one pla
|
|
|
127
128
|
context file is the point of the prompt:
|
|
128
129
|
|
|
129
130
|
```bash
|
|
130
|
-
AGY_MODEL="Gemini 3.
|
|
131
|
+
AGY_MODEL="Gemini 3.7 Flash (Low)" agy-run \
|
|
131
132
|
"Read the cwd context file and report the dialogue language plus one Hard Constraint."
|
|
132
|
-
AGY_MODEL="Gemini 3.
|
|
133
|
+
AGY_MODEL="Gemini 3.7 Flash (Low)" agy-run \
|
|
133
134
|
"Without using a file pointer, is there a project-specific planning skill in this repo? Name it and cite its path."
|
|
134
135
|
```
|
|
135
136
|
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# `agy` models & flags (reference)
|
|
2
2
|
|
|
3
3
|
The source of truth is the live binary: `agy --version`, `agy --help`, `agy models`. The tables below
|
|
4
|
-
were captured from **v1.
|
|
4
|
+
were captured from **v1.1.13**; if the binary disagrees, the binary wins. The wrapper command is
|
|
5
5
|
`agy-run`, backed by `bin/agy.sh`.
|
|
6
6
|
|
|
7
7
|
## Headless behaviour
|
|
8
8
|
|
|
9
9
|
Use `-p`, `--print`, or `--prompt` to run one non-interactive prompt and print the text response. The
|
|
10
|
-
wrapper always uses headless `-p`.
|
|
11
|
-
|
|
10
|
+
wrapper always uses headless `-p`. v1.1.13 adds `--output-format text|json|stream-json` and
|
|
11
|
+
`--json-schema` (structured output); **text stays the wrapper default** — raw passthrough
|
|
12
|
+
(`agy-run "…" -- --output-format json`) is possible but rides with NO first-class parsing or schema
|
|
13
|
+
validation (first-class adoption is a separate backlog item). When the caller needs structure
|
|
14
|
+
through the wrapper, ask for Markdown, bullets, tables, or fenced blocks, then validate the text
|
|
15
|
+
yourself.
|
|
12
16
|
|
|
13
17
|
## Wrapper contract
|
|
14
18
|
|
|
@@ -30,7 +34,7 @@ Environment:
|
|
|
30
34
|
|
|
31
35
|
| Var | Default | Effect |
|
|
32
36
|
|---|---|---|
|
|
33
|
-
| `AGY_MODEL` | `Gemini 3.
|
|
37
|
+
| `AGY_MODEL` | `Gemini 3.7 Flash (High)` | model display string; set empty (`AGY_MODEL=`) to drop `--model` and let `agy` use `settings.json` |
|
|
34
38
|
| `AGY_TIMEOUT` | `5m` | value passed to `--print-timeout` |
|
|
35
39
|
| `AGY_HARD_TIMEOUT` | `= AGY_TIMEOUT` | hard `timeout(1)` wall-clock cap (a duration string) |
|
|
36
40
|
| `AGY_MAX_PROMPT_BYTES` | `120000` | single-argv byte ceiling. `agy` takes the prompt as ONE `-p` argv; past `MAX_ARG_STRLEN` (~131072) `execve` fails with a cryptic `Argument list too long`. The wrapper measures the resolved `-`/`@file` prompt and fails loud over the ceiling. A huge **literal** `agy-run "<huge>"` fails at the wrapper's own `exec`, so route large prompts via `-`/`@file`. |
|
|
@@ -55,7 +59,7 @@ agy-review --continue | --conversation <id> [--decided @f] [--focus "…"] #
|
|
|
55
59
|
|
|
56
60
|
| Var | Default | Effect |
|
|
57
61
|
|---|---|---|
|
|
58
|
-
| `AGY_MODEL` | `Gemini 3.
|
|
62
|
+
| `AGY_MODEL` | `Gemini 3.7 Flash (High)` | frontier default (fork (a), 2026-08-14); **any** model is allowed — a sub-frontier one earns a silenceable advisory (quality-first, not a gate) |
|
|
59
63
|
| `AGY_PROBE` | `0` | `1` silences the off-frontier model advisory AND lets `code` run without `--facts` (an ungrounded probe never attests — its receipt is probe-marked) |
|
|
60
64
|
| `AGY_REVIEW_MAX_TOTAL_BYTES` | `240000` | the ceiling on the SUM of all outgoing prompt bytes an oversized `code` review's chunked feed may send; checked BEFORE the first turn is spent |
|
|
61
65
|
| `AGY_REVIEW_ALLOW_ADDDIR` | `0` | **RETIRED** — recognized so an existing settings line never warns as unknown, but it arms nothing. An oversized `code` review is a chunked feed with a per-part delivery proof; the `--add-dir` offload it armed could not be verified (headless `agy` auto-denies `read_file`) |
|
|
@@ -72,11 +76,17 @@ Pass the **exact display string** from `agy models`, or set `AGY_MODEL`.
|
|
|
72
76
|
|
|
73
77
|
| Model string | Practical use |
|
|
74
78
|
|---|---|
|
|
75
|
-
| `Gemini 3.
|
|
76
|
-
| `Gemini 3.
|
|
77
|
-
| `Gemini 3.
|
|
79
|
+
| `Gemini 3.7 Flash (Low)` | lowest-cost smoke tests, cheap probes, simple rewrites (newest Flash) |
|
|
80
|
+
| `Gemini 3.7 Flash (Medium)` | fast summaries, context-reachability checks |
|
|
81
|
+
| `Gemini 3.7 Flash (High)` | wrapper + review default — asserted frontier-grade (fork (a)) |
|
|
82
|
+
| `Gemini 3.6 Flash (Low)` | previous Flash generation, still served — prefer 3.7 |
|
|
83
|
+
| `Gemini 3.6 Flash (Medium)` | previous Flash generation, still served — prefer 3.7 |
|
|
84
|
+
| `Gemini 3.6 Flash (High)` | previous Flash generation, still served — prefer 3.7 |
|
|
85
|
+
| `Gemini 3.5 Flash (Low)` | older Flash generation, still served — prefer 3.7 |
|
|
86
|
+
| `Gemini 3.5 Flash (Medium)` | older Flash generation, still served — prefer 3.7 |
|
|
87
|
+
| `Gemini 3.5 Flash (High)` | older Flash generation, still served — prefer 3.7 |
|
|
78
88
|
| `Gemini 3.1 Pro (Low)` | cheaper Pro pass for medium reasoning |
|
|
79
|
-
| `Gemini 3.1 Pro (High)` |
|
|
89
|
+
| `Gemini 3.1 Pro (High)` | hard reasoning, plan critique, architecture review (slower, deeper) |
|
|
80
90
|
| `Claude Sonnet 4.6 (Thinking)` | cross-vendor reasoning comparison |
|
|
81
91
|
| `Claude Opus 4.6 (Thinking)` | expensive deep critique when the user wants another high-end pass |
|
|
82
92
|
| `GPT-OSS 120B (Medium)` | open-weights-style comparison / diversity pass |
|
|
@@ -84,11 +94,11 @@ Pass the **exact display string** from `agy models`, or set `AGY_MODEL`.
|
|
|
84
94
|
Examples:
|
|
85
95
|
|
|
86
96
|
```bash
|
|
87
|
-
AGY_MODEL="Gemini 3.
|
|
97
|
+
AGY_MODEL="Gemini 3.7 Flash (Low)" agy-run "Read AGENTS.md and report one Hard Constraint."
|
|
88
98
|
AGY_MODEL="Claude Sonnet 4.6 (Thinking)" AGY_TIMEOUT=10m agy-run @review-prompt.md
|
|
89
99
|
```
|
|
90
100
|
|
|
91
|
-
## Flags (from `agy --help`, v1.
|
|
101
|
+
## Flags (from `agy --help`, v1.1.13)
|
|
92
102
|
|
|
93
103
|
| Flag | Meaning | Notes |
|
|
94
104
|
|---|---|---|
|
|
@@ -102,12 +112,19 @@ AGY_MODEL="Claude Sonnet 4.6 (Thinking)" AGY_TIMEOUT=10m agy-run @review-prompt.
|
|
|
102
112
|
| `--dangerously-skip-permissions` | auto-approve all tool permissions | avoid by default; use only with explicit user approval |
|
|
103
113
|
| `--sandbox` | run with terminal restrictions enabled | prefer when delegating a prompt that might trigger tool/terminal work |
|
|
104
114
|
| `--log-file <path>` | override the CLI log-file path | keep logs secret-free and out of committed artifacts |
|
|
115
|
+
| `--output-format <fmt>` | print-mode output: `text` (default), `json`, `stream-json` | NEW in 1.1.x; not wrapper-adopted (backlog) |
|
|
116
|
+
| `--json-schema <s\|path>` | enforce structured output (stream-json final result) | NEW in 1.1.x; not wrapper-adopted (backlog) |
|
|
117
|
+
| `--effort <low\|medium\|high>` | reasoning effort for the session | NEW in 1.1.x; the display strings already carry an effort tier — the wrapper keeps model selection in ONE place (`AGY_MODEL`) |
|
|
118
|
+
| `--mode <m>` | agent execution mode (`accept-edits`, `plan`) | NEW in 1.1.x; not used by the wrapper |
|
|
119
|
+
| `--agent` / `--project <id>` / `--new-project` | agent + project selection for the session | NEW in 1.1.x; not used by the wrapper |
|
|
120
|
+
| `--disable-slash-commands` | disable slash command/skill expansion in print mode | NEW in 1.1.x; not used by the wrapper |
|
|
105
121
|
|
|
106
|
-
## Subcommands (v1.
|
|
122
|
+
## Subcommands (v1.1.13)
|
|
107
123
|
|
|
108
|
-
`changelog`, `help`, `install`, `models`, `plugin` / `plugins`, `update`.
|
|
124
|
+
`agent` / `agents`, `changelog`, `help`, `install`, `models`, `plugin` / `plugins`, `update`.
|
|
109
125
|
|
|
110
|
-
**
|
|
126
|
+
**Still not available in v1.1.13:** any `agy inspect`. Wrapper output stays plain text (the
|
|
127
|
+
`--output-format` lane is not adopted here — see the backlog row).
|
|
111
128
|
|
|
112
129
|
## Project-context flags
|
|
113
130
|
|
|
@@ -9,7 +9,7 @@ works in any project.
|
|
|
9
9
|
```bash
|
|
10
10
|
curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
11
11
|
export PATH="$HOME/.local/bin:$PATH" # add to ~/.bashrc / ~/.zshrc to persist
|
|
12
|
-
agy --version # expect 1.
|
|
12
|
+
agy --version # expect 1.1.13 or newer
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
- The binary is **`agy`** (not `antigravity`); it installs to `~/.local/bin/agy`.
|
|
@@ -59,12 +59,13 @@ agy --version
|
|
|
59
59
|
echo "say OK" | agy-run -
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Expected: the version prints (`1.
|
|
62
|
+
Expected: the version prints (`1.1.13` or newer), then a short reply containing `OK`. If `agy-run`
|
|
63
63
|
reports `'agy' not found`, fix your `PATH` (step 1). If it asks you to sign in, complete step 2.
|
|
64
64
|
|
|
65
65
|
## Notes
|
|
66
66
|
|
|
67
|
-
- `agy-run` is headless and
|
|
67
|
+
- `agy-run` is headless and text by default; the CLI's 1.1.x `--output-format json` can ride
|
|
68
|
+
passthrough (`-- --output-format json`) but the wrapper adds no parsing/validation.
|
|
68
69
|
- `AGY_MODEL` selects the exact model display string; `AGY_TIMEOUT` controls `--print-timeout`.
|
|
69
70
|
- Extra `agy` flags go after `--`, e.g. `agy-run @prompt.md -- --add-dir .`.
|
|
70
71
|
- Re-run interactive `agy` only when the OAuth token expires or the account changes.
|
package/capability.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.8.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",
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- opt-in-capability: none — an on-demand assembler that leaves no persistent state the advisor could observe -->
|
|
4
4
|
|
|
5
|
-
The **grounded-review facts assembler** (AD-038) — an ungrounded `agy` review GUESSES, and while the grounding contract is mechanized (`agy-review code --facts @f`), populating the facts file was a manual chore. This mode emits the **mechanical** facts sources of a payload (constraints / autonomy / plan / ledger digest); the orchestrator still owns any judgment-bearing additions. **Catalogued honestly as a WRITER** — `--out <path>` writes one file — with the invariant: `--out` accepts **only system-temp destinations outside the repo ($TMPDIR / /tmp — rewritable scratch) or a FRESH gitignored in-repo path (create-only, exclusive write)** and REFUSES everything else: a tracked path, an in-repo not-ignored path (a new untracked file would itself move the review fingerprint the facts are about to ground), an EXISTING in-repo file even when gitignored (the `.env` clobber class — this writer is bridge-tier auto-allowable), any other outside-repo destination, and symlink/non-regular leaves; **stdout is the default**. It never commits and never runs a subscription CLI.
|
|
5
|
+
The **grounded-review facts assembler** (AD-038) — an ungrounded `agy` review GUESSES, and while the grounding contract is mechanized (`agy-review code --facts @f`), populating the facts file was a manual chore. This mode emits the **mechanical** facts sources of a payload (constraints / autonomy / plan / ledger digest); the orchestrator still owns any judgment-bearing additions — delivered via `--extra`, never a shell append onto the emitted file (corpus #88/#95). **Catalogued honestly as a WRITER** — `--out <path>` writes one file — with the invariant: `--out` accepts **only system-temp destinations outside the repo ($TMPDIR / /tmp — rewritable scratch) or a FRESH gitignored in-repo path (create-only, exclusive write)** and REFUSES everything else: a tracked path, an in-repo not-ignored path (a new untracked file would itself move the review fingerprint the facts are about to ground), an EXISTING in-repo file even when gitignored (the `.env` clobber class — this writer is bridge-tier auto-allowable), any other outside-repo destination, and symlink/non-regular leaves; **stdout is the default**. It never commits and never runs a subscription CLI.
|
|
6
6
|
|
|
7
|
-
Run `node ${CLAUDE_SKILL_DIR}/tools/grounding.mjs [--constraints] [--autonomy] [--plan <path>] [--reserve-bytes <n>] [--out <path>]`:
|
|
7
|
+
Run `node ${CLAUDE_SKILL_DIR}/tools/grounding.mjs [--constraints] [--autonomy] [--plan <path>] [--extra <text|@file>]... [--reserve-bytes <n>] [--out <path>]`:
|
|
8
8
|
|
|
9
9
|
1. **`--constraints`** — slice the root `AGENTS.md` **Hard Constraints** section, verbatim and whole (exactly ONE matching heading; zero or several is a loud STOP, never a guess — the marker-slot discipline).
|
|
10
10
|
2. **`--autonomy`** (AD-044 Plan 3) — append the COMPUTED effective autonomy policy: the shared resolver (`resolveAutonomy`) over the **git-top** `docs/ai/autonomy.json` renders every red-line + per-activity level with a stated source line. An ABSENT file is exit 0 — the computed defaults ARE the effective policy (unlike `velocity-profile --autonomy`, which writes settings and refuses an undeclared policy); a malformed/unreadable policy fails CLOSED (exit 1). Informational for the reviewing backend — enforcement stays the OS sandbox + the orchestrator. Rides between the constraints and the plan sections.
|
|
11
11
|
3. **`--plan <path>`** — extract the plan's decision-bearing canonical sections, verbatim + whole: `## Approach` (REQUIRED — its "What we are NOT doing" text rides inside; it is not a heading in canon) and `## Verification` (REQUIRED — STOP if missing), plus `## Decisions (locked)` when present (the optional engine §7 heading); a DUPLICATE heading is always a STOP.
|
|
12
|
+
4. **`--extra <text|@file>`** (corpus #88/#95 — the fourth firing of the same pre-dispatch append step) — append orchestrator-supplied facts byte-VERBATIM after the mechanical sections (repeatable, argv order; the `agy-review --facts` convention: literal text, or `@path` read whole through a race-free descriptor). An `@file` must resolve inside the PROVEN git work tree (rev-parse success — no cwd fallback; the git dir itself is refused) or the system temp surface — anything else refuses loudly (the exfil class: this tool is bridge-tier auto-allowable), as does a missing, EMPTY, or non-regular file (a FIFO cannot block the read). The merge happens INSIDE the tool, so the promptless lane is the invocation itself.
|
|
12
13
|
5. **Byte budget** — the output honors the same `AGY_MAX_PROMPT_BYTES` contract the agy wrapper enforces (override may only tighten; the OS argv ceiling is rejected), MINUS **`--reserve-bytes <n>`** — the artifact share the caller expects `agy-review` to add around these facts. Overflow is trimmed tail-first with a loud in-band marker + stderr report — never a silent cut.
|
|
13
14
|
6. Feed the result to the wrapper: `agy-review code --facts @<out>`. The `procedures` advisor renders this invocation as a concrete pre-step whenever the resolved review dispatch includes agy — populated with the in-flight plan path when exactly one plan is in flight.
|
|
14
15
|
|
|
15
|
-
**Invariants:** writer (writes at most the ONE `--out` scratch file — system-temp, or a fresh gitignored in-repo path, exclusive-create) · never commits · never runs a subscription CLI · verbatim slices
|
|
16
|
+
**Invariants:** writer (writes at most the ONE `--out` scratch file — system-temp, or a fresh gitignored in-repo path, exclusive-create) · never commits · never runs a subscription CLI · verbatim slices + verbatim extras (assembly is mechanical; facts judgment stays with the orchestrator — `--extra` carries it, the tool never edits it).
|
package/tools/grounding.mjs
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
// it is not a heading in canon) and `## Verification` (REQUIRED — STOP if
|
|
12
12
|
// missing), plus `## Decisions (locked)` (optional-if-absent, the engine §7
|
|
13
13
|
// heading this release adds); a DUPLICATE heading is always a STOP.
|
|
14
|
+
// --extra <text|@file> append orchestrator-supplied facts verbatim AFTER the mechanical halves
|
|
15
|
+
// (repeatable; @file reads are confined to the work tree + the system temp
|
|
16
|
+
// surface — the merge happens INSIDE the tool, corpus #88/#95).
|
|
14
17
|
//
|
|
15
18
|
// Byte budget: the output honors the same AGY_MAX_PROMPT_BYTES contract the agy wrapper enforces
|
|
16
19
|
// (default 120000; the override may only TIGHTEN — above the OS single-argv ceiling ~131000 is
|
|
@@ -31,6 +34,7 @@ import { tmpdir } from 'node:os';
|
|
|
31
34
|
import { pathToFileURL } from 'node:url';
|
|
32
35
|
import { spawnSync } from 'node:child_process';
|
|
33
36
|
import { fail } from './orchestration-config.mjs';
|
|
37
|
+
import { readRegularFileNoFollow } from './fs-read-nofollow.mjs';
|
|
34
38
|
// (f) --autonomy (AD-044 Plan 3): the effective per-project autonomy policy for the facts payload.
|
|
35
39
|
// READ core only — never autonomy-write.mjs (the import-split invariant).
|
|
36
40
|
import { AUTONOMY_REL, loadAutonomy, resolveAutonomy, isSparseSeedConfig } from './autonomy-config.mjs';
|
|
@@ -81,7 +85,7 @@ export const sliceSection = (text, heading, { optional = false, label = 'documen
|
|
|
81
85
|
|
|
82
86
|
// ── assembly ───────────────────────────────────────────────────────────────────────
|
|
83
87
|
|
|
84
|
-
export const assembleGrounding = ({ constraintsText = null, autonomyText = null, planText = null, planLabel = 'plan' } = {}) => {
|
|
88
|
+
export const assembleGrounding = ({ constraintsText = null, autonomyText = null, planText = null, planLabel = 'plan', extraTexts = [] } = {}) => {
|
|
85
89
|
const parts = [];
|
|
86
90
|
if (constraintsText != null) {
|
|
87
91
|
parts.push(sliceSection(constraintsText, CONSTRAINTS_HEADING, { label: 'AGENTS.md' }));
|
|
@@ -96,6 +100,10 @@ export const assembleGrounding = ({ constraintsText = null, autonomyText = null,
|
|
|
96
100
|
if (section != null) parts.push(section);
|
|
97
101
|
}
|
|
98
102
|
}
|
|
103
|
+
// Orchestrator extras ride LAST, verbatim in argv order — live judgment facts read after the
|
|
104
|
+
// mechanical slices, and the merge happens INSIDE the tool (corpus #88/#95: a shell append onto
|
|
105
|
+
// the emitted facts file was the recurring un-covered lane).
|
|
106
|
+
for (const t of extraTexts) parts.push(t);
|
|
99
107
|
return parts.join('\n');
|
|
100
108
|
};
|
|
101
109
|
|
|
@@ -151,10 +159,23 @@ const resolveAutonomyFacts = ({ cwd }) => {
|
|
|
151
159
|
return renderAutonomyFacts(config, source);
|
|
152
160
|
};
|
|
153
161
|
|
|
162
|
+
// The realpath'd system temp surface ($TMPDIR / os.tmpdir() / /tmp) — the shared scratch boundary
|
|
163
|
+
// for the --out write guard and the --extra read guard.
|
|
164
|
+
const systemTempRoots = () => [...new Set([tmpdir(), process.env.TMPDIR, '/tmp'].filter(Boolean).map((p) => {
|
|
165
|
+
try {
|
|
166
|
+
return realpathSync(p);
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}).filter(Boolean))];
|
|
171
|
+
|
|
154
172
|
// ── the --out destination guard (gitignored / out-of-repo scratch ONLY) ────────────────
|
|
155
173
|
|
|
156
174
|
const gitLine = (args, cwd) => {
|
|
157
|
-
|
|
175
|
+
// Ambient GIT_* location vars (GIT_DIR / GIT_WORK_TREE / …) would let rev-parse prove a FOREIGN
|
|
176
|
+
// tree — every location answer must come from cwd alone, for every gitLine consumer.
|
|
177
|
+
const env = Object.fromEntries(Object.entries(process.env).filter(([k]) => !/^GIT_/i.test(k)));
|
|
178
|
+
const r = spawnSync('git', args, { cwd, env, encoding: 'utf8', windowsHide: true });
|
|
158
179
|
return r.error || r.status == null ? null : { status: r.status, stdout: r.stdout ?? '' };
|
|
159
180
|
};
|
|
160
181
|
|
|
@@ -199,13 +220,7 @@ export const assertScratchDestination = (outPath, cwd) => {
|
|
|
199
220
|
// the repo is scratch" would let an unattended run overwrite e.g. ~/.bashrc promptless.
|
|
200
221
|
// $TMPDIR / os.tmpdir() / /tmp are the scratch surface; everything else refuses loudly.
|
|
201
222
|
const assertTempScratch = () => {
|
|
202
|
-
const tempRoots =
|
|
203
|
-
try {
|
|
204
|
-
return realpathSync(p);
|
|
205
|
-
} catch {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
}).filter(Boolean))];
|
|
223
|
+
const tempRoots = systemTempRoots();
|
|
209
224
|
if (!tempRoots.some((t) => full === t || full.startsWith(`${t}${sep}`))) {
|
|
210
225
|
throw fail(1, `--out refuses an outside-repo destination that is not under a system temp root (${full}) — grounding output is scratch: use $TMPDIR//tmp, or a fresh gitignored in-repo path (temp roots checked: ${tempRoots.join(', ')})`);
|
|
211
226
|
}
|
|
@@ -243,7 +258,8 @@ export const assertScratchDestination = (outPath, cwd) => {
|
|
|
243
258
|
const HELP = `grounding — grounded-review facts assembler for the agent-workflow family (AD-038).
|
|
244
259
|
|
|
245
260
|
Usage:
|
|
246
|
-
node grounding.mjs [--constraints] [--autonomy] [--plan <path>] [--
|
|
261
|
+
node grounding.mjs [--constraints] [--autonomy] [--plan <path>] [--extra <text|@file>]...
|
|
262
|
+
[--reserve-bytes <n>] [--out <path>]
|
|
247
263
|
|
|
248
264
|
--constraints slice the root AGENTS.md "Hard Constraints" section verbatim
|
|
249
265
|
(exactly one matching heading, else a loud STOP)
|
|
@@ -255,6 +271,14 @@ Usage:
|
|
|
255
271
|
--plan <path> extract the plan's decision-bearing sections verbatim + whole:
|
|
256
272
|
"## Approach" + "## Verification" (REQUIRED — STOP if missing),
|
|
257
273
|
"## Decisions (locked)" when present; a duplicate heading is a STOP
|
|
274
|
+
--extra <text|@file> append orchestrator-supplied extra facts byte-verbatim AFTER the
|
|
275
|
+
mechanical sections (repeatable, argv order; the agy-review --facts
|
|
276
|
+
convention: literal text, or @path read whole through a race-free
|
|
277
|
+
descriptor). An @file must resolve inside the PROVEN git work tree
|
|
278
|
+
(rev-parse success; the git dir itself refused) or the system temp
|
|
279
|
+
surface — anything else refuses loudly, as does a missing, empty, or
|
|
280
|
+
non-regular file. The merge happens INSIDE the tool: no shell append
|
|
281
|
+
onto the emitted facts file
|
|
258
282
|
--reserve-bytes <n> the artifact share agy-review will add around these facts — the output
|
|
259
283
|
budget becomes AGY_MAX_PROMPT_BYTES − n (loud tail-trim on overflow)
|
|
260
284
|
--out <path> write instead of stdout — system-temp scratch (rewritable), or a FRESH
|
|
@@ -274,11 +298,19 @@ const parseArgs = (argv) => {
|
|
|
274
298
|
let plan = null;
|
|
275
299
|
let out = null;
|
|
276
300
|
let reserve = 0;
|
|
301
|
+
const extra = [];
|
|
277
302
|
for (let i = 0; i < argv.length; i += 1) {
|
|
278
303
|
const a = argv[i];
|
|
279
304
|
if (a === '--constraints') constraints = true;
|
|
280
305
|
else if (a === '--autonomy') autonomy = true;
|
|
281
|
-
else if (a === '--
|
|
306
|
+
else if (a === '--extra') {
|
|
307
|
+
const val = argv[i + 1];
|
|
308
|
+
if (val == null || val === '' || val === '@' || val.startsWith('--')) {
|
|
309
|
+
throw fail(2, '--extra requires <text|@file> (repeatable)');
|
|
310
|
+
}
|
|
311
|
+
extra.push(val);
|
|
312
|
+
i += 1;
|
|
313
|
+
} else if (a === '--plan') {
|
|
282
314
|
plan = argv[i + 1];
|
|
283
315
|
if (!plan || plan.startsWith('--')) throw fail(2, '--plan requires a <path>');
|
|
284
316
|
i += 1;
|
|
@@ -293,10 +325,10 @@ const parseArgs = (argv) => {
|
|
|
293
325
|
i += 1;
|
|
294
326
|
} else throw fail(2, `unknown argument: ${a}`);
|
|
295
327
|
}
|
|
296
|
-
if (!constraints && !autonomy && plan == null) {
|
|
297
|
-
throw fail(2, 'nothing to assemble — pass --constraints, --autonomy, and/or --
|
|
328
|
+
if (!constraints && !autonomy && plan == null && extra.length === 0) {
|
|
329
|
+
throw fail(2, 'nothing to assemble — pass --constraints, --autonomy, --plan <path>, and/or --extra <text|@file>');
|
|
298
330
|
}
|
|
299
|
-
return { constraints, autonomy, plan, out, reserve };
|
|
331
|
+
return { constraints, autonomy, plan, out, reserve, extra };
|
|
300
332
|
};
|
|
301
333
|
|
|
302
334
|
const resolveBudget = (env, reserve) => {
|
|
@@ -316,7 +348,7 @@ export const main = (argv, ctx = {}) => {
|
|
|
316
348
|
const env = ctx.env ?? process.env;
|
|
317
349
|
try {
|
|
318
350
|
if (argv.includes('--help') || argv.includes('-h')) return { code: 0, stdout: HELP, stderr: '' };
|
|
319
|
-
const { constraints, autonomy, plan, out, reserve } = parseArgs(argv);
|
|
351
|
+
const { constraints, autonomy, plan, out, reserve, extra } = parseArgs(argv);
|
|
320
352
|
const budget = resolveBudget(env, reserve);
|
|
321
353
|
|
|
322
354
|
const readOrStop = (path, label) => {
|
|
@@ -348,8 +380,65 @@ export const main = (argv, ctx = {}) => {
|
|
|
348
380
|
}
|
|
349
381
|
const planText = plan != null ? readOrStop(plan, 'plan file') : null;
|
|
350
382
|
|
|
383
|
+
// --extra @file reads are CONFINED: the bridge tier auto-allows this tool with an args
|
|
384
|
+
// wildcard, so an unconfined @file would let an unattended run ship ANY readable file
|
|
385
|
+
// (~/.ssh, ~/.bashrc) into a prompt payload bound for a subscription CLI. The admitted read
|
|
386
|
+
// surface — computed ONCE per invocation — is the PROVEN git work tree (rev-parse success
|
|
387
|
+
// required; a cwd fallback would collapse the guard when cwd=$HOME) plus the system temp
|
|
388
|
+
// surface, MINUS the git dir(s) — repository internals never enter a facts payload. A non-@
|
|
389
|
+
// value is literal fact text (the agy-review --facts convention).
|
|
390
|
+
const extraReadSurface = () => {
|
|
391
|
+
const tempRoots = systemTempRoots();
|
|
392
|
+
const top = gitLine(['rev-parse', '--show-toplevel'], cwd);
|
|
393
|
+
if (top == null || top.status !== 0) return { tempRoots, topReal: null, gitDirsReal: [] };
|
|
394
|
+
const topReal = realpathSync(top.stdout.replace(/\r?\n$/, ''));
|
|
395
|
+
const gitDirsReal = ['--absolute-git-dir', '--git-common-dir'].map((flag) => {
|
|
396
|
+
const r = gitLine(['rev-parse', flag], cwd);
|
|
397
|
+
if (r == null || r.status !== 0) {
|
|
398
|
+
throw fail(1, `--extra cannot resolve the git dir (git rev-parse ${flag} failed) — refusing @file reads in an unmappable repo`);
|
|
399
|
+
}
|
|
400
|
+
return realpathSync(resolve(cwd, r.stdout.replace(/\r?\n$/, '')));
|
|
401
|
+
});
|
|
402
|
+
// The linked-worktree `.git` is a FILE inside the tree yet outside both answers above —
|
|
403
|
+
// repository metadata all the same.
|
|
404
|
+
gitDirsReal.push(join(topReal, '.git'));
|
|
405
|
+
return { tempRoots, topReal, gitDirsReal };
|
|
406
|
+
};
|
|
407
|
+
const surface = extra.some((v) => v.startsWith('@')) ? extraReadSurface() : null;
|
|
408
|
+
const resolveExtra = (value) => {
|
|
409
|
+
if (!value.startsWith('@')) return value;
|
|
410
|
+
const ref = value.slice(1);
|
|
411
|
+
const real = (() => {
|
|
412
|
+
try {
|
|
413
|
+
// Canonicalize the PARENT only — the leaf stays un-dereferenced so the no-follow open
|
|
414
|
+
// refuses a symlink leaf instead of silently reading its target.
|
|
415
|
+
const lexical = resolve(cwd, ref);
|
|
416
|
+
return join(realpathSync(dirname(lexical)), basename(lexical));
|
|
417
|
+
} catch (err) {
|
|
418
|
+
throw fail(1, `--extra file '${ref}' is unreadable (${(err && err.code) || err}) — STOP`);
|
|
419
|
+
}
|
|
420
|
+
})();
|
|
421
|
+
const within = (root) => real === root || real.startsWith(`${root}${sep}`);
|
|
422
|
+
const inTree = surface.topReal != null && within(surface.topReal);
|
|
423
|
+
if (!inTree && !surface.tempRoots.some(within)) {
|
|
424
|
+
throw fail(1, `--extra '@${ref}' resolves outside the work tree and the system temp surface (${real}) — refusing to read it into the facts payload`);
|
|
425
|
+
}
|
|
426
|
+
if (surface.gitDirsReal.some(within)) {
|
|
427
|
+
throw fail(1, `--extra '@${ref}' resolves inside the git dir (${real}) — repository internals never enter a facts payload`);
|
|
428
|
+
}
|
|
429
|
+
// Descriptor-bound read (the kit's ONE no-follow door): a FIFO cannot block the open, and a
|
|
430
|
+
// leaf swapped after the containment checks cannot change what the fd reads.
|
|
431
|
+
const r = readRegularFileNoFollow(real);
|
|
432
|
+
if (r.outcome === 'absent') throw fail(1, `--extra file '${ref}' is unreadable (ENOENT) — STOP`);
|
|
433
|
+
if (r.outcome === 'foreign') throw fail(1, `--extra file '${ref}' is not a regular file (${r.className}) — refusing; STOP`);
|
|
434
|
+
if (r.outcome !== 'ok') throw fail(1, `--extra file '${ref}' is unreadable (${r.code}) — STOP`);
|
|
435
|
+
if (r.content.trim() === '') throw fail(1, `--extra file '${ref}' is empty — nothing to append; STOP`);
|
|
436
|
+
return r.content; // byte-verbatim — no trailing-newline normalization
|
|
437
|
+
};
|
|
438
|
+
const extraTexts = extra.map(resolveExtra);
|
|
439
|
+
|
|
351
440
|
const parts = [];
|
|
352
|
-
const assembled = assembleGrounding({ constraintsText, autonomyText, planText, planLabel: plan ?? 'plan' });
|
|
441
|
+
const assembled = assembleGrounding({ constraintsText, autonomyText, planText, planLabel: plan ?? 'plan', extraTexts });
|
|
353
442
|
if (assembled) parts.push(assembled);
|
|
354
443
|
const payload = parts.join('\n');
|
|
355
444
|
const { text, trimmedBytes } = trimToBudget(payload, budget);
|