@zswarm/core 0.2.5 → 0.2.7
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/dist/harness.d.ts +27 -2
- package/dist/harness.js +68 -2
- package/dist/host/cli.js +5 -2
- package/dist/host/relay.d.ts +2 -0
- package/dist/host/relay.js +60 -9
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/ops/dispatch.d.ts +9 -0
- package/dist/ops/dispatch.js +25 -3
- package/dist/ops/restart.d.ts +57 -0
- package/dist/ops/restart.js +416 -0
- package/dist/ops/serve-install.d.ts +8 -1
- package/dist/ops/serve-install.js +160 -73
- package/dist/ops/serve.d.ts +28 -0
- package/dist/ops/serve.js +35 -0
- package/dist/policy.js +1 -0
- package/dist/schema.d.ts +28 -1
- package/dist/schema.js +140 -6
- package/package.json +1 -1
package/dist/schema.js
CHANGED
|
@@ -15,6 +15,7 @@ export const OP_NAMES = [
|
|
|
15
15
|
"keys",
|
|
16
16
|
"interrupt",
|
|
17
17
|
"spawn",
|
|
18
|
+
"restart",
|
|
18
19
|
"close",
|
|
19
20
|
"worktrees",
|
|
20
21
|
"unworktree",
|
|
@@ -42,6 +43,7 @@ export const TARGET_OPS = [
|
|
|
42
43
|
"status",
|
|
43
44
|
"keys",
|
|
44
45
|
"interrupt",
|
|
46
|
+
"restart",
|
|
45
47
|
"close",
|
|
46
48
|
"rename",
|
|
47
49
|
"focus",
|
|
@@ -57,25 +59,29 @@ export const PARAMS = [
|
|
|
57
59
|
{
|
|
58
60
|
name: "to",
|
|
59
61
|
type: "string",
|
|
60
|
-
flags: ["--to", "-t"],
|
|
62
|
+
flags: ["--to", "-t", "--pane"],
|
|
63
|
+
ops: [...TARGET_OPS, "broadcast", "log"],
|
|
61
64
|
description: "target pane: id (3 / terminal_3) or unique title/command; broadcast takes a comma list; log filters by it",
|
|
62
65
|
},
|
|
63
66
|
{
|
|
64
67
|
name: "all",
|
|
65
68
|
type: "boolean",
|
|
66
69
|
flags: ["--all", "-a"],
|
|
70
|
+
ops: ["broadcast", "sessions"],
|
|
67
71
|
description: "broadcast: every terminal pane in the session; sessions: include EXITED resurrectable sessions",
|
|
68
72
|
},
|
|
69
73
|
{
|
|
70
74
|
name: "live",
|
|
71
75
|
type: "boolean",
|
|
72
76
|
flags: ["--live", "--active"],
|
|
77
|
+
ops: ["sessions"],
|
|
73
78
|
description: "sessions: only live (non-EXITED) sessions — this is the default; use --all to include EXITED",
|
|
74
79
|
},
|
|
75
80
|
{
|
|
76
81
|
name: "exited",
|
|
77
82
|
type: "boolean",
|
|
78
83
|
flags: ["--exited"],
|
|
84
|
+
ops: ["sessions"],
|
|
79
85
|
cliOnly: true,
|
|
80
86
|
description: "sessions: list only EXITED (resurrectable) sessions; rows carry name, exited, age and ageSeconds",
|
|
81
87
|
},
|
|
@@ -83,6 +89,7 @@ export const PARAMS = [
|
|
|
83
89
|
name: "pruneExited",
|
|
84
90
|
type: "boolean",
|
|
85
91
|
flags: ["--prune-exited"],
|
|
92
|
+
ops: ["sessions"],
|
|
86
93
|
cliOnly: true,
|
|
87
94
|
description: "sessions: delete EXITED sessions (all, or those matching --older-than) with zellij delete-session; a live session is never removed",
|
|
88
95
|
},
|
|
@@ -90,6 +97,7 @@ export const PARAMS = [
|
|
|
90
97
|
name: "olderThan",
|
|
91
98
|
type: "string",
|
|
92
99
|
flags: ["--older-than"],
|
|
100
|
+
ops: ["sessions"],
|
|
93
101
|
cliOnly: true,
|
|
94
102
|
description: "sessions --prune-exited: only delete sessions created at least this long ago (e.g. 7d, 12h, 30m; default all exited)",
|
|
95
103
|
},
|
|
@@ -97,6 +105,7 @@ export const PARAMS = [
|
|
|
97
105
|
name: "dryRun",
|
|
98
106
|
type: "boolean",
|
|
99
107
|
flags: ["--dry-run"],
|
|
108
|
+
ops: ["sessions"],
|
|
100
109
|
cliOnly: true,
|
|
101
110
|
description: "sessions --prune-exited: report what would be deleted without deleting",
|
|
102
111
|
},
|
|
@@ -104,6 +113,7 @@ export const PARAMS = [
|
|
|
104
113
|
name: "json",
|
|
105
114
|
type: "boolean",
|
|
106
115
|
flags: ["--json"],
|
|
116
|
+
ops: ["sessions"],
|
|
107
117
|
cliOnly: true,
|
|
108
118
|
description: "sessions: rows are name, exited, age and ageSeconds; the CLI prints JSON either way",
|
|
109
119
|
},
|
|
@@ -123,60 +133,70 @@ export const PARAMS = [
|
|
|
123
133
|
name: "group",
|
|
124
134
|
type: "string",
|
|
125
135
|
flags: ["--group", "-g"],
|
|
136
|
+
ops: ["broadcast"],
|
|
126
137
|
description: "broadcast: narrow the selection to panes whose title or command contains this",
|
|
127
138
|
},
|
|
128
139
|
{
|
|
129
140
|
name: "channel",
|
|
130
141
|
type: "string",
|
|
131
142
|
flags: ["--channel"],
|
|
143
|
+
ops: ["signal", "await"],
|
|
132
144
|
description: "signal/await: channel name",
|
|
133
145
|
},
|
|
134
146
|
{
|
|
135
147
|
name: "payload",
|
|
136
148
|
type: "string",
|
|
137
149
|
flags: ["--payload"],
|
|
150
|
+
ops: ["signal"],
|
|
138
151
|
description: "signal: short note stored with the post",
|
|
139
152
|
},
|
|
140
153
|
{
|
|
141
154
|
name: "count",
|
|
142
155
|
type: "number",
|
|
143
156
|
flags: ["--count"],
|
|
157
|
+
ops: ["await"],
|
|
144
158
|
description: "await: how many posts to wait for (default 1)",
|
|
145
159
|
},
|
|
146
160
|
{
|
|
147
161
|
name: "clear",
|
|
148
162
|
type: "boolean",
|
|
149
163
|
flags: ["--clear"],
|
|
164
|
+
ops: ["signal", "bus", "serve"],
|
|
150
165
|
description: "signal: reset the channel (all channels when none is given); bus: forget the installed plugin; serve: stop and unregister the owned Windows zswarm-serve logon task, or the Linux/macOS serve service, if present",
|
|
151
166
|
},
|
|
152
167
|
{
|
|
153
168
|
name: "install",
|
|
154
169
|
type: "boolean",
|
|
155
170
|
flags: ["--install"],
|
|
171
|
+
ops: ["bus", "serve"],
|
|
156
172
|
description: "bus: load the event-bus plugin in a pane so its permission prompt can be answered, then remember it; serve: register the current-user Windows Interactive logon task, or on Linux/macOS a systemd user unit (with linger) or launchd job whose token lives in ~/.zswarm/serve/, and wait for authenticated hello plus host session visibility",
|
|
157
173
|
},
|
|
158
174
|
{
|
|
159
175
|
name: "runAs",
|
|
160
176
|
type: "string",
|
|
161
177
|
flags: ["--run-as"],
|
|
178
|
+
ops: ["serve"],
|
|
162
179
|
description: "serve --install/--clear on Linux/macOS, run as root: install the service for this user (a LaunchDaemon with UserName on macOS, the user's systemd units on Linux), for accounts that never log in",
|
|
163
180
|
},
|
|
164
181
|
{
|
|
165
182
|
name: "reset",
|
|
166
183
|
type: "boolean",
|
|
167
184
|
flags: ["--reset"],
|
|
185
|
+
ops: ["tail"],
|
|
168
186
|
description: "tail: forget the stored cursor and return the whole screen",
|
|
169
187
|
},
|
|
170
188
|
{
|
|
171
189
|
name: "sampleMs",
|
|
172
190
|
type: "number",
|
|
173
191
|
flags: ["--sample-ms"],
|
|
192
|
+
ops: ["status"],
|
|
174
193
|
description: "status: explicitly sample twice with this gap (fallback default 400); 0 reports running/exited only; default prefers bus changes",
|
|
175
194
|
},
|
|
176
195
|
{
|
|
177
196
|
name: "sinceLast",
|
|
178
197
|
type: "boolean",
|
|
179
198
|
flags: ["--since-last"],
|
|
199
|
+
ops: ["status"],
|
|
180
200
|
description: "status: classify changes since the previous bus observation (default when bus available); first observation is unknown unless a prompt is recognized",
|
|
181
201
|
},
|
|
182
202
|
{
|
|
@@ -195,33 +215,60 @@ export const PARAMS = [
|
|
|
195
215
|
name: "limit",
|
|
196
216
|
type: "number",
|
|
197
217
|
flags: ["--limit"],
|
|
218
|
+
ops: ["log"],
|
|
198
219
|
description: "log: how many entries to return (default 20)",
|
|
199
220
|
},
|
|
200
221
|
{
|
|
201
222
|
name: "since",
|
|
202
223
|
type: "string",
|
|
203
224
|
flags: ["--since"],
|
|
225
|
+
ops: ["log"],
|
|
204
226
|
description: "log: only entries at or after this epoch millisecond",
|
|
205
227
|
},
|
|
206
228
|
{
|
|
207
229
|
name: "failed",
|
|
208
230
|
type: "boolean",
|
|
209
231
|
flags: ["--failed"],
|
|
232
|
+
ops: ["log"],
|
|
210
233
|
description: "log: only deliveries that did not land",
|
|
211
234
|
},
|
|
212
235
|
{
|
|
213
236
|
name: "body",
|
|
214
237
|
type: "string",
|
|
215
238
|
flags: ["--body", "-b", "--text"],
|
|
239
|
+
ops: ["send", "broadcast"],
|
|
216
240
|
description: "send: message body",
|
|
217
241
|
},
|
|
218
242
|
{
|
|
219
243
|
name: "bodyFile",
|
|
220
244
|
type: "string",
|
|
221
245
|
flags: ["--body-file"],
|
|
246
|
+
ops: ["send"],
|
|
222
247
|
cliOnly: true,
|
|
223
248
|
description: "send: read UTF-8 on the caller from PATH, or - for stdin; cannot combine with --body/--text",
|
|
224
249
|
},
|
|
250
|
+
{
|
|
251
|
+
name: "handoff",
|
|
252
|
+
type: "string",
|
|
253
|
+
flags: [],
|
|
254
|
+
ops: ["restart"],
|
|
255
|
+
description: "restart: handoff text to deliver to the relaunched agent (MCP inline form; the CLI fills this from --handoff-file)",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "handoffFile",
|
|
259
|
+
type: "string",
|
|
260
|
+
flags: ["--handoff-file"],
|
|
261
|
+
ops: ["restart"],
|
|
262
|
+
cliOnly: true,
|
|
263
|
+
description: "restart: read the handoff UTF-8 on the caller from PATH, or - for stdin; a short handoff is pasted, a long one becomes a pointer line, and --handoff-self writes the agent's handoff to this path",
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
name: "handoffSelf",
|
|
267
|
+
type: "boolean",
|
|
268
|
+
flags: ["--handoff-self"],
|
|
269
|
+
ops: ["restart"],
|
|
270
|
+
description: "restart: before exiting, ask the running agent to write its handoff to the file and print a marker, then deliver it after relaunch",
|
|
271
|
+
},
|
|
225
272
|
{
|
|
226
273
|
name: "text",
|
|
227
274
|
type: "string",
|
|
@@ -232,36 +279,42 @@ export const PARAMS = [
|
|
|
232
279
|
name: "from",
|
|
233
280
|
type: "string",
|
|
234
281
|
flags: ["--from", "-f"],
|
|
282
|
+
ops: ["send", "broadcast"],
|
|
235
283
|
description: "send: sender label in the [zswarm from=…] prefix (default: ZSWARM_FROM, else the sending pane's title, else swarm)",
|
|
236
284
|
},
|
|
237
285
|
{
|
|
238
286
|
name: "raw",
|
|
239
287
|
type: "boolean",
|
|
240
288
|
flags: ["--raw"],
|
|
289
|
+
ops: ["send", "broadcast"],
|
|
241
290
|
description: "send: skip the peer prefix (default false)",
|
|
242
291
|
},
|
|
243
292
|
{
|
|
244
293
|
name: "full",
|
|
245
294
|
type: "boolean",
|
|
246
295
|
flags: ["--full"],
|
|
296
|
+
ops: ["dump", "wait", "tail"],
|
|
247
297
|
description: "dump/wait: include full scrollback (default false)",
|
|
248
298
|
},
|
|
249
299
|
{
|
|
250
300
|
name: "max",
|
|
251
301
|
type: "number",
|
|
252
302
|
flags: ["--max"],
|
|
303
|
+
ops: ["dump", "wait", "tail", "layout", "diff"],
|
|
253
304
|
description: "dump/wait: max text chars (dump 8000, wait 2000; keeps tail, 0 = unlimited)",
|
|
254
305
|
},
|
|
255
306
|
{
|
|
256
307
|
name: "head",
|
|
257
308
|
type: "boolean",
|
|
258
309
|
flags: ["--head"],
|
|
310
|
+
ops: ["dump"],
|
|
259
311
|
description: "dump: keep the start instead of the tail when truncating",
|
|
260
312
|
},
|
|
261
313
|
{
|
|
262
314
|
name: "for",
|
|
263
315
|
type: "string",
|
|
264
316
|
flags: ["--for"],
|
|
317
|
+
ops: ["wait"],
|
|
265
318
|
values: ["idle", "match", "either"],
|
|
266
319
|
description: "wait: stop on a quiet screen, on a match, or whichever lands first (default: match if match= given, else idle)",
|
|
267
320
|
},
|
|
@@ -269,42 +322,49 @@ export const PARAMS = [
|
|
|
269
322
|
name: "match",
|
|
270
323
|
type: "string",
|
|
271
324
|
flags: ["--match", "-m"],
|
|
325
|
+
ops: ["wait"],
|
|
272
326
|
description: "wait: text to look for in the pane screen",
|
|
273
327
|
},
|
|
274
328
|
{
|
|
275
329
|
name: "regex",
|
|
276
330
|
type: "boolean",
|
|
277
331
|
flags: ["--regex"],
|
|
332
|
+
ops: ["wait"],
|
|
278
333
|
description: "wait: treat match as a regex (default false)",
|
|
279
334
|
},
|
|
280
335
|
{
|
|
281
336
|
name: "ignoreCase",
|
|
282
337
|
type: "boolean",
|
|
283
338
|
flags: ["--ignore-case"],
|
|
339
|
+
ops: ["wait"],
|
|
284
340
|
description: "wait: case-insensitive match (default false)",
|
|
285
341
|
},
|
|
286
342
|
{
|
|
287
343
|
name: "idleMs",
|
|
288
344
|
type: "number",
|
|
289
345
|
flags: ["--idle-ms"],
|
|
346
|
+
ops: ["wait"],
|
|
290
347
|
description: "wait: screen must be unchanged this long to count as idle (default 2000)",
|
|
291
348
|
},
|
|
292
349
|
{
|
|
293
350
|
name: "pollMs",
|
|
294
351
|
type: "number",
|
|
295
352
|
flags: ["--poll-ms"],
|
|
353
|
+
ops: ["wait"],
|
|
296
354
|
description: "wait: fallback poll interval (default 150; bus path polls at 50ms)",
|
|
297
355
|
},
|
|
298
356
|
{
|
|
299
357
|
name: "timeoutMs",
|
|
300
358
|
type: "number",
|
|
301
359
|
flags: ["--timeout-ms"],
|
|
302
|
-
|
|
360
|
+
ops: ["wait", "status", "spawn", "restart", "doctor", "serve", "send", "dump", "tail", "keys", "interrupt", "close", "await"],
|
|
361
|
+
description: "wait: timeout (default 60000); status/spawn/restart: overall deadline (default 30000); doctor: overall deadline (default 10000), including Tailscale/SSH/hello/host checks; serve --install: overall install/readiness deadline (default 30000)",
|
|
303
362
|
},
|
|
304
363
|
{
|
|
305
364
|
name: "keys",
|
|
306
365
|
type: "stringOrArray",
|
|
307
366
|
flags: ["--key", "--keys", "-k"],
|
|
367
|
+
ops: ["keys", "interrupt"],
|
|
308
368
|
repeat: true,
|
|
309
369
|
description: 'keys: key specs, one per entry — "Ctrl c", "Esc", "F1", "Up". A bare string is one key; comma-separate for several.',
|
|
310
370
|
},
|
|
@@ -312,72 +372,84 @@ export const PARAMS = [
|
|
|
312
372
|
name: "chars",
|
|
313
373
|
type: "string",
|
|
314
374
|
flags: ["--chars"],
|
|
375
|
+
ops: ["keys"],
|
|
315
376
|
description: "keys: literal characters to type instead of key specs (no Enter unless enter=true)",
|
|
316
377
|
},
|
|
317
378
|
{
|
|
318
379
|
name: "enter",
|
|
319
380
|
type: "boolean",
|
|
320
381
|
flags: ["--enter"],
|
|
382
|
+
ops: ["keys"],
|
|
321
383
|
description: "keys: press Enter after the keys/chars",
|
|
322
384
|
},
|
|
323
385
|
{
|
|
324
386
|
name: "hard",
|
|
325
387
|
type: "boolean",
|
|
326
388
|
flags: ["--hard"],
|
|
389
|
+
ops: ["interrupt"],
|
|
327
390
|
description: "interrupt: send Ctrl c instead of the default Esc",
|
|
328
391
|
},
|
|
329
392
|
{
|
|
330
393
|
name: "command",
|
|
331
394
|
type: "stringOrArray",
|
|
332
395
|
flags: ["--command", "--cmd", "-c"],
|
|
333
|
-
|
|
396
|
+
ops: ["spawn", "restart"],
|
|
397
|
+
description: "spawn: program to run in the new pane, argv-style (no shell). Empty starts a plain shell. restart: command to type in a shell pane instead of the profile's launch command",
|
|
334
398
|
},
|
|
335
399
|
{
|
|
336
400
|
name: "cwd",
|
|
337
401
|
type: "string",
|
|
338
402
|
flags: ["--cwd"],
|
|
403
|
+
ops: ["spawn", "worktrees", "unworktree", "diff", "checkpoint"],
|
|
339
404
|
description: "spawn: working directory for the new pane; worktrees/unworktree: any directory inside the repo",
|
|
340
405
|
},
|
|
341
406
|
{
|
|
342
407
|
name: "worktree",
|
|
343
408
|
type: "string",
|
|
344
409
|
flags: ["--worktree", "-w"],
|
|
410
|
+
ops: ["spawn", "unworktree"],
|
|
345
411
|
description: "spawn: branch to give the peer its own git worktree (overrides cwd); unworktree: alias for branch",
|
|
346
412
|
},
|
|
347
413
|
{
|
|
348
414
|
name: "worktreeRoot",
|
|
349
415
|
type: "string",
|
|
350
416
|
flags: ["--worktree-root"],
|
|
417
|
+
ops: ["spawn", "unworktree"],
|
|
351
418
|
description: "where worktrees live (default <repo>-worktrees beside the repo, or ZSWARM_WORKTREE_ROOT)",
|
|
352
419
|
},
|
|
353
420
|
{
|
|
354
421
|
name: "baseRef",
|
|
355
422
|
type: "string",
|
|
356
423
|
flags: ["--base-ref", "--base"],
|
|
424
|
+
ops: ["spawn"],
|
|
357
425
|
description: "spawn: ref to branch from when the worktree branch is new",
|
|
358
426
|
},
|
|
359
427
|
{
|
|
360
428
|
name: "path",
|
|
361
429
|
type: "string",
|
|
362
430
|
flags: ["--path"],
|
|
431
|
+
ops: ["unworktree", "diff", "checkpoint"],
|
|
363
432
|
description: "unworktree: worktree path to remove",
|
|
364
433
|
},
|
|
365
434
|
{
|
|
366
435
|
name: "branch",
|
|
367
436
|
type: "string",
|
|
368
437
|
flags: ["--branch"],
|
|
438
|
+
ops: ["unworktree", "diff", "checkpoint"],
|
|
369
439
|
description: "unworktree: remove the worktree holding this branch",
|
|
370
440
|
},
|
|
371
441
|
{
|
|
372
442
|
name: "name",
|
|
373
443
|
type: "string",
|
|
374
444
|
flags: ["--name", "-n"],
|
|
445
|
+
ops: ["spawn", "rename"],
|
|
375
446
|
description: "spawn: pane (or tab) name; rename: the new name",
|
|
376
447
|
},
|
|
377
448
|
{
|
|
378
449
|
name: "submit",
|
|
379
450
|
type: "string",
|
|
380
451
|
flags: ["--submit"],
|
|
452
|
+
ops: ["send", "broadcast"],
|
|
381
453
|
values: ["auto", "double-enter", "none"],
|
|
382
454
|
description: 'send/broadcast: auto verifies the paste actually submitted and presses Enter again if not (default). The result reports submitted: true, "queued" (held behind a running turn), false (still in the composer), "unverified" (the screen changed but the body is not visible), or "not-delivered" (the pane was unchanged apart from the composer, so the op fails not_delivered and a resend is safe)',
|
|
383
455
|
},
|
|
@@ -385,48 +457,56 @@ export const PARAMS = [
|
|
|
385
457
|
name: "observeMs",
|
|
386
458
|
type: "number",
|
|
387
459
|
flags: ["--observe-ms"],
|
|
460
|
+
ops: ["send", "dump", "tail", "wait", "keys", "interrupt", "close", "spawn"],
|
|
388
461
|
description: "spawn: observe creation/alias for up to 3000ms; pane lookup: retry absence for 1000ms (scaled up to 5x when the first Zellij call is slow); 0 disables retries",
|
|
389
462
|
},
|
|
390
463
|
{
|
|
391
464
|
name: "settleMs",
|
|
392
465
|
type: "number",
|
|
393
466
|
flags: ["--settle-ms"],
|
|
467
|
+
ops: ["send", "broadcast"],
|
|
394
468
|
description: "send/broadcast: pause before checking the paste landed (default 300, scaled up to 5x when the first Zellij call is slow; explicit value wins)",
|
|
395
469
|
},
|
|
396
470
|
{
|
|
397
471
|
name: "confirm",
|
|
398
472
|
type: "boolean",
|
|
399
473
|
flags: ["--confirm"],
|
|
474
|
+
ops: ["send", "broadcast"],
|
|
400
475
|
description: 'send/broadcast: after the send, dump once more and report what it sees; paste again only on "not-delivered" (positive evidence nothing landed), press Enter when the body is still in the composer, and never paste the body twice',
|
|
401
476
|
},
|
|
402
477
|
{
|
|
403
478
|
name: "ifIdle",
|
|
404
479
|
type: "boolean",
|
|
405
480
|
flags: ["--if-idle"],
|
|
481
|
+
ops: ["send"],
|
|
406
482
|
description: "send: refuse a pane that a relay has leased (pane_leased) or whose harness is visibly working (pane_busy) instead of pasting into it",
|
|
407
483
|
},
|
|
408
484
|
{
|
|
409
485
|
name: "expect",
|
|
410
486
|
type: "string",
|
|
411
487
|
flags: ["--expect"],
|
|
488
|
+
ops: ["send", "keys", "interrupt"],
|
|
412
489
|
description: "send/keys/interrupt: case-insensitive substring required on the current screen immediately before input",
|
|
413
490
|
},
|
|
414
491
|
{
|
|
415
492
|
name: "message",
|
|
416
493
|
type: "string",
|
|
417
494
|
flags: ["--message"],
|
|
495
|
+
ops: ["checkpoint"],
|
|
418
496
|
description: "checkpoint: commit message",
|
|
419
497
|
},
|
|
420
498
|
{
|
|
421
499
|
name: "stat",
|
|
422
500
|
type: "boolean",
|
|
423
501
|
flags: ["--stat"],
|
|
502
|
+
ops: ["diff"],
|
|
424
503
|
description: "diff: stat only, no patch body",
|
|
425
504
|
},
|
|
426
505
|
{
|
|
427
506
|
name: "direction",
|
|
428
507
|
type: "string",
|
|
429
508
|
flags: ["--direction", "-d"],
|
|
509
|
+
ops: ["spawn"],
|
|
430
510
|
values: ["right", "left", "up", "down"],
|
|
431
511
|
description: "spawn: split direction",
|
|
432
512
|
},
|
|
@@ -434,66 +514,77 @@ export const PARAMS = [
|
|
|
434
514
|
name: "floating",
|
|
435
515
|
type: "boolean",
|
|
436
516
|
flags: ["--floating"],
|
|
517
|
+
ops: ["spawn"],
|
|
437
518
|
description: "spawn: open the pane floating",
|
|
438
519
|
},
|
|
439
520
|
{
|
|
440
521
|
name: "width",
|
|
441
522
|
type: "string",
|
|
442
523
|
flags: ["--width"],
|
|
524
|
+
ops: ["spawn"],
|
|
443
525
|
description: "spawn: floating pane width (e.g. 80 or 50%)",
|
|
444
526
|
},
|
|
445
527
|
{
|
|
446
528
|
name: "height",
|
|
447
529
|
type: "string",
|
|
448
530
|
flags: ["--height"],
|
|
531
|
+
ops: ["spawn"],
|
|
449
532
|
description: "spawn: floating pane height (e.g. 20 or 40%)",
|
|
450
533
|
},
|
|
451
534
|
{
|
|
452
535
|
name: "tab",
|
|
453
536
|
type: "string",
|
|
454
537
|
flags: ["--tab"],
|
|
538
|
+
ops: ["broadcast", "rename", "spawn"],
|
|
455
539
|
description: "tab name: broadcast targets it, rename retitles it, spawn opens the new pane's tab by it",
|
|
456
540
|
},
|
|
457
541
|
{
|
|
458
542
|
name: "newTab",
|
|
459
543
|
type: "boolean",
|
|
460
544
|
flags: ["--new-tab"],
|
|
545
|
+
ops: ["spawn"],
|
|
461
546
|
description: "spawn: open a new tab instead of splitting",
|
|
462
547
|
},
|
|
463
548
|
{
|
|
464
549
|
name: "layout",
|
|
465
550
|
type: "string",
|
|
466
551
|
flags: ["--layout", "-l"],
|
|
552
|
+
ops: ["spawn"],
|
|
467
553
|
description: "spawn: layout name for the new tab (newTab=true)",
|
|
468
554
|
},
|
|
469
555
|
{
|
|
470
556
|
name: "closeOnExit",
|
|
471
557
|
type: "boolean",
|
|
472
558
|
flags: ["--close-on-exit"],
|
|
559
|
+
ops: ["spawn"],
|
|
473
560
|
description: "spawn: close the pane when its command exits",
|
|
474
561
|
},
|
|
475
562
|
{
|
|
476
563
|
name: "allowSelf",
|
|
477
564
|
type: "boolean",
|
|
478
565
|
flags: ["--allow-self"],
|
|
566
|
+
ops: ["send", "keys", "close", "interrupt", "broadcast"],
|
|
479
567
|
description: "send/keys/close: allow targeting zswarm's own pane (default false)",
|
|
480
568
|
},
|
|
481
569
|
{
|
|
482
570
|
name: "force",
|
|
483
571
|
type: "boolean",
|
|
484
572
|
flags: ["--force"],
|
|
485
|
-
|
|
573
|
+
ops: ["send", "keys", "unworktree", "bus", "interrupt", "broadcast", "restart"],
|
|
574
|
+
description: "send/keys: write to a pane whose command has exited; restart: restart a pane that a relay has leased; unworktree: remove a busy or dirty worktree; bus: close orphan bus panes and reload this session's plugin",
|
|
486
575
|
},
|
|
487
576
|
{
|
|
488
577
|
name: "listen",
|
|
489
578
|
type: "string",
|
|
490
579
|
flags: ["--listen"],
|
|
580
|
+
ops: ["serve"],
|
|
491
581
|
description: "serve: bind address (default 127.0.0.1:9419). Loopback needs no Tailscale; a non-loopback literal must be a verified local Tailscale IP (see docs/tailscale.md). Reach via ZSWARM_SERVE / --serve (direct host:port, private Tailscale Serve tcp:// frontend, or ssh:// to remote loopback)",
|
|
492
582
|
},
|
|
493
583
|
{
|
|
494
584
|
name: "verbose",
|
|
495
585
|
type: "boolean",
|
|
496
586
|
flags: ["--verbose", "-v"],
|
|
587
|
+
ops: ["list", "send", "spawn", "status"],
|
|
497
588
|
description: "list/send/spawn: include cwd/focus/exited/floating (and the pane on send/spawn)",
|
|
498
589
|
},
|
|
499
590
|
];
|
|
@@ -533,7 +624,7 @@ export function mcpInputSchema() {
|
|
|
533
624
|
}
|
|
534
625
|
export const MCP_TOOL_DESCRIPTION = `zSwarm Zellij pane coordination (op=${OP_NAMES.join("|")}). ` +
|
|
535
626
|
"List panes, send text into a CLI pane (paste+Enter), block until a pane goes idle or prints a match, " +
|
|
536
|
-
"send raw keys, open or close panes, and give a peer its own git worktree. " +
|
|
627
|
+
"send raw keys, open or close panes, restart an agent in its pane with an optional handoff, and give a peer its own git worktree. " +
|
|
537
628
|
"Same host as Zellij, or ZSWARM_SSH / ZSWARM_SERVE for a remote crew.";
|
|
538
629
|
const FLAG_INDEX = new Map(PARAMS.flatMap((p) => p.flags.map((flag) => [flag, p])));
|
|
539
630
|
export function cliUsage() {
|
|
@@ -552,6 +643,49 @@ export function cliUsage() {
|
|
|
552
643
|
lines.push("", "Guards: writes refuse zswarm's own pane (--allow-self) and exited panes (--force). --expect requires the screen to contain a substring first.", "Bus: `zswarm bus --install` once per Zellij session. `--force` closes orphan bus panes and reloads; do not use it as a retry.", "Remote: ZSWARM_SSH (+ ZSWARM_TMP=auto or ZSWARM_SSH_MODE=interactive on Windows). Or run `zswarm serve --listen` next to Zellij and set ZSWARM_SERVE / --serve (host:port, tcp://, or ssh://user@host?servePort=9419) plus ZSWARM_SERVE_TOKEN. Serve defaults to loopback and always requires a token; an explicit local Tailscale IP is allowed only after host verification. Private raw TCP Tailscale Serve keeps the backend on 127.0.0.1 behind `tailscale serve --tcp=…` (docs/tailscale.md). ssh:// does not start remote serve. Windows default recipe: `zswarm serve --install` (verified readiness).", "Hosts (CLI only, see docs/hosts.md): `zswarm slot`, `zswarm crew`, `zswarm relay`, `zswarm host`; `zswarm <command> --help` for each.", "Doctor: `zswarm doctor --session crew` inspects local, --ssh, and --serve routes without installs, pane changes, or plugin launch. See docs/doctor.md and docs/tailscale.md.", "Env: ZSWARM_BIN, ZSWARM_PATH, ZSWARM_SESSION, ZSWARM_SELF_PANE, ZSWARM_FROM, ZELLIJ_PANE_ID, ZELLIJ_SESSION_NAME, ZSWARM_BUS, ZSWARM_BUS_PLUGIN, ZSWARM_SSH, ZSWARM_SSH_BIN, ZSWARM_SSH_OPTS, ZSWARM_TMP, ZSWARM_SSH_MODE, ZSWARM_SERVE, ZSWARM_SERVE_TOKEN, ZSWARM_TAILSCALE_BIN, ZSWARM_CACHE_TTL_MS", "");
|
|
553
644
|
return lines.join("\n");
|
|
554
645
|
}
|
|
646
|
+
/**
|
|
647
|
+
* True when argv asks for help: `--help` or `-h` as a flag of its own, not the
|
|
648
|
+
* value of a flag that takes one (`--body -h` sends "-h") and not after `--`.
|
|
649
|
+
*/
|
|
650
|
+
export function wantsHelp(argv) {
|
|
651
|
+
const valued = new Set(PARAMS.filter((p) => p.type !== "boolean").flatMap((p) => p.flags));
|
|
652
|
+
for (let i = 0; i < argv.length; i++) {
|
|
653
|
+
const arg = argv[i];
|
|
654
|
+
if (arg === "--")
|
|
655
|
+
return false;
|
|
656
|
+
if (arg === "--help" || arg === "-h")
|
|
657
|
+
return true;
|
|
658
|
+
if (valued.has(arg))
|
|
659
|
+
i++; // its value may be anything, "-h" included
|
|
660
|
+
}
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Per-command help for `zswarm <op> --help`: the usage line, the positional
|
|
665
|
+
* shorthand, and only the flags whose `ops` include this op. A flag without
|
|
666
|
+
* `ops` (session, --local, --ssh, --fresh, --serve) applies to every op.
|
|
667
|
+
* Render from the same PARAMS table that parses the flags, so they cannot drift.
|
|
668
|
+
*/
|
|
669
|
+
export function commandUsage(op) {
|
|
670
|
+
const lines = [`usage: zswarm ${op} [options]`, ""];
|
|
671
|
+
const positional = op === "send"
|
|
672
|
+
? " positional: first bare argument is --to, second is --body"
|
|
673
|
+
: TARGET_OPS.includes(op)
|
|
674
|
+
? " positional: first bare argument is --to"
|
|
675
|
+
: undefined;
|
|
676
|
+
if (positional)
|
|
677
|
+
lines.push(positional, "");
|
|
678
|
+
for (const param of PARAMS) {
|
|
679
|
+
if (param.flags.length === 0)
|
|
680
|
+
continue;
|
|
681
|
+
if (param.ops && !param.ops.includes(op))
|
|
682
|
+
continue;
|
|
683
|
+
const value = param.type === "boolean" ? "" : param.type === "number" ? " N" : " VALUE";
|
|
684
|
+
lines.push(` ${param.flags.join(", ").padEnd(28)}${value.trim().padEnd(6)}${param.description}`);
|
|
685
|
+
}
|
|
686
|
+
lines.push("");
|
|
687
|
+
return lines.join("\n");
|
|
688
|
+
}
|
|
555
689
|
/** Turn argv (without the op) into dispatch args, driven by PARAMS. */
|
|
556
690
|
/**
|
|
557
691
|
* Pull the op out of argv, tolerating flags before it.
|
|
@@ -561,7 +695,7 @@ export function cliUsage() {
|
|
|
561
695
|
* an unknown op. Only positions that already errored are affected: if argv[0]
|
|
562
696
|
* is a real op it wins, so `send reviewer list` still sends the word "list".
|
|
563
697
|
*/
|
|
564
|
-
function extractOp(argv) {
|
|
698
|
+
export function extractOp(argv) {
|
|
565
699
|
const first = argv[0];
|
|
566
700
|
if (first && !first.startsWith("-")) {
|
|
567
701
|
return { op: first, rest: argv.slice(1) };
|