@hydra-acp/cli 0.1.33 → 0.1.34
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/README.md +15 -18
- package/dist/cli.js +2863 -2193
- package/dist/index.d.ts +44 -116
- package/dist/index.js +160 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
## What it is
|
|
29
29
|
|
|
30
|
-
`hydra-acp` is a daemon + CLI shim that implements
|
|
30
|
+
`hydra-acp` is a daemon + CLI shim that implements two open ACP RFDs as a single coherent surface, on top of the standard ACP protocol (including `session/list` for session discovery), plus the official ACP Registry as its agent-distribution mechanism.
|
|
31
31
|
|
|
32
32
|
### The standards it stitches together
|
|
33
33
|
|
|
34
|
-
ACP itself is the [Agent Client Protocol](https://agentclientprotocol.com/) — a JSON-RPC 2.0 protocol between editors (clients) and AI coding agents. Today the protocol is canonically a 1:1 stdio relationship: one editor spawns one agent and owns its stdin/stdout.
|
|
34
|
+
ACP itself is the [Agent Client Protocol](https://agentclientprotocol.com/) — a JSON-RPC 2.0 protocol between editors (clients) and AI coding agents. Today the protocol is canonically a 1:1 stdio relationship: one editor spawns one agent and owns its stdin/stdout. Two RFDs in the [`agentclientprotocol/agent-client-protocol`](https://github.com/agentclientprotocol/agent-client-protocol) repo extend that model. `hydra-acp` is one daemon that implements both together so they can be used as a coherent system rather than two independent extensions.
|
|
35
35
|
|
|
36
36
|
#### 1. Multi-Client Session Attach — [RFD #533](https://github.com/agentclientprotocol/agent-client-protocol/pull/533)
|
|
37
37
|
|
|
@@ -42,17 +42,15 @@ Adds two new methods that turn ACP from 1:1 into 1:N:
|
|
|
42
42
|
|
|
43
43
|
Every event the agent emits is broadcast to every attached client; clients self-filter what they act on. Permission requests broadcast the same way: the first response wins, and the rest receive a `session/update` notification with `sessionUpdate: "permission_resolved"`. Capability is advertised in `initialize` under `agentCapabilities.sessionCapabilities.attach`.
|
|
44
44
|
|
|
45
|
-
#### 2.
|
|
45
|
+
#### 2. Streamable HTTP & WebSocket Transport — [RFD: streamable-http-websocket-transport](https://agentclientprotocol.com/rfds/streamable-http-websocket-transport) (WebSocket profile only)
|
|
46
46
|
|
|
47
|
-
Defines the
|
|
47
|
+
Defines the network transport that lets ACP run between processes that aren't parent and child. The RFD specifies two profiles on one `/acp` endpoint: a Streamable HTTP profile (POST/GET-SSE/DELETE with `Acp-Connection-Id` and `Acp-Session-Id` headers, HTTP/2 required) and a WebSocket profile (GET with `Upgrade: websocket`). The RFD explicitly permits servers to support **only** the WebSocket profile, and that's the route `hydra-acp` takes — the Streamable HTTP half isn't implemented. The RFD itself is still Draft as of April 2026, with the routing model rewritten twice in the six weeks before this writing, so deferring HTTP-transport work until the spec stabilizes is deliberate.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
On the WebSocket side, `hydra-acp` exposes its WSS endpoint at `/acp`: a client sends `GET /acp` with `Upgrade: websocket`, receives a `101 Switching Protocols` response, and the connection becomes a bidirectional stream of JSON-RPC text frames (binary frames are ignored). The server negotiates the `acp.v1` subprotocol via the standard `Sec-WebSocket-Protocol` mechanism (echoed back in the 101 when advertised; absent otherwise). Authentication is layered on top — HTTP headers, query parameters, or WebSocket subprotocols — and is treated as orthogonal by the spec. `hydra-acp` authenticates via a bearer token carried in a `hydra-acp-token.<token>` subprotocol entry or a `?token=<token>` query parameter.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
### Standard ACP it relies on
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Defines the network transport that lets ACP run between processes that aren't parent and child. The relevant half for `hydra-acp` is the WebSocket binding: a client sends `GET /acp` with `Upgrade: websocket`, receives a `101 Switching Protocols` response, and the connection becomes a bidirectional stream of JSON-RPC text frames (binary frames are ignored). Authentication is layered on top — HTTP headers, query parameters, or WebSocket subprotocols — and is treated as orthogonal by the spec. `hydra-acp` exposes its WSS endpoint at `/acp` and authenticates via a bearer token carried in a WebSocket subprotocol or a query parameter.
|
|
53
|
+
Beyond the bedrock of `initialize` / `session/new` / `session/prompt`, the daemon implements **`session/list`** ([Protocol: Session List](https://agentclientprotocol.com/protocol/session-list), stabilized 2026-03-09) so any compliant client can enumerate sessions known to the daemon and attach to one — `{ sessionId, cwd, title?, updatedAt?, _meta? }` per entry, with `cwd` filtering and `cursor`-based pagination. Hydra-specific fields ride under `_meta["hydra-acp"]` per the [Extensibility](https://agentclientprotocol.com/protocol/extensibility) convention.
|
|
56
54
|
|
|
57
55
|
### The registry it depends on
|
|
58
56
|
|
|
@@ -83,10 +81,10 @@ Agents are sourced from the [ACP Registry](https://github.com/agentclientprotoco
|
|
|
83
81
|
|
|
84
82
|
1. **Editor spawns `hydra-acp`** as it would any ACP agent. The shim looks like a normal stdio agent.
|
|
85
83
|
2. **Shim opens a WSS connection** to the daemon at `/acp`, authenticating via the bearer token.
|
|
86
|
-
3. **`session/new` from the editor** → daemon resolves the requested agent against the cached ACP Registry, downloads it on first use under `~/.hydra-acp/agents/`, spawns it as a child process, and creates an ACP session inside it
|
|
84
|
+
3. **`session/new` from the editor** → daemon resolves the requested agent against the cached ACP Registry, downloads it on first use under `~/.hydra-acp/agents/`, spawns it as a child process, and creates an ACP session inside it.
|
|
87
85
|
4. **`session/attach` from a second client** → daemon adds the new client to the session's broadcast list and replays history per `historyPolicy` (per RFD #533).
|
|
88
86
|
5. **Notifications** fan out to every attached client. **Prompts** are serialized through the daemon's per-session queue. **Permission requests** broadcast to every attached client; first response wins and the rest receive a `session/update` with `sessionUpdate: "permission_resolved"` carrying the resolving client's outcome.
|
|
89
|
-
6. **`session/list`** returns the daemon's
|
|
87
|
+
6. **`session/list`** returns the daemon's sessions (live and cold), filterable by `cwd`.
|
|
90
88
|
7. **`session/detach`** lets a client leave voluntarily; the session continues until the last client detaches (per RFD #533).
|
|
91
89
|
|
|
92
90
|
### Why a shim?
|
|
@@ -99,7 +97,7 @@ Clients that adopt the streamable-http-websocket-transport RFD natively can conn
|
|
|
99
97
|
|
|
100
98
|
The shim and daemon together implement a "resume hint" pattern that lets editor sessions survive a daemon restart without the editor noticing:
|
|
101
99
|
|
|
102
|
-
1. **The daemon's `session/new` and `session/attach` responses include a `_meta` block**, with hydra-specific data namespaced under `_meta["hydra-acp"]` (per the [
|
|
100
|
+
1. **The daemon's `session/new` and `session/attach` responses include a `_meta` block**, with hydra-specific data namespaced under `_meta["hydra-acp"]` (per the ACP [Extensibility](https://agentclientprotocol.com/protocol/extensibility) convention). The underlying agent's own `_meta` keys, if any, are passed through unchanged alongside `hydra-acp`.
|
|
103
101
|
2. **The shim caches that namespaced data in a `SessionTracker`** as messages flow through, keyed by the hydra sessionId the editor knows.
|
|
104
102
|
3. **The shim's WS connection is wrapped in a `ResilientWsStream`** that reconnects with exponential backoff (200ms → 5s, capped, max 60 attempts) and buffers outbound messages from the editor while disconnected.
|
|
105
103
|
4. **After each successful reconnect, the shim replays a `session/attach`** for every cached session, including the resume hints under `_meta["hydra-acp"].resume`.
|
|
@@ -504,7 +502,7 @@ Logs are also fanned out to stderr while the daemon is running. To follow live:
|
|
|
504
502
|
|
|
505
503
|
## Wire protocol
|
|
506
504
|
|
|
507
|
-
The daemon's WSS endpoint follows the [Streamable HTTP & WebSocket Transport RFD](https://agentclientprotocol.com/rfds/streamable-http-websocket-transport):
|
|
505
|
+
The daemon's WSS endpoint follows the WebSocket profile of the [Streamable HTTP & WebSocket Transport RFD](https://agentclientprotocol.com/rfds/streamable-http-websocket-transport) (the Streamable HTTP profile isn't implemented — see the transport section above):
|
|
508
506
|
|
|
509
507
|
```
|
|
510
508
|
GET /acp HTTP/1.1
|
|
@@ -513,9 +511,9 @@ Upgrade: websocket
|
|
|
513
511
|
Sec-WebSocket-Protocol: acp.v1, hydra-acp-token.<token>
|
|
514
512
|
```
|
|
515
513
|
|
|
516
|
-
Frames are JSON-RPC 2.0 text frames; binary frames are ignored.
|
|
514
|
+
The server selects `acp.v1` and echoes it back in `Sec-WebSocket-Protocol` on the 101 response; the `hydra-acp-token.<token>` entry is consumed as auth and never echoed. Frames are JSON-RPC 2.0 text frames; binary frames are ignored.
|
|
517
515
|
|
|
518
|
-
The first JSON-RPC message a client sends is `initialize` (per ACP)
|
|
516
|
+
The first JSON-RPC message a client sends is `initialize` (per ACP).
|
|
519
517
|
|
|
520
518
|
### Methods implemented
|
|
521
519
|
|
|
@@ -525,13 +523,12 @@ Standard ACP:
|
|
|
525
523
|
- `session/new` — create a new session, spawning the requested agent
|
|
526
524
|
- `session/prompt`
|
|
527
525
|
- `session/cancel`
|
|
526
|
+
- `session/list { cwd?, cursor? }` — enumerate sessions known to the daemon
|
|
528
527
|
|
|
529
528
|
RFD additions:
|
|
530
529
|
|
|
531
530
|
- `session/attach { sessionId, historyPolicy: "full"|"pending_only"|"none" }` — RFD #533
|
|
532
531
|
- `session/detach { sessionId }` — RFD #533
|
|
533
|
-
- `session/list { cwd?, cursor?, limit? }` — RFD: session-list
|
|
534
|
-
- `proxy/initialize` — RFD: proxy-chains
|
|
535
532
|
|
|
536
533
|
Capabilities advertised in the `initialize` response:
|
|
537
534
|
|
|
@@ -550,7 +547,7 @@ Capabilities advertised in the `initialize` response:
|
|
|
550
547
|
"loadSession": false,
|
|
551
548
|
"sessionCapabilities": {
|
|
552
549
|
"attach": {},
|
|
553
|
-
"list":
|
|
550
|
+
"list": {}
|
|
554
551
|
}
|
|
555
552
|
}
|
|
556
553
|
}
|