@hydra-acp/cli 0.1.50 → 0.1.52

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 CHANGED
@@ -93,62 +93,58 @@ Existing ACP clients are stdio-based: they `spawn(command)` a process and exchan
93
93
 
94
94
  Clients that adopt the streamable-http-websocket-transport RFD natively can connect to the daemon's `/acp` endpoint directly without the shim.
95
95
 
96
- ### Surviving daemon restarts (resurrection)
96
+ ### Cat mode
97
+
98
+ `hydra-acp cat` is a pipe-friendly headless verb: it feeds stdin to a fresh
99
+ session as the user prompt and streams the agent's text reply to stdout. No
100
+ TUI, no JSON-RPC for the caller, no terminal control sequences in the
101
+ output — just text in, text out, exit code 0 on a clean turn. Hydra ends up
102
+ usable as a unix filter, with the agent as the program in the middle of the
103
+ pipeline.
104
+
105
+ A few properties keep it well-behaved:
106
+
107
+ - **Sandboxed cwd by default.** Piped invocations get a fresh empty tempdir as
108
+ the agent's `cwd`, and the permission handler rejects every tool call that
109
+ isn't one of the `hydra-acp-stdin` MCP tools (head / tail / grep / read on
110
+ the piped bytes). The agent has nothing to look at except the data you
111
+ piped in. Override with `--cwd <path>` when you want it poking at the
112
+ project (e.g. "find docs in the codebase that mention this error").
113
+ - **Smart about size.** Small inputs are inlined into the prompt. Large inputs
114
+ (default >1 MiB) get the daemon's in-memory `hydra-acp-stdin` MCP server:
115
+ bytes flow into a ring buffer and the agent pulls them on demand via
116
+ `head`, `tail`, `grep`, `read`, and `info`. A multi-gigabyte log isn't a
117
+ context-window problem; it's a fixed-size buffer the agent samples.
118
+ - **`--follow` for live streams.** Pipe `tail -f` into `--follow` and each quiet
119
+ burst on stdin is sent as a new turn. The standing prompt (`-p`) is sent
120
+ only on the first turn; later turns carry just the new bytes.
121
+ - **`--detach` to share the session.** By default the session lives as long as
122
+ the cat process; on stdin EOF it dies. With `--detach` it stays in the
123
+ daemon, `hydra-acp session` lists it, and the slack / browser / notifier
124
+ extensions can ride on it. Useful for kicking off a long-running watch
125
+ from a shell script and following it on your phone.
126
+
127
+ A few examples:
97
128
 
98
- The shim and daemon together implement a "resume hint" pattern that lets editor sessions survive a daemon restart without the editor noticing:
99
-
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`.
101
- 2. **The shim caches that namespaced data in a `SessionTracker`** as messages flow through, keyed by the hydra sessionId the editor knows.
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.
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`.
104
- 5. **If the daemon already knows the session** (e.g., the daemon never died, just a network blip), it ignores the resume hint and does a normal attach.
105
- 6. **If the daemon doesn't know the session**, it resurrects: spawns a fresh agent of `agentId` in `cwd`, runs `initialize`, calls ACP `session/load { sessionId: upstreamSessionId }` against the agent, and registers a new hydra `Session` *with the same hydra sessionId the shim claimed*. The editor sees nothing.
106
-
107
- The resurrection is serialized per hydra sessionId, so two shims racing to reattach to the same session don't both spawn fresh agents.
108
-
109
- **What this requires:** the underlying agent must support `loadSession` and persist its own session state to disk between processes (e.g., claude-code-acp does, in `~/.claude/sessions/`). For agents that don't support load, resurrection fails on the daemon side and the shim surfaces an error to the editor.
110
-
111
- **What gets lost across restart:** the daemon's in-memory streaming history and in-flight tool calls. The agent's persisted state — past completed turns, conversation context — is recovered via `session/load`. The agent will need to re-issue any tool call that was mid-stream when the daemon died.
112
-
113
- **In-flight permission prompts:** the shim tracks open `session/request_permission` requests it has forwarded to the editor. On any reconnect (which always implies the previous daemon-side promise is gone), the shim emits a `session/update` notification with `sessionUpdate: "permission_resolved"` toward the editor for each pending request, carrying the original `toolCallId` plus `outcome: { kind: "cancelled", reason: "daemon-disconnected" }` and `resolvedBy: { clientId: "hydra-acp" }`. Editors that handle `permission_resolved` per [RFD #533](https://github.com/agentclientprotocol/agent-client-protocol/pull/533) will dismiss their in-flight permission UI. Any response the editor still sends afterward is silently dropped by the new daemon (unknown request id).
129
+ ```sh
130
+ # One-shot question, no stdin.
131
+ hydra-acp -p "tools to convert a HEIC photo to JPEG on linux?"
114
132
 
115
- ### Wire shape of `_meta`
133
+ # Analyze a big log without copy-pasting it into a chat window.
134
+ journalctl -u nginx --since "1 hour ago" | hydra-acp cat -p "anything alarming?"
116
135
 
117
- A hydra `session/new` response looks like:
136
+ # Treat hydra as the filter in a unix pipeline — output is plain text,
137
+ # so tee / grep / jq downstream just work.
138
+ git log --since="last monday" --pretty=full | hydra-acp cat -p "draft release notes, one bullet per user-visible change, grouped by version" | tee RELEASE_NOTES.md
118
139
 
119
- ```json
120
- {
121
- "sessionId": "hydra_session_abc123",
122
- "_meta": {
123
- "agent-vendor": { "sequence": 7 },
124
- "hydra-acp": {
125
- "upstreamSessionId": "u_xyz",
126
- "agentId": "claude-code",
127
- "cwd": "/path/to/project"
128
- }
129
- }
130
- }
140
+ # Watch a live log and only speak up when something's wrong. --detach
141
+ # keeps the session in the daemon, so you can follow it on your phone
142
+ # via the slack extension after closing the shell.
143
+ tail -F /var/log/app.log | hydra-acp cat --follow --detach -p "if a line looks like an error or stack trace, summarize it. otherwise stay silent."
131
144
  ```
132
145
 
133
- The `agent-vendor` key (illustrative) is whatever the underlying agent put in *its* `_meta` block hydra forwards that through unchanged. Only the `hydra-acp` namespace is hydra's. The same shape applies to `session/attach` responses.
134
-
135
- For resurrection, the shim sends `session/attach` with a resume hint nested in the same namespace:
136
-
137
- ```json
138
- {
139
- "sessionId": "hydra_session_abc123",
140
- "historyPolicy": "pending_only",
141
- "_meta": {
142
- "hydra-acp": {
143
- "resume": {
144
- "upstreamSessionId": "u_xyz",
145
- "agentId": "claude-code",
146
- "cwd": "/path/to/project"
147
- }
148
- }
149
- }
150
- }
151
- ```
146
+ Sessions created by `cat` are normal hydra sessions, so `hydra-acp session`,
147
+ `session export`, `/hydra title`, and the rest of the surface all work on them.
152
148
 
153
149
  ## Install
154
150