@estebanforge/pi-antigravity-bridge 1.0.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 +125 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/docs/ARCHITECTURE.md +48 -0
- package/docs/DEVELOPMENT.md +64 -0
- package/docs/PI-BRIDGE-GAPS.md +186 -0
- package/docs/PI-INVOKETOOL-PATCH.md +227 -0
- package/extensions/index.ts +474 -0
- package/package.json +69 -0
- package/src/ask-tool.ts +579 -0
- package/src/config.ts +119 -0
- package/src/diff-render.ts +190 -0
- package/src/discovery.ts +199 -0
- package/src/mcp-server.ts +443 -0
- package/src/models.ts +261 -0
- package/src/patcher.ts +571 -0
- package/src/poller.ts +202 -0
- package/src/protobuf.ts +184 -0
- package/src/provider.ts +502 -0
- package/src/runner.ts +386 -0
- package/src/sessions.ts +159 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0] - 2026-07-29
|
|
6
|
+
|
|
7
|
+
First release. A streaming Gemini model provider for pi, built on Google's
|
|
8
|
+
`agy` CLI, plus an MCP tool bridge that lets agy use pi's installed tools
|
|
9
|
+
(memory, codegraph, Slack, Asana, web, peer delegation, etc.) instead of its
|
|
10
|
+
own. Registers `antigravity/*` models in pi's `/model` picker and streams
|
|
11
|
+
responses by polling the SQLite database agy writes and decoding its
|
|
12
|
+
protobuf step payloads. No generated protobuf code, no native SQLite
|
|
13
|
+
dependency.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
#### Streaming provider
|
|
18
|
+
|
|
19
|
+
- **Gemini provider for pi.** `antigravity/gemini-*` models appear in pi's
|
|
20
|
+
`/model` picker, discovered live from `agy models` (with a fallback catalog
|
|
21
|
+
when discovery fails). Picking one routes each turn through the provider.
|
|
22
|
+
- **Real streaming.** A concurrent poll loop (250ms, `PRAGMA data_version`
|
|
23
|
+
coalescing) reads agy's conversation DB while agy is still running, so text
|
|
24
|
+
and tool activity arrive during the turn, not replayed at exit. Three
|
|
25
|
+
trailing polls catch the final flush; abort skips them for prompt cancel.
|
|
26
|
+
- **Hand-rolled protobuf decoder** for agy's `step_payload` blobs: agent text
|
|
27
|
+
at field 20.1, tool calls at field 5.4 (name@2/9, input@3), title at 30.4.
|
|
28
|
+
Field numbers verified against real agy 1.1.7 databases and cross-checked
|
|
29
|
+
against the shindgew/agy-acp and shubzkothekar/antigravity-acp decoders.
|
|
30
|
+
Unknown fields are skipped per protobuf wire rules.
|
|
31
|
+
- **Multi-turn conversations.** A pi session is bound to an agy conversation
|
|
32
|
+
id (persisted at `~/.pi/agent/antigravity-bridge/sessions.json`) and
|
|
33
|
+
resumed via `--conversation <id>`. agy keeps its own history; only the latest
|
|
34
|
+
user message is sent each turn. Atomic, dirty-key-merged writes survive
|
|
35
|
+
concurrent pi processes.
|
|
36
|
+
- **`/agy` slash command** with status, an interactive picker (mode,
|
|
37
|
+
permissions), and direct subcommands. Settings persist to
|
|
38
|
+
`~/.pi/agent/antigravity-bridge/config.json`.
|
|
39
|
+
- **Configurable execution mode** (`accept-edits` default, or `plan`) and
|
|
40
|
+
permissions, overridable by `AGY_MODE` /
|
|
41
|
+
`AGY_SKIP_PERMISSIONS` env vars.
|
|
42
|
+
- **`--dangerously-skip-permissions` passed by default.** Technically
|
|
43
|
+
required: `accept-edits` auto-approves file edits but not shell commands,
|
|
44
|
+
so a `run_command` would otherwise hang on an unanswerable `y/n` prompt in
|
|
45
|
+
non-interactive `-p` mode (upstream google-antigravity/antigravity-cli#318).
|
|
46
|
+
Consistent with pi's own no-confirmation-gate design.
|
|
47
|
+
- **Conversation-id discovery** by snapshot/diff of agy's conversations dir
|
|
48
|
+
(agy `-p` never prints the id). Refuses to bind on ambiguity.
|
|
49
|
+
- **Tool-activity visibility.** agy's closed tool loop surfaces in pi's
|
|
50
|
+
thinking panel as `[agy tool: <name>]`. agy edits/commands land on disk;
|
|
51
|
+
pi's tools never fire (architectural wall, documented).
|
|
52
|
+
- **Cross-turn context continuity.** agy keeps its own history, but it now
|
|
53
|
+
also receives pi-side context it wasn't spawned for (compaction summaries,
|
|
54
|
+
turns from other providers or pi's own tools) as a brief digest with the
|
|
55
|
+
prompt each turn, so multi-turn work and provider switches stay coherent.
|
|
56
|
+
- **Edit diffs in the thinking stream.** When agy writes a file, pi's thinking
|
|
57
|
+
panel shows a line-numbered diff of the change as it lands. Works across
|
|
58
|
+
nested repos, submodules, and multi-repo workspaces; degrades cleanly for
|
|
59
|
+
binary, off-repo, or unchanged files.
|
|
60
|
+
- **Tests.** Unit tests for the protobuf decoder; a
|
|
61
|
+
deterministic fake-agy test that asserts events stream during the run and
|
|
62
|
+
that abort returns promptly (guards the "provider did not actually stream"
|
|
63
|
+
regression class).
|
|
64
|
+
|
|
65
|
+
#### MCP tool bridge (agy -> pi tools)
|
|
66
|
+
|
|
67
|
+
- **`AskAntigravity` tool** is now provided by this extension (ported from
|
|
68
|
+
`pi-ask-antigravity` v1.1.0). The bridge ships BOTH the streaming
|
|
69
|
+
antigravity provider AND the one-shot delegation tool - the same combined
|
|
70
|
+
shape as `pi-claude-bridge`. Model aliases (flash/pro/gemini, tier/version
|
|
71
|
+
qualifiers), one-shot vs continued-conversation modes, and the `mode`/
|
|
72
|
+
`digest` params are all preserved.
|
|
73
|
+
- **Cross-extension clash avoidance.** When both this bridge and
|
|
74
|
+
`pi-ask-antigravity` are installed, the bridge wins and
|
|
75
|
+
`pi-ask-antigravity` silently registers nothing (it detects the bridge via
|
|
76
|
+
package resolution, order-independent). The `AskAntigravity` tool is never
|
|
77
|
+
duplicated.
|
|
78
|
+
- **`/agy` gains `model` and `thinking` subcommands + picker rows** for the
|
|
79
|
+
tool's defaults (alias flash/pro/gemini; tier low/medium/high). Persisted
|
|
80
|
+
alongside the provider settings in `config.json`.
|
|
81
|
+
- **MCP tool bridge.** agy runs as pi's Gemini provider; the bridge exposes
|
|
82
|
+
pi's installed tools to agy over a Streamable HTTP MCP server so agy can
|
|
83
|
+
call them (memory, codegraph, Slack, Asana, web, peer delegation, etc.)
|
|
84
|
+
instead of doing the work itself. Per-pid config directory at
|
|
85
|
+
`~/.pi/agent/antigravity-bridge/agy-mcp-<pid>/`, written into agy's
|
|
86
|
+
`--add-dir` path so agy reads `.agents/mcp_config.json` from there.
|
|
87
|
+
Global agy config is never touched.
|
|
88
|
+
- **Capability gate.** The bridge checks for `pi.invokeTool` at startup and
|
|
89
|
+
silently no-ops the MCP server if the patch is absent (clean pi reinstall
|
|
90
|
+
drops the patch; bridge still runs as a provider).
|
|
91
|
+
- **Tool filtering.** Builtin tools that agy already has natively (read,
|
|
92
|
+
write, edit, bash, ls, grep, find) are filtered out so agy does not double
|
|
93
|
+
up on its own equivalents; `AskAntigravity` is filtered to avoid recursion.
|
|
94
|
+
Every other registered tool is exposed.
|
|
95
|
+
- **Security.** Shared-secret `x-bridge-token` header, request body size cap,
|
|
96
|
+
per-call `AbortController` so agy can cancel in-flight tool calls, full
|
|
97
|
+
request handler `try/catch`, rawHeaders rewrite for Hono's protocol clamp.
|
|
98
|
+
|
|
99
|
+
#### Documentation
|
|
100
|
+
|
|
101
|
+
- `docs/ARCHITECTURE.md` - bridge design and per-pid config layout.
|
|
102
|
+
- `docs/DEVELOPMENT.md` - how to run tests, rebuild, and iterate.
|
|
103
|
+
- `docs/PI-INVOKETOOL-PATCH.md` - the local patch to pi's dist that the
|
|
104
|
+
bridge depends on.
|
|
105
|
+
- `docs/PI-BRIDGE-GAPS.md` - capability gaps, as actionable tasks (G1-G10).
|
|
106
|
+
G1 (conversation history) and G8 (edit diffs) are closed via no-patch,
|
|
107
|
+
provider/decode-side work; the rest (streaming progress, UI primitives,
|
|
108
|
+
MCP-server double-exposure, etc.) remain open, triaged by effort and payoff.
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
|
|
112
|
+
- **Protocol-version clamp for the MCP bridge.** agy negotiates a protocol
|
|
113
|
+
version newer than the SDK this bridge ships: `@modelcontextprotocol/sdk`
|
|
114
|
+
1.29.0 tops out at `2025-11-25`, but agy sends `2026-07-28`. `initialize` is
|
|
115
|
+
exempt from the transport's header check and the SDK downgrades its body
|
|
116
|
+
version itself, yet every follow-up (`tools/list`, `tools/call`,
|
|
117
|
+
`notifications/initialized`) is validated against the `MCP-Protocol-Version`
|
|
118
|
+
header and rejected with `400 Bad Request: Unsupported protocol version`,
|
|
119
|
+
surfaced as a `transport-error` on every turn. The bridge now rewrites any
|
|
120
|
+
unsupported header value to `LATEST_PROTOCOL_VERSION` before the transport
|
|
121
|
+
sees it. The server is stateless (a fresh transport per request), so it
|
|
122
|
+
cannot track the negotiated version across requests; clamping to LATEST is
|
|
123
|
+
the correct downgrade. Hono's Node->Web conversion reads `req.rawHeaders`,
|
|
124
|
+
not the parsed `req.headers` object, so the value is rewritten in the raw
|
|
125
|
+
array (and mirrored on `req.headers` for other readers).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EstebanForge
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# pi-antigravity-bridge
|
|
2
|
+
|
|
3
|
+
A Gemini model provider **and** the `AskAntigravity` delegation tool for [pi](https://github.com/earendil-works/pi-coding-agent), both built on Google's `agy` CLI. It registers `antigravity/gemini-*` models in pi's `/model` picker (streaming), and provides the `AskAntigravity` tool for one-shot delegation - the same combined shape as `pi-claude-bridge`.
|
|
4
|
+
|
|
5
|
+
<img width="3024" height="1774" alt="image" src="https://github.com/user-attachments/assets/9fc2f368-7292-4dde-851b-db2bd579263c" align="center" />
|
|
6
|
+
|
|
7
|
+
If you also have [`@estebanforge/pi-ask-antigravity`](https://github.com/EstebanForge/pi-ask-antigravity) installed, this bridge takes over: pi-ask-antigravity detects the bridge and registers nothing, so the `AskAntigravity` tool is never duplicated.
|
|
8
|
+
|
|
9
|
+
## What it does
|
|
10
|
+
|
|
11
|
+
You pick a Gemini model in pi's `/model` picker. pi routes each turn through this provider. The provider spawns `agy -p` in your workspace, polls the SQLite database agy writes as it works, decodes the protobuf step payloads, and streams the agent text back into pi token by token.
|
|
12
|
+
|
|
13
|
+
Multi-turn works. The provider binds a pi session to an agy conversation id (persisted under `~/.pi/agent/antigravity-bridge/sessions.json`) and resumes it on the next turn via `--conversation <id>`. agy keeps its own history, so only the latest user message is sent each turn.
|
|
14
|
+
|
|
15
|
+
## What it cannot do
|
|
16
|
+
|
|
17
|
+
agy runs its own closed tool loop (`read_file`, `write_file`, `edit_file`, `run_command`) against `--add-dir`. By default pi's own `read`/`write`/`edit`/`bash` do not fire for agy's file and shell work, and that is fine: agy has capable native equivalents. What used to be a hard wall for everything else is now bridgeable; see [MCP tool bridge](#mcp-tool-bridge-agy-uses-pis-tools) below.
|
|
18
|
+
|
|
19
|
+
Residual limits (with or without the bridge):
|
|
20
|
+
|
|
21
|
+
- agy's own edits still land directly on disk; pi's inline diff review does not engage for them.
|
|
22
|
+
- agy commands run without per-action approval, same as every other tool in pi. See [Permissions](#permissions) below.
|
|
23
|
+
- No token usage or cost accounting. agy does not expose token counts, so usage reports as zero.
|
|
24
|
+
|
|
25
|
+
## MCP tool bridge (agy uses pi's tools)
|
|
26
|
+
|
|
27
|
+
While agy is the active model it normally cannot see pi's universe of extensions: agentmemory, codegraph, web search, slack/asana, the `Ask*` delegations, and any other installed pi tool. This extension optionally bridges that gap.
|
|
28
|
+
|
|
29
|
+
When the capability is present the bridge starts a localhost MCP server inside pi's process. `tools/list` returns pi's registered tools (built-in file/shell tools and `AskAntigravity` are filtered out), and `tools/call` executes them via `pi.invokeTool()`. agy discovers the server through a per-invocation config: the bridge writes `.agents/mcp_config.json` into a bridge-controlled dir (`~/.pi/agent/antigravity-bridge/agy-mcp-<pid>/`) and the provider passes that dir as an extra `--add-dir` when it spawns agy. The user's global agy config (`~/.gemini/config/mcp_config.json`) is never touched, so standalone agy outside pi is unaffected.
|
|
30
|
+
|
|
31
|
+
**Capability requirement.** `pi.invokeTool()` is not (yet) part of upstream pi. On first load with the patch missing, the extension **asks you once** whether to apply it (see [Install](#install)); once applied it activates after a full `pi` restart. Without it the bridge detects the missing capability at load time, skips the MCP server, and everything else works unchanged. See [docs/PI-INVOKETOOL-PATCH.md](docs/PI-INVOKETOOL-PATCH.md) for what the patch is, and `/agy patch status|apply|restore` to inspect, force, or undo it.
|
|
32
|
+
|
|
33
|
+
**Recursion safety.** Only the provider's agy receives the extra `--add-dir`. The `AskAntigravity` tool spawns its own agy with just the workspace, so that inner agy starts plain (no pi tools) and cannot re-enter. `AskAntigravity` is also filtered from the exposed tool list. Standalone agy is unaffected because nothing is written to its global config.
|
|
34
|
+
|
|
35
|
+
**Cost / fan-out.** Every registered pi tool except builtins (and `AskAntigravity`) is exposed, including other delegation tools like `AskClaude`/`AskCodex`. agy can therefore chain into other models via the bridge, which is a new cost/time fan-out vector that did not exist before this feature.
|
|
36
|
+
|
|
37
|
+
**Security.** The MCP server binds to `127.0.0.1` only and requires a per-session shared-secret header (`x-bridge-token`) that agy sends from the bridge config; browsers cannot set custom headers on a simple cross-origin POST, so this blocks web CSRF against the loopback server. Request bodies are size-capped. This is intended for single-user developer machines: any local process running as the same user can read the token from the per-pid config and call the exposed tools, so do not run it on a shared host where you do not trust other same-user processes.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
> ⚠️ **Heads-up: this extension patches your `pi` install.** When it loads and
|
|
42
|
+
> the running pi lacks `pi.invokeTool()`, it **asks you once** whether to edit
|
|
43
|
+
> files inside your globally-installed `@earendil-works/pi-coding-agent/dist/`
|
|
44
|
+
> (adding one method) to enable the MCP tool bridge. This is, for now, the only
|
|
45
|
+
> way agy can use Pi internal tooling.
|
|
46
|
+
>
|
|
47
|
+
> - **Yes** → applies the patch (reversible via `/agy patch restore`) and tells
|
|
48
|
+
> you to restart pi. The bridge starts on the next launch.
|
|
49
|
+
>
|
|
50
|
+
> - **No** → it remembers your choice and stays silent; it won't ask again until
|
|
51
|
+
> you run `/agy patch apply`. The provider and AskAntigravity tool keep working;
|
|
52
|
+
> only the MCP tool bridge stays off.
|
|
53
|
+
>
|
|
54
|
+
> - The apply is **idempotent & safe** (only what's missing; aborts cleanly if a
|
|
55
|
+
> pi update moved the code), **backed up** (under
|
|
56
|
+
> `~/.pi/agent/antigravity-bridge/pi-patch-backup/`), and **self-healing** (a
|
|
57
|
+
> `pi` reinstall/update wipes `dist/`; re-applied on the next start).
|
|
58
|
+
>
|
|
59
|
+
> The patch only takes effect after a **full `pi` restart** (quit + relaunch) —
|
|
60
|
+
> `/reload` is **not** enough, because pi caches its compiled core for the
|
|
61
|
+
> process.
|
|
62
|
+
>
|
|
63
|
+
> Details for the patch can be found in [docs/PI-INVOKETOOL-PATCH.md](docs/PI-INVOKETOOL-PATCH.md).
|
|
64
|
+
|
|
65
|
+
Install with pi's package manager:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pi install npm:@estebanforge/pi-antigravity-bridge
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Requires the **`agy` CLI** installed and authenticated. If you don't have it, follow Google's [official install guide](https://antigravity.google/docs/cli/install) for your platform, then run `agy` once to complete Google OAuth. The extension resolves `agy` on `$PATH`, or via the `AGY_BIN` environment variable.
|
|
72
|
+
|
|
73
|
+
Also requires Node 22.5 or newer (uses the built-in `node:sqlite`).
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
Pick a model and talk to pi as usual:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
/model
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Look for the models namespaced as: antigravity
|
|
84
|
+
|
|
85
|
+
Or specify a model directly:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
/model antigravity/gemini-3-6-flash-medium
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Model ids are slugified from the `agy models` output (`Gemini 3.6 Flash (Medium)` becomes `gemini-3-6-flash-medium`). Discovery runs once at extension load. Run `/reload` after an `agy update` to refresh the list.
|
|
92
|
+
|
|
93
|
+
If `agy models` fails at load (binary missing, auth not done, network stall), a fallback catalog still populates the picker so you get a clear runtime error instead of an empty list.
|
|
94
|
+
|
|
95
|
+
### The /agy command
|
|
96
|
+
|
|
97
|
+
`/agy` configures the provider at runtime. Settings persist to `~/.pi/agent/antigravity-bridge/config.json` and take effect on the next turn.
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
/agy status, or open the mode/permissions/model/thinking picker (TUI)
|
|
101
|
+
/agy status print current mode, permissions, model + session counts
|
|
102
|
+
/agy mode plan review-only: agy plans but writes nothing
|
|
103
|
+
/agy mode accept-edits agy applies edits directly (default)
|
|
104
|
+
/agy permissions on|off auto-approve / prompt for tool calls (see warning)
|
|
105
|
+
/agy model flash|pro|gemini default model alias for the AskAntigravity tool
|
|
106
|
+
/agy thinking low|medium|high default thinking tier for the AskAntigravity tool
|
|
107
|
+
/agy patch status|apply|restore inspect / force / undo the pi.invokeTool patch
|
|
108
|
+
/agy clear drop all session bindings (force fresh conversations)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Permissions
|
|
112
|
+
|
|
113
|
+
pi itself has no built-in approval gate. Unlike codex, claude, or agy running interactively, pi does not prompt you to confirm each tool action before it runs. That is the host environment this extension lives in.
|
|
114
|
+
|
|
115
|
+
Because agy in `-p` (print) mode cannot answer an interactive `y/n` prompt, this extension passes `--dangerously-skip-permissions` by default. It is technically necessary: `accept-edits` auto-approves file edits but not shell commands, so a `run_command` would otherwise hang forever waiting for a prompt nothing can answer (upstream [google-antigravity/antigravity-cli#318](https://github.com/google-antigravity/antigravity-cli/issues/318)). The net effect is that agy executes commands the same way pi already executes your other tools: without per-action review.
|
|
116
|
+
|
|
117
|
+
If you want agy to execute nothing, use `/agy mode plan`. Do not combine `--sandbox` with skip-permissions ([#36](https://github.com/google-antigravity/antigravity-cli/issues/36)).
|
|
118
|
+
|
|
119
|
+
### Run pi inside a sandbox
|
|
120
|
+
|
|
121
|
+
For isolation when running any agent that executes commands without a confirmation gate, run pi inside [**construct-cli**](https://github.com/EstebanForge/construct-cli) - EstebanForge's sandbox for AI agents. Isolated container, no path escape, ephemeral filesystem, `strict` / `offline` network modes, secret redaction. The blast radius of a bad command stays in the container, not your host. Install and usage instructions are in that repo.
|
|
122
|
+
|
|
123
|
+
### Environment variables
|
|
124
|
+
|
|
125
|
+
| Variable | Purpose |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `AGY_BIN` | Path to the agy binary. Defaults to `agy` on PATH. |
|
|
128
|
+
| `AGY_EXTRA_ARGS` | Extra args appended to every invocation. Whitespace-split. |
|
|
129
|
+
| `AGY_CONVERSATIONS_DIR` | Override the conversations DB directory. |
|
|
130
|
+
| `AGY_MODE` | Override execution mode: `plan` (review-only) or `accept-edits` (default). Wins over the config file. |
|
|
131
|
+
| `AGY_SKIP_PERMISSIONS` | `1`/`true` (default) to pass `--dangerously-skip-permissions` so commands don't hang on an unanswerable prompt in `-p` mode. `0`/`false` to prompt (hangs any `run_command` non-interactively). Wins over the config file. |
|
|
132
|
+
| `AGY_DEFAULT_MODEL` | Default model alias for the `AskAntigravity` tool (`flash`/`pro`/`gemini`, or a tier/version qualifier). Wins over the config file. |
|
|
133
|
+
| `AGY_DEFAULT_THINKING` | Default thinking tier for the `AskAntigravity` tool: `low`/`medium`/`high`. Anything else falls back to `medium`. Wins over the config file. |
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
Build, test, and debug instructions live in [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md). For the internal architecture (decode pipeline, polling, conversation discovery) see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
|
138
|
+
|
|
139
|
+
## Terms of Service notice
|
|
140
|
+
|
|
141
|
+
Google's [Antigravity ToS](https://antigravity.google/terms) (Section 6) prohibits accessing the service "in connection with products not provided by us", and names as its example using tools like Hermes/OpenClaw with Antigravity OAuth. That targets reusing your credentials in a non-Google harness that calls Google's backend directly.
|
|
142
|
+
|
|
143
|
+
This extension does not do that. It spawns the official, unmodified `agy` binary as a subprocess; `agy` performs its own OAuth and makes its own calls to Google. This code never sees, extracts, or reuses your token, and never contacts Antigravity's backend. It only reads the local SQLite file `agy` writes. From Google's server-side view there is no signal that distinguishes "agy launched by pi" from "agy launched by a terminal, an IDE task runner, or cron": same signed binary, same authenticated calls.
|
|
144
|
+
|
|
145
|
+
Google's reported enforcement to date (the February 2026 suspensions) targeted token-reuse tools, not spawning the official CLI.
|
|
146
|
+
|
|
147
|
+
pi-antigravity-bridge practical risk is low, near zero. But not zero: the "in connection with" wording is broad, and Google can suspend accounts at its discretion regardless of whether a breach is provable. Grey area. Safe for now. You should read "news" about this online from time to time.
|
|
148
|
+
|
|
149
|
+
This is engineering analysis, not legal advice. Use against your own Antigravity account at your own risk; I am not responsible for any consequence to your account.
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
How the provider works internally. For build/test/debug workflow see [DEVELOPMENT.md](./DEVELOPMENT.md).
|
|
4
|
+
|
|
5
|
+
## Module map
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
extensions/index.ts registerProvider + model discovery + /agy command (entry)
|
|
9
|
+
src/provider.ts streamSimple: pi Context -> agy turn -> pi event stream
|
|
10
|
+
src/runner.ts spawn agy -p, concurrent poll loop, abort/timeout, emit events
|
|
11
|
+
src/poller.ts read-only node:sqlite handle over one conversation DB
|
|
12
|
+
src/protobuf.ts hand-rolled varint walker + extractors (field 20.1 = text)
|
|
13
|
+
src/discovery.ts snapshot/diff to bind the conversation id agy never prints
|
|
14
|
+
src/models.ts agy models -> pi Model projection
|
|
15
|
+
src/sessions.ts atomic JSON store: pi session -> agy conversation + last step
|
|
16
|
+
src/config.ts persisted runtime config (mode, permissions, model/thinking defaults)
|
|
17
|
+
src/ask-tool.ts the AskAntigravity one-shot delegation tool (model/thinking defaults)
|
|
18
|
+
src/mcp-server.ts MCP tool bridge: exposes pi's tools to agy over Streamable HTTP
|
|
19
|
+
src/patcher.ts Auto-applies the pi.invokeTool local patch to enable the MCP tool bridge
|
|
20
|
+
src/diff-render.ts render agy's file edits as git diffs in pi's thinking stream
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
No generated protobuf code, no native SQLite dependency.
|
|
24
|
+
|
|
25
|
+
## The decode pipeline
|
|
26
|
+
|
|
27
|
+
agy writes each step to a SQLite row with a protobuf blob in `step_payload`. The text we want lives at field 20, submessage field 1. Tool calls live at field 5, submessage field 4, with the name at field 2 or 9 and the raw input JSON at field 3. These field numbers are reverse-engineered facts (cross-checked against the shindgew/agy-acp and shubzkothekar/antigravity-acp decoders, then verified against real databases on agy 1.1.7). They are load-bearing. Unknown fields are skipped per protobuf wire rules, so a future agy that adds fields will not break decoding.
|
|
28
|
+
|
|
29
|
+
### Step types
|
|
30
|
+
|
|
31
|
+
| step_type | meaning |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| 15 | agent text (payload field 20 -> field 1) |
|
|
34
|
+
| 14 | thinking |
|
|
35
|
+
| 23 | title update (payload field 30 -> field 4) |
|
|
36
|
+
| 5, 7, 8, 9, 17, 21, 33, 101, 132, 138 | tool run (payload field 5 -> field 4 -> name@2/9, input@3) |
|
|
37
|
+
|
|
38
|
+
Status 3 = complete; anything else = in-flight.
|
|
39
|
+
|
|
40
|
+
## Polling
|
|
41
|
+
|
|
42
|
+
The runner spawns `agy -p`, then polls its conversation DB on a 250ms interval concurrent with the running process (this is what makes the provider actually stream, not replay at exit). Each tick issues a single `PRAGMA data_version` check; while agy is thinking and has not committed, that check is false and no row SELECT runs at all (neither the new-row read nor the in-place re-read of the step agy is currently extending). Only when a commit lands do both reads fire in one pass. Three trailing polls at 100ms after agy exits catch the last flush; on abort these are skipped so cancellation is prompt.
|
|
43
|
+
|
|
44
|
+
## Conversation id discovery
|
|
45
|
+
|
|
46
|
+
agy `-p` does not print the conversation id. On a fresh run the runner snapshots the `*.db` stems in the conversations dir before spawn, then diffs after. Exactly one new file = ours; zero new = refuse to bind (surfaced as an error rather than a guess).
|
|
47
|
+
|
|
48
|
+
When **more than one** new file appears (a concurrent agy or subagent started in parallel), the runner passes its spawned pid to `newConversationId`, which scans the process tree's open file descriptors (`/proc/<pid>/fd` on Linux) to find the single candidate `.db` our own agy is writing to. This is the authoritative disambiguator: mtime cannot separate two *active* concurrent runs, and the user-message payload (`step_type 98`) is undocumented and deeply nested, so content-matching would risk a silent misbind. When the pid is unavailable, the platform is not Linux, the process has already exited (the AskAntigravity tool binds post-exit), or the scan itself is ambiguous, discovery fails safe to null rather than guessing.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Development & Debugging
|
|
2
|
+
|
|
3
|
+
How to build, test, and debug this extension outside pi.
|
|
4
|
+
|
|
5
|
+
## Build, test, typecheck
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm test # unit tests (protobuf decoder, runner streaming/abort, mcp bridge)
|
|
10
|
+
npm run build # tsc --noEmit type check
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The integration scripts below spawn a real `agy` process and need a logged-in account. The unit tests (`npm test`) need neither.
|
|
14
|
+
|
|
15
|
+
## Standalone scripts
|
|
16
|
+
|
|
17
|
+
These exercise the pipeline without pi. Useful for isolating where a bug lives (decoder? poller? provider? pi loader?).
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Decode any conversation DB and print agent text + tool calls.
|
|
21
|
+
# Accepts a UUID (resolved against ~/.gemini/antigravity-cli/conversations/)
|
|
22
|
+
# or an absolute path. Fastest way to check the protobuf decoder against
|
|
23
|
+
# real data. No agy spawn, no network.
|
|
24
|
+
npm run decode-db -- <uuid-or-path>
|
|
25
|
+
|
|
26
|
+
# Spawn agy and stream decoded events to stdout with timestamps. Proves the
|
|
27
|
+
# concurrent poll loop actually streams (events arrive during the run, not
|
|
28
|
+
# only at exit). Use this to reproduce a hang or a missing-event bug.
|
|
29
|
+
npm run run-agy -- "Say hello"
|
|
30
|
+
npm run run-agy -- --model "Gemini 3.6 Flash (Medium)" --mode plan "Review src/protobuf.ts"
|
|
31
|
+
npm run run-agy -- --conversation <uuid> "follow up" # resume a turn
|
|
32
|
+
|
|
33
|
+
# Drive the provider's streamSimple directly (no pi TUI) and assert the
|
|
34
|
+
# full event lifecycle: start -> text_start -> text_delta -> text_end ->
|
|
35
|
+
# done. The closest thing to a pi turn without pi.
|
|
36
|
+
npx tsx scripts/test-provider.ts
|
|
37
|
+
|
|
38
|
+
# Load the extension through a mock ExtensionAPI and assert registerProvider
|
|
39
|
+
# + registerCommand (/agy) fire with the right shape. No agy spawn.
|
|
40
|
+
npx tsx scripts/test-extension.ts
|
|
41
|
+
|
|
42
|
+
# Load the extension through pi's REAL loader and confirm the antigravity/*
|
|
43
|
+
# models register. This is the in-pi smoke test.
|
|
44
|
+
npm run smoke:pi
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Debugging a hang or "stuck" turn
|
|
48
|
+
|
|
49
|
+
Most "stuck" reports trace to one of:
|
|
50
|
+
|
|
51
|
+
1. **agy blocked on a permission prompt.** `accept-edits` auto-approves file edits but NOT shell commands. Any `run_command` prompts `y/n`, which hangs forever in non-interactive `-p` mode. The provider passes `--dangerously-skip-permissions` by default to avoid this. If you turned it off (`/agy permissions off`), that is why. See the README Permissions section.
|
|
52
|
+
2. **agy never started.** Check `AGY_BIN` is on PATH (or set explicitly). The runner swallows spawn ENOENT into the result's stderr, surfaced by the provider as an error event.
|
|
53
|
+
3. **Conversation id never bound.** The snapshot/diff discovery refuses to bind if more than one new `.db` appears (ambiguous). `scripts/decode-db.ts` against the suspected DB confirms agy wrote steps.
|
|
54
|
+
4. **Print-mode environmental hang.** `pi -p` can hang with zero output in some containers (upstream [google-antigravity/antigravity-cli#318](https://github.com/google-antigravity/antigravity-cli/issues/318)). It affects built-in providers too, not this extension. Validate the turn with `scripts/test-provider.ts` instead.
|
|
55
|
+
|
|
56
|
+
## Regression tests worth knowing
|
|
57
|
+
|
|
58
|
+
- `tests/protobuf.test.ts` - pure decoder math (varint, field walking, nested submessages).
|
|
59
|
+
- `tests/runner-streaming.test.ts` - a fake agy writes rows on a delay; asserts events arrive DURING the run (not all at exit) and that abort returns promptly. This is the test that guards the "provider did not actually stream" class of bug.
|
|
60
|
+
- `tests/mcp-server.test.ts` - the MCP tool bridge end-to-end against a real (port 0) server: capability gate, per-pid config lifecycle, shared-secret token gate, 1 MB body cap, protocol-version clamp, and tool-call dispatch through `pi.invokeTool`. Guards the security and transport-correctness of the bridge.
|
|
61
|
+
|
|
62
|
+
## Module map
|
|
63
|
+
|
|
64
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md) for the module map and the decode-pipeline / polling internals.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# pi-antigravity-bridge: capability gaps
|
|
2
|
+
|
|
3
|
+
Status of the MCP tool bridge between agy (Antigravity CLI, used as pi's Gemini
|
|
4
|
+
provider) and pi's extension/builtin tools. This doc tracks **open gaps only**.
|
|
5
|
+
Shipped work lives in `CHANGELOG.md` (most recently: a conversation-history
|
|
6
|
+
delta digest, and git-sourced edit diffs). Ideas that were weighed and rejected
|
|
7
|
+
are listed at the end under "Discarded ideas".
|
|
8
|
+
|
|
9
|
+
## What the bridge already does
|
|
10
|
+
|
|
11
|
+
agy -> bridge MCP server -> `pi.invokeTool(name, args)` -> pi's tool registry
|
|
12
|
+
-> result returned through MCP -> agy model context. The chain was verified
|
|
13
|
+
end-to-end with `memory_search` and `ask_user_question`. The bridge exposes
|
|
14
|
+
pi's extension tools (builtins are filtered out since agy has native
|
|
15
|
+
equivalents; `AskAntigravity` is filtered to avoid recursion).
|
|
16
|
+
|
|
17
|
+
What this means in practice: agy can read/write files, use memory, navigate
|
|
18
|
+
code with codegraph, search the web, post to Slack, create Asana tasks, spawn
|
|
19
|
+
subagents, prompt the user with `ask_user_question`, and delegate to peer
|
|
20
|
+
reviewers (Claude, Codex, Antigravity), all by going through pi's installed
|
|
21
|
+
tooling instead of its own. Tools run in pi's process with pi's own credentials,
|
|
22
|
+
so a secret never crosses the bridge. agy's file edits surface as git-sourced
|
|
23
|
+
diffs in pi's thinking stream, and each turn agy receives a delta digest of
|
|
24
|
+
pi-side context (compaction summaries, other-provider turns) it was not spawned
|
|
25
|
+
for.
|
|
26
|
+
|
|
27
|
+
## Open gaps
|
|
28
|
+
|
|
29
|
+
Three gaps remain. Every one either needs a pi dist patch (the maintenance cost
|
|
30
|
+
the shipped gaps deliberately avoided) or a verify-before-build step. Ordered by
|
|
31
|
+
former G-number.
|
|
32
|
+
|
|
33
|
+
**Numbering note:** the G1/G2/G3 labels below are this living doc's renumbered
|
|
34
|
+
open set, NOT the historical G1-G10 in `CHANGELOG.md`. In that historical list
|
|
35
|
+
G1 = conversation-history digest and G8 = edit diffs; both are now closed
|
|
36
|
+
(shipped in 1.0.0) and so dropped from here, leaving the three renumbered below.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### G1. Stream progress for long tool calls [HIGH IMPACT]
|
|
41
|
+
|
|
42
|
+
**Status:** Open
|
|
43
|
+
**Objective:** Stop blocking on long tools (`web_research`, `librarian`,
|
|
44
|
+
`codegraph_explore` on big repos). Push partial output back to agy so pi's UI
|
|
45
|
+
shows live progress instead of a frozen spinner.
|
|
46
|
+
|
|
47
|
+
**Why:** Today the bridge blocks until the tool returns. The user has no signal
|
|
48
|
+
that work is happening. This is partly a pi-side gap (most long tools do not
|
|
49
|
+
emit progress) and partly a bridge-transport gap.
|
|
50
|
+
|
|
51
|
+
**Scope:**
|
|
52
|
+
- `docs/PI-INVOKETOOL-PATCH.md`: expose pi's progress bus.
|
|
53
|
+
- `src/mcp-server.ts`: switch from blocking `invokeTool` to a streaming RPC
|
|
54
|
+
using MCP `notifications/progress` (or a `pi_tool_progress` SSE channel).
|
|
55
|
+
- pi-side: audit long tools and add progress emission where missing.
|
|
56
|
+
|
|
57
|
+
**Acceptance criteria:**
|
|
58
|
+
- [ ] A tool that runs >1s emits at least one progress notification.
|
|
59
|
+
- [ ] pi's TUI spinner updates during the call, not only on completion.
|
|
60
|
+
- [ ] Result content is identical to the blocking path (no data loss).
|
|
61
|
+
- [ ] Fallback: if a tool does not emit progress, behavior matches today.
|
|
62
|
+
|
|
63
|
+
**Effort:** Large. Touches pi's progress bus and the MCP transport.
|
|
64
|
+
|
|
65
|
+
**Blocks:** None. **Blocked by:** None.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### G2. Expose pi's UI primitives [MEDIUM-HIGH IMPACT]
|
|
70
|
+
|
|
71
|
+
**Status:** Open
|
|
72
|
+
**Objective:** Let agy drive pi's native UI: confirm dialogs, toasts,
|
|
73
|
+
file/directory pickers, status/footer updates.
|
|
74
|
+
|
|
75
|
+
**Why:** agy can already `ask_user_question`. Missing: confirm/permission
|
|
76
|
+
dialog for destructive ops (agy falls back to its own out-of-theme dialog),
|
|
77
|
+
notification toast (for "task started" / "save ok"), native file picker
|
|
78
|
+
(replaced today by asking for a path in text), and status-bar updates
|
|
79
|
+
("Antigravity: working on X"). Note: this does NOT unlock a native diff viewer
|
|
80
|
+
for agy edits, that path is structurally closed (see G8 in `CHANGELOG.md`).
|
|
81
|
+
|
|
82
|
+
**Scope:**
|
|
83
|
+
- `docs/PI-INVOKETOOL-PATCH.md`: expose `AgentSession.ui` helpers.
|
|
84
|
+
- `src/mcp-server.ts`: wrappers for `pi_confirm`, `pi_notify`,
|
|
85
|
+
`pi_select_file`, `pi_select_directory`, `pi_set_status`.
|
|
86
|
+
|
|
87
|
+
**Acceptance criteria:**
|
|
88
|
+
- [ ] `pi_confirm(message)` pops pi's native confirm UI and returns boolean.
|
|
89
|
+
- [ ] `pi_notify(message)` shows a toast.
|
|
90
|
+
- [ ] `pi_select_file`/`pi_select_directory` return chosen paths or null.
|
|
91
|
+
- [ ] `pi_set_status(text)` updates the footer; clears on empty string.
|
|
92
|
+
- [ ] Tests cover each primitive with a mocked `ui` seam.
|
|
93
|
+
|
|
94
|
+
**Effort:** Medium-large. Each primitive is a small pi patch plus a wrapper.
|
|
95
|
+
|
|
96
|
+
**Blocks:** None. **Blocked by:** None.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### G3. Lifecycle event subscription [MEDIUM IMPACT]
|
|
101
|
+
|
|
102
|
+
**Status:** Open
|
|
103
|
+
**Objective:** Let a long-lived agy session observe pi events: `turn_start`,
|
|
104
|
+
`turn_end`, `tool_call`, `tool_result`, `compaction`.
|
|
105
|
+
|
|
106
|
+
**Why:** Today the bridge handles only `session_start` and `session_shutdown`.
|
|
107
|
+
agy is fire-and-forget per turn. Event subscription would enable a class of
|
|
108
|
+
"observer" tooling.
|
|
109
|
+
|
|
110
|
+
**Caveat:** agy is request-response per turn (`-p`), not event-reactive. Before
|
|
111
|
+
building, confirm there is a real consumer that can act on an async event
|
|
112
|
+
stream; otherwise this risks the same "no consumer" failure that sank
|
|
113
|
+
file-watching (see Discarded ideas).
|
|
114
|
+
|
|
115
|
+
**Scope:**
|
|
116
|
+
- `docs/PI-INVOKETOOL-PATCH.md`: add an event-emitter seam on `AgentSession`.
|
|
117
|
+
- `src/mcp-server.ts`: `pi_subscribe(event)` returns a stream id; an SSE
|
|
118
|
+
channel pushes events.
|
|
119
|
+
|
|
120
|
+
**Acceptance criteria:**
|
|
121
|
+
- [ ] `pi_subscribe("tool_call")` returns a stream id and subsequent tool calls
|
|
122
|
+
arrive on the channel.
|
|
123
|
+
- [ ] Unsubscribe cleans up the stream (no leak).
|
|
124
|
+
- [ ] At least three event types supported at close.
|
|
125
|
+
- [ ] No perf regression on the event hot path.
|
|
126
|
+
|
|
127
|
+
**Effort:** Large. Non-trivial pi-side patching.
|
|
128
|
+
|
|
129
|
+
**Blocks:** None. **Blocked by:** Confirm a real event-driven consumer exists.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Discarded ideas (not worth it)
|
|
134
|
+
|
|
135
|
+
Weighed and rejected; kept here as a graveyard so they are not re-proposed. Full
|
|
136
|
+
reasoning is in project memory.
|
|
137
|
+
|
|
138
|
+
- **Expose pi's other MCP clients** — REMOVED. pi has no native
|
|
139
|
+
MCP-client support and no MCP extension is in use, so there are no pi
|
|
140
|
+
MCP-client tools to double-expose. The bridge already surfaces every tool pi
|
|
141
|
+
actually registers.
|
|
142
|
+
- **Refresh tool list mid-session** — DECLINED. The bridge already
|
|
143
|
+
re-queries `pi.getAllTools()` on every `tools/list` (stateless server), and
|
|
144
|
+
agy reconnects and re-lists every turn (`-p`), so a tool registered
|
|
145
|
+
mid-session appears next turn. The heartbeat would only help a long-lived
|
|
146
|
+
client that caches the list, and there is none.
|
|
147
|
+
- **Settings, env, and secrets access** — DECLINED. Tools exposed via
|
|
148
|
+
the bridge run in pi's process (`pi.invokeTool` -> `tool.execute`) and
|
|
149
|
+
self-authenticate with pi's own credentials, so agy already uses pi's creds
|
|
150
|
+
for every tool; a credential never crosses the bridge. A `pi_get_setting`
|
|
151
|
+
accessor was predicated on credential reuse that does not apply.
|
|
152
|
+
- **Image / binary content blocks** — NOT NEEDED. pi shares the
|
|
153
|
+
path to any image it produces (e.g. `/tmp/pi-clipboard-<uuid>.png`), and agy
|
|
154
|
+
reaches and reads those files directly via the bridge's `read` tool, so
|
|
155
|
+
returning image content blocks over the transport would duplicate a path
|
|
156
|
+
that already works end-to-end. No agy transport change or pi patch required.
|
|
157
|
+
- **File-watching / live state** — DECLINED. agy is request-response
|
|
158
|
+
per turn, not event-reactive; nothing consumes a file-watch SSE stream, and
|
|
159
|
+
re-reads are cheap and correct. Watchers would add inotify/FSEvents handles,
|
|
160
|
+
races, and cleanup for no gain.
|
|
161
|
+
|
|
162
|
+
## How to close a gap
|
|
163
|
+
|
|
164
|
+
For each open gap, the default shape:
|
|
165
|
+
|
|
166
|
+
1. Identify the pi-side API to expose (or add).
|
|
167
|
+
2. Extend the patch in `docs/PI-INVOKETOOL-PATCH.md` with a read (or write)
|
|
168
|
+
accessor.
|
|
169
|
+
3. Add a bridge tool wrapper in `src/mcp-server.ts` that calls the patched API.
|
|
170
|
+
4. Register the tool name with the bridge (it appears in agy's tool catalog on
|
|
171
|
+
the next session).
|
|
172
|
+
5. Add a test under `tests/mcp-server.test.ts` that round-trips a real call.
|
|
173
|
+
6. Tick the gap's acceptance checkboxes.
|
|
174
|
+
|
|
175
|
+
Most need no change to agy, only the bridge (and, for some, pi's dist). Note:
|
|
176
|
+
the two shipped gaps were closed without any pi dist patch or new MCP tool, by
|
|
177
|
+
working provider/decode-side (`src/provider.ts`, `src/diff-render.ts`); the
|
|
178
|
+
shape above is a default, not a requirement.
|
|
179
|
+
|
|
180
|
+
## Cross-references
|
|
181
|
+
|
|
182
|
+
- `docs/ARCHITECTURE.md` — bridge design and per-pid config layout.
|
|
183
|
+
- `docs/PI-INVOKETOOL-PATCH.md` — the local patch to pi that this whole
|
|
184
|
+
feature depends on.
|
|
185
|
+
- `docs/DEVELOPMENT.md` — how to run tests, rebuild, and iterate.
|
|
186
|
+
- `CHANGELOG.md` — shipped work (conversation-history digest, edit diffs).
|