@estebanforge/pi-antigravity-bridge 1.4.0 → 1.4.2

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 CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.4.2] - 2026-09-04
6
+
7
+ ### Changed
8
+
9
+ - `bridgeTools` now defaults to `all` (every registered non-builtin pi tool) instead of `mcp`. The `mcp` surface filters to pi-mcp-adapter tools and serves an empty catalog on installs without that adapter, which left the bridge registered but tool-less from the model's point of view. `none` still opts out entirely; explicit `"bridgeTools": "mcp"` in an existing config keeps pinning the narrow surface.
10
+ - Skill discovery now mirrors pi's directory-based scan (docs/skills.md): global `~/.pi/agent/skills` AND `~/.agents/skills`, project `.pi/skills` plus `.agents/skills` in cwd and ancestors up to the git root (project dirs only when pi has trusted the project, same gate pi applies), recursive SKILL.md discovery with grouping folders, per-style root/`.md` rules, hidden entries skipped, and description-less skills dropped. Pi's other skill sources (`skills` settings array, `package.json`, `--skill`) are not mirrored. Previously only one flat level of two directories was scanned, and `~/.agents/skills` (where pi actually reads most skills) was missing entirely, so `activate_skill` never appeared.
11
+ - `/agy` now exposes the full runtime config surface: new `/agy bridge all|mcp|none` (which pi tools the MCP bridge hands to agy) and `/agy acp-bin <path|auto>` (target a specific ACP server binary; applies on the next ACP turn), plus Bridge tools, Context digest, and System prompt rows in the bare `/agy` settings picker. Usage strings and `/agy status` list every knob.
12
+
13
+ ## [1.4.1] - 2026-09-04
14
+
15
+ ### Added
16
+
17
+ - Self-service ACP setup (`src/acp/setup.ts`): `/agy engine acp` now prepares the whole engine instead of printing instructions. It installs the official server binary from the antigravity-acp registry entry (`agentclientprotocol/registry`) into the pinned layout `~/.local/opt/agy-acp/<build>/` with a `current` symlink and the zip sha256 recorded (no upstream checksums exist; plan §12), points `acp.bin` at it, and prepares the login: `oauth-personal` by default, which is the user's own Antigravity subscription (the same Google account and plan as the `agy` CLI; the server opens the browser on the first ACP message, tokens persist). Credential values are never read or written (`acp_token.json` is only stat()ed); `gemini-api-key` stays a manual headless option, never the default. A `session_start` self-heal repeats the check silently when everything is ready and surfaces the manual steps only on failure; `AcpDriverOptions.bin` accepts a resolver so a mid-session install is picked up by the next turn without a restart; `/agy doctor` shows binary source and auth type. Tests inject the registry, archive, and unpacker, so the suite stays offline.
18
+
19
+ ### Fixed
20
+
21
+ - Stream-json frames split across pipe chunks are now reassembled instead of dropped: `AgyDriver` buffers the trailing partial stdout line (the scheme `JsonRpcSession.feed` already used on the ACP engine). Previously a large `tool` frame or the `result` frame split by a pipe boundary was lost whole, which could turn a successful turn into a bogus "agy exited with status 0" error. Regression test drives a fake agy whose reply is deliberately split mid-line.
22
+ - Both drivers attach an `'error'` listener on the child's stdin: an async pipe failure (EPIPE when agy/the ACP server dies mid-write) now fails the turn (ACP: tears the connection down) instead of escaping as an uncaught exception that kills the whole pi process.
23
+ - ACP permission answering is fail-closed: `session/request_permission` selects the first reject option unless the turn runs with `skipPermissions`. Previously every request was auto-approved regardless of the `permissions` setting shown by `/agy status`. The unsupported `engine=acp` + `mode=plan` combination is now refused at `/agy engine`, `/agy mode`, and the settings picker, and fails the turn with a visible error instead of silently running non-plan (ACP has no review-only mode in RC01).
24
+ - Startup-log fix hardening: four genuine ACP failure events (`session-load-failed-creating-fresh`, `connection-exited`, `cancel-failed`, `unsupported-server-request`) surface again; the dead MCP entries (`capability-missing`, `self-patch-error`) are gone; `call-tool-fail` no longer toasts for the routine fail-all on turn end / session shutdown.
25
+ - Startup log leaks: the ACP driver log sink now forwards only genuine failures (`start-failed`, `spawn-error`, `parse-error`, `write-failed`, `mode-apply-failed`, `timeout`, `stall`, `auth-required`) to stderr; routine lifecycle (`driver-created`, spawn, session new/load) stays in the `#lifecycle` ring buffer under `/agy doctor`. The MCP bridge logger no longer toasts (or headless-stderr-logs) normal startup/teardown events (`listening`, `bridge-config-written`, `bridge-config-removed`, `closed`); only failures surface, as warning toasts. The stream-json engine already had no terminal sink.
26
+
5
27
  ## [1.4.0] - 2026-09-04
