cofluxd 0.14.0 → 1.0.0
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 +34 -67
- package/account-client.mjs +101 -0
- package/coflux.mjs +399 -0
- package/cofluxd.mjs +9 -277
- package/package.json +6 -3
- package/skills/coflux/SKILL.md +129 -81
package/skills/coflux/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: coflux
|
|
3
|
-
description:
|
|
3
|
+
description: Use coflux to open visible terminals, read, wait, type, report progress, notify the user and obtain preview URLs. Prefer zero-credential local commands in the current workspace; use the account CLI across workspaces and devices. Coordinates arrive through coflux-session or COFLUX_* variables.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Working inside coflux
|
|
@@ -10,13 +10,12 @@ machines from a browser or a phone and take over at any time. This skill gives y
|
|
|
10
10
|
user can see and take over, a progress line and a call button on the workspace card, preview URLs,
|
|
11
11
|
and a way to operate the other workspaces and devices under the account when you need to.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
workspace goes through MCP.**
|
|
13
|
+
**Use local commands in this workspace and account CLI commands across workspaces and devices.**
|
|
15
14
|
|
|
16
15
|
| Track | Credentials | Reach | Use for |
|
|
17
16
|
|---|---|---|---|
|
|
18
|
-
| Local commands `
|
|
19
|
-
|
|
|
17
|
+
| Local commands `coflux terminal/progress/notify/ports` | none (the daemon identifies you by process tree) | **the workspace your cwd is in** | open, read, wait, send, report progress, call the user, preview URLs: the default, fastest, no network dependency |
|
|
18
|
+
| Account CLI | app login or `coflux login` | all devices and workspaces in the account | child workspaces and remote terminals; JSON output |
|
|
20
19
|
|
|
21
20
|
Of the local commands, `send`/`read`/`wait`/`notify`/`progress` complete entirely inside the
|
|
22
21
|
local daemon and never touch the center; `new`/`list`/`ports` are relayed to the center by the
|
|
@@ -36,22 +35,86 @@ env | grep '^COFLUX_'
|
|
|
36
35
|
|
|
37
36
|
- **`COFLUX_WORKSPACE_ID` is non-empty** (or the `<coflux-session>` block is present) → you are in
|
|
38
37
|
a coflux terminal with an up-to-date daemon. The variables below are your coordinates; pass
|
|
39
|
-
these ids to
|
|
38
|
+
these ids to account CLI commands directly instead of guessing from `list_*`:
|
|
40
39
|
|
|
41
40
|
| Variable | Meaning |
|
|
42
41
|
|---|---|
|
|
43
42
|
| `COFLUX_DEVICE_ID` | id of the device you run on (the id in `list_devices`) |
|
|
44
43
|
| `COFLUX_PROJECT_ID` | owning project id; empty string for a directory workspace without a repository |
|
|
45
|
-
| `COFLUX_WORKSPACE_ID` |
|
|
44
|
+
| `COFLUX_WORKSPACE_ID` | the workspace this terminal was **opened** in (the id in `list_workspaces`). The variable is frozen when the terminal starts; the workspace the terminal *belongs to* can still change — see below. `coflux workspace` is the authority |
|
|
46
45
|
| `COFLUX_TASK_ID` | id of this terminal (the taskId / terminalId used by local commands and `read_terminal`) |
|
|
47
46
|
| `COFLUX_SESSION_ID` | id of this PTY session |
|
|
48
|
-
| `COFLUX_MCP_URL` | the center's MCP URL; the user configures MCP with it |
|
|
49
47
|
|
|
50
|
-
- **Variables empty or absent
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
- **Variables empty or absent**: there is no local terminal context. Use `coflux whoami` to check
|
|
49
|
+
account access and the account CLI to discover workspaces. Ask the user to log in when needed;
|
|
50
|
+
never fabricate COFLUX_* coordinates.
|
|
51
|
+
|
|
52
|
+
### Two workspaces to keep apart: owning and effective
|
|
53
|
+
|
|
54
|
+
- **Owning workspace** = the workspace this terminal **belongs to**: what the user's sidebar shows it
|
|
55
|
+
under, what its turn state, branch and diff stats are attributed to. It starts out as
|
|
56
|
+
`COFLUX_WORKSPACE_ID` and moves with you when you enter or leave a git worktree (below).
|
|
57
|
+
- **Effective workspace** = the workspace **your current working directory is inside**. This is what
|
|
58
|
+
every local command acts on.
|
|
59
|
+
|
|
60
|
+
They are the same until your cwd wanders off. A plain `cd <path>` moves a *live* session — same
|
|
61
|
+
conversation, no restart — and a coflux child workspace is a normal registered git worktree, so a
|
|
62
|
+
session whose terminal belongs to workspace A can end up working inside workspace B. From that
|
|
63
|
+
moment, in B:
|
|
64
|
+
|
|
65
|
+
- `coflux terminal new` opens the terminal **in B**, under B in the user's sidebar, running in B's
|
|
66
|
+
directory, counting against B's terminal cap;
|
|
67
|
+
- `coflux terminal list` lists B's terminals, and A's terminals answer `read` / `wait` / `send`
|
|
68
|
+
with "not in this workspace or does not exist" (`cd` back to A to reach them again);
|
|
69
|
+
- Account CLI calls need **B's** id as `workspaceId`;
|
|
70
|
+
- the terminal itself stays under A, and `progress`, `notify` and `ports` still belong to it,
|
|
71
|
+
whatever your cwd is; `COFLUX_TASK_ID` and `COFLUX_SESSION_ID` never change.
|
|
72
|
+
|
|
73
|
+
If your cwd is outside every coflux workspace (say `/tmp`), local commands fall back to the owning
|
|
74
|
+
workspace.
|
|
75
|
+
|
|
76
|
+
A terminal opened before the daemon was upgraded is the one case with no owning workspace at all:
|
|
77
|
+
its local commands are refused with "predates the daemon upgrade" whatever your cwd is, because the
|
|
78
|
+
daemon never guesses ownership from a directory. Open a new terminal.
|
|
79
|
+
|
|
80
|
+
### coflux follows you into a git worktree
|
|
81
|
+
|
|
82
|
+
`EnterWorktree` switches this live session into a git worktree (its own, or an existing one you point
|
|
83
|
+
it at), `ExitWorktree` switches back, and resuming a session that had entered one puts you straight
|
|
84
|
+
back in it. **coflux comes along**: the terminal's *owning* workspace moves to the workspace that
|
|
85
|
+
worktree is, and if coflux has never seen that worktree it registers it as a child workspace of this
|
|
86
|
+
project first — a new card appears in the user's sidebar, with its branch and diff stats. Nothing is
|
|
87
|
+
interrupted: same terminal, same PTY, same conversation, and the user keeps watching it where it now
|
|
88
|
+
lives. When Claude Code cleans up its own worktree on exit, that workspace's terminals move back to
|
|
89
|
+
the project's main workspace and the record disappears by itself.
|
|
90
|
+
|
|
91
|
+
So, after entering or leaving a worktree, owning **and** effective are both the new workspace: pass
|
|
92
|
+
its id to account CLI commands and everything local already acts on it. The plugin drops the new id next to the
|
|
93
|
+
tool result, and `coflux workspace` always tells you. Two things stay behind on purpose:
|
|
94
|
+
|
|
95
|
+
- `COFLUX_WORKSPACE_ID` (and the id in the `<coflux-session>` block from earlier in this session)
|
|
96
|
+
still names where the terminal was *opened*; it is frozen when the PTY starts and cannot be
|
|
97
|
+
rewritten. Never reuse it after a move.
|
|
98
|
+
- The shell inside this terminal keeps its own directory. That is only about the shell; it does not
|
|
99
|
+
affect where your work is attributed.
|
|
100
|
+
|
|
101
|
+
Nothing happens when coflux cannot follow, and nothing is blocked either: another repository, a
|
|
102
|
+
directory that is not a git repository, a terminal opened in a directory workspace (no project), or
|
|
103
|
+
a daemon that is down or too old — the session just carries on with the ownership it had.
|
|
104
|
+
|
|
105
|
+
### Ask where you are
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
coflux workspace
|
|
109
|
+
{"workspaceId":"ws-b","path":"/Users/me/.coflux/worktrees/ws-b","owningWorkspaceId":"ws-a","moved":true}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
One line of JSON: `workspaceId` (+ `path`) is the **effective** workspace, `owningWorkspaceId` is the
|
|
113
|
+
workspace this terminal belongs to right now, and `moved` says whether they differ. With the plugin
|
|
114
|
+
installed you also get a `<coflux-session-moved>` block at the start of every prompt while the two
|
|
115
|
+
differ — but that block only arrives with the **next** user prompt. **About to call an account command right
|
|
116
|
+
after a `cd`? Run `coflux workspace` first** and use the `workspaceId` it prints; do not reuse
|
|
117
|
+
`COFLUX_WORKSPACE_ID`.
|
|
55
118
|
|
|
56
119
|
## When to open a terminal
|
|
57
120
|
|
|
@@ -76,12 +139,13 @@ own tools are faster, and a pile of one-second terminals is just noise to the us
|
|
|
76
139
|
There are two kinds, told apart by one single thing: **whether you pass a command**.
|
|
77
140
|
|
|
78
141
|
```sh
|
|
79
|
-
|
|
80
|
-
|
|
142
|
+
coflux terminal new --title="Run unit tests" --cmd="pnpm -C tests test" # job terminal
|
|
143
|
+
coflux terminal new --title="Debug shell" # session terminal
|
|
81
144
|
```
|
|
82
145
|
|
|
83
146
|
`--title` is the name the user sees in the sidebar; **name it properly**: "Run unit tests",
|
|
84
|
-
"Start dev server", never "terminal 1". Either kind runs in the
|
|
147
|
+
"Start dev server", never "terminal 1". Either kind runs in the directory of the workspace your cwd
|
|
148
|
+
is in (which is not always the one this terminal was opened in — see "owning and effective").
|
|
85
149
|
|
|
86
150
|
Always write `--cmd=<value>` and `--title=<value>` with the `=`, never separated by a space: a
|
|
87
151
|
value that starts with `-` is otherwise taken for another option and the call fails outright.
|
|
@@ -105,14 +169,14 @@ from what is on screen, and `wait` is only meaningful after you have sent `exit`
|
|
|
105
169
|
|
|
106
170
|
Driving a session terminal:
|
|
107
171
|
|
|
108
|
-
1. `
|
|
109
|
-
2. `
|
|
172
|
+
1. `coflux terminal new --title="Debug shell"` → prints a taskId.
|
|
173
|
+
2. `coflux terminal read <taskId>` until you see the shell prompt. The shell needs a moment to
|
|
110
174
|
start and the first read can come back empty — **never `send` before you have seen a prompt**.
|
|
111
|
-
3. `
|
|
175
|
+
3. `coflux terminal send <taskId> --text="pnpm build" --enter`, then `read` again to see what
|
|
112
176
|
happened. One send per command; nothing signals you when a command finished, so read until the
|
|
113
177
|
prompt is back. To make that unambiguous, end the command with a marker of your own
|
|
114
178
|
(`pnpm build; echo DONE-$?`) and read until the marker shows up.
|
|
115
|
-
4. `
|
|
179
|
+
4. `coflux terminal send <taskId> --text="exit" --enter` when you are done; the terminal then
|
|
116
180
|
becomes `exited` with the shell's exit code.
|
|
117
181
|
|
|
118
182
|
The new terminal has the same `COFLUX_*` variables (pointing at its own task/session ids, same
|
|
@@ -121,9 +185,9 @@ workspace as you).
|
|
|
121
185
|
### See how far it got
|
|
122
186
|
|
|
123
187
|
```sh
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
188
|
+
coflux terminal list # every terminal in the workspace your cwd is in: id, state, exit code, title
|
|
189
|
+
coflux terminal read <taskId> # a terminal's content (plain text, last 200 lines by default)
|
|
190
|
+
coflux terminal read <taskId> --lines 50
|
|
127
191
|
```
|
|
128
192
|
|
|
129
193
|
`list` states are `running` / `exited` / `idle`; `exited` carries `exit=<code>`.
|
|
@@ -135,8 +199,8 @@ history, and empty for the first moments after opening. Both are immediate.
|
|
|
135
199
|
### Wait for a command to finish
|
|
136
200
|
|
|
137
201
|
```sh
|
|
138
|
-
|
|
139
|
-
|
|
202
|
+
coflux terminal wait <taskId> # block until that terminal exits and print the exit code (default cap 30 minutes)
|
|
203
|
+
coflux terminal wait <taskId> --timeout 300 # custom timeout in seconds; a timeout fails loudly with a non-zero exit
|
|
140
204
|
```
|
|
141
205
|
|
|
142
206
|
To wait for a command use `wait`; **do not write your own polling loop**. One command blocks
|
|
@@ -155,10 +219,10 @@ not any command's: check what a command did by reading the screen.
|
|
|
155
219
|
**Keep working, and be woken up when it finishes.** `wait` blocks, so run it as a backgrounded Bash
|
|
156
220
|
call of your own:
|
|
157
221
|
|
|
158
|
-
1. `
|
|
159
|
-
2. Run `
|
|
222
|
+
1. `coflux terminal new --title="Run the test suite" --cmd="pnpm -C tests test"` → prints a taskId.
|
|
223
|
+
2. Run `coflux terminal wait <taskId>` as a backgrounded Bash call, then go do something else.
|
|
160
224
|
3. The host wakes you when that call exits. Check its output for `# exited exit=<code>`, then
|
|
161
|
-
`
|
|
225
|
+
`coflux terminal read <taskId>` to see what actually happened.
|
|
162
226
|
|
|
163
227
|
That gets you both halves at once: the user watches (and can take over) a real terminal, and you are
|
|
164
228
|
still told the moment it is over, instead of blocking or polling for it.
|
|
@@ -166,8 +230,8 @@ still told the moment it is over, instead of blocking or polling for it.
|
|
|
166
230
|
### Type into a terminal
|
|
167
231
|
|
|
168
232
|
```sh
|
|
169
|
-
|
|
170
|
-
|
|
233
|
+
coflux terminal send <taskId> --text "y" --enter # type a line and press Enter
|
|
234
|
+
coflux terminal send <taskId> --enter # just press Enter
|
|
171
235
|
```
|
|
172
236
|
|
|
173
237
|
For interactive confirmations (y/N, menus), or to add a command in the same shell after the
|
|
@@ -184,7 +248,7 @@ previous one finished. Discipline:
|
|
|
184
248
|
### Report progress
|
|
185
249
|
|
|
186
250
|
```sh
|
|
187
|
-
|
|
251
|
+
coflux progress "Reproduced; narrowing down the relay reconnect timing"
|
|
188
252
|
```
|
|
189
253
|
|
|
190
254
|
One sentence telling the user how far you are, shown on the workspace card and replaced by the
|
|
@@ -199,7 +263,7 @@ If unsure: when the user does not have to do anything, use `progress`.
|
|
|
199
263
|
### Call the user
|
|
200
264
|
|
|
201
265
|
```sh
|
|
202
|
-
|
|
266
|
+
coflux notify "Both approaches work; I need you to pick one"
|
|
203
267
|
```
|
|
204
268
|
|
|
205
269
|
The user's sidebar switches this workspace to "waiting for interaction" and shows this sentence;
|
|
@@ -213,7 +277,7 @@ extra notify. This is for "what you have to say cannot be guessed from the statu
|
|
|
213
277
|
### Hand the user a clickable preview
|
|
214
278
|
|
|
215
279
|
```sh
|
|
216
|
-
|
|
280
|
+
coflux ports
|
|
217
281
|
```
|
|
218
282
|
|
|
219
283
|
Lists every listening port in this workspace with its public preview URL. After starting a dev
|
|
@@ -223,72 +287,56 @@ server, use it to get the URL and tell the user directly; they click it and nobo
|
|
|
223
287
|
|
|
224
288
|
Errors are one readable sentence; do what they say: "not inside a coflux terminal" = you are not
|
|
225
289
|
in a coflux session; "terminal is not in this workspace or does not exist" = check the id with
|
|
226
|
-
`list
|
|
227
|
-
|
|
290
|
+
`list`, and if you moved into another workspace that is exactly what a terminal of the other one
|
|
291
|
+
looks like (`coflux workspace` to confirm, `cd` back to reach it); "predates the daemon upgrade" =
|
|
292
|
+
that terminal was opened before the daemon upgrade, open a new one; a `new` without `--cmd` refused for a missing command = this machine's daemon is older
|
|
228
293
|
than session terminals, tell the user to run `cofluxd update && cofluxd restart` (or pass a command
|
|
229
294
|
and use a job terminal); "daemon is not connected to the center" only appears on
|
|
230
295
|
`new`/`list`/`ports`, retry once it reconnects.
|
|
231
296
|
|
|
232
|
-
##
|
|
233
|
-
|
|
234
|
-
Local commands only see the workspace you are in. Use the MCP server named `coflux` in the host
|
|
235
|
-
**only** for these:
|
|
236
|
-
|
|
237
|
-
- **Open an isolated child workspace to work in parallel**: `create_workspace` (project id from
|
|
238
|
-
`$COFLUX_PROJECT_ID`) really runs `git worktree add` on the device; then `create_terminal` runs
|
|
239
|
-
commands there. The same two kinds apply: `create_terminal` with a `command` opens a
|
|
240
|
-
job terminal, without one it opens a session terminal.
|
|
241
|
-
- **Look at or operate terminals in other workspaces or on other devices**: `list_*` →
|
|
242
|
-
`read_terminal` / `send_terminal_input`.
|
|
243
|
-
- **Join everything under the account when you are not inside a coflux terminal** (for example
|
|
244
|
-
Claude Code the user started on their own machine).
|
|
245
|
-
- **Never run `git worktree add` yourself**: inside a coflux project the plugin blocks
|
|
246
|
-
`git worktree add|remove|move` and points you to `create_workspace` / `remove_workspace`; a
|
|
247
|
-
worktree you create is invisible to the user and cannot host a terminal.
|
|
297
|
+
## Account CLI: across workspaces and devices
|
|
248
298
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
### When MCP is not configured
|
|
253
|
-
|
|
254
|
-
Run `claude mcp list` (Codex: `codex mcp list`) to see whether `coflux` is there. If not, give
|
|
255
|
-
the user the one-line setup, with the URL from `$COFLUX_MCP_URL` (it is the center's public URL
|
|
256
|
-
+ `/mcp`):
|
|
299
|
+
The bundled CLI can use the desktop app's login without receiving its token. For a standalone CLI,
|
|
300
|
+
use `coflux login --username <account> --password-stdin`; the user supplies the password safely,
|
|
301
|
+
never as a command argument. Account commands return JSON. A workspace ID identifies its device.
|
|
257
302
|
|
|
258
303
|
```sh
|
|
259
|
-
|
|
260
|
-
|
|
304
|
+
coflux device list
|
|
305
|
+
coflux project list --device <deviceId>
|
|
306
|
+
coflux workspace list --device <deviceId>
|
|
307
|
+
coflux workspace new --project <projectId> --branch <branch>
|
|
308
|
+
coflux terminal new --workspace <workspaceId> --title <title> [--cmd <command>]
|
|
309
|
+
coflux terminal list --workspace <workspaceId>
|
|
310
|
+
coflux terminal read <terminalId> --remote
|
|
311
|
+
coflux terminal send <terminalId> --remote --text <text> [--enter]
|
|
312
|
+
coflux terminal wait <terminalId> --remote --timeout 30
|
|
313
|
+
coflux terminal stop <terminalId> --remote
|
|
314
|
+
coflux terminal remove <terminalId> --remote
|
|
315
|
+
coflux workspace rename <workspaceId> --name <name>
|
|
316
|
+
coflux workspace remove <workspaceId>
|
|
317
|
+
coflux ports --remote --device <deviceId>
|
|
261
318
|
```
|
|
262
319
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
### Using the tools
|
|
268
|
-
|
|
269
|
-
The tool list and each tool's contract (parameters, limits, what an error means) come from the
|
|
270
|
-
MCP server itself: read the tool descriptions in the host, they are the source of truth and this
|
|
271
|
-
file does not repeat them. Take ids from the `COFLUX_*` variables first; for anything outside this
|
|
272
|
-
workspace, find ids with the `list_*` tools.
|
|
273
|
-
|
|
274
|
-
The local-command disciplines apply to MCP just the same: `read_terminal` before
|
|
275
|
-
`send_terminal_input`, stop when refused because the user is taking over (communicate with
|
|
276
|
-
`cofluxd notify` instead of retrying), `wait_terminal` instead of a polling loop around
|
|
277
|
-
`read_terminal`, and stop on "needs upgrade" (tell the user to run
|
|
278
|
-
`cofluxd update && cofluxd restart` on that device; do not retry or work around it).
|
|
320
|
+
`--remote` selects account access, including other workspaces on this machine. Read before sending;
|
|
321
|
+
stop immediately when the user takes over. If a write times out, inspect the result before retrying.
|
|
322
|
+
Exiting the CLI does not stop its terminals. Delete workspaces through `coflux workspace remove`
|
|
323
|
+
so the filesystem and workspace records stay consistent.
|
|
279
324
|
|
|
280
325
|
## Boundaries
|
|
281
326
|
|
|
282
327
|
- You can open, read, wait and type, but **typing is a restricted write with humans first**: you
|
|
283
328
|
cannot write into a terminal the user is taking over (you are refused explicitly), and the user
|
|
284
329
|
taking over at any time displaces you. Do not fight a human for a terminal.
|
|
285
|
-
- Local commands only see **the workspace
|
|
286
|
-
|
|
330
|
+
- Local commands only see **the workspace your cwd is in** (`coflux workspace` says which one);
|
|
331
|
+
use the account CLI for other workspaces and machines in the same account.
|
|
287
332
|
- A workspace has a cap on concurrently live terminals (default 8, including the user's own).
|
|
288
333
|
On hitting the cap, `list` first: usually some finished terminals were never collected. If the
|
|
289
334
|
user really filled it up, `notify` them instead of forcing it.
|
|
290
|
-
- `new`/`list`/`ports` and
|
|
335
|
+
- `new`/`list`/`ports` and account commands need the daemon connected to the center; "letting the
|
|
291
336
|
user see" is their whole point. `send`/`read`/`wait`/`notify`/`progress` do not depend on the
|
|
292
337
|
center. When disconnected they fail loudly rather than degrade silently.
|
|
293
338
|
- `COFLUX_*` variables exist only in PTYs opened by coflux; exporting or changing them yourself
|
|
294
|
-
has no effect, the center only trusts the ids it issued.
|
|
339
|
+
has no effect, the center only trusts the ids it issued. `COFLUX_WORKSPACE_ID` always means the
|
|
340
|
+
workspace this terminal was **opened** in and goes stale the moment coflux follows you into a
|
|
341
|
+
worktree; both "where does this terminal belong now" and "where am I acting" come from
|
|
342
|
+
`coflux workspace`.
|