@cabane/companion 0.6.35 → 0.6.37
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 +128 -36
- package/dist/cli.js +416 -789
- package/dist/runtime.js +274 -119
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Both halves are load-bearing, for different reasons:
|
|
|
32
32
|
- **The install** puts `claude` on your PATH (`which claude` should resolve). That PATH probe is how the Companion exposes Claude Code — it needs no configuration, but without `claude` the device won't offer it.
|
|
33
33
|
- **The login** writes the credential the turn actually uses. The Companion does _not_ run your global `claude` to answer a turn — inference goes through the bundled Claude Agent SDK — but the SDK reads the credential your Claude Code login left on disk. So a machine with `claude` installed and never logged in looks fine (the Connector reads **Online**) and then fails every turn with **"Sign-in needed"**.
|
|
34
34
|
|
|
35
|
-
**Codex** — install the Codex CLI and log in (`codex login`, or set `CODEX_API_KEY` in Codex's own environment — Cabane never sees the key). Unlike Claude Code, which is auto-detected on the PATH, Codex is an explicit opt-in: a one-line `codex` block in `~/.cabane/config.json
|
|
35
|
+
**Codex** — install the Codex CLI and log in (`codex login`, or set `CODEX_API_KEY` in Codex's own environment — Cabane never sees the key). Unlike Claude Code, which is auto-detected on the PATH, Codex is an explicit opt-in: accept the offer from `cabane-companion start`, run `cabane-companion connect codex`, or add a one-line `codex` block in `~/.cabane/config.json`. → [full setup](https://app.cabane.ai/docs/reference/connectors/chatgpt)
|
|
36
36
|
|
|
37
37
|
**opencode** — install it, authenticate a provider through its own flow, and start its server (`opencode serve`); the Companion addresses it at the URL you give it. → [full setup](https://app.cabane.ai/docs/reference/connectors/opencode)
|
|
38
38
|
|
|
@@ -66,12 +66,8 @@ Open the printed URL, enter the code in **Settings → Connectors**, give the de
|
|
|
66
66
|
# Run `cabane-companion start` — it will pull the agents assigned to this device and run them.
|
|
67
67
|
|
|
68
68
|
cabane-companion start
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# → Dashboard: http://127.0.0.1:7474
|
|
72
|
-
#
|
|
73
|
-
# Listening for messages…
|
|
74
|
-
# [14:32:14] 4f6a93d2 — replied (8.4s)
|
|
69
|
+
# ✓ Cabane companion is running in the background.
|
|
70
|
+
# Stop: cabane-companion stop Logs: ~/.cabane/companion.log
|
|
75
71
|
```
|
|
76
72
|
|
|
77
73
|
A headless machine needs no browser of its own: run `cabane-companion pair` on it, then open **Settings → Connectors** in any browser you're signed in to and enter the short code it printed. The device token is delivered straight to the waiting CLI over the pairing channel — nothing is ever copied or pasted.
|
|
@@ -80,38 +76,134 @@ A freshly paired device runs nothing yet — it has no agents. In **Workspace se
|
|
|
80
76
|
|
|
81
77
|
## Commands
|
|
82
78
|
|
|
83
|
-
| Command
|
|
84
|
-
|
|
|
85
|
-
| `pair [--server <url>]`
|
|
86
|
-
| `start [--
|
|
87
|
-
| `
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
|
|
|
79
|
+
| Command | What it does |
|
|
80
|
+
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `pair [--server <url>]` | Pair this device using a short code confirmed in Settings → Connectors. `start` does this automatically when needed. |
|
|
82
|
+
| `start [--foreground] [--daemon]` | Pair if needed, offer detected coding harnesses, and run in the background. `--daemon` is an accepted compatibility alias for the default. `--foreground` stays attached for a terminal or external supervisor. A non-interactive `start` also stays attached. |
|
|
83
|
+
| `connect <claude-code\|codex\|opencode>` | Connect a detected coding harness now or update the running Companion over its control socket. |
|
|
84
|
+
| `stop` | Stop a foreground or detached Companion cleanly. Idempotent — "nothing running" is a success. |
|
|
85
|
+
| `status` | Print the paired device, log/transcript paths, process mode, pid and uptime, declared secret names, and local overrides. |
|
|
86
|
+
| `transcript [file] [--last] [-f]` | Show a recent full agent transcript. No args lists recent turns; `--last` renders the newest; `--follow` live-watches new turns. |
|
|
87
|
+
| `logout [-y] [--purge]` | Remove the device token and cached agent credentials. `--purge` removes the whole local config. Neither removes the device from Cabane. |
|
|
88
|
+
| `--version` / `-V` | Print the Companion version. |
|
|
92
89
|
|
|
93
90
|
Lifecycle — **register / deactivate / remove** a device, and **assign agents** to it — lives in the Cabane app (Settings → Devices, and each workspace's Agents page), not the CLI.
|
|
94
91
|
|
|
95
|
-
##
|
|
92
|
+
## Background and supervised operation
|
|
93
|
+
|
|
94
|
+
In an interactive terminal, `cabane-companion start` backgrounds itself, returns the prompt, and keeps running after the terminal closes:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
cabane-companion start
|
|
98
|
+
# ✓ Cabane companion is running in the background.
|
|
99
|
+
# Stop: cabane-companion stop Logs: ~/.cabane/companion.log
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`start --daemon` takes the same path for compatibility. This detached process does not survive logout or reboot and Cabane does not install, enable, or update a login service. Use `cabane-companion status` to check it and `cabane-companion stop` to stop it.
|
|
103
|
+
|
|
104
|
+
If you want restart or login persistence, configure your own supervisor to run `cabane-companion start --foreground`. The supervisor owns when the process starts and restarts; the Companion never writes these files for you.
|
|
105
|
+
|
|
106
|
+
### Find the executable paths
|
|
96
107
|
|
|
97
|
-
|
|
108
|
+
The examples below need absolute paths because service managers do not load your interactive shell setup:
|
|
98
109
|
|
|
99
110
|
```sh
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# → Dashboard: http://127.0.0.1:7474
|
|
103
|
-
# Logs: ~/.cabane/companion.log
|
|
104
|
-
# Status: cabane-companion status
|
|
105
|
-
# Stop: cabane-companion stop
|
|
111
|
+
command -v node
|
|
112
|
+
printf '%s\n' "$(npm root -g)/@cabane/companion/dist/cli.js"
|
|
106
113
|
```
|
|
107
114
|
|
|
108
|
-
|
|
115
|
+
Confirm both paths exist, then substitute them for `/absolute/path/to/node` and `/absolute/path/to/cli.js`. NVM and global npm paths are often versioned and can move after a Node or package upgrade. After every upgrade, run these commands again, update both paths in your supervisor config, and reload/restart it.
|
|
116
|
+
|
|
117
|
+
### macOS LaunchAgent
|
|
118
|
+
|
|
119
|
+
Save this as `~/Library/LaunchAgents/ai.cabane.companion.plist`, replacing both paths:
|
|
120
|
+
|
|
121
|
+
```xml
|
|
122
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
123
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
124
|
+
<plist version="1.0">
|
|
125
|
+
<dict>
|
|
126
|
+
<key>Label</key><string>ai.cabane.companion</string>
|
|
127
|
+
<key>ProgramArguments</key>
|
|
128
|
+
<array>
|
|
129
|
+
<string>/absolute/path/to/node</string>
|
|
130
|
+
<string>/absolute/path/to/cli.js</string>
|
|
131
|
+
<string>start</string>
|
|
132
|
+
<string>--foreground</string>
|
|
133
|
+
</array>
|
|
134
|
+
<key>RunAtLoad</key><true/>
|
|
135
|
+
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
|
|
136
|
+
<key>StandardOutPath</key><string>/tmp/cabane-companion.out.log</string>
|
|
137
|
+
<key>StandardErrorPath</key><string>/tmp/cabane-companion.err.log</string>
|
|
138
|
+
</dict>
|
|
139
|
+
</plist>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Load it with `launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.cabane.companion.plist`. Adding a login-persistent LaunchAgent is security-sensitive behavior and may be reported by macOS or endpoint-security tooling. Cabane cannot prevent or hide that report.
|
|
143
|
+
|
|
144
|
+
To update moved executable paths, unload it, edit the two paths, then load it again:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/ai.cabane.companion.plist
|
|
148
|
+
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/ai.cabane.companion.plist
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
To remove it completely:
|
|
152
|
+
|
|
153
|
+
```sh
|
|
154
|
+
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/ai.cabane.companion.plist
|
|
155
|
+
rm ~/Library/LaunchAgents/ai.cabane.companion.plist
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Linux systemd user unit
|
|
159
|
+
|
|
160
|
+
Save this as `~/.config/systemd/user/cabane-companion.service`, replacing both paths:
|
|
161
|
+
|
|
162
|
+
```ini
|
|
163
|
+
[Unit]
|
|
164
|
+
Description=Cabane Companion
|
|
165
|
+
After=network-online.target
|
|
166
|
+
|
|
167
|
+
[Service]
|
|
168
|
+
Type=simple
|
|
169
|
+
ExecStart=/absolute/path/to/node /absolute/path/to/cli.js start --foreground
|
|
170
|
+
Restart=on-failure
|
|
171
|
+
RestartSec=5
|
|
172
|
+
|
|
173
|
+
[Install]
|
|
174
|
+
WantedBy=default.target
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Load it with:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
systemctl --user daemon-reload
|
|
181
|
+
systemctl --user enable --now cabane-companion.service
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
A user service normally stops when its login session ends. If this machine must keep running it after logout, an administrator can enable lingering with `sudo loginctl enable-linger "$USER"`; that is a separate operating-system persistence decision.
|
|
185
|
+
|
|
186
|
+
After an NVM/npm upgrade, stop the unit, rediscover and replace both executable paths, then reload and restart it:
|
|
187
|
+
|
|
188
|
+
```sh
|
|
189
|
+
systemctl --user stop cabane-companion.service
|
|
190
|
+
systemctl --user daemon-reload
|
|
191
|
+
systemctl --user start cabane-companion.service
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
To remove it completely:
|
|
195
|
+
|
|
196
|
+
```sh
|
|
197
|
+
systemctl --user disable --now cabane-companion.service
|
|
198
|
+
rm ~/.config/systemd/user/cabane-companion.service
|
|
199
|
+
systemctl --user daemon-reload
|
|
200
|
+
```
|
|
109
201
|
|
|
110
|
-
|
|
202
|
+
If you enabled lingering only for this Companion, undo it separately with `sudo loginctl disable-linger "$USER"`.
|
|
111
203
|
|
|
112
|
-
|
|
204
|
+
### Other supervisors
|
|
113
205
|
|
|
114
|
-
`cabane-companion start
|
|
206
|
+
Run `cabane-companion start --foreground`. Configure the supervisor itself for restart and login/boot behavior, and use absolute executable paths when it does not load your interactive shell. Removing the supervisor configuration removes the persistence; no Cabane-managed service remains.
|
|
115
207
|
|
|
116
208
|
## Configuring an agent: what's in Cabane vs. on this machine
|
|
117
209
|
|
|
@@ -131,7 +223,7 @@ There's a deliberate split. **What the agent is** — its mode, MCP servers, mod
|
|
|
131
223
|
|
|
132
224
|
### Working directory + prepare-hook (set on this machine)
|
|
133
225
|
|
|
134
|
-
A `coding` agent needs a directory to run in — a path that only exists on your machine, so it lives in `~/.cabane/config.json`, not in Cabane. Add an `agents` map keyed by the agent's id, its `@username`, or `workspace-slug/username` (all three show up in `cabane-companion status
|
|
226
|
+
A `coding` agent needs a directory to run in — a path that only exists on your machine, so it lives in `~/.cabane/config.json`, not in Cabane. Add an `agents` map keyed by the agent's id, its `@username`, or `workspace-slug/username` (all three show up in `cabane-companion status`, copy-pasteable):
|
|
135
227
|
|
|
136
228
|
```jsonc
|
|
137
229
|
{
|
|
@@ -208,7 +300,7 @@ What "exposed" means differs per harness, because each is discoverable in a diff
|
|
|
208
300
|
|
|
209
301
|
Each harness has a full setup page in the docs — install, login, enable, verify — linked above; this section is just the shape of it and the config the Companion reads.
|
|
210
302
|
|
|
211
|
-
**You usually don't hand-edit the config.** `cabane-companion start`
|
|
303
|
+
**You usually don't hand-edit the config.** Interactive `cabane-companion start` offers each detected harness, and `cabane-companion connect codex` (or `claude-code` / `opencode`) can connect one later. Editing `~/.cabane/config.json` yourself is the fallback and what a headless device wants:
|
|
212
304
|
|
|
213
305
|
```jsonc
|
|
214
306
|
{
|
|
@@ -218,9 +310,9 @@ Each harness has a full setup page in the docs — install, login, enable, verif
|
|
|
218
310
|
}
|
|
219
311
|
```
|
|
220
312
|
|
|
221
|
-
Either block is optional and independent — set only the harnesses you have. Codex is a local CLI the bundled `@openai/codex-sdk` spawns per turn, so it takes a flag and no URL; opencode is a long-lived server addressed by URL, so run one `opencode serve` per Companion process. A hand-edit needs a restart (`cabane-companion stop && cabane-companion start`); the
|
|
313
|
+
Either block is optional and independent — set only the harnesses you have. Codex is a local CLI the bundled `@openai/codex-sdk` spawns per turn, so it takes a flag and no URL; opencode is a long-lived server addressed by URL, so run one `opencode serve` per Companion process. A hand-edit needs a restart (`cabane-companion stop && cabane-companion start`); the `connect` command updates a running Companion over its control socket.
|
|
222
314
|
|
|
223
|
-
Everything else about a Companion-run agent is the same whichever harness runs it — same assignment, same working directory, same secrets
|
|
315
|
+
Everything else about a Companion-run agent is the same whichever harness runs it — same assignment, same working directory, same secrets. A harness is a way to execute a turn, not a different way to run the Companion.
|
|
224
316
|
|
|
225
317
|
## Files on disk
|
|
226
318
|
|
|
@@ -229,14 +321,14 @@ Everything else about a Companion-run agent is the same whichever harness runs i
|
|
|
229
321
|
├── config.json # device identity: baseUrl + device token (cabdev_…) + device id/label,
|
|
230
322
|
│ # plus optional per-agent `agents` overrides (cwd / prepareHook), the
|
|
231
323
|
│ # optional harness blocks (`codex` enabled, `opencode` serverUrl), and
|
|
232
|
-
│ #
|
|
324
|
+
│ # legacy local prefs. mode 600.
|
|
233
325
|
│ # No account password, no full-account token.
|
|
234
326
|
├── credentials.json # agentId → per-agent workspace-bound token, cached on first assignment
|
|
235
327
|
│ # pull (delivered once, then never re-sent). mode 600.
|
|
236
328
|
├── secrets.json # operator-declared { NAME: "value" } store for ${PLACEHOLDER} resolution. mode 600.
|
|
237
329
|
├── cursors/<workspace_id> # last-seen SSE event id per workspace
|
|
238
330
|
├── outbox/<workspace_id>/ # durable per-agent commit queue — a reply survives a transient API outage
|
|
239
|
-
├── runtime.json # written while `start` runs:
|
|
331
|
+
├── runtime.json # written while `start` runs: control socket + pid (swept on exit)
|
|
240
332
|
├── transcripts/ # one JSONL file per dispatch — the full agent turn (see below)
|
|
241
333
|
└── companion.log # rolling JSON-lines log
|
|
242
334
|
```
|
|
@@ -245,7 +337,7 @@ No SQLite, no embedded DB. Cabane is the source of truth for which agents to run
|
|
|
245
337
|
|
|
246
338
|
## Debugging a turn: transcripts
|
|
247
339
|
|
|
248
|
-
|
|
340
|
+
Cabane shows the agent's final reply, but not _how_ it got there. When a turn misbehaves — an agent that "couldn't read the file", a tool that errored, MCP tools that didn't load, a missing secret — the full picture is on disk. Every dispatch — on whichever harness ran it — writes the complete turn stream (the system init with its tool list, every tool call **and its result**, the assistant text, the outcome) to a JSONL file under `~/.cabane/transcripts/`. On a failed turn, the Companion log also prints the exact path.
|
|
249
341
|
|
|
250
342
|
Read one back in a readable form:
|
|
251
343
|
|
|
@@ -262,4 +354,4 @@ It renders the conversation step by step — `🔧 tool(input) → ok/ERROR: res
|
|
|
262
354
|
|
|
263
355
|
## What v0 doesn't do yet
|
|
264
356
|
|
|
265
|
-
There's no OS-service install — `start
|
|
357
|
+
There's no OS-service install — an interactive `start` runs detached but doesn't survive logout/reboot or auto-restart on crash. A non-interactive `start` stays attached for a supervisor or provisioner. There's no per-tool permissioning for `coding` mode yet. And there's no self-update; re-run `npm i -g @cabane/companion@latest` to pick up a new version.
|