@primusclaw/connector 0.1.1 → 0.1.3

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 +71 -13
  2. package/dist/cli.js +877 -176
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -71,15 +71,22 @@ CLAW_CONNECTOR_KEY='replace-with-your-claw-api-key' claw-connector login --serve
71
71
 
72
72
  The key is stored as it is in `credentials.json` (mode 0600) and is for trying things out; the device sign-in is the normal way.
73
73
 
74
- **4. Run**
74
+ **4. Keep it running**
75
75
 
76
76
  ```sh
77
- claw-connector run
77
+ claw-connector service install
78
+ claw-connector service status
78
79
  ```
79
80
 
80
- It prints `connecting claude to https://claw.example.com/claw-api as "<machine name>"` and stays in the foreground: keep it in a
81
- terminal tab, `tmux` or `screen`. Ctrl-C stops it and every agent it started. From another terminal, `claw-connector status` shows
82
- whether it is running and signed in.
81
+ 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
+ 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.
83
+ It uses `systemd --user` on Linux and launchd on macOS. On Linux, run `loginctl enable-linger $USER` once (`service install` says so
84
+ when it is needed) so it also runs while you are logged out. In a container without systemd, `service install` starts a small
85
+ supervisor and writes `keepalive.sh`; have the container's startup command and a 5-minute cron job run that script (it does nothing
86
+ when the supervisor is up) so a restarted container comes back by itself. See [Keeping it running](#keeping-it-running).
87
+
88
+ To try it in the foreground instead, `claw-connector run` prints `connecting claude to https://claw.example.com/claw-api as
89
+ "<machine name>"` and stays up until Ctrl-C, which stops it and every agent it started.
83
90
 
84
91
  **5. See it in Clawy**
85
92
 
@@ -157,6 +164,23 @@ unattended while Cursor keeps asking. For that agent the connector then:
157
164
  `mode_update` carry `unattended`, so a client can always show whether a session asks. `status` and the line `run` prints
158
165
  at start-up name the agents without per-step approval.
159
166
 
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
182
+ settings are replaced by the mode the connector sets and reads back.
183
+
160
184
  **The risk, in one sentence:** an agent without per-step approval acts on whatever it is told, including text it read in
161
185
  a file or a web page, with everything your account can do inside its roots (and `--force` or full access reach outside the
162
186
  sandbox the adapter would otherwise keep), and nobody is asked first.
@@ -307,8 +331,9 @@ session stops the agent process; it never deletes the conversation.
307
331
  | `init [--approval ask\|never \| AGENT=ask\|never] [--no-hooks]` | Write a sample `agents.toml`; an existing file is never touched. `--approval never` turns per-step approval off (see above). Also installs the Claude Code session hooks (`--no-hooks` skips that). |
308
332
  | `hooks install\|uninstall\|status` | The `SessionStart`/`SessionEnd` hooks alone; `--config-dir DIR` names the Claude config directory (default: those of the `claude-attach` agents, else `$CLAUDE_CONFIG_DIR` or `~/.claude`). |
309
333
  | `login` | Device sign-in. `--key <api key>` (or `CLAW_CONNECTOR_KEY`) is for development only. After a revocation, run it again: it connects this machine as a new connector. |
310
- | `run` | Connect and serve. Exit code 3 means the connector was revoked. |
311
- | `status [--json]` | Running or not, paused, signed in, agents, adapter processes. |
334
+ | `run [--supervised]` | Connect and serve. Exit code 78 means starting it again will not help: the connector was revoked, Claw or the identity service refused the sign-in (at start, or for two minutes in a row while running), or there is no usable `agents.toml` or sign-in; the reason is kept in `needs-login.json`, and until `login` removes it `run` exits 78 at once without contacting Claw. `--supervised` marks a run the service started. Any other non-zero exit is worth a restart. A unit written by hand for 0.1.2 and older (`RestartPreventExitStatus=3`): replace it with `claw-connector service install`, which writes the same file. |
335
+ | `service install\|uninstall\|status [--supervisor systemd\|launchd\|script] [--env NAME ...]` | Keep `run` up (see [Keeping it running](#keeping-it-running)). `install` stops a `run` started by hand so the service takes over; `status` also lists the last five disconnects and why. |
336
+ | `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)). |
312
337
  | `pause` / `resume` | Stop every agent within a second and stay offline, or undo that. |
313
338
  | `stop` | Stop the running connector and every agent it started. |
314
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. |
@@ -325,7 +350,38 @@ the connector sees it within a heartbeat, stops every agent and exits without re
325
350
  refused). `~/.local/state/claw-connector/` (or `$XDG_STATE_HOME/claw-connector/`): `connector.json` (the connector's identity and the
326
351
  commands handled), `sessions.json`, `outbox/` (events not yet acknowledged by Claw), `audit.jsonl` (spawn, directory
327
352
  decisions, every command received, every permission request and answer, every automatic approval, mode changes),
328
- `logs/`, `children.json`, `connector.pid`. `CLAW_CONNECTOR_HOME=/some/dir` keeps all of it under one directory.
353
+ `logs/`, `children.json`, `connector.pid`, `disconnects.jsonl`, `needs-login.json` (only after a run that needs a new sign-in), and with
354
+ the script supervisor `supervisor.pid`, `keepalive.sh` and `run.log`. `CLAW_CONNECTOR_HOME=/some/dir` keeps all of it under one directory.
355
+
356
+ ## Keeping it running
357
+
358
+ `service install` picks the supervisor (override with `--supervisor`):
359
+
360
+ - **systemd** (Linux, when systemd is the machine's init): `~/.config/systemd/user/claw-connector.service` with `Restart=on-failure`,
361
+ `RestartSec=5`, `RestartPreventExitStatus=78` and no start limit. Logs: `journalctl --user -u claw-connector`.
362
+ - **launchd** (macOS): `~/Library/LaunchAgents/com.primusclaw.connector.plist` (mode 0600) with `KeepAlive` on any unclean exit. launchd cannot
363
+ exempt one exit code, so a run it started exits 0 instead of 78.
364
+ Log: `run.log` in the state directory.
365
+ - **script** (a container without systemd; an `systemctl` that answers "Running in chroot" counts as none): `claw-connector supervise`
366
+ runs in the background and restarts the connector 5 seconds after it dies; `keepalive.sh` in the state directory starts that
367
+ supervisor unless it is alive (recorded pid and start time) or a sign-in is needed. Nothing restarts the supervisor after the container
368
+ restarts, so call `keepalive.sh` from the container's startup command and from a 5-minute cron job. Log: `run.log`.
369
+
370
+ A successful `login` starts an installed service again, so after a revocation or a refused key signing in is the whole fix.
371
+ `keepalive.sh` and the script supervisor start nothing while only a person can help (no `agents.toml`, not signed in,
372
+ `needs-login.json`); under launchd every exit 78 is turned into a clean exit, which launchd does not restart. The service
373
+ installed for a state directory is recorded in its `service.json`.
374
+
375
+ The unit carries `PATH` (so the agents are found), `CLAW_CONNECTOR_HOME`, `XDG_CONFIG_HOME`, `XDG_STATE_HOME`, `CLAUDE_CONFIG_DIR`,
376
+ `CODEX_HOME`, the CA and proxy variables and `LANG` from the shell that ran `install` (a proxy URL with a password in it only when named with `--env`, e.g. `--env HTTPS_PROXY`); `--env NAME` adds another, except a name that looks
377
+ like a credential (`KEY`, `TOKEN`, `SECRET`, `PASSWORD`, `CREDENTIAL`), which is never written into a unit. Run `install` again after
378
+ changing any of them, or after moving Node. With a service installed, `claw-connector stop` stops the connector until the next login,
379
+ boot or keep-alive check; to stay offline use `pause`, or `service uninstall`.
380
+
381
+ **Why it went down.** Every disconnect is appended to `disconnects.jsonl` in the state directory: `server_closed` (a Claw release or
382
+ restart, `superseded` by another run, `token_expired`; reconnected at once), `stream_lost` (the network, with the error), `stopped`,
383
+ `revoked`, `auth_failed`, `failed`, and `process_died` (the previous run never shut down: killed, crashed or the machine restarted;
384
+ dated by its last heartbeat). `status` shows the latest, `service status` the last five.
329
385
 
330
386
  ## Restarts and crashes
331
387
 
@@ -399,21 +455,23 @@ workflow, fails if the workflow file stops having that shape, or if its environm
399
455
 
400
456
  1. Set the new version in `package.json` and `src/version.ts` (`scripts/check-pack.mjs` fails if they disagree) and merge that to `main`.
401
457
  2. Write the release notes from the PR descriptions, not from commit subjects: every change states in its PR what a user will now observe.
402
- For the PRs that touched `connector/` since the previous release (`prev` is its tag, or for the first workflow release the commit 0.1.0 was
403
- published from):
458
+ For the PRs that touched `connector/` since the previous release (`prev` is the newest `connector-v*` tag, the previous release's;
459
+ `next` is the version merged in step 1, read from `package.json` on `main`):
404
460
  ```sh
405
- prev=connector-v0.1.0
406
461
  git fetch origin main --tags
462
+ prev=$(git tag --list 'connector-v*' --sort=-version:refname | head -n 1)
463
+ next=$(git show origin/main:connector/package.json | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).version')
464
+ [ "$prev" != "connector-v$next" ] || echo "connector-v$next is already released: step 1 is not merged yet" >&2
407
465
  for n in $(git log --first-parent --format=%s "$prev"..origin/main -- connector/ | grep -o '(#[0-9]*)$' | tr -d '(#)'); do
408
466
  gh pr view "$n" --repo AMD-AGI/PrimusClaw --json number,title,body --jq '"## #\(.number) \(.title)\n\n\(.body)\n"'
409
467
  done > notes.md
410
468
  ```
411
469
  Edit `notes.md` into the notes a user of the package wants to read.
412
470
  3. Publish the release on the merged commit (not as a pre-release):
413
- `gh release create connector-v0.1.1 --target <sha-on-main> --title "claw-connector 0.1.1" --notes-file notes.md`
471
+ `gh release create "connector-v$next" --target <sha-on-main> --title "claw-connector $next" --notes-file notes.md`
414
472
  4. The `package` job runs and writes a summary: the commit, whether the release workflow at that commit equals the one on `main`, and the
415
473
  tarball's name, sha256 and files. A reviewer opens the run, checks that the tagged commit is the reviewed one on `main` and that the
416
474
  workflow file is `main`'s (if the summary says it is different, read the diff first), and approves `publish`. The job then attests the
417
475
  tarball, attaches it to the release and publishes it.
418
- 5. Check it: `npm view @primusclaw/connector version`, and `gh attestation verify primusclaw-connector-0.1.1.tgz --repo AMD-AGI/PrimusClaw`
476
+ 5. Check it: `npm view @primusclaw/connector version`, and `gh attestation verify "primusclaw-connector-$next.tgz" --repo AMD-AGI/PrimusClaw`
419
477
  on the tarball attached to the release.