@phyzess/pappra 0.1.0-beta.18 → 0.1.0-beta.19

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.
@@ -0,0 +1,604 @@
1
+ import { failure, hasContinuityOptions } from './options.js';
2
+ import { collaborationUsage, runCollaborationCommand, } from './commands/collaboration.js';
3
+ import { collaborationMessageUsage, runCollaborationMessageCommand, } from './commands/collaboration-message.js';
4
+ import { collaborationPreflightUsage, runCollaborationPreflightCommand, } from './commands/collaboration-preflight.js';
5
+ import { collaborationCapabilitiesUsage, runCollaborationCapabilitiesCommand, } from './commands/collaboration-capabilities.js';
6
+ import { collaborationStateUsage, runCollaborationStateCommand, } from './commands/collaboration-state.js';
7
+ import { collaborationResourcesUsage, runCollaborationResourcesCommand, } from './commands/collaboration-resources.js';
8
+ import { collaborationHandoffUsage, runCollaborationHandoffCommand, } from './commands/collaboration-handoff.js';
9
+ import { collaborationRecoveryUsage, runCollaborationRecoveryCommand, } from './commands/collaboration-recovery.js';
10
+ import { collaborationRecoveryRunUsage, parseCollaborationRecoveryRunArgs, runCollaborationRecoveryRunCommand, } from './commands/collaboration-recovery-run.js';
11
+ import { collaborationWorkRunUsage, parseCollaborationWorkRunArgs, runCollaborationWorkRunCommand, } from './commands/collaboration-work-run.js';
12
+ import { collaborationBindingUsage, runCollaborationBindingCommand, } from './commands/collaboration-binding.js';
13
+ import { collaborationPlanUsage, runCollaborationPlanCommand, } from './commands/collaboration-plan.js';
14
+ import { collaborationRolloverUsage, runCollaborationRolloverCommand, } from './commands/collaboration-rollover.js';
15
+ import { collaborationBootstrapUsage, runCollaborationBootstrapCommand, } from './commands/collaboration-bootstrap.js';
16
+ import { collaborationTransitionUsage, runCollaborationTransitionCommand, } from './commands/collaboration-transition.js';
17
+ export async function routeCollaboration(request) {
18
+ const { values, args, info, output, json } = request;
19
+ const { action: collaborationAction, rpcRequestTimeout, rpcOperationTimeout, } = request;
20
+ if (values.help) {
21
+ const usage = collaborationAction === 'recovery-run'
22
+ ? collaborationRecoveryRunUsage
23
+ : collaborationAction === 'work-run'
24
+ ? collaborationWorkRunUsage
25
+ : collaborationAction === 'transition' ||
26
+ collaborationAction?.startsWith('transition:') === true
27
+ ? collaborationTransitionUsage
28
+ : collaborationAction === 'bootstrap' ||
29
+ collaborationAction?.startsWith('bootstrap:') === true
30
+ ? collaborationBootstrapUsage
31
+ : collaborationAction === 'message' ||
32
+ collaborationAction?.startsWith('message:') === true
33
+ ? collaborationMessageUsage
34
+ : collaborationAction?.startsWith('capabilities:') === true
35
+ ? collaborationCapabilitiesUsage
36
+ : collaborationAction?.startsWith('state:') === true
37
+ ? collaborationStateUsage
38
+ : collaborationAction?.startsWith('resource:') === true
39
+ ? collaborationResourcesUsage
40
+ : collaborationAction?.startsWith('handoff:') === true
41
+ ? collaborationHandoffUsage
42
+ : collaborationAction?.startsWith('recovery:') === true
43
+ ? collaborationRecoveryUsage
44
+ : collaborationAction?.startsWith('binding:') === true
45
+ ? collaborationBindingUsage
46
+ : collaborationAction === 'plan'
47
+ ? collaborationPlanUsage
48
+ : collaborationAction?.startsWith('rollover:') ===
49
+ true || collaborationAction === 'rollover'
50
+ ? collaborationRolloverUsage
51
+ : collaborationAction === 'preflight'
52
+ ? collaborationPreflightUsage
53
+ : collaborationUsage;
54
+ if (json) {
55
+ output.stdout(`${JSON.stringify({ ...info, commands: ['collab'], usage })}\n`);
56
+ }
57
+ else {
58
+ output.stdout(usage);
59
+ }
60
+ return 0;
61
+ }
62
+ if (collaborationAction === 'work-run') {
63
+ const allowed = new Set(['request', 'apply', 'json']);
64
+ const extra = Object.entries(values)
65
+ .filter(([, value]) => value !== undefined)
66
+ .map(([key]) => key)
67
+ .filter((key) => !allowed.has(key));
68
+ const parsedWork = parseCollaborationWorkRunArgs(args.slice(2));
69
+ if (extra.length || parsedWork.errors.length) {
70
+ failure(output, json, 'invalid_arguments', `collab work-run accepts only --request, --apply and --json.${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}${parsedWork.errors.length ? ` ${parsedWork.errors.join(' ')}` : ''}\n${collaborationWorkRunUsage}`);
71
+ return 2;
72
+ }
73
+ return runCollaborationWorkRunCommand({ ...parsedWork.options, json }, output);
74
+ }
75
+ if (collaborationAction === 'recovery-run') {
76
+ const allowed = new Set(['request', 'apply', 'json']);
77
+ const extra = Object.entries(values)
78
+ .filter(([, value]) => value !== undefined)
79
+ .map(([key]) => key)
80
+ .filter((key) => !allowed.has(key));
81
+ const parsedRecovery = parseCollaborationRecoveryRunArgs(args.slice(2));
82
+ if (extra.length || parsedRecovery.errors.length) {
83
+ failure(output, json, 'invalid_arguments', `collab recovery-run accepts only --request, --apply and --json.${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}${parsedRecovery.errors.length ? ` ${parsedRecovery.errors.join(' ')}` : ''}\n${collaborationRecoveryRunUsage}`);
84
+ return 2;
85
+ }
86
+ return runCollaborationRecoveryRunCommand({ ...parsedRecovery.options, json }, output);
87
+ }
88
+ if (collaborationAction === 'capabilities:derive') {
89
+ const duplicate = [
90
+ '--live',
91
+ '--harness',
92
+ '--assignment',
93
+ '--template',
94
+ '--execution',
95
+ '--session',
96
+ '--events',
97
+ ].filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
98
+ .length > 1);
99
+ if (duplicate.length) {
100
+ failure(output, json, 'invalid_arguments', `collab capabilities derive rejects duplicate option(s): ${duplicate.join(', ')}.\n${collaborationCapabilitiesUsage}`);
101
+ return 2;
102
+ }
103
+ const allowed = new Set([
104
+ 'live',
105
+ 'assignment',
106
+ 'harness',
107
+ 'template',
108
+ 'execution',
109
+ 'session',
110
+ 'events',
111
+ 'json',
112
+ ]);
113
+ const extra = Object.entries(values)
114
+ .filter(([, value]) => value !== undefined)
115
+ .map(([key]) => key)
116
+ .filter((key) => !allowed.has(key));
117
+ if (extra.length) {
118
+ failure(output, json, 'invalid_arguments', `collab capabilities derive accepts only its own options: ${extra.join(', ')}.\n${collaborationCapabilitiesUsage}`);
119
+ return 2;
120
+ }
121
+ return runCollaborationCapabilitiesCommand({
122
+ harness: values.harness ?? null,
123
+ assignmentFile: values.assignment ?? null,
124
+ templateFile: values.template ?? null,
125
+ executionFile: values.execution ?? null,
126
+ sessionFile: values.session ?? null,
127
+ eventsFile: values.events ?? null,
128
+ live: values.live ?? false,
129
+ json,
130
+ }, output);
131
+ }
132
+ if (collaborationAction?.startsWith('state:')) {
133
+ const selected = collaborationAction.slice('state:'.length);
134
+ const stateAction = selected === 'show' || selected === 'doctor' || selected === 'epoch-check'
135
+ ? selected
136
+ : null;
137
+ const stateFlags = stateAction === 'epoch-check'
138
+ ? ['--task-root', '--owner-epoch']
139
+ : ['--task-root'];
140
+ const duplicate = stateFlags.filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
141
+ .length > 1);
142
+ const allowed = new Set([
143
+ 'task-root',
144
+ 'json',
145
+ ...(stateAction === 'epoch-check' ? ['owner-epoch'] : []),
146
+ ]);
147
+ const extra = Object.entries(values)
148
+ .filter(([, value]) => value !== undefined)
149
+ .map(([key]) => key)
150
+ .filter((key) => !allowed.has(key));
151
+ if (stateAction === null || duplicate.length || extra.length) {
152
+ failure(output, json, 'invalid_arguments', `collab state accepts only show/doctor/epoch-check and their own options.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationStateUsage}`);
153
+ return 2;
154
+ }
155
+ return runCollaborationStateCommand({
156
+ action: stateAction,
157
+ taskRoot: values['task-root'] ?? null,
158
+ ownerEpoch: values['owner-epoch'] ?? null,
159
+ json,
160
+ }, output);
161
+ }
162
+ if (collaborationAction?.startsWith('resource:')) {
163
+ const selected = collaborationAction.slice('resource:'.length);
164
+ const resourceAction = selected === 'list' || selected === 'claim' || selected === 'release'
165
+ ? selected
166
+ : null;
167
+ const resourceFlags = resourceAction === 'list'
168
+ ? ['--task-root']
169
+ : ['--task-root', '--request'];
170
+ const duplicate = resourceFlags.filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
171
+ .length > 1);
172
+ const allowed = new Set([
173
+ 'task-root',
174
+ 'json',
175
+ ...(resourceAction === 'list' ? [] : ['request', 'apply']),
176
+ ]);
177
+ const extra = Object.entries(values)
178
+ .filter(([, value]) => value !== undefined)
179
+ .map(([key]) => key)
180
+ .filter((key) => !allowed.has(key));
181
+ if (resourceAction === null || duplicate.length || extra.length) {
182
+ failure(output, json, 'invalid_arguments', `collab resource accepts only list/claim/release and their own options.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationResourcesUsage}`);
183
+ return 2;
184
+ }
185
+ return runCollaborationResourcesCommand({
186
+ action: resourceAction,
187
+ taskRoot: values['task-root'] ?? null,
188
+ requestFile: values.request ?? null,
189
+ apply: values.apply === true,
190
+ json,
191
+ }, output);
192
+ }
193
+ if (collaborationAction?.startsWith('handoff:')) {
194
+ const selected = collaborationAction.slice('handoff:'.length);
195
+ const handoffAction = selected === 'inventory' ||
196
+ selected === 'begin' ||
197
+ selected === 'stopped' ||
198
+ selected === 'rebind' ||
199
+ selected === 'transfer' ||
200
+ selected === 'confirm' ||
201
+ selected === 'complete' ||
202
+ selected === 'abort' ||
203
+ selected === 'release-dispatch'
204
+ ? selected
205
+ : null;
206
+ const duplicateFlags = handoffAction === 'inventory'
207
+ ? ['--task-root', '--subtask-id', '--attempt']
208
+ : ['--task-root', '--request'];
209
+ const duplicate = duplicateFlags.filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
210
+ .length > 1);
211
+ const allowed = new Set([
212
+ 'task-root',
213
+ 'json',
214
+ ...(handoffAction === 'inventory'
215
+ ? ['subtask-id', 'attempt']
216
+ : ['request', 'apply']),
217
+ ]);
218
+ const extra = Object.entries(values)
219
+ .filter(([, value]) => value !== undefined)
220
+ .map(([key]) => key)
221
+ .filter((key) => !allowed.has(key));
222
+ if (handoffAction === null || duplicate.length || extra.length) {
223
+ failure(output, json, 'invalid_arguments', `collab handoff accepts only inventory or a handoff mutation action and their own options.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationHandoffUsage}`);
224
+ return 2;
225
+ }
226
+ return runCollaborationHandoffCommand({
227
+ action: handoffAction,
228
+ taskRoot: values['task-root'] ?? null,
229
+ requestFile: values.request ?? null,
230
+ subtaskId: values['subtask-id'] ?? null,
231
+ attempt: values.attempt ?? null,
232
+ apply: values.apply === true,
233
+ json,
234
+ }, output);
235
+ }
236
+ if (collaborationAction?.startsWith('recovery:')) {
237
+ const selected = collaborationAction.slice('recovery:'.length);
238
+ const recoveryAction = selected === 'inspect' ||
239
+ selected === 'reconcile' ||
240
+ selected === 'lock-break'
241
+ ? selected
242
+ : null;
243
+ const duplicateFlags = recoveryAction === 'inspect'
244
+ ? ['--task-root']
245
+ : ['--task-root', '--request'];
246
+ const duplicate = duplicateFlags.filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
247
+ .length > 1);
248
+ const allowed = new Set([
249
+ 'task-root',
250
+ 'json',
251
+ ...(recoveryAction === 'inspect' ? [] : ['request', 'apply']),
252
+ ]);
253
+ const extra = Object.entries(values)
254
+ .filter(([, value]) => value !== undefined)
255
+ .map(([key]) => key)
256
+ .filter((key) => !allowed.has(key));
257
+ if (recoveryAction === null || duplicate.length || extra.length) {
258
+ failure(output, json, 'invalid_arguments', `collab recovery accepts only inspect/reconcile/lock-break and their own options.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationRecoveryUsage}`);
259
+ return 2;
260
+ }
261
+ return runCollaborationRecoveryCommand({
262
+ action: recoveryAction,
263
+ taskRoot: values['task-root'] ?? null,
264
+ requestFile: values.request ?? null,
265
+ apply: values.apply === true,
266
+ json,
267
+ }, output);
268
+ }
269
+ if (collaborationAction?.startsWith('binding:')) {
270
+ const selected = collaborationAction.slice('binding:'.length);
271
+ const bindingAction = selected === 'list' ||
272
+ selected === 'resolve' ||
273
+ selected === 'bind' ||
274
+ selected === 'unbind'
275
+ ? selected
276
+ : null;
277
+ const allowedFlags = bindingAction === 'list'
278
+ ? ['root']
279
+ : bindingAction === 'resolve'
280
+ ? ['task-id', 'root', 'roots']
281
+ : bindingAction === 'bind'
282
+ ? ['task-id', 'record', 'root', 'apply']
283
+ : bindingAction === 'unbind'
284
+ ? ['task-id', 'root', 'apply']
285
+ : [];
286
+ const duplicate = allowedFlags.filter((flag) => args.filter((arg) => arg === `--${flag}` || arg.startsWith(`--${flag}=`)).length > 1);
287
+ const allowed = new Set([...allowedFlags, 'json']);
288
+ const extra = Object.entries(values)
289
+ .filter(([, value]) => value !== undefined)
290
+ .map(([key]) => key)
291
+ .filter((key) => !allowed.has(key));
292
+ const missing = bindingAction === null
293
+ ? []
294
+ : [
295
+ ...(bindingAction === 'resolve' ||
296
+ bindingAction === 'bind' ||
297
+ bindingAction === 'unbind'
298
+ ? ['task-id']
299
+ : []),
300
+ ...(bindingAction === 'bind' ? ['record'] : []),
301
+ ].filter((flag) => values[flag] === undefined ||
302
+ values[flag] === null);
303
+ if (bindingAction === null ||
304
+ duplicate.length ||
305
+ extra.length ||
306
+ missing.length) {
307
+ failure(output, json, 'invalid_arguments', `collab binding accepts only list/resolve/bind/unbind and their own options.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}${missing.length ? ` Missing: ${missing.join(', ')}.` : ''}\n${collaborationBindingUsage}`);
308
+ return 2;
309
+ }
310
+ return runCollaborationBindingCommand({
311
+ action: bindingAction,
312
+ root: values.root ?? null,
313
+ taskId: values['task-id'] ?? null,
314
+ record: values.record ?? null,
315
+ roots: values.roots ?? null,
316
+ apply: values.apply === true,
317
+ json,
318
+ }, output);
319
+ }
320
+ if (collaborationAction === 'transition' ||
321
+ collaborationAction?.startsWith('transition:') === true) {
322
+ const selected = collaborationAction === 'transition'
323
+ ? null
324
+ : collaborationAction.slice('transition:'.length);
325
+ const transitionAction = selected === 'plan' || selected === 'apply' ? selected : null;
326
+ const duplicate = ['--task-root', '--request'].filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
327
+ .length > 1);
328
+ const allowed = new Set(['task-root', 'request', 'json']);
329
+ const extra = Object.entries(values)
330
+ .filter(([, value]) => value !== undefined)
331
+ .map(([key]) => key)
332
+ .filter((key) => !allowed.has(key));
333
+ if (transitionAction === null || duplicate.length || extra.length) {
334
+ failure(output, json, 'invalid_arguments', `collab transition accepts only plan|apply with --task-root, --request and --json.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}${transitionAction === null ? ' Missing: plan or apply.' : ''}\n${collaborationTransitionUsage}`);
335
+ return 2;
336
+ }
337
+ return runCollaborationTransitionCommand({
338
+ action: transitionAction,
339
+ taskRoot: values['task-root'] ?? null,
340
+ requestFile: values.request ?? null,
341
+ json,
342
+ }, output);
343
+ }
344
+ if (collaborationAction?.startsWith('rollover:') ||
345
+ collaborationAction === 'rollover') {
346
+ const selected = collaborationAction === 'rollover'
347
+ ? null
348
+ : collaborationAction.slice('rollover:'.length);
349
+ const rolloverAction = selected === 'inspect' || selected === 'plan' ? selected : null;
350
+ const duplicate = ['--task-root', '--request'].filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
351
+ .length > 1);
352
+ const allowed = new Set(['task-root', 'request', 'json']);
353
+ const extra = Object.entries(values)
354
+ .filter(([, value]) => value !== undefined)
355
+ .map(([key]) => key)
356
+ .filter((key) => !allowed.has(key));
357
+ if (rolloverAction === null || duplicate.length || extra.length) {
358
+ failure(output, json, 'invalid_arguments', `collab rollover accepts only inspect or plan with --task-root, --request and --json.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}${rolloverAction === null ? ' Missing: inspect or plan.' : ''}\n${collaborationRolloverUsage}`);
359
+ return 2;
360
+ }
361
+ return runCollaborationRolloverCommand({
362
+ action: rolloverAction,
363
+ taskRoot: values['task-root'] ?? null,
364
+ requestFile: values.request ?? null,
365
+ json,
366
+ }, output);
367
+ }
368
+ if (collaborationAction === 'plan') {
369
+ // `plan` is the only collab action that reads --config: the plan document is an
370
+ // explicit bounded file, not a global flag other commands silently accept.
371
+ const duplicate = ['--task-root', '--config'].filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
372
+ .length > 1);
373
+ const allowed = new Set(['task-root', 'config', 'json']);
374
+ const extra = Object.entries(values)
375
+ .filter(([, value]) => value !== undefined)
376
+ .map(([key]) => key)
377
+ .filter((key) => !allowed.has(key));
378
+ if (duplicate.length || extra.length) {
379
+ failure(output, json, 'invalid_arguments', `collab plan accepts only --task-root, --config and --json.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationPlanUsage}`);
380
+ return 2;
381
+ }
382
+ return runCollaborationPlanCommand({
383
+ taskRoot: values['task-root'] ?? null,
384
+ planFile: values.config ?? null,
385
+ json,
386
+ }, output);
387
+ }
388
+ if (collaborationAction === 'bootstrap' ||
389
+ collaborationAction?.startsWith('bootstrap:') === true) {
390
+ const selected = collaborationAction === 'bootstrap'
391
+ ? null
392
+ : collaborationAction.slice('bootstrap:'.length);
393
+ const action = selected === 'plan' || selected === 'apply' ? selected : null;
394
+ const duplicate = ['--task-root', '--request'].filter((flag) => args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`))
395
+ .length > 1);
396
+ const allowed = new Set(['task-root', 'request', 'json']);
397
+ const extra = Object.entries(values)
398
+ .filter(([, value]) => value !== undefined)
399
+ .map(([key]) => key)
400
+ .filter((key) => !allowed.has(key));
401
+ if (action === null || duplicate.length || extra.length) {
402
+ failure(output, json, 'invalid_arguments', `collab bootstrap requires plan|apply and only --task-root, --request and --json.${duplicate.length ? ` Duplicate: ${duplicate.join(', ')}.` : ''}${extra.length ? ` Unexpected: ${extra.join(', ')}.` : ''}\n${collaborationBootstrapUsage}`);
403
+ return 2;
404
+ }
405
+ return runCollaborationBootstrapCommand({
406
+ action,
407
+ taskRoot: values['task-root'] ?? null,
408
+ requestFile: values.request ?? null,
409
+ json,
410
+ }, output);
411
+ }
412
+ if (collaborationAction === 'preflight') {
413
+ if (values.version ||
414
+ values.config !== undefined ||
415
+ values['install-runtime'] === true ||
416
+ values['runtime-tarball'] !== undefined ||
417
+ values['runtime-version'] !== undefined ||
418
+ values.root !== undefined ||
419
+ values.goal !== undefined ||
420
+ values.prepared !== undefined ||
421
+ values.controller !== undefined ||
422
+ values['domain-root'] !== undefined ||
423
+ values['task-root'] !== undefined ||
424
+ values.message !== undefined ||
425
+ values['message-id'] !== undefined ||
426
+ values.binding !== undefined ||
427
+ values.retry === true ||
428
+ values['caller-pane'] !== undefined ||
429
+ values.session !== undefined ||
430
+ values.harness !== undefined ||
431
+ values.template !== undefined ||
432
+ values.execution !== undefined ||
433
+ values.events !== undefined ||
434
+ values.request !== undefined ||
435
+ values['owner-epoch'] !== undefined ||
436
+ values['subtask-id'] !== undefined ||
437
+ values.attempt !== undefined ||
438
+ values['task-id'] !== undefined ||
439
+ values.record !== undefined ||
440
+ values.roots !== undefined ||
441
+ values.apply === true ||
442
+ values['include-private'] === true ||
443
+ values['include-archived'] === true ||
444
+ hasContinuityOptions(values)) {
445
+ failure(output, json, 'invalid_arguments', `collab preflight accepts only its own options.\n${collaborationPreflightUsage}`);
446
+ return 2;
447
+ }
448
+ return runCollaborationPreflightCommand({
449
+ cwd: process.cwd(),
450
+ assignmentFile: values.assignment ?? null,
451
+ capabilitiesFile: values.capabilities ?? null,
452
+ maxAgeMinutes: values['max-age-minutes'] ?? null,
453
+ json,
454
+ }, output);
455
+ }
456
+ const separator = collaborationAction?.indexOf(':') ?? -1;
457
+ if (separator >= 0) {
458
+ const group = collaborationAction?.slice(0, separator) ?? '';
459
+ const selected = collaborationAction?.slice(separator + 1) ?? '';
460
+ const messageAction = group === 'message' &&
461
+ (selected === 'send' ||
462
+ selected === 'list' ||
463
+ selected === 'read' ||
464
+ selected === 'notify')
465
+ ? selected
466
+ : null;
467
+ const provided = new Set();
468
+ if (values.message !== undefined)
469
+ provided.add('message');
470
+ if (values['message-id'] !== undefined)
471
+ provided.add('message-id');
472
+ if (values.binding !== undefined)
473
+ provided.add('binding');
474
+ if (values.limit !== undefined)
475
+ provided.add('limit');
476
+ if (values.apply === true)
477
+ provided.add('apply');
478
+ if (values.retry === true)
479
+ provided.add('retry');
480
+ if (values['caller-pane'] !== undefined)
481
+ provided.add('caller-pane');
482
+ const allowedByAction = {
483
+ send: new Set(['message', 'apply']),
484
+ list: new Set(['limit']),
485
+ read: new Set(['message-id']),
486
+ notify: new Set([
487
+ 'message-id',
488
+ 'binding',
489
+ 'apply',
490
+ 'retry',
491
+ 'caller-pane',
492
+ ]),
493
+ };
494
+ const requiredByAction = {
495
+ send: ['message'],
496
+ list: [],
497
+ read: ['message-id'],
498
+ notify: ['message-id', 'binding'],
499
+ };
500
+ const actionFlagsValid = messageAction !== null &&
501
+ [...provided].every((flag) => allowedByAction[messageAction].has(flag)) &&
502
+ requiredByAction[messageAction].every((flag) => provided.has(flag));
503
+ if (messageAction === null ||
504
+ !actionFlagsValid ||
505
+ values.version ||
506
+ values.config !== undefined ||
507
+ values['install-runtime'] === true ||
508
+ values['runtime-tarball'] !== undefined ||
509
+ values['runtime-version'] !== undefined ||
510
+ values.root !== undefined ||
511
+ values.goal !== undefined ||
512
+ values.prepared !== undefined ||
513
+ values.capabilities !== undefined ||
514
+ values.controller !== undefined ||
515
+ values['domain-root'] !== undefined ||
516
+ values.assignment !== undefined ||
517
+ values['max-age-minutes'] !== undefined ||
518
+ values.session !== undefined ||
519
+ values.harness !== undefined ||
520
+ values.template !== undefined ||
521
+ values.execution !== undefined ||
522
+ values.events !== undefined ||
523
+ values.request !== undefined ||
524
+ values['owner-epoch'] !== undefined ||
525
+ values['subtask-id'] !== undefined ||
526
+ values.attempt !== undefined ||
527
+ values['task-id'] !== undefined ||
528
+ values.record !== undefined ||
529
+ values.roots !== undefined ||
530
+ values['include-private'] === true ||
531
+ values['include-archived'] === true ||
532
+ hasContinuityOptions(values)) {
533
+ failure(output, json, 'invalid_arguments', `collab message requires send/list/read/notify with only its own options.\n${collaborationMessageUsage}`);
534
+ return 2;
535
+ }
536
+ return runCollaborationMessageCommand({
537
+ cwd: process.cwd(),
538
+ action: messageAction,
539
+ json,
540
+ taskRoot: values['task-root'] ?? null,
541
+ messageFile: values.message ?? null,
542
+ messageId: values['message-id'] ?? null,
543
+ bindingFile: values.binding ?? null,
544
+ apply: values.apply === true,
545
+ retry: values.retry === true,
546
+ limit: values.limit ?? null,
547
+ callerPane: values['caller-pane'] ?? null,
548
+ }, output);
549
+ }
550
+ const action = collaborationAction === 'prepare' ||
551
+ collaborationAction === 'run' ||
552
+ collaborationAction === 'query'
553
+ ? collaborationAction
554
+ : null;
555
+ if (action === null ||
556
+ values.version ||
557
+ values.config !== undefined ||
558
+ values['install-runtime'] === true ||
559
+ values['runtime-tarball'] !== undefined ||
560
+ values['runtime-version'] !== undefined ||
561
+ values.root !== undefined ||
562
+ values['include-private'] === true ||
563
+ values['task-root'] !== undefined ||
564
+ values.message !== undefined ||
565
+ values['message-id'] !== undefined ||
566
+ values.binding !== undefined ||
567
+ values.retry === true ||
568
+ values['caller-pane'] !== undefined ||
569
+ values.assignment !== undefined ||
570
+ values['max-age-minutes'] !== undefined ||
571
+ values.session !== undefined ||
572
+ values.harness !== undefined ||
573
+ values.template !== undefined ||
574
+ values.execution !== undefined ||
575
+ values.events !== undefined ||
576
+ values.request !== undefined ||
577
+ values['owner-epoch'] !== undefined ||
578
+ values['subtask-id'] !== undefined ||
579
+ values.attempt !== undefined ||
580
+ values['task-id'] !== undefined ||
581
+ values.record !== undefined ||
582
+ values.roots !== undefined ||
583
+ values['include-archived'] === true ||
584
+ hasContinuityOptions(values)) {
585
+ failure(output, json, 'invalid_arguments', 'collab requires prepare/run/query and only collab options.');
586
+ return 2;
587
+ }
588
+ return runCollaborationCommand({
589
+ cwd: process.cwd(),
590
+ action,
591
+ json,
592
+ goalFile: values.goal ?? null,
593
+ preparedFile: values.prepared ?? null,
594
+ capabilitiesFile: values.capabilities ?? null,
595
+ controller: values.controller ?? null,
596
+ domainRoot: values['domain-root'] ?? null,
597
+ ...(rpcRequestTimeout === undefined
598
+ ? {}
599
+ : { rpcRequestTimeoutMs: Number(rpcRequestTimeout) }),
600
+ ...(rpcOperationTimeout === undefined
601
+ ? {}
602
+ : { rpcOperationTimeoutMs: Number(rpcOperationTimeout) }),
603
+ }, output);
604
+ }