feat(acp): bundle into CLI, on-demand install, S1 safety + evidence (U8)
Wires the ACP runtime plugin into the published CLI (RUNTIME_PLUGIN_IDS in tsup.config) and the on-demand BUILTIN_PLUGINS catalog (experimental), matching the untrusted-subprocess security posture. Adds the Risk S1 default-policy safety: an acpAllowUnrestricted acknowledgement (default false) — without it, a blanket allow on a sensitive category is escalated to approval rather than auto-approved under the allow-all default policy, applied in both the permission floor and fs write gating. Adds docs/acp-contract.md (launch/readiness + failure taxonomy), a README with the AGENTS.md-required upstream evidence (SDK repo/docs/release/integrity), a bundle-output test for the staged plugin, and a @runfusion/fusion minor changeset. Package green at 179 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
66
docs/acp-contract.md
Normal file
66
docs/acp-contract.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# ACP (Agent Client Protocol) Runtime Contract
|
||||
|
||||
Date: 2026-06-03
|
||||
|
||||
Launch/readiness contract and failure taxonomy for `fusion-plugin-acp-runtime`,
|
||||
which drives any external [Agent Client Protocol](https://agentclientprotocol.com)
|
||||
agent over JSON-RPC/stdio. Mirrors the shape of `docs/cursor-cli-contract.md`.
|
||||
|
||||
## Transport
|
||||
|
||||
- **Newline-delimited JSON-RPC 2.0 over stdio** (no Content-Length framing).
|
||||
Provided by `@agentclientprotocol/sdk` (`ndJsonStream` + `ClientSideConnection`).
|
||||
- The client (Fusion) launches the agent as a subprocess with piped stdio. The
|
||||
agent's stdin is the JSON-RPC *output* stream; its stdout is the *input* stream.
|
||||
- `stderr` is captured (redacted) for diagnostics, never parsed as protocol.
|
||||
|
||||
## Invocation and binary detection
|
||||
|
||||
- Unlike a single-vendor CLI, ACP is a protocol — the agent binary + ACP-mode
|
||||
flag are user-configured:
|
||||
- `acpBinaryPath` — e.g. `gemini`, `npx`, or an absolute path.
|
||||
- `acpArgs` — the flag(s) that put the agent in ACP/stdio mode, e.g. `["--acp"]`.
|
||||
- The subprocess environment is built from the `acpEnvAllowList` allow-list only
|
||||
(inherited `process.env` is **not** forwarded — the agent is untrusted).
|
||||
|
||||
## Readiness = the `initialize` handshake
|
||||
|
||||
There is no `--version` probe. Readiness is the protocol handshake itself:
|
||||
|
||||
1. Spawn the agent subprocess.
|
||||
2. Send `initialize { protocolVersion: 1, clientCapabilities: { fs } }` under a
|
||||
timeout (default 30s — research flagged Gemini-on-macOS OAuth and Claude-adapter
|
||||
`session/new` stalls).
|
||||
3. The agent responds with its integer `protocolVersion`, `agentCapabilities`,
|
||||
and `authMethods`.
|
||||
4. The client compares the integer protocol version; an unsupported version is a
|
||||
hard failure (do not assume the agent errors first).
|
||||
|
||||
`fs` capabilities are advertised **only** when `acpFsRead`/`acpFsWrite` are
|
||||
enabled (writes default OFF).
|
||||
|
||||
## Failure taxonomy (`probe.ts` `AcpProbeReason`)
|
||||
|
||||
| Reason | Trigger |
|
||||
| --- | --- |
|
||||
| `ok` | Handshake completed (with `authRequired: true` when `authMethods` is non-empty) |
|
||||
| `missing_binary` | Spawn `ENOENT` (binary not found, code 127) |
|
||||
| `spawn_error` | Other spawn failure |
|
||||
| `handshake_timeout` | `initialize` did not complete within the bound (code 124) |
|
||||
| `incompatible_protocol` | Agent negotiated an unsupported integer protocol version |
|
||||
| `unauthenticated` | Agent requires an auth method the client cannot satisfy |
|
||||
|
||||
## Lifecycle / teardown
|
||||
|
||||
- The engine has no `AbortSignal` in the runtime contract; teardown enters via an
|
||||
unawaited synchronous `dispose()` plus the process-registry kill. The
|
||||
**registry SIGKILL is the authoritative no-orphan / no-deadlock guarantee**; a
|
||||
best-effort `session/cancel` + pending-permission drain runs first when timing
|
||||
allows but is opportunistic.
|
||||
|
||||
## Sources
|
||||
|
||||
- https://agentclientprotocol.com (introduction, schema, transports, initialization, tool-calls)
|
||||
- `@agentclientprotocol/sdk` v0.24.0 — https://www.npmjs.com/package/@agentclientprotocol/sdk
|
||||
- Validation: the SDK example echo agent (CI) + an in-repo controllable fixture
|
||||
(`src/__tests__/fixtures/echo-agent.mjs`); Gemini CLI / Claude-adapter for manual e2e.
|
||||
Reference in New Issue
Block a user