@zswarm/core 0.2.5 → 0.2.6
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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/schema.d.ts +27 -0
- package/dist/schema.js +112 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type { RoutingContext } from "./ops/routing.js";
|
|
|
29
29
|
export type { DispatchDeps, OpsResult, ServeInstallDeps } from "./ops/types.js";
|
|
30
30
|
export { DEFAULT_DOCTOR_TIMEOUT_MS, DOCTOR_FAILED_CODE, DOCTOR_SCOPE_FIELD, DOCTOR_SCOPE_HOST, DOCTOR_TAILSCALE_MAX_MS, HOST_REPORT_INCOMPLETE_CODE, HOST_REPORT_INVALID_CODE, doctorOp, inspectDoctorHost, coverHostReport, hostDoctorRequest, isRequiredFailure, mergeHostReply, type DoctorCheck, type DoctorCheckScope, type DoctorCheckState, type DoctorReport, type DoctorRoute, type HostInspectInput, } from "./ops/doctor.js";
|
|
31
31
|
export { normalizeKey, normalizeKeys, tokenizeCommand } from "./keys.js";
|
|
32
|
-
export { cliUsage, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES, PARAMS, TARGET_OPS, type OpName, type ParamSpec, type ParamType, } from "./schema.js";
|
|
32
|
+
export { cliUsage, commandUsage, wantsHelp, extractOp, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES, PARAMS, TARGET_OPS, type OpName, type ParamSpec, type ParamType, } from "./schema.js";
|
|
33
33
|
export { HOST_COMMANDS, hostUsage, parseHostArgs, runHostCommand } from "./host/cli.js";
|
|
34
34
|
export { findPython, runSlot, slotScriptPath } from "./host/slot.js";
|
|
35
35
|
export { installServeService, serveServiceName, serveServiceSpec, serveTokenFromEnv, serveTokenPath, uninstallServeService, SERVE_AWAIT_SESSION_ENV, SERVE_TOKEN_FILE_ENV, type ServeServiceInput, } from "./host/serve-service.js";
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export { classify, lastLine, mapPool, peerStatus, DEFAULT_STATUS_TIMEOUT_MS, STA
|
|
|
27
27
|
export { normalizeScreen, unfoldScreen, truncateDumpText, DEFAULT_DUMP_MAX_CHARS, DEFAULT_WAIT_MAX_CHARS, } from "./ops/util.js";
|
|
28
28
|
export { DEFAULT_DOCTOR_TIMEOUT_MS, DOCTOR_FAILED_CODE, DOCTOR_SCOPE_FIELD, DOCTOR_SCOPE_HOST, DOCTOR_TAILSCALE_MAX_MS, HOST_REPORT_INCOMPLETE_CODE, HOST_REPORT_INVALID_CODE, doctorOp, inspectDoctorHost, coverHostReport, hostDoctorRequest, isRequiredFailure, mergeHostReply, } from "./ops/doctor.js";
|
|
29
29
|
export { normalizeKey, normalizeKeys, tokenizeCommand } from "./keys.js";
|
|
30
|
-
export { cliUsage, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES, PARAMS, TARGET_OPS, } from "./schema.js";
|
|
30
|
+
export { cliUsage, commandUsage, wantsHelp, extractOp, mcpInputSchema, parseCliArgv, MCP_TOOL_DESCRIPTION, OP_NAMES, PARAMS, TARGET_OPS, } from "./schema.js";
|
|
31
31
|
export { HOST_COMMANDS, hostUsage, parseHostArgs, runHostCommand } from "./host/cli.js";
|
|
32
32
|
export { findPython, runSlot, slotScriptPath } from "./host/slot.js";
|
|
33
33
|
export { installServeService, serveServiceName, serveServiceSpec, serveTokenFromEnv, serveTokenPath, uninstallServeService, SERVE_AWAIT_SESSION_ENV, SERVE_TOKEN_FILE_ENV, } from "./host/serve-service.js";
|
package/dist/schema.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type ParamSpec = {
|
|
|
12
12
|
type: ParamType;
|
|
13
13
|
/** CLI flags; empty means the parameter is reachable through MCP only. */
|
|
14
14
|
flags: string[];
|
|
15
|
+
/** Ops this flag belongs to; omitted means it applies to every op (routing/global flags). */
|
|
16
|
+
ops?: readonly OpName[];
|
|
15
17
|
/** Repeatable flags collect into an array (`--key a --key b`). */
|
|
16
18
|
repeat?: boolean;
|
|
17
19
|
/** Local CLI preprocessing, excluded from the MCP protocol. */
|
|
@@ -24,4 +26,29 @@ export declare const PARAMS: readonly ParamSpec[];
|
|
|
24
26
|
export declare function mcpInputSchema(): Record<string, unknown>;
|
|
25
27
|
export declare const MCP_TOOL_DESCRIPTION: string;
|
|
26
28
|
export declare function cliUsage(): string;
|
|
29
|
+
/**
|
|
30
|
+
* True when argv asks for help: `--help` or `-h` as a flag of its own, not the
|
|
31
|
+
* value of a flag that takes one (`--body -h` sends "-h") and not after `--`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function wantsHelp(argv: readonly string[]): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Per-command help for `zswarm <op> --help`: the usage line, the positional
|
|
36
|
+
* shorthand, and only the flags whose `ops` include this op. A flag without
|
|
37
|
+
* `ops` (session, --local, --ssh, --fresh, --serve) applies to every op.
|
|
38
|
+
* Render from the same PARAMS table that parses the flags, so they cannot drift.
|
|
39
|
+
*/
|
|
40
|
+
export declare function commandUsage(op: OpName): string;
|
|
41
|
+
/** Turn argv (without the op) into dispatch args, driven by PARAMS. */
|
|
42
|
+
/**
|
|
43
|
+
* Pull the op out of argv, tolerating flags before it.
|
|
44
|
+
*
|
|
45
|
+
* The op normally comes first. When it does not — `zswarm --session crew list`
|
|
46
|
+
* — the first token is a flag, and taking argv[0] blindly reported the flag as
|
|
47
|
+
* an unknown op. Only positions that already errored are affected: if argv[0]
|
|
48
|
+
* is a real op it wins, so `send reviewer list` still sends the word "list".
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractOp(argv: string[]): {
|
|
51
|
+
op: string;
|
|
52
|
+
rest: string[];
|
|
53
|
+
};
|
|
27
54
|
export declare function parseCliArgv(argv: string[]): Record<string, unknown>;
|
package/dist/schema.js
CHANGED
|
@@ -57,25 +57,29 @@ export const PARAMS = [
|
|
|
57
57
|
{
|
|
58
58
|
name: "to",
|
|
59
59
|
type: "string",
|
|
60
|
-
flags: ["--to", "-t"],
|
|
60
|
+
flags: ["--to", "-t", "--pane"],
|
|
61
|
+
ops: [...TARGET_OPS, "broadcast", "log"],
|
|
61
62
|
description: "target pane: id (3 / terminal_3) or unique title/command; broadcast takes a comma list; log filters by it",
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
name: "all",
|
|
65
66
|
type: "boolean",
|
|
66
67
|
flags: ["--all", "-a"],
|
|
68
|
+
ops: ["broadcast", "sessions"],
|
|
67
69
|
description: "broadcast: every terminal pane in the session; sessions: include EXITED resurrectable sessions",
|
|
68
70
|
},
|
|
69
71
|
{
|
|
70
72
|
name: "live",
|
|
71
73
|
type: "boolean",
|
|
72
74
|
flags: ["--live", "--active"],
|
|
75
|
+
ops: ["sessions"],
|
|
73
76
|
description: "sessions: only live (non-EXITED) sessions — this is the default; use --all to include EXITED",
|
|
74
77
|
},
|
|
75
78
|
{
|
|
76
79
|
name: "exited",
|
|
77
80
|
type: "boolean",
|
|
78
81
|
flags: ["--exited"],
|
|
82
|
+
ops: ["sessions"],
|
|
79
83
|
cliOnly: true,
|
|
80
84
|
description: "sessions: list only EXITED (resurrectable) sessions; rows carry name, exited, age and ageSeconds",
|
|
81
85
|
},
|
|
@@ -83,6 +87,7 @@ export const PARAMS = [
|
|
|
83
87
|
name: "pruneExited",
|
|
84
88
|
type: "boolean",
|
|
85
89
|
flags: ["--prune-exited"],
|
|
90
|
+
ops: ["sessions"],
|
|
86
91
|
cliOnly: true,
|
|
87
92
|
description: "sessions: delete EXITED sessions (all, or those matching --older-than) with zellij delete-session; a live session is never removed",
|
|
88
93
|
},
|
|
@@ -90,6 +95,7 @@ export const PARAMS = [
|
|
|
90
95
|
name: "olderThan",
|
|
91
96
|
type: "string",
|
|
92
97
|
flags: ["--older-than"],
|
|
98
|
+
ops: ["sessions"],
|
|
93
99
|
cliOnly: true,
|
|
94
100
|
description: "sessions --prune-exited: only delete sessions created at least this long ago (e.g. 7d, 12h, 30m; default all exited)",
|
|
95
101
|
},
|
|
@@ -97,6 +103,7 @@ export const PARAMS = [
|
|
|
97
103
|
name: "dryRun",
|
|
98
104
|
type: "boolean",
|
|
99
105
|
flags: ["--dry-run"],
|
|
106
|
+
ops: ["sessions"],
|
|
100
107
|
cliOnly: true,
|
|
101
108
|
description: "sessions --prune-exited: report what would be deleted without deleting",
|
|
102
109
|
},
|
|
@@ -104,6 +111,7 @@ export const PARAMS = [
|
|
|
104
111
|
name: "json",
|
|
105
112
|
type: "boolean",
|
|
106
113
|
flags: ["--json"],
|
|
114
|
+
ops: ["sessions"],
|
|
107
115
|
cliOnly: true,
|
|
108
116
|
description: "sessions: rows are name, exited, age and ageSeconds; the CLI prints JSON either way",
|
|
109
117
|
},
|
|
@@ -123,60 +131,70 @@ export const PARAMS = [
|
|
|
123
131
|
name: "group",
|
|
124
132
|
type: "string",
|
|
125
133
|
flags: ["--group", "-g"],
|
|
134
|
+
ops: ["broadcast"],
|
|
126
135
|
description: "broadcast: narrow the selection to panes whose title or command contains this",
|
|
127
136
|
},
|
|
128
137
|
{
|
|
129
138
|
name: "channel",
|
|
130
139
|
type: "string",
|
|
131
140
|
flags: ["--channel"],
|
|
141
|
+
ops: ["signal", "await"],
|
|
132
142
|
description: "signal/await: channel name",
|
|
133
143
|
},
|
|
134
144
|
{
|
|
135
145
|
name: "payload",
|
|
136
146
|
type: "string",
|
|
137
147
|
flags: ["--payload"],
|
|
148
|
+
ops: ["signal"],
|
|
138
149
|
description: "signal: short note stored with the post",
|
|
139
150
|
},
|
|
140
151
|
{
|
|
141
152
|
name: "count",
|
|
142
153
|
type: "number",
|
|
143
154
|
flags: ["--count"],
|
|
155
|
+
ops: ["await"],
|
|
144
156
|
description: "await: how many posts to wait for (default 1)",
|
|
145
157
|
},
|
|
146
158
|
{
|
|
147
159
|
name: "clear",
|
|
148
160
|
type: "boolean",
|
|
149
161
|
flags: ["--clear"],
|
|
162
|
+
ops: ["signal", "bus", "serve"],
|
|
150
163
|
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
164
|
},
|
|
152
165
|
{
|
|
153
166
|
name: "install",
|
|
154
167
|
type: "boolean",
|
|
155
168
|
flags: ["--install"],
|
|
169
|
+
ops: ["bus", "serve"],
|
|
156
170
|
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
171
|
},
|
|
158
172
|
{
|
|
159
173
|
name: "runAs",
|
|
160
174
|
type: "string",
|
|
161
175
|
flags: ["--run-as"],
|
|
176
|
+
ops: ["serve"],
|
|
162
177
|
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
178
|
},
|
|
164
179
|
{
|
|
165
180
|
name: "reset",
|
|
166
181
|
type: "boolean",
|
|
167
182
|
flags: ["--reset"],
|
|
183
|
+
ops: ["tail"],
|
|
168
184
|
description: "tail: forget the stored cursor and return the whole screen",
|
|
169
185
|
},
|
|
170
186
|
{
|
|
171
187
|
name: "sampleMs",
|
|
172
188
|
type: "number",
|
|
173
189
|
flags: ["--sample-ms"],
|
|
190
|
+
ops: ["status"],
|
|
174
191
|
description: "status: explicitly sample twice with this gap (fallback default 400); 0 reports running/exited only; default prefers bus changes",
|
|
175
192
|
},
|
|
176
193
|
{
|
|
177
194
|
name: "sinceLast",
|
|
178
195
|
type: "boolean",
|
|
179
196
|
flags: ["--since-last"],
|
|
197
|
+
ops: ["status"],
|
|
180
198
|
description: "status: classify changes since the previous bus observation (default when bus available); first observation is unknown unless a prompt is recognized",
|
|
181
199
|
},
|
|
182
200
|
{
|
|
@@ -195,30 +213,35 @@ export const PARAMS = [
|
|
|
195
213
|
name: "limit",
|
|
196
214
|
type: "number",
|
|
197
215
|
flags: ["--limit"],
|
|
216
|
+
ops: ["log"],
|
|
198
217
|
description: "log: how many entries to return (default 20)",
|
|
199
218
|
},
|
|
200
219
|
{
|
|
201
220
|
name: "since",
|
|
202
221
|
type: "string",
|
|
203
222
|
flags: ["--since"],
|
|
223
|
+
ops: ["log"],
|
|
204
224
|
description: "log: only entries at or after this epoch millisecond",
|
|
205
225
|
},
|
|
206
226
|
{
|
|
207
227
|
name: "failed",
|
|
208
228
|
type: "boolean",
|
|
209
229
|
flags: ["--failed"],
|
|
230
|
+
ops: ["log"],
|
|
210
231
|
description: "log: only deliveries that did not land",
|
|
211
232
|
},
|
|
212
233
|
{
|
|
213
234
|
name: "body",
|
|
214
235
|
type: "string",
|
|
215
236
|
flags: ["--body", "-b", "--text"],
|
|
237
|
+
ops: ["send", "broadcast"],
|
|
216
238
|
description: "send: message body",
|
|
217
239
|
},
|
|
218
240
|
{
|
|
219
241
|
name: "bodyFile",
|
|
220
242
|
type: "string",
|
|
221
243
|
flags: ["--body-file"],
|
|
244
|
+
ops: ["send"],
|
|
222
245
|
cliOnly: true,
|
|
223
246
|
description: "send: read UTF-8 on the caller from PATH, or - for stdin; cannot combine with --body/--text",
|
|
224
247
|
},
|
|
@@ -232,36 +255,42 @@ export const PARAMS = [
|
|
|
232
255
|
name: "from",
|
|
233
256
|
type: "string",
|
|
234
257
|
flags: ["--from", "-f"],
|
|
258
|
+
ops: ["send", "broadcast"],
|
|
235
259
|
description: "send: sender label in the [zswarm from=…] prefix (default: ZSWARM_FROM, else the sending pane's title, else swarm)",
|
|
236
260
|
},
|
|
237
261
|
{
|
|
238
262
|
name: "raw",
|
|
239
263
|
type: "boolean",
|
|
240
264
|
flags: ["--raw"],
|
|
265
|
+
ops: ["send", "broadcast"],
|
|
241
266
|
description: "send: skip the peer prefix (default false)",
|
|
242
267
|
},
|
|
243
268
|
{
|
|
244
269
|
name: "full",
|
|
245
270
|
type: "boolean",
|
|
246
271
|
flags: ["--full"],
|
|
272
|
+
ops: ["dump", "wait", "tail"],
|
|
247
273
|
description: "dump/wait: include full scrollback (default false)",
|
|
248
274
|
},
|
|
249
275
|
{
|
|
250
276
|
name: "max",
|
|
251
277
|
type: "number",
|
|
252
278
|
flags: ["--max"],
|
|
279
|
+
ops: ["dump", "wait", "tail", "layout", "diff"],
|
|
253
280
|
description: "dump/wait: max text chars (dump 8000, wait 2000; keeps tail, 0 = unlimited)",
|
|
254
281
|
},
|
|
255
282
|
{
|
|
256
283
|
name: "head",
|
|
257
284
|
type: "boolean",
|
|
258
285
|
flags: ["--head"],
|
|
286
|
+
ops: ["dump"],
|
|
259
287
|
description: "dump: keep the start instead of the tail when truncating",
|
|
260
288
|
},
|
|
261
289
|
{
|
|
262
290
|
name: "for",
|
|
263
291
|
type: "string",
|
|
264
292
|
flags: ["--for"],
|
|
293
|
+
ops: ["wait"],
|
|
265
294
|
values: ["idle", "match", "either"],
|
|
266
295
|
description: "wait: stop on a quiet screen, on a match, or whichever lands first (default: match if match= given, else idle)",
|
|
267
296
|
},
|
|
@@ -269,42 +298,49 @@ export const PARAMS = [
|
|
|
269
298
|
name: "match",
|
|
270
299
|
type: "string",
|
|
271
300
|
flags: ["--match", "-m"],
|
|
301
|
+
ops: ["wait"],
|
|
272
302
|
description: "wait: text to look for in the pane screen",
|
|
273
303
|
},
|
|
274
304
|
{
|
|
275
305
|
name: "regex",
|
|
276
306
|
type: "boolean",
|
|
277
307
|
flags: ["--regex"],
|
|
308
|
+
ops: ["wait"],
|
|
278
309
|
description: "wait: treat match as a regex (default false)",
|
|
279
310
|
},
|
|
280
311
|
{
|
|
281
312
|
name: "ignoreCase",
|
|
282
313
|
type: "boolean",
|
|
283
314
|
flags: ["--ignore-case"],
|
|
315
|
+
ops: ["wait"],
|
|
284
316
|
description: "wait: case-insensitive match (default false)",
|
|
285
317
|
},
|
|
286
318
|
{
|
|
287
319
|
name: "idleMs",
|
|
288
320
|
type: "number",
|
|
289
321
|
flags: ["--idle-ms"],
|
|
322
|
+
ops: ["wait"],
|
|
290
323
|
description: "wait: screen must be unchanged this long to count as idle (default 2000)",
|
|
291
324
|
},
|
|
292
325
|
{
|
|
293
326
|
name: "pollMs",
|
|
294
327
|
type: "number",
|
|
295
328
|
flags: ["--poll-ms"],
|
|
329
|
+
ops: ["wait"],
|
|
296
330
|
description: "wait: fallback poll interval (default 150; bus path polls at 50ms)",
|
|
297
331
|
},
|
|
298
332
|
{
|
|
299
333
|
name: "timeoutMs",
|
|
300
334
|
type: "number",
|
|
301
335
|
flags: ["--timeout-ms"],
|
|
336
|
+
ops: ["wait", "status", "spawn", "doctor", "serve", "send", "dump", "tail", "keys", "interrupt", "close", "await"],
|
|
302
337
|
description: "wait: timeout (default 60000); status/spawn: overall deadline (default 30000); doctor: overall deadline (default 10000), including Tailscale/SSH/hello/host checks; serve --install: overall install/readiness deadline (default 30000)",
|
|
303
338
|
},
|
|
304
339
|
{
|
|
305
340
|
name: "keys",
|
|
306
341
|
type: "stringOrArray",
|
|
307
342
|
flags: ["--key", "--keys", "-k"],
|
|
343
|
+
ops: ["keys", "interrupt"],
|
|
308
344
|
repeat: true,
|
|
309
345
|
description: 'keys: key specs, one per entry — "Ctrl c", "Esc", "F1", "Up". A bare string is one key; comma-separate for several.',
|
|
310
346
|
},
|
|
@@ -312,72 +348,84 @@ export const PARAMS = [
|
|
|
312
348
|
name: "chars",
|
|
313
349
|
type: "string",
|
|
314
350
|
flags: ["--chars"],
|
|
351
|
+
ops: ["keys"],
|
|
315
352
|
description: "keys: literal characters to type instead of key specs (no Enter unless enter=true)",
|
|
316
353
|
},
|
|
317
354
|
{
|
|
318
355
|
name: "enter",
|
|
319
356
|
type: "boolean",
|
|
320
357
|
flags: ["--enter"],
|
|
358
|
+
ops: ["keys"],
|
|
321
359
|
description: "keys: press Enter after the keys/chars",
|
|
322
360
|
},
|
|
323
361
|
{
|
|
324
362
|
name: "hard",
|
|
325
363
|
type: "boolean",
|
|
326
364
|
flags: ["--hard"],
|
|
365
|
+
ops: ["interrupt"],
|
|
327
366
|
description: "interrupt: send Ctrl c instead of the default Esc",
|
|
328
367
|
},
|
|
329
368
|
{
|
|
330
369
|
name: "command",
|
|
331
370
|
type: "stringOrArray",
|
|
332
371
|
flags: ["--command", "--cmd", "-c"],
|
|
372
|
+
ops: ["spawn"],
|
|
333
373
|
description: "spawn: program to run in the new pane, argv-style (no shell). Empty starts a plain shell.",
|
|
334
374
|
},
|
|
335
375
|
{
|
|
336
376
|
name: "cwd",
|
|
337
377
|
type: "string",
|
|
338
378
|
flags: ["--cwd"],
|
|
379
|
+
ops: ["spawn", "worktrees", "unworktree", "diff", "checkpoint"],
|
|
339
380
|
description: "spawn: working directory for the new pane; worktrees/unworktree: any directory inside the repo",
|
|
340
381
|
},
|
|
341
382
|
{
|
|
342
383
|
name: "worktree",
|
|
343
384
|
type: "string",
|
|
344
385
|
flags: ["--worktree", "-w"],
|
|
386
|
+
ops: ["spawn", "unworktree"],
|
|
345
387
|
description: "spawn: branch to give the peer its own git worktree (overrides cwd); unworktree: alias for branch",
|
|
346
388
|
},
|
|
347
389
|
{
|
|
348
390
|
name: "worktreeRoot",
|
|
349
391
|
type: "string",
|
|
350
392
|
flags: ["--worktree-root"],
|
|
393
|
+
ops: ["spawn", "unworktree"],
|
|
351
394
|
description: "where worktrees live (default <repo>-worktrees beside the repo, or ZSWARM_WORKTREE_ROOT)",
|
|
352
395
|
},
|
|
353
396
|
{
|
|
354
397
|
name: "baseRef",
|
|
355
398
|
type: "string",
|
|
356
399
|
flags: ["--base-ref", "--base"],
|
|
400
|
+
ops: ["spawn"],
|
|
357
401
|
description: "spawn: ref to branch from when the worktree branch is new",
|
|
358
402
|
},
|
|
359
403
|
{
|
|
360
404
|
name: "path",
|
|
361
405
|
type: "string",
|
|
362
406
|
flags: ["--path"],
|
|
407
|
+
ops: ["unworktree", "diff", "checkpoint"],
|
|
363
408
|
description: "unworktree: worktree path to remove",
|
|
364
409
|
},
|
|
365
410
|
{
|
|
366
411
|
name: "branch",
|
|
367
412
|
type: "string",
|
|
368
413
|
flags: ["--branch"],
|
|
414
|
+
ops: ["unworktree", "diff", "checkpoint"],
|
|
369
415
|
description: "unworktree: remove the worktree holding this branch",
|
|
370
416
|
},
|
|
371
417
|
{
|
|
372
418
|
name: "name",
|
|
373
419
|
type: "string",
|
|
374
420
|
flags: ["--name", "-n"],
|
|
421
|
+
ops: ["spawn", "rename"],
|
|
375
422
|
description: "spawn: pane (or tab) name; rename: the new name",
|
|
376
423
|
},
|
|
377
424
|
{
|
|
378
425
|
name: "submit",
|
|
379
426
|
type: "string",
|
|
380
427
|
flags: ["--submit"],
|
|
428
|
+
ops: ["send", "broadcast"],
|
|
381
429
|
values: ["auto", "double-enter", "none"],
|
|
382
430
|
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
431
|
},
|
|
@@ -385,48 +433,56 @@ export const PARAMS = [
|
|
|
385
433
|
name: "observeMs",
|
|
386
434
|
type: "number",
|
|
387
435
|
flags: ["--observe-ms"],
|
|
436
|
+
ops: ["send", "dump", "tail", "wait", "keys", "interrupt", "close", "spawn"],
|
|
388
437
|
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
438
|
},
|
|
390
439
|
{
|
|
391
440
|
name: "settleMs",
|
|
392
441
|
type: "number",
|
|
393
442
|
flags: ["--settle-ms"],
|
|
443
|
+
ops: ["send", "broadcast"],
|
|
394
444
|
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
445
|
},
|
|
396
446
|
{
|
|
397
447
|
name: "confirm",
|
|
398
448
|
type: "boolean",
|
|
399
449
|
flags: ["--confirm"],
|
|
450
|
+
ops: ["send", "broadcast"],
|
|
400
451
|
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
452
|
},
|
|
402
453
|
{
|
|
403
454
|
name: "ifIdle",
|
|
404
455
|
type: "boolean",
|
|
405
456
|
flags: ["--if-idle"],
|
|
457
|
+
ops: ["send"],
|
|
406
458
|
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
459
|
},
|
|
408
460
|
{
|
|
409
461
|
name: "expect",
|
|
410
462
|
type: "string",
|
|
411
463
|
flags: ["--expect"],
|
|
464
|
+
ops: ["send", "keys", "interrupt"],
|
|
412
465
|
description: "send/keys/interrupt: case-insensitive substring required on the current screen immediately before input",
|
|
413
466
|
},
|
|
414
467
|
{
|
|
415
468
|
name: "message",
|
|
416
469
|
type: "string",
|
|
417
470
|
flags: ["--message"],
|
|
471
|
+
ops: ["checkpoint"],
|
|
418
472
|
description: "checkpoint: commit message",
|
|
419
473
|
},
|
|
420
474
|
{
|
|
421
475
|
name: "stat",
|
|
422
476
|
type: "boolean",
|
|
423
477
|
flags: ["--stat"],
|
|
478
|
+
ops: ["diff"],
|
|
424
479
|
description: "diff: stat only, no patch body",
|
|
425
480
|
},
|
|
426
481
|
{
|
|
427
482
|
name: "direction",
|
|
428
483
|
type: "string",
|
|
429
484
|
flags: ["--direction", "-d"],
|
|
485
|
+
ops: ["spawn"],
|
|
430
486
|
values: ["right", "left", "up", "down"],
|
|
431
487
|
description: "spawn: split direction",
|
|
432
488
|
},
|
|
@@ -434,66 +490,77 @@ export const PARAMS = [
|
|
|
434
490
|
name: "floating",
|
|
435
491
|
type: "boolean",
|
|
436
492
|
flags: ["--floating"],
|
|
493
|
+
ops: ["spawn"],
|
|
437
494
|
description: "spawn: open the pane floating",
|
|
438
495
|
},
|
|
439
496
|
{
|
|
440
497
|
name: "width",
|
|
441
498
|
type: "string",
|
|
442
499
|
flags: ["--width"],
|
|
500
|
+
ops: ["spawn"],
|
|
443
501
|
description: "spawn: floating pane width (e.g. 80 or 50%)",
|
|
444
502
|
},
|
|
445
503
|
{
|
|
446
504
|
name: "height",
|
|
447
505
|
type: "string",
|
|
448
506
|
flags: ["--height"],
|
|
507
|
+
ops: ["spawn"],
|
|
449
508
|
description: "spawn: floating pane height (e.g. 20 or 40%)",
|
|
450
509
|
},
|
|
451
510
|
{
|
|
452
511
|
name: "tab",
|
|
453
512
|
type: "string",
|
|
454
513
|
flags: ["--tab"],
|
|
514
|
+
ops: ["broadcast", "rename", "spawn"],
|
|
455
515
|
description: "tab name: broadcast targets it, rename retitles it, spawn opens the new pane's tab by it",
|
|
456
516
|
},
|
|
457
517
|
{
|
|
458
518
|
name: "newTab",
|
|
459
519
|
type: "boolean",
|
|
460
520
|
flags: ["--new-tab"],
|
|
521
|
+
ops: ["spawn"],
|
|
461
522
|
description: "spawn: open a new tab instead of splitting",
|
|
462
523
|
},
|
|
463
524
|
{
|
|
464
525
|
name: "layout",
|
|
465
526
|
type: "string",
|
|
466
527
|
flags: ["--layout", "-l"],
|
|
528
|
+
ops: ["spawn"],
|
|
467
529
|
description: "spawn: layout name for the new tab (newTab=true)",
|
|
468
530
|
},
|
|
469
531
|
{
|
|
470
532
|
name: "closeOnExit",
|
|
471
533
|
type: "boolean",
|
|
472
534
|
flags: ["--close-on-exit"],
|
|
535
|
+
ops: ["spawn"],
|
|
473
536
|
description: "spawn: close the pane when its command exits",
|
|
474
537
|
},
|
|
475
538
|
{
|
|
476
539
|
name: "allowSelf",
|
|
477
540
|
type: "boolean",
|
|
478
541
|
flags: ["--allow-self"],
|
|
542
|
+
ops: ["send", "keys", "close", "interrupt", "broadcast"],
|
|
479
543
|
description: "send/keys/close: allow targeting zswarm's own pane (default false)",
|
|
480
544
|
},
|
|
481
545
|
{
|
|
482
546
|
name: "force",
|
|
483
547
|
type: "boolean",
|
|
484
548
|
flags: ["--force"],
|
|
549
|
+
ops: ["send", "keys", "unworktree", "bus", "interrupt", "broadcast"],
|
|
485
550
|
description: "send/keys: write to a pane whose command has exited; unworktree: remove a busy or dirty worktree; bus: close orphan bus panes and reload this session's plugin",
|
|
486
551
|
},
|
|
487
552
|
{
|
|
488
553
|
name: "listen",
|
|
489
554
|
type: "string",
|
|
490
555
|
flags: ["--listen"],
|
|
556
|
+
ops: ["serve"],
|
|
491
557
|
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
558
|
},
|
|
493
559
|
{
|
|
494
560
|
name: "verbose",
|
|
495
561
|
type: "boolean",
|
|
496
562
|
flags: ["--verbose", "-v"],
|
|
563
|
+
ops: ["list", "send", "spawn", "status"],
|
|
497
564
|
description: "list/send/spawn: include cwd/focus/exited/floating (and the pane on send/spawn)",
|
|
498
565
|
},
|
|
499
566
|
];
|
|
@@ -552,6 +619,49 @@ export function cliUsage() {
|
|
|
552
619
|
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
620
|
return lines.join("\n");
|
|
554
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* True when argv asks for help: `--help` or `-h` as a flag of its own, not the
|
|
624
|
+
* value of a flag that takes one (`--body -h` sends "-h") and not after `--`.
|
|
625
|
+
*/
|
|
626
|
+
export function wantsHelp(argv) {
|
|
627
|
+
const valued = new Set(PARAMS.filter((p) => p.type !== "boolean").flatMap((p) => p.flags));
|
|
628
|
+
for (let i = 0; i < argv.length; i++) {
|
|
629
|
+
const arg = argv[i];
|
|
630
|
+
if (arg === "--")
|
|
631
|
+
return false;
|
|
632
|
+
if (arg === "--help" || arg === "-h")
|
|
633
|
+
return true;
|
|
634
|
+
if (valued.has(arg))
|
|
635
|
+
i++; // its value may be anything, "-h" included
|
|
636
|
+
}
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Per-command help for `zswarm <op> --help`: the usage line, the positional
|
|
641
|
+
* shorthand, and only the flags whose `ops` include this op. A flag without
|
|
642
|
+
* `ops` (session, --local, --ssh, --fresh, --serve) applies to every op.
|
|
643
|
+
* Render from the same PARAMS table that parses the flags, so they cannot drift.
|
|
644
|
+
*/
|
|
645
|
+
export function commandUsage(op) {
|
|
646
|
+
const lines = [`usage: zswarm ${op} [options]`, ""];
|
|
647
|
+
const positional = op === "send"
|
|
648
|
+
? " positional: first bare argument is --to, second is --body"
|
|
649
|
+
: TARGET_OPS.includes(op)
|
|
650
|
+
? " positional: first bare argument is --to"
|
|
651
|
+
: undefined;
|
|
652
|
+
if (positional)
|
|
653
|
+
lines.push(positional, "");
|
|
654
|
+
for (const param of PARAMS) {
|
|
655
|
+
if (param.flags.length === 0)
|
|
656
|
+
continue;
|
|
657
|
+
if (param.ops && !param.ops.includes(op))
|
|
658
|
+
continue;
|
|
659
|
+
const value = param.type === "boolean" ? "" : param.type === "number" ? " N" : " VALUE";
|
|
660
|
+
lines.push(` ${param.flags.join(", ").padEnd(28)}${value.trim().padEnd(6)}${param.description}`);
|
|
661
|
+
}
|
|
662
|
+
lines.push("");
|
|
663
|
+
return lines.join("\n");
|
|
664
|
+
}
|
|
555
665
|
/** Turn argv (without the op) into dispatch args, driven by PARAMS. */
|
|
556
666
|
/**
|
|
557
667
|
* Pull the op out of argv, tolerating flags before it.
|
|
@@ -561,7 +671,7 @@ export function cliUsage() {
|
|
|
561
671
|
* an unknown op. Only positions that already errored are affected: if argv[0]
|
|
562
672
|
* is a real op it wins, so `send reviewer list` still sends the word "list".
|
|
563
673
|
*/
|
|
564
|
-
function extractOp(argv) {
|
|
674
|
+
export function extractOp(argv) {
|
|
565
675
|
const first = argv[0];
|
|
566
676
|
if (first && !first.startsWith("-")) {
|
|
567
677
|
return { op: first, rest: argv.slice(1) };
|