6
28
 
7
29
  ### Added
package/README.md CHANGED
@@ -25,7 +25,7 @@ Turns run through one of two engines behind the same provider surface (`config.e
25
25
 
26
26
  Engine-dependent features: pi image attachments ride natively only on the ACP engine (the picker offers image attach automatically when `config.engine` is `acp`; the stream-json CLI prompt is text-only). With the optional G1 digest enabled, its delivery also differs: ACP ships it as a native `embeddedContext` resource block, stream-json prepends it to the prompt text.
27
27
 
28
- Switch with `/agy engine acp|stream-json` (takes effect on restart). ACP needs the server binary installed locally (`AGY_ACP_BIN` or `config.acp.bin`; layout and pinning in [docs/ACP-ADOPTION-PLAN.md](docs/ACP-ADOPTION-PLAN.md)), and its own one-time credential setup: run `/agy acp-auth` for the steps. The ACP server keeps its own auth state; the token never touches this code. Sessions are engine-scoped, so switching engines never crosses conversations.
28
+ Switch with `/agy engine acp|stream-json` (takes effect on restart). Setup is automatic: switching to `acp` installs Google's official ACP server binary from the [antigravity-acp registry entry](https://github.com/agentclientprotocol/registry) (`~/.local/opt/agy-acp/<build>/` + a `current` symlink, zip sha256 recorded; layout and pinning in [docs/ACP-ADOPTION-PLAN.md](docs/ACP-ADOPTION-PLAN.md)) and prepares the login. The login is your Antigravity subscription: on your first ACP message the server opens the Google login in your browser, and you sign in with the same account and plan you use for the Antigravity CLI (`agy`). It is no different from logging into the CLI; the server just keeps its own token file on your machine, like any Google tool, and this extension never sees your credentials. If you also export `GEMINI_API_KEY`, it is ignored: the server uses the auth type in settings.json, and setup always writes `oauth-personal`. A session start self-heals the same way, silently when everything is ready. Manual instructions (`/agy acp-auth`) surface only when a step fails. Sessions are engine-scoped, so switching engines never crosses conversations.
29
29
 
30
30
  ## What it cannot do
31
31
 
@@ -104,19 +104,21 @@ If `agy models` fails at load (binary missing, auth not done, network stall), a
104
104
 
105
105
  | Key | Values | Default |
106
106
  | --- | --- | --- |
107
- | `bridgeTools` | `none` (bridge off), `mcp` (pi-mcp-adapter tools), `all` (every non-builtin tool, incl. other `Ask*` delegations) | `mcp` |
107
+ | `bridgeTools` | `none` (bridge off), `all` (every non-builtin tool, incl. other `Ask*` delegations), `mcp` (pi-mcp-adapter tools + skills bridge only) | `all` |
108
108
  | `digest` | `off` (stable prompts; agy's prompt cache hits) or `on` (inject a delta of pi-side context - compaction summaries, other-provider turns - into each agy prompt; the delta changes every turn, so agy re-bills the full context). Enable for mixed-provider sessions where agy must see pi-side context | `off` |
109
109
  | `systemPrompt` | `on` (prepend pi's system prompt - operating instructions plus the global agent-dir `AGENTS.md` and ancestor `AGENTS.md`/`CLAUDE.md` - to the first prompt of each new agy conversation) or `off` (agy-native behavior) | `on` |
110
110
 
111
111
  Env overrides: `AGY_BRIDGE_TOOLS`, `AGY_DIGEST`, `AGY_SYSTEM_PROMPT`. Env wins over the file, so while `AGY_DIGEST` or `AGY_SYSTEM_PROMPT` is set, the matching `/agy digest` or `/agy system-prompt` toggle persists a value that never takes effect.
112
112
 
113
+ The `activate_skill` catalog mirrors pi's directory-based skill discovery: the two global dirs plus project dirs, the latter only when pi has trusted the project (same gate pi itself applies). Pi's other skill sources - the `skills` settings array, `package.json` entries, and `--skill` CLI paths - are not mirrored and won't appear in the catalog.
114
+
113
115
  ### The /agy command
114
116
 
115
117
  `/agy` configures the provider at runtime. Settings persist to `~/.pi/agent/antigravity-bridge/config.json` and take effect on the next turn.
116
118
 
117
119
  ```
118
- /agy status, or open the mode/permissions/model/thinking picker (TUI)
119
- /agy status print current mode, permissions, model + session counts
120
+ /agy status, or open the full settings picker (TUI)
121
+ /agy status print current settings + session counts
120
122
  /agy doctor bridge state, driver counters, bridge port, last lifecycle events
121
123
  /agy mode plan review-only: agy plans but writes nothing
122
124
  /agy mode accept-edits agy applies edits directly (default)
@@ -125,8 +127,10 @@ Env overrides: `AGY_BRIDGE_TOOLS`, `AGY_DIGEST`, `AGY_SYSTEM_PROMPT`. Env wins o
125
127
  /agy thinking low|medium|high default thinking tier for the AskAntigravity tool
126
128
  /agy digest on|off inject pi-side context into agy prompts (default off; see table above)
127
129
  /agy system-prompt on|off send pi's system prompt + AGENTS.md to new agy conversations (default on)
128
- /agy engine acp|stream-json switch the turn engine (restart to apply; default stream-json)
129
- /agy acp-auth one-time credential setup for the ACP engine
130
+ /agy bridge all|mcp|none which pi tools the MCP bridge exposes to agy (default all; none = bridge off)
131
+ /agy acp-bin <path|auto> point the ACP engine at a specific server binary (auto = setup installs, or AGY_ACP_BIN; applies on the next ACP turn)
132
+ /agy engine acp|stream-json switch the turn engine (restart to apply; default stream-json; acp runs self-service setup: binary install + auth bootstrap)
133
+ /agy acp-auth manual ACP credential setup (fallback; auto-setup normally covers this; default login = your Antigravity subscription, same account as the agy CLI)
130
134
  /agy patch-cleanup restore the original pi files if an older version patched them
131
135
  /agy clear drop all session bindings (force fresh conversations)
132
136
  ```
@@ -149,7 +153,7 @@ For isolation when running any agent that executes commands without a confirmati
149
153
  | --- | --- |
150
154
  | `AGY_BIN` | Path to the agy binary. Defaults to `agy` on PATH. |
151
155
  | `AGY_ENGINE` | Turn engine: `stream-json` (default) or `acp`. Wins over the config file. |
152
- | `AGY_ACP_BIN` | Path to the ACP server binary (`agy_acp_server.par`). Defaults to `agy_acp_server.par` on PATH. Wins over `config.acp.bin`. |
156
+ | `AGY_ACP_BIN` | Path to the ACP server binary (`agy_acp_server.par`). Defaults to `agy_acp_server.par` on PATH. Wins over `config.acp.bin`. When neither points at a binary, auto-setup installs one. |
153
157
  | `AGY_EXTRA_ARGS` | Extra args appended to every invocation. Whitespace-split. |
154
158
  | `AGY_CONVERSATIONS_DIR` | Override the conversations DB directory. |
155
159
  | `AGY_MODE` | Override execution mode: `plan` (review-only) or `accept-edits` (default). Wins over the config file. |
@@ -6,7 +6,7 @@ PASS through the full stack. Gate F VERIFIED live (`scripts/smoke-acp-bridge.mjs
6
6
  the real server lists bridge tools and completes a tool call through the
7
7
  registered mcpServers entry. §6 parity run LIVE on both engines: 14/14
8
8
  (`scripts/parity-live.mjs`). Phase-1 acceptance: ALL `[x]` (docs included).
9
- Gates: A PASS, B ABSENT (managed — legacy engine retained
9
+ Gates: A PASS, B ABSENT (managed — streaming engine retained
10
10
  until upstream ships usage), C PASS, D FAIL on RC01 (kill+reload fallback
11
11
  VERIFIED live, incl. the stale-exit race fix), E PASS, F PASS (verified
12
12
  live 2026-09-03). Verdicts in section 8.1; full captured protocol data in
@@ -20,7 +20,7 @@ Peer review 2: Antigravity (agy), 2026-09-03. Verdict PROCEED WITH CHANGES.
20
20
  7 findings integrated: Gate A made a blocking gate for the default flip (the
21
21
  ACP binary takes no model flags, so the recycle fallback could not carry a
22
22
  model), sessions re-keyed per engine (`@acp` suffix) after the engine-field
23
- design was shown to erase legacy bindings on rollback, parked-timer pause
23
+ design was shown to erase streaming bindings on rollback, parked-timer pause
24
24
  changed to remaining-budget semantics, acp-permission plumbing specified
25
25
  through a TurnDriver interface, session/cancel + session/close pulled into
26
26
  phase 1, AskAntigravity migration moved from phase 3 to phase 4.
@@ -47,7 +47,7 @@ Adopt the official Google ACP server (`agy_acp_server.par`, registry id
47
47
  switch. The existing stream-json engine stays the default until the ACP
48
48
  engine proves parity. Every change is an improvement or a one-to-one
49
49
  replacement. No functionality is removed until a later phase deletes the
50
- legacy engine on purpose.
50
+ streaming engine on purpose.
51
51
 
52
52
  Cross-references: [ARCHITECTURE.md](./ARCHITECTURE.md),
53
53
  [PI-BRIDGE-GAPS.md](./PI-BRIDGE-GAPS.md), [DEVELOPMENT.md](./DEVELOPMENT.md).
@@ -165,8 +165,8 @@ is an unmaintained contract. ACP is the maintained one.
165
165
  | Module | Role today | Disposition under ACP |
166
166
  | --- | --- | --- |
167
167
  | `src/provider.ts` | streamSimple: pi Context to agy turn to pi events; G9 round-trips; G1 digest; G10 system prompt | KEEP unchanged (additive thought-delta `if` only). Engine-agnostic by contract |
168
- | `src/driver.ts` | persistent stream-json process, turn queue, recycle, timers | KEEP as legacy engine. DELETE in phase 4 |
169
- | `src/stream-events.ts` | NDJSON parser + usage mapping | KEEP as legacy. DELETE in phase 4 |
168
+ | `src/driver.ts` | persistent stream-json process, turn queue, recycle, timers | KEEP as streaming engine. DELETE in phase 4 |
169
+ | `src/stream-events.ts` | NDJSON parser + usage mapping | KEEP as streaming. DELETE in phase 4 |
170
170
  | `src/sessions.ts` | pi session to agy conversation store | KEEP. Add `engine` tag (section 9.4) |
171
171
  | `src/config.ts` | runtime config | KEEP. Add engine + acp block (section 9.5) |
172
172
  | `src/models.ts` | `agy models` to pi Model projection | KEEP. Catalog source stays the CLI until ACP exposes one (probe A.6) |
@@ -256,10 +256,10 @@ Every box must be `[x]` on the ACP engine before phase 4 flips the default.
256
256
  Tested with the parity suite (section 11) and `scripts/parity-live.mjs`
257
257
  (live, both engines: 14/14, 2026-09-03).
258
258
 
259
- - [x] Text streams token-adjacent to legacy (no full-text re-sends) — live
259
+ - [x] Text streams token-adjacent to streaming (no full-text re-sends) — live
260
260
  both engines, delta stream + cumulative-resend guard held
261
261
  - [x] Multi-turn conversation continuity via `session/load` or our store —
262
- live: ACP `session/load` (history suppressed, clean reply), legacy
262
+ live: ACP `session/load` (history suppressed, clean reply), streaming
263
263
  `--conversation` resume; the provider's session store supplies the id
264
264
  - [x] Turn serialization: two concurrent streamSimple calls never interleave
265
265
  — live both engines (queue releases only on settle) + driver tests
@@ -276,23 +276,23 @@ Tested with the parity suite (section 11) and `scripts/parity-live.mjs`
276
276
  - [x] Abort: pi user abort produces `aborted`, the server process survives,
277
277
  the next turn on the session works — live both engines (aborted=true,
278
278
  recovery turn OK). "Process survives" holds on NEITHER engine and is
279
- the documented Gate D behavior: legacy kills the child; RC01 has no
279
+ the documented Gate D behavior: streaming kills the child; RC01 has no
280
280
  cancel, ACP tears down after the -32601 probe and reloads next turn
281
281
  - [x] pi session restart resumes the right conversation (engine-tagged) —
282
282
  engine-scoped key tests + live `session/load`
283
283
  - [x] Engine rollback preserves the other engine's conversation bindings
284
284
  (engine-scoped keys, 9.4) — sessions tests (per-entry engine field
285
- rejected precisely because set() would erase the legacy binding)
285
+ rejected precisely because set() would erase the streaming binding)
286
286
  - [x] Model catalog: same `antigravity/*` model ids and effort tiers resolve
287
287
  — shared provider catalog, engine-independent by construction
288
288
  - [x] Model/effort switch takes effect (gate A mechanism) — live: ACP
289
- `set_config_option` on a LOADED session; legacy recycle+resume
289
+ `set_config_option` on a LOADED session; streaming recycle+resume
290
290
  - [x] G1 digest and G10 system prompt reach the prompt identically — shared
291
291
  prompt assembly in the provider; the driver receives the final prompt
292
292
  - [x] Skills `activate_skill` answered by the bridge as today — bridge
293
293
  server dep, same server serves both engines (ACP transport live)
294
294
  - [x] Usage counters: present (mapped) or documented-absent (zero-usage),
295
- per gate B — live: legacy mapped, ACP absent (Gate B row in the
295
+ per gate B — live: streaming mapped, ACP absent (Gate B row in the
296
296
  parity matrix)
297
297
  - [x] `/agy doctor` shows connection state, session id, prompt/session stats,
298
298
  lifecycle log — implemented engine-aware (phase 1); re-verify in pi
@@ -303,7 +303,7 @@ Tested with the parity suite (section 11) and `scripts/parity-live.mjs`
303
303
  as a visible `ACP session failed: Invalid params` turn error in the
304
304
  first parity attempt, exactly as designed
305
305
  - [x] `ask-tool` one-shot returns text, duration, abort/timeout states, and a
306
- resumable session id — unchanged legacy `agy -p` path (phase-2 probe
306
+ resumable session id — unchanged `agy -p` path (phase-2 probe
307
307
  decides whether it moves to ACP)
308
308
  - [x] Overall-turn timer pauses while any round-trip is parked; a slow human
309
309
  permission decision cannot kill the turn — fake tests (park/kickIdle
@@ -396,8 +396,8 @@ What to record for each gate:
396
396
  | A | Model + effort switch per session? | `set_config_option` (or equivalent) switches both; next prompt uses them | NONE viable: the ACP binary takes no model flags, so respawn-per-switch cannot carry a model; a settings.json rewrite per switch is the only theoretical path and is rejected (unproven, racy). Gate A FAIL blocks the phase 4 default flip; ACP stays opt-in; the gap goes upstream |
397
397
  | B | Usage anywhere? | Any update or `_meta` carries token counts | Zero-usage documented; README notes it |
398
398
  | C | `tool_call` content richness | rawInput/output/locations enough to retire WrapperReplay + native-tools | Keep current replay machinery unchanged |
399
- | D | Cancel latency + state | `stopReason: cancelled` within ~2s; session reusable after | Keep kill semantics on legacy; on ACP keep kill as escalation path |
400
- | E | Startup cost | Cold start < 5s, steady RSS sane for a long-lived process | Spawn per turn-group only (like legacy recycle cadence) |
399
+ | D | Cancel latency + state | `stopReason: cancelled` within ~2s; session reusable after | Keep kill semantics on streaming; on ACP keep kill as escalation path |
400
+ | E | Startup cost | Cold start < 5s, steady RSS sane for a long-lived process | Spawn per turn-group only (like the streaming recycle cadence) |
401
401
  | F | MCP `mcpServers` registration | Bridge `tools/list` visible to the agent mid-turn | Keep bridge wired some other protocol-sanctioned way; if none, G9 parking breaks and phase 1 is BLOCKED |
402
402
  | F.7 | Slash behavior | Commands not auto-expanded against our prompt text | Prefix-safe prompt assembly unchanged |
403
403
 
@@ -478,7 +478,7 @@ scripts/smoke-acp.mjs live smoke, gated by AGY_ACP_LIVE=1 (spends quota),
478
478
  `AcpDriver` matches the existing `AgyDriver` public surface: `state`,
479
479
  `activeHandle`, `run()`, `reentry()`, `kickIdle()`, `set onTurnEnd()`,
480
480
  `snapshot()`, `close()`. `DriverActivity` gains one additive variant; the
481
- legacy engine never emits it:
481
+ streaming engine never emits it:
482
482
 
483
483
  ```ts
484
484
  // stream-events/driver today: { type: "thought"; tokens: number }
@@ -487,7 +487,7 @@ legacy engine never emits it:
487
487
  ```
488
488
 
489
489
  `provider.ts` change: when `delta` is present call `appendThinking`, else keep
490
- the current token-count behavior. One `if`, additive, legacy untouched.
490
+ the current token-count behavior. One `if`, additive, streaming untouched.
491
491
 
492
492
  Interface extraction (review 2, finding 7): `provider.ts` imports the
493
493
  concrete `AgyDriver` class today; deleting `driver.ts` in phase 4 would break
@@ -504,7 +504,7 @@ correlation-map entry (the pending `session/prompt` request, any unanswered
504
504
  client-side requests), the driver settles the turn outcome as
505
505
  `ERROR`/`aborted` (never left pending), and `onTurnEnd` fires so the
506
506
  provider's `roundTrips.failAll()` fails parked round-trips exactly as the
507
- legacy driver's `failTurn` path does. Nothing is ever written to a dead
507
+ streaming driver's `failTurn` path does. Nothing is ever written to a dead
508
508
  socket; no promise survives the kill. Mirrors `ToolRoundTrips.failAll()`.
509
509
 
510
510
  Event mapping (`src/acp/events.ts`):
@@ -524,7 +524,7 @@ Event mapping (`src/acp/events.ts`):
524
524
  | `refusal` / `max_turn_requests` / `max_tokens` | TurnOutcome ERROR / OK+note | `error` / `stop` + `errorMessage` |
525
525
  | `user_message_chunk` (during `session/load` only) | suppressed (history replay) | never emitted to pi as live text |
526
526
 
527
- Defensive guard ported from the legacy engine: if an `agent_message_chunk`
527
+ Defensive guard ported from the streaming engine: if an `agent_message_chunk`
528
528
  repeats the full accumulated text instead of a delta, detect and slice (the
529
529
  `isCumulativeResend` lesson; same agy binary lineage, same quirk class).
530
530
  Guard plus test ship in phase 1. Honest labeling: the ACP spec defines chunks
@@ -575,24 +575,24 @@ parked and, on settle, re-arms it with the REMAINING budget (`deadline -
575
575
  now`), never a fresh cap: the overall timer is a turn DEADLINE, not an
576
576
  inactivity guard. Every park carries its own timeout (`BRIDGE_TIMEOUT_MS`),
577
577
  so a paused deadline cannot hang forever. Driver-local (AcpDriver only);
578
- legacy behavior untouched; ships in phase 1.
578
+ streaming behavior untouched; ships in phase 1.
579
579
 
580
580
  ### 9.4 Sessions schema (engine-scoped keys)
581
581
 
582
582
  The first design (a per-entry `engine` field) was rejected in review 2:
583
583
  `set()` overwrites the single `sid:<pi-session>` key, so one ACP turn ERASES
584
- the legacy conversation binding, and a rollback loses continuity, breaking
584
+ the streaming conversation binding, and a rollback loses continuity, breaking
585
585
  the section 13 guarantee. Engines scope at the KEY level instead:
586
586
 
587
587
  ```jsonc
588
588
  // ~/.pi/agent/antigravity-bridge/sessions.json
589
589
  {
590
- "sid:<pi-session>": { "conversationId": "<legacy id>", "lastStepIdx": -1, "lastMessageCount": 42 },
590
+ "sid:<pi-session>": { "conversationId": "<streaming id>", "lastStepIdx": -1, "lastMessageCount": 42 },
591
591
  "sid:<pi-session>@acp": { "conversationId": "<ACP sessionId>", "lastStepIdx": -1, "lastMessageCount": 42 }
592
592
  }
593
593
  ```
594
594
 
595
- - Un-suffixed keys belong to the legacy engine, byte-compatible with every
595
+ - Un-suffixed keys belong to the streaming engine, byte-compatible with every
596
596
  persisted store; ACP keys carry an `@acp` suffix appended by
597
597
  `sessionKey()` when `config.engine === "acp"`.
598
598
  - Engines never touch each other's keys: rollback keeps both continuations,
@@ -747,11 +747,11 @@ ACP-PROTOCOL-REFERENCE.md "Phase-2 probe findings".
747
747
 
748
748
  ### Phase 3: consolidation (immediate priority, opt-in only)
749
749
 
750
- Hard rule: Keep both engines in the extension. Default engine remains `stream-json`. All items below are non-breaking opt-in enhancements for the ACP engine that do NOT alter default behavior or touch legacy paths.
750
+ Hard rule: Keep both engines in the extension. Default engine remains `stream-json`. All items below are non-breaking opt-in enhancements for the ACP engine that do NOT alter default behavior or touch streaming paths.
751
751
 
752
752
  Queue:
753
- 1. [x] Gate C evaluation: `native-tools.ts` + `WrapperReplay` retired on the ACP engine (retained for legacy `stream-json` engine). ACP turns emit thinking labels for tool executions without parking turns for synthetic re-execution or wrapper cards; bridge MCP tools (`bridge_call`) continue parking natively. Verified: live parity 14/14 held.
754
- 2. [x] Retire `diff-render.ts` (git path) on the ACP engine — DONE 2026-09-04. The phase-2 probe proved ACP surfaces edit diffs natively (`tool_call` `content[]` `{type:"diff", path, oldText?, newText}`), which is richer AND cheaper than the git-sourced path: implemented as (a) `events.ts` extracts the first diff entry into the `tool_done` activity (`AcpEditDiff`); (b) `provider.ts` renders it on ACP turns via the new `formatInlineDiff` (in-memory `generateDiffString`, same line-numbered format, ZERO git subprocesses) instead of `TurnDiffContext.diffEdit`; (c) `diff-render.ts` git machinery remains solely for the `stream-json` engine. Tests: diff extraction (with/without `oldText`), ACP thinking-stream rendering (`+2 B` line-numbered), label-only fallback, no parking, legacy path unchanged. Verified: 165/165 vitest, tsc clean, live parity 14/14.
753
+ 1. [x] Gate C evaluation: `native-tools.ts` + `WrapperReplay` retired on the ACP engine (retained for the streaming (`stream-json`) engine). ACP turns emit thinking labels for tool executions without parking turns for synthetic re-execution or wrapper cards; bridge MCP tools (`bridge_call`) continue parking natively. Verified: live parity 14/14 held.
754
+ 2. [x] Retire `diff-render.ts` (git path) on the ACP engine — DONE 2026-09-04. The phase-2 probe proved ACP surfaces edit diffs natively (`tool_call` `content[]` `{type:"diff", path, oldText?, newText}`), which is richer AND cheaper than the git-sourced path: implemented as (a) `events.ts` extracts the first diff entry into the `tool_done` activity (`AcpEditDiff`); (b) `provider.ts` renders it on ACP turns via the new `formatInlineDiff` (in-memory `generateDiffString`, same line-numbered format, ZERO git subprocesses) instead of `TurnDiffContext.diffEdit`; (c) `diff-render.ts` git machinery remains solely for the `stream-json` engine. Tests: diff extraction (with/without `oldText`), ACP thinking-stream rendering (`+2 B` line-numbered), label-only fallback, no parking, streaming path unchanged. Verified: 165/165 vitest, tsc clean, live parity 14/14.
755
755
  3. [x] `/agy doctor` diagnostics expansion — DONE 2026-09-04. The ACP
756
756
  snapshot now carries `reconnects` (connections beyond the first =
757
757
  Gate D kills + stale-exit replacements) and the handshake `agentInfo`
@@ -773,17 +773,17 @@ Status: 🚧 Phase 3 remaining items are COMPLETE (2026-09-04): 168/168 tests,
773
773
  tsc clean, live parity 14/14, embeddedContext verified live (resource block
774
774
  with a secret word answered correctly). Remaining phase-3 acceptance:
775
775
  deleted-code census lands with phase 4's deletions (nothing deletes in
776
- phase 3 — the legacy modules stay for the `stream-json` engine).
776
+ phase 3 — the streaming modules stay for the `stream-json` engine).
777
777
 
778
- ### Phase 4: default flip and legacy deletion (deferred, next month)
778
+ ### Phase 4: default flip and streaming deletion (deferred, next month)
779
779
 
780
780
  All items below are deferred until a full soak cycle of both engines has completed and upstream conditions are met:
781
781
 
782
- 1. AskAntigravity migration to ACP one-shot (migrating while `stream-json` is default breaks legacy-only users who haven't onboarded ACP auth; legacy conversation ids cannot resume under ACP). `mode: "plan"` delegations keep the legacy `agy -p --mode plan` path (committed exception).
782
+ 1. AskAntigravity migration to ACP one-shot (migrating while `stream-json` is default breaks streaming-only users who haven't onboarded ACP auth; streaming conversation ids cannot resume under ACP). `mode: "plan"` delegations keep the `agy -p --mode plan` path (committed exception).
783
783
  2. Delete `src/discovery.ts` (`/proc` fd-scan) once AskAntigravity migration completes.
784
784
  3. Default flip: `config.engine` default becomes `"acp"` after one full release soak cycle with both engines shipping. Gate A PASS is verified.
785
785
  4. Upstream Gate B resolution: Google ships usage counters in ACP payloads.
786
- 5. Legacy engine deletion: `src/driver.ts`, `src/stream-events.ts`, and legacy tests deleted one release after the flip AND only once Gate B has lifted (so zero-usage is never forced).
786
+ 5. Streaming engine deletion: `src/driver.ts`, `src/stream-events.ts`, and streaming tests deleted one release after the flip AND only once Gate B has lifted (so zero-usage is never forced).
787
787
 
788
788
  Acceptance: default-flip release ships with the parity suite as acceptance evidence; deletion release has zero references to the removed modules.
789
789
 
@@ -801,7 +801,7 @@ Acceptance: default-flip release ships with the parity suite as acceptance evide
801
801
  - **Provider**: the existing `provider-streaming` / `provider-digest` /
802
802
  `provider-sysprompt` suites run against both engines via the shared driver
803
803
  contract. New case: thought delta path.
804
- - **Sessions**: engine-tag matching, legacy-file compatibility (no tag),
804
+ - **Sessions**: engine-tag matching, streaming-file compatibility (no tag),
805
805
  cross-engine miss starts fresh.
806
806
  - **Config**: narrowing of stale/garbage `engine` values, env precedence.
807
807
  - **Parity suite**: the section 6 checklist encoded as an integration run
@@ -836,8 +836,8 @@ Install layout:
836
836
  ## 13. Rollback
837
837
 
838
838
  At any phase: `AGY_ENGINE=stream-json` (or `/agy engine stream-json`) returns
839
- to the legacy engine. Sessions are keyed per engine (9.4), so the legacy
840
- engine resumes its own conversations untouched. The legacy engine is only deleted in
839
+ to the streaming engine. Sessions are keyed per engine (9.4), so the streaming
840
+ engine resumes its own conversations untouched. The streaming engine is only deleted in
841
841
  phase 4, one release after the flip, so rollback stays possible throughout.
842
842
 
843
843
  ## 14. Documentation updates
@@ -856,7 +856,7 @@ phase 4, one release after the flip, so rollback stays possible throughout.
856
856
  | # | Risk | L | I | Response |
857
857
  | --- | --- | --- | --- | --- |
858
858
  | R1 | Gate A fails (no model switch) | M | H | default flip blocked; ACP stays opt-in; escalate upstream. No ship-anyway: model switching is not optional |
859
- | R2 | Gate F fails (bridge not registrable) | L | H | BLOCKS phase 1; escalate upstream, keep legacy |
859
+ | R2 | Gate F fails (bridge not registrable) | L | H | BLOCKS phase 1; escalate upstream, keep streaming |
860
860
  | R3 | Usage absent (CONFIRMED, Gate B) | H | M | zero-usage documented on ACP; stream-json retained as secondary engine; phase-4 deletion conditioned on Gate B lift (review 4) |
861
861
  | R4 | Binary churn (hourly registry, RC builds) | M | M | pin by build id, record sha256 |
862
862
  | R5 | Server rejects second simultaneous session | L | M | one session per connection (today's model), N connections instead |
@@ -247,7 +247,7 @@ unreachable on RC01 — no cancel method).
247
247
 
248
248
  - Chunks are pure DELTAS. Verified by content: numbers split mid-token across
249
249
  chunk boundaries (`"...\n39\n40\n4"` then `"1\n42\n43..."`), and no chunk
250
- ever contained a full prefix of the accumulated text. The legacy
250
+ ever contained a full prefix of the accumulated text. The stream-json
251
251
  cumulative-resend failure mode was NOT observed over ACP (defensive guard
252
252
  stays cheap insurance).
253
253
  - Throughput: 300 numbers (~600 tokens) completed within one 25 s poll;