@hydra-acp/cli 0.1.22 → 0.1.24
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 +49 -47
- package/dist/cli.js +2622 -433
- package/dist/index.d.ts +171 -26
- package/dist/index.js +1605 -206
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -185,7 +185,7 @@ hydra-acp # bare invocation in a TTY launches
|
|
|
185
185
|
hydra-acp tui # explicit form
|
|
186
186
|
|
|
187
187
|
# 5. List live sessions.
|
|
188
|
-
hydra-acp
|
|
188
|
+
hydra-acp session
|
|
189
189
|
|
|
190
190
|
# 6. Attach a second client to an existing session.
|
|
191
191
|
# Bare invocation auto-detects: TUI in a terminal, ACP shim when piped.
|
|
@@ -203,29 +203,29 @@ hydra-acp launch <agent> # launcher mode: shim that forces th
|
|
|
203
203
|
hydra-acp --session-id <id> # attach to existing session
|
|
204
204
|
# (TUI in a TTY, shim otherwise)
|
|
205
205
|
|
|
206
|
-
hydra-acp init # generate
|
|
206
|
+
hydra-acp init # generate the service token
|
|
207
207
|
hydra-acp daemon start [--foreground] # detached by default; --foreground to attach
|
|
208
208
|
hydra-acp daemon stop
|
|
209
209
|
hydra-acp daemon status
|
|
210
210
|
|
|
211
|
-
hydra-acp
|
|
212
|
-
hydra-acp
|
|
213
|
-
hydra-acp
|
|
214
|
-
hydra-acp
|
|
211
|
+
hydra-acp session # list sessions
|
|
212
|
+
hydra-acp session kill <id> # close a live session (keeps the on-disk record so it can be resurrected)
|
|
213
|
+
hydra-acp session remove <id> # remove a session entirely (live or cold)
|
|
214
|
+
hydra-acp session export <id> [--out <file>|.]
|
|
215
215
|
# write a session bundle (meta + history) to <file>,
|
|
216
216
|
# to a default-named file when --out=., or to stdout
|
|
217
|
-
hydra-acp
|
|
217
|
+
hydra-acp session import <file>|- [--replace]
|
|
218
218
|
# import a bundle from <file> or stdin (-);
|
|
219
219
|
# --replace overwrites an existing lineage match
|
|
220
220
|
|
|
221
|
-
hydra-acp
|
|
222
|
-
hydra-acp
|
|
223
|
-
hydra-acp
|
|
224
|
-
hydra-acp
|
|
225
|
-
hydra-acp
|
|
221
|
+
hydra-acp extension # list configured extensions and live state
|
|
222
|
+
hydra-acp extension add <name> # add to config (--command, --args, --env, --disabled)
|
|
223
|
+
hydra-acp extension remove <name> # remove from config
|
|
224
|
+
hydra-acp extension start|stop|restart <n> # lifecycle on a running extension
|
|
225
|
+
hydra-acp extension logs <name> [-f] [-n] # tail (default 50) or follow an extension's log
|
|
226
226
|
|
|
227
|
-
hydra-acp
|
|
228
|
-
hydra-acp
|
|
227
|
+
hydra-acp agent # list agents in the registry
|
|
228
|
+
hydra-acp agent install <id> # pre-install an agent (else lazy on first use)
|
|
229
229
|
|
|
230
230
|
hydra-acp config # print resolved config path/values
|
|
231
231
|
```
|
|
@@ -241,15 +241,15 @@ A bare invocation (`hydra-acp` with no subcommand) auto-dispatches based on whet
|
|
|
241
241
|
hydra-acp launch claude-code
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
-
When the editor sends `session/new`, the shim rewrites the params to `{ ..., agentId: "claude-code" }` before forwarding to the daemon. The daemon resolves `claude-code` against the cached ACP Registry, downloads/installs the agent on first use under `~/.hydra-acp/agents/`, and spawns the subprocess. The editor sees a normal ACP agent. From then on, `hydra-acp
|
|
244
|
+
When the editor sends `session/new`, the shim rewrites the params to `{ ..., agentId: "claude-code" }` before forwarding to the daemon. The daemon resolves `claude-code` against the cached ACP Registry, downloads/installs the agent on first use under `~/.hydra-acp/agents/`, and spawns the subprocess. The editor sees a normal ACP agent. From then on, `hydra-acp session` lists the live session and any other client can `session/attach` to it.
|
|
245
245
|
|
|
246
|
-
`<agent>` is the registry ID — e.g. `claude-code`, `gemini-cli`, `codex`. Run `hydra-acp
|
|
246
|
+
`<agent>` is the registry ID — e.g. `claude-code`, `gemini-cli`, `codex`. Run `hydra-acp agent` to browse what's available, or fetch the registry CDN URL directly.
|
|
247
247
|
|
|
248
248
|
If both `launch <agent>` and `--session-id` are given, `--session-id` wins (attach mode); the agent is ignored because the agent process is already running.
|
|
249
249
|
|
|
250
250
|
### Naming sessions from the editor
|
|
251
251
|
|
|
252
|
-
Pass `--name <label>` or set `HYDRA_ACP_NAME` and the first `session/new` from that shim is labeled accordingly. The label flows through `_meta["hydra-acp"].name` on the wire, lands in `Session.title`, and shows up in `session/list` and `hydra-acp
|
|
252
|
+
Pass `--name <label>` or set `HYDRA_ACP_NAME` and the first `session/new` from that shim is labeled accordingly. The label flows through `_meta["hydra-acp"].name` on the wire, lands in `Session.title`, and shows up in `session/list` and `hydra-acp session`. Subsequent `session/new` calls from the same shim are not labeled — first one wins. The label survives daemon restart (it's carried in the resume hints).
|
|
253
253
|
|
|
254
254
|
```text
|
|
255
255
|
HYDRA_ACP_NAME="$BUFFER_NAME" hydra-acp launch claude-acp
|
|
@@ -267,19 +267,19 @@ Slash commands of the form `/hydra <verb> [args]` are intercepted by hydra befor
|
|
|
267
267
|
|---|---|
|
|
268
268
|
| `/hydra title` | Asks the agent for a one-line summary, applies it as the new title via `session_info_update`. The sub-prompt and reply are suppressed from clients. |
|
|
269
269
|
| `/hydra title <text>` | Sets the title to `<text>` directly. No agent call. |
|
|
270
|
-
| `/hydra agent <agent>` | Swaps the agent process backing this session. Spawns the new agent (must be in the registry — see `hydra-acp
|
|
270
|
+
| `/hydra agent <agent>` | Swaps the agent process backing this session. Spawns the new agent (must be in the registry — see `hydra-acp agent list`), kills the old one, and feeds the conversation transcript so far back in as the first prompt to the new agent. `session_info_update` carries the new `agentId`; a synthetic `agent_message_chunk` banner marks the switch in the transcript. The on-disk session record is updated so resurrection brings the session back on the new agent. |
|
|
271
271
|
|
|
272
272
|
These work from anywhere a session prompt can be typed — the TUI's input box, agent-shell, the slack thread composer, the browser chat composer. Hydra detects them server-side; clients send them as ordinary `session/prompt` requests.
|
|
273
273
|
|
|
274
274
|
### Exporting and importing sessions
|
|
275
275
|
|
|
276
|
-
`hydra-acp
|
|
276
|
+
`hydra-acp session export` writes a session to a `*.hydra` JSON bundle (meta + history + optional prompt history). `hydra-acp session import` brings it back into the local daemon as a new cold session. Use this to archive a session before clearing it, share one with a teammate, restore from backup, or move work between machines without running both daemons live.
|
|
277
277
|
|
|
278
278
|
```text
|
|
279
|
-
hydra-acp
|
|
280
|
-
hydra-acp
|
|
281
|
-
hydra-acp
|
|
282
|
-
hydra-acp
|
|
279
|
+
hydra-acp session export hydra_session_abc --out backup.hydra
|
|
280
|
+
hydra-acp session import backup.hydra # → new local id
|
|
281
|
+
hydra-acp session import backup.hydra # error: already imported
|
|
282
|
+
hydra-acp session import backup.hydra --replace # overwrites in place
|
|
283
283
|
```
|
|
284
284
|
|
|
285
285
|
Each session carries a stable **`lineageId`** that survives every export/import hop, so the same bundle imported twice is detected as a duplicate — the second import errors with the existing local id. `--replace` overrides that and overwrites the existing local copy, killing any live session first and preserving the local `sessionId` so bookmarks (Slack threads, editor session links) keep resolving.
|
|
@@ -331,8 +331,7 @@ When you ask hydra to spawn an agent (via `launch <agent>`, `--agent`, or `HYDRA
|
|
|
331
331
|
{
|
|
332
332
|
"daemon": {
|
|
333
333
|
"host": "127.0.0.1",
|
|
334
|
-
"port":
|
|
335
|
-
"authToken": "hydra_token_<random>",
|
|
334
|
+
"port": 55514,
|
|
336
335
|
"logLevel": "info"
|
|
337
336
|
},
|
|
338
337
|
"registry": {
|
|
@@ -343,9 +342,11 @@ When you ask hydra to spawn an agent (via `launch <agent>`, `--agent`, or `HYDRA
|
|
|
343
342
|
}
|
|
344
343
|
```
|
|
345
344
|
|
|
345
|
+
The service token lives in its own file (`~/.hydra-acp/auth-token`, mode 0600) and is never written to `config.json` — so the config file stays safe to version-control.
|
|
346
|
+
|
|
346
347
|
`daemon.sessionIdleTimeoutSeconds` (default 3600 — one hour) controls how long a session with no recorded agent or user activity stays alive before the daemon closes it. Snapshot-shaped state pings (model/mode/title/commands) and bare attach/detach don't count as activity — only recordable broadcasts (prompts, agent chunks, tool calls, permission prompts) do, so persistent observer clients like the slack/notifier/approver/browser extensions can't pin a quiet session open. In-flight turns and unresolved permission requests defer the close until they settle. The disk record stays so the session can be resurrected later via `session/load`, at which point extensions re-attach automatically through their poll loops. Set to `0` to disable.
|
|
347
348
|
|
|
348
|
-
`daemon.sessionRecentMinutes` (default 30) controls how far back `hydra-acp
|
|
349
|
+
`daemon.sessionRecentMinutes` (default 30) controls how far back `hydra-acp session` (and the `/v1/sessions` REST endpoint without `?all=true`) looks for cold (disk-only) sessions. Set to `0` to never list cold sessions.
|
|
349
350
|
|
|
350
351
|
`tui.mouse` (default `true`) controls whether the TUI captures mouse events. With capture on, the scroll wheel drives scrollback but selecting text requires `shift+drag` to bypass mouse reporting in your terminal. Set to `false` to disable capture — plain click-drag selects text, but wheel-driven scrollback stops working (use `PgUp` / `PgDn` instead).
|
|
351
352
|
|
|
@@ -374,11 +375,11 @@ Each extension is launched with these env vars set:
|
|
|
374
375
|
|
|
375
376
|
| Env var | Example |
|
|
376
377
|
|---|---|
|
|
377
|
-
| `HYDRA_ACP_DAEMON_URL` | `http://127.0.0.1:
|
|
378
|
+
| `HYDRA_ACP_DAEMON_URL` | `http://127.0.0.1:55514` |
|
|
378
379
|
| `HYDRA_ACP_DAEMON_HOST` | `127.0.0.1` |
|
|
379
|
-
| `HYDRA_ACP_DAEMON_PORT` | `
|
|
380
|
+
| `HYDRA_ACP_DAEMON_PORT` | `55514` |
|
|
380
381
|
| `HYDRA_ACP_TOKEN` | `hydra_token_<hex>` |
|
|
381
|
-
| `HYDRA_ACP_WS_URL` | `ws://127.0.0.1:
|
|
382
|
+
| `HYDRA_ACP_WS_URL` | `ws://127.0.0.1:55514/acp` |
|
|
382
383
|
| `HYDRA_ACP_HOME` | `~/.hydra-acp` |
|
|
383
384
|
| `HYDRA_ACP_EXTENSION_NAME` | the `name` from config |
|
|
384
385
|
|
|
@@ -387,14 +388,14 @@ Extension stdout/stderr are appended to `~/.hydra-acp/extensions/<name>.log`.
|
|
|
387
388
|
While the daemon is running you can manage extensions without bouncing it:
|
|
388
389
|
|
|
389
390
|
```text
|
|
390
|
-
hydra-acp
|
|
391
|
-
hydra-acp
|
|
392
|
-
hydra-acp
|
|
391
|
+
hydra-acp extension # table of name/status/pid/restarts/started/log
|
|
392
|
+
hydra-acp extension restart hydra-acp-slack
|
|
393
|
+
hydra-acp extension logs hydra-acp-slack --follow
|
|
393
394
|
```
|
|
394
395
|
|
|
395
396
|
`stop` suppresses the auto-restart backoff; the extension stays down until the next `start`, `restart`, or daemon bounce. `add`/`remove` are config-only — restart the daemon to apply.
|
|
396
397
|
|
|
397
|
-
**Trust model**: extensions run with the same privileges as the daemon and receive its full
|
|
398
|
+
**Trust model**: extensions run with the same privileges as the daemon and receive its full service token. Treat extensions as part of your trusted compute base — review extensions before installing and don't run untrusted code through this mechanism.
|
|
398
399
|
|
|
399
400
|
#### Optional extensions
|
|
400
401
|
|
|
@@ -404,8 +405,8 @@ Various ready-made extensions ship under the same `@hydra-acp` npm scope. All ar
|
|
|
404
405
|
|
|
405
406
|
```sh
|
|
406
407
|
npm install -g @hydra-acp/slack
|
|
407
|
-
hydra-acp
|
|
408
|
-
hydra-acp
|
|
408
|
+
hydra-acp extension add hydra-acp-slack --command hydra-acp-slack
|
|
409
|
+
hydra-acp extension start hydra-acp-slack # if the daemon is already running
|
|
409
410
|
```
|
|
410
411
|
|
|
411
412
|
You'll also need a Slack app and a config at `~/.hydra-acp-slack.conf` — see the [package's setup section](https://github.com/smagnuso/hydra-acp-slack#setup) for scopes, tokens, and authorized users.
|
|
@@ -414,8 +415,8 @@ You'll also need a Slack app and a config at `~/.hydra-acp-slack.conf` — see t
|
|
|
414
415
|
|
|
415
416
|
```sh
|
|
416
417
|
npm install -g @hydra-acp/browser
|
|
417
|
-
hydra-acp
|
|
418
|
-
hydra-acp
|
|
418
|
+
hydra-acp extension add hydra-acp-browser --command hydra-acp-browser
|
|
419
|
+
hydra-acp extension start hydra-acp-browser
|
|
419
420
|
```
|
|
420
421
|
|
|
421
422
|
The first launch generates `~/.hydra-acp-browser/authkey` and writes the open URL (with `?authkey=…`) to `~/.hydra-acp-browser/link`. Defaults to localhost-only; see the [package's HTTPS section](https://github.com/smagnuso/hydra-acp-browser#https) for binding to a LAN address with TLS.
|
|
@@ -424,23 +425,23 @@ The first launch generates `~/.hydra-acp-browser/authkey` and writes the open UR
|
|
|
424
425
|
|
|
425
426
|
```sh
|
|
426
427
|
npm install -g @hydra-acp/notifier
|
|
427
|
-
hydra-acp
|
|
428
|
-
hydra-acp
|
|
428
|
+
hydra-acp extension add hydra-acp-notifier --command hydra-acp-notifier
|
|
429
|
+
hydra-acp extension start hydra-acp-notifier
|
|
429
430
|
```
|
|
430
431
|
|
|
431
432
|
**[`@hydra-acp/approver`](https://github.com/smagnuso/hydra-acp-approver) — headless permission auto-responder.** Attaches to every live session and answers `session/request_permission` based on a JS rule at `~/.hydra-acp/approver.config.js`. When the rule returns an `optionId` it wins the race and dismisses the prompt before any human client sees it; when it abstains (returns `null`), the prompt stays open for your interactive clients. Useful for centralizing approval policy in one place so per-client approve lambdas can go away.
|
|
432
433
|
|
|
433
434
|
```sh
|
|
434
435
|
npm install -g @hydra-acp/approver
|
|
435
|
-
hydra-acp
|
|
436
|
-
hydra-acp
|
|
436
|
+
hydra-acp extension add hydra-acp-approver --command hydra-acp-approver
|
|
437
|
+
hydra-acp extension start hydra-acp-approver
|
|
437
438
|
```
|
|
438
439
|
|
|
439
440
|
Without a config file the approver abstains on everything — installing it has no behavioral effect until you write a rule.
|
|
440
441
|
|
|
441
|
-
Per-extension config (env vars, args, custom command paths) goes in the same `extensions` block in `~/.hydra-acp/config.json` — see the snippet above. `hydra-acp
|
|
442
|
+
Per-extension config (env vars, args, custom command paths) goes in the same `extensions` block in `~/.hydra-acp/config.json` — see the snippet above. `hydra-acp extension logs <name> -f` tails an extension's stdout/stderr if you need to debug.
|
|
442
443
|
|
|
443
|
-
The
|
|
444
|
+
The service token (stored at `~/.hydra-acp/auth-token`, mode 0600) is generated on `hydra-acp init` and required as `Authorization: Bearer <token>` for every REST call and as a WebSocket subprotocol or query parameter for `wss://.../acp`. The token never leaves `~/.hydra-acp/`.
|
|
444
445
|
|
|
445
446
|
For remote access (binding to a non-loopback address), enable TLS via:
|
|
446
447
|
|
|
@@ -461,7 +462,8 @@ The daemon refuses to bind to non-loopback hosts without TLS configured.
|
|
|
461
462
|
|
|
462
463
|
```
|
|
463
464
|
~/.hydra-acp/
|
|
464
|
-
├── config.json # daemon config
|
|
465
|
+
├── config.json # daemon config (safe to version-control)
|
|
466
|
+
├── auth-token # service token (mode 0600, never in config.json)
|
|
465
467
|
├── daemon.pid # PID + port lockfile (when running)
|
|
466
468
|
├── daemon.<N>.log # rotated daemon logs (10 MB or daily, whichever first)
|
|
467
469
|
├── current.log # symlink to the active daemon.<N>.log
|
|
@@ -480,7 +482,7 @@ The daemon's WSS endpoint follows the [Streamable HTTP & WebSocket Transport RFD
|
|
|
480
482
|
|
|
481
483
|
```
|
|
482
484
|
GET /acp HTTP/1.1
|
|
483
|
-
Host: localhost:
|
|
485
|
+
Host: localhost:55514
|
|
484
486
|
Upgrade: websocket
|
|
485
487
|
Sec-WebSocket-Protocol: acp.v1, hydra-acp-token.<token>
|
|
486
488
|
```
|
|
@@ -553,13 +555,13 @@ Sessions are also reachable via `session/list` over ACP itself, for clients that
|
|
|
553
555
|
|
|
554
556
|
## Security
|
|
555
557
|
|
|
556
|
-
The daemon exposes a process-management surface. Treat the
|
|
558
|
+
The daemon exposes a process-management surface. Treat the service token like an SSH key.
|
|
557
559
|
|
|
558
560
|
- **Default bind is `127.0.0.1`.** Cross-host access requires TLS + a strong token.
|
|
559
561
|
- **No anonymous access.** Every request — REST and WSS — must present the bearer token.
|
|
560
562
|
- **Token rotation:** `hydra-acp init --rotate-token` invalidates the old token; running clients are kicked.
|
|
561
563
|
- **Sandboxing is the user's responsibility.** Spawned agents inherit the daemon's filesystem and shell. Run the daemon under a restricted user or inside a container if you don't trust agents fully.
|
|
562
|
-
- **Subprocess scope:** agent processes inherit `cwd` and a sanitized environment. The daemon does not pass its
|
|
564
|
+
- **Subprocess scope:** agent processes inherit `cwd` and a sanitized environment. The daemon does not pass its service token through to spawned agents.
|
|
563
565
|
|
|
564
566
|
## Registry entry mockup
|
|
565
567
|
|