@primusclaw/connector 0.1.3 → 0.1.5

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.
Files changed (3) hide show
  1. package/README.md +54 -17
  2. package/dist/cli.js +1344 -381
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,8 +41,12 @@ If npm answers `EACCES`, point its global prefix at a directory you own (`npm co
41
41
  ```sh
42
42
  claw-connector init # writes agents.toml and prints where: ~/.config/claw-connector/agents.toml unless XDG_CONFIG_HOME or CLAW_CONNECTOR_HOME is set
43
43
  claw-connector status # after you edit it: prints a "problem:" line if the file is wrong
44
+ claw-connector doctor # starts each agent's adapter, opens a session (no prompt) and checks the modes it offers
44
45
  ```
45
46
 
47
+ `init` runs the same check as `doctor` at the end. `doctor` says `ok` for an agent whose phone sessions will open, and otherwise a
48
+ `problem:` line with the fix, for example an agent whose sessions would be refused with `mode_unavailable`.
49
+
46
50
  By default every agent asks before it writes a file or runs a command, and your phone answers each question. To let phone sessions run
47
51
  like your terminal instead, run `claw-connector init --approval never` (or set `approval = "never"` on an agent later); see
48
52
  [Running without per-step approval](#running-without-per-step-approval).
@@ -80,6 +84,8 @@ claw-connector service status
80
84
 
81
85
  This starts the connector now and keeps it up: at login and after a reboot, and again 5 seconds after it dies for any reason, except
82
86
  one that only you can fix (the connector was revoked, or Claw refused the sign-in), which leaves it stopped until you run `login` again.
87
+ Only `claw-connector stop` (or stopping the service) stops it for good: a `kill` of the connector's process from anywhere else ends it
88
+ with exit 75, and it is started again.
83
89
  It uses `systemd --user` on Linux and launchd on macOS. On Linux, run `loginctl enable-linger $USER` once (`service install` says so
84
90
  when it is needed) so it also runs while you are logged out. In a container without systemd, `service install` starts a small
85
91
  supervisor and writes `keepalive.sh`; have the container's startup command and a 5-minute cron job run that script (it does nothing
@@ -94,7 +100,8 @@ In Clawy (or any chat client built on Claw), send `/agents`. The agents of this
94
100
  A session started there runs on this machine, inside one of your `roots`, and each permission request comes back as a card in the chat.
95
101
 
96
102
  To disconnect: `claw-connector pause` (stay offline until `resume`), `claw-connector stop`, or `claw-connector logout` (also
97
- asks the identity service to revoke the device sign-in; a saved key is deleted from this machine, not revoked at Claw).
103
+ revokes this machine's connector at Claw, so it can be sent nothing more, and asks the identity service to revoke the device
104
+ sign-in; a saved key is deleted from this machine, not revoked at Claw).
98
105
 
99
106
  ## agents.toml
100
107
 
@@ -135,6 +142,16 @@ Presets and the adapter versions they pin (override `command` and `args` to move
135
142
  | `codex` | `npx @agentclientprotocol/codex-acp@2.3.0` | `read-only` | `read-only` | `agent-full-access` |
136
143
  | `cursor` | `agent acp` (the Cursor CLI) | `ask` | `ask`, `plan` | `agent`, started as `agent --force acp` |
137
144
 
145
+ The pinned adapters (the `npx -y <package>@<version>` presets above) are installed once into the connector's state
146
+ directory (`adapters/<package>@<version>`), by `init`, by `service install` and in the background when `run` starts, and are
147
+ then started from there with the connector's own Node.js: a session does not wait for npx to look the package up in a
148
+ registry (about 70 seconds when the registry cannot be reached) or download it (Claude's adapter takes about 350 MB on
149
+ disk with its dependencies), and a repository's own `.npmrc` cannot pick the registry. The install uses `npm install` with your npm
150
+ settings (`~/.npmrc`, `npm_config_*`, an `npm_config_registry` in the agent's `env`). A session that opens while its
151
+ adapter is still being installed waits for it; if the install failed, the agent's npx command runs as before, in the
152
+ connector's state directory, and the install is tried again in the background ten minutes later. An agent with its own
153
+ `command` or `args` is started exactly as written.
154
+
138
155
  `claude-attach` does not start new conversations: it takes over Claude Code conversations that already exist on this
139
156
  machine (see [Taking over an existing conversation](#taking-over-an-existing-conversation)).
140
157
 
@@ -164,23 +181,20 @@ unattended while Cursor keeps asking. For that agent the connector then:
164
181
  `mode_update` carry `unattended`, so a client can always show whether a session asks. `status` and the line `run` prints
165
182
  at start-up name the agents without per-step approval.
166
183
 
167
- **Before the first phone session, check which way your Claude settings go.** When `permissions.defaultMode` is
168
- `bypassPermissions` in your user `settings.json` (`$CLAUDE_CONFIG_DIR`, else `~/.claude`) or in Claude's managed settings,
169
- every session of a `claude` agent without `approval = "never"` is closed with `mode_not_enforced` (a `claude-attach`
170
- agent accepts the warning while it takes a conversation over, so it is not affected).
171
- `claw-connector status` and the start-up line of `run` say so for each such agent:
172
-
173
- ```
174
- warning: claude: sessions will be refused (mode_not_enforced): Claude defaults to bypassPermissions here (permissions.defaultMode in /home/me/.claude/settings.json); set approval = "never" on this agent or change defaultMode
175
- ```
176
-
177
- Choose one: `approval = "never"` on that agent (knowing the risk below), or another `defaultMode` in that file. The check
178
- reads the two files from which the Claude adapter takes `bypassPermissions` (it ignores that value in a repository's
179
- `.claude/settings.json` and `.claude/settings.local.json`), and only the exact spelling counts, as for the adapter; root
180
- without `IS_SANDBOX` cannot use bypass, and `permissions.disableBypassPermissionsMode = "disable"` turns it off. It applies
181
- to every agent that runs `claude-agent-acp` except `claude-attach`. Codex and Cursor have no equivalent: their own
184
+ **Your own Claude settings may default to `bypassPermissions`** (`permissions.defaultMode` in your user `settings.json`,
185
+ `$CLAUDE_CONFIG_DIR` or `~/.claude`, or in Claude's managed settings). For a `claude` agent that asks (no
186
+ `approval = "never"`), the connector tells the adapter to leave that mode out (`allowDangerouslySkipPermissions: false`),
187
+ so its sessions start in `default` and ask; before 0.1.5 each of them was closed with `mode_not_enforced`. An agent with
188
+ `approval = "never"` runs in `bypassPermissions` either way. A `claude-attach` agent takes over a conversation in the mode
189
+ its terminal chose and accepts the adapter's warning while it starts. Codex and Cursor have no equivalent: their own
182
190
  settings are replaced by the mode the connector sets and reads back.
183
191
 
192
+ **Root.** Claude Code offers `bypassPermissions` to root only when `IS_SANDBOX` is set. For an agent that runs
193
+ `claude-agent-acp` with `approval = "never"` (or `allow_unsafe_modes = true`), the connector sets `IS_SANDBOX=1` in that
194
+ agent's adapter environment when it runs as root, and `run` prints a `note:` line saying so; nothing else gets it. Without
195
+ that, every phone session of such an agent was refused with `mode_unavailable`. To keep it off, set `IS_SANDBOX` yourself
196
+ in the agent's `[agents.env]` (an empty value is kept as it is; `status` then warns that sessions will be refused).
197
+
184
198
  **The risk, in one sentence:** an agent without per-step approval acts on whatever it is told, including text it read in
185
199
  a file or a web page, with everything your account can do inside its roots (and `--force` or full access reach outside the
186
200
  sandbox the adapter would otherwise keep), and nobody is asked first.
@@ -257,6 +271,17 @@ reference, title, directory, last activity, and whether anything holds it open),
257
271
  chat client can offer a choice; `session.new` then names the chosen one (`resume_ref`). Claw and the chat client know no
258
272
  product: the agent's `kind` is the label `attach`.
259
273
 
274
+ **You do not have to add this agent.** Every agent made from the `claude` preset brings one with the same roots, adapter,
275
+ approval and environment, named `<id>-sessions`, so the conversations already on the machine show up on the phone by
276
+ themselves. `existing_sessions = false` on the `claude` agent turns that off; an explicit `claude-attach` agent reading the same
277
+ Claude config directory replaces it.
278
+
279
+ Each entry also says, for a conversation a terminal holds open, what Claude Code says that terminal is doing (`activity`:
280
+ `working`, `waiting` for the person at it, or `idle`; with `waiting`, `waiting_for` in its words, such as "input needed"). The
281
+ connector looks at Claude Code's session registry and projects directory every 10 seconds (file names and times only; nothing
282
+ is started) and reports a change at once instead of at the next heartbeat, so a conversation a terminal has just opened, or one
283
+ that starts waiting, reaches the phone within seconds.
284
+
260
285
  ```toml
261
286
  [[agents]]
262
287
  id = "claude-attach"
@@ -318,6 +343,18 @@ A transcript written within the last 10 seconds is refused too (a terminal that
318
343
  `session_live`, `recently_written` and `twin_check_failed`; the agent that this connector itself started for the conversation
319
344
  is not mistaken for a twin.
320
345
 
346
+ A conversation that a terminal has open when the phone asks for it is not refused but watched, read-only. Nothing is
347
+ started: the connector reads the transcript the terminal writes, from its end (opened read-only; nothing is ever written to it),
348
+ and sends each new line as the update an adapter would have sent (the user's words, the agent's words, the steps it starts
349
+ and how they end; thinking and sub-agents are left out), scrubbed for credentials like every event and marked `read_only`.
350
+ The last twenty updates already there are sent first, marked `replay`. `session_started` says `read_only: true` and
351
+ `read_only_reason: "session_live"`. A prompt, a mode change or a decision sent to it is refused with
352
+ `read_only_live_session` and reaches nothing that could write to the transcript; the server refuses them too
353
+ (`session_read_only`). The heartbeat still reports the conversation as `live`, and an attach agent's capabilities say `watch_live: true`, so a
354
+ client offers the watch only where the connector can do it. When the terminal no longer has it open the
355
+ watch ends (`session_closed`, reason `terminal_closed`), and taking it over is then a new session, through every check
356
+ above. A watched session stays read-only across a restart of the connector.
357
+
321
358
  The ask mode still applies: a conversation keeps the mode it was left in, often one that never asks (`bypassPermissions`),
322
359
  and the adapter says so while it sets the session up. That warning describes the mode that is about to be replaced, so it is
323
360
  set aside until the ask mode (`default`) is locked and read back from the adapter; a warning that comes after that, or a mode
@@ -336,7 +373,7 @@ session stops the agent process; it never deletes the conversation.
336
373
  | `status [--json]` | Running or not, paused, signed in, agents, adapter processes, the last disconnect and its reason (`last down:`), a `problem:` line when a new sign-in is needed, and a `warning:` line for each agent whose sessions will be refused because Claude's own settings default to `bypassPermissions` (see [Running without per-step approval](#running-without-per-step-approval)). |
337
374
  | `pause` / `resume` | Stop every agent within a second and stay offline, or undo that. |
338
375
  | `stop` | Stop the running connector and every agent it started. |
339
- | `logout` | Stop, ask the identity service to revoke the sign-in, delete it from this machine. The stored connector id stays, so the next sign-in reuses the same connector. |
376
+ | `logout` | Stop, revoke this machine's connector at Claw (with a key, `DELETE /v1/remote-agents/connectors/:cid`; with a device sign-in, the connector-side `POST .../connectors/:cid/revoke`), ask the identity service to revoke the sign-in, and delete it from this machine. The next sign-in registers a new connector. When Claw cannot be reached or refuses (a Claw from before the connector-side route refuses a device sign-in), the sign-in is still deleted, but `logout` says the connector was not revoked, prints the `curl` that revokes it with a Claw API key of yours, keeps its id (so a later sign-in reuses it), and exits 1. |
340
377
 
341
378
  **Kill switch.** Every adapter is started in its own process group and recorded (pid and start time) in
342
379
  `children.json`. `stop`, `pause`, a revocation and Ctrl-C signal exactly those groups: a process that is not recorded, or