cool-workflow 0.1.83 → 0.1.85

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.
Files changed (60) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +6 -0
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/capability-core.js +89 -2
  11. package/dist/capability-registry.js +269 -2
  12. package/dist/cli/command-surface.js +1362 -0
  13. package/dist/cli.js +2 -1318
  14. package/dist/mcp-server.js +5 -1452
  15. package/dist/mcp-surface.js +1467 -0
  16. package/dist/run-export.js +139 -1
  17. package/dist/telemetry-demo.js +119 -0
  18. package/dist/types/report-bundle.js +6 -0
  19. package/dist/types.js +1 -0
  20. package/dist/version.js +1 -1
  21. package/dist/worker-accept/acceptance.js +114 -0
  22. package/dist/worker-accept/blackboard-fanout.js +80 -0
  23. package/dist/worker-accept/blackboard-linkage.js +19 -0
  24. package/dist/worker-accept/context.js +2 -0
  25. package/dist/worker-accept/telemetry-ledger.js +116 -0
  26. package/dist/worker-accept/validation.js +77 -0
  27. package/dist/worker-accept/verifier-completion.js +73 -0
  28. package/dist/worker-isolation.js +19 -444
  29. package/docs/agent-delegation-drive.7.md +6 -0
  30. package/docs/cli-mcp-parity.7.md +13 -3
  31. package/docs/contract-migration-tooling.7.md +6 -0
  32. package/docs/control-plane-scheduling.7.md +6 -0
  33. package/docs/durable-state-and-locking.7.md +6 -0
  34. package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
  35. package/docs/execution-backends.7.md +6 -0
  36. package/docs/index.md +1 -0
  37. package/docs/multi-agent-cli-mcp-surface.7.md +6 -0
  38. package/docs/multi-agent-eval-replay-harness.7.md +6 -0
  39. package/docs/multi-agent-operator-ux.7.md +6 -0
  40. package/docs/node-snapshot-diff-replay.7.md +6 -0
  41. package/docs/observability-cost-accounting.7.md +6 -0
  42. package/docs/project-index.md +17 -6
  43. package/docs/real-execution-backends.7.md +6 -0
  44. package/docs/release-and-migration.7.md +6 -0
  45. package/docs/release-tooling.7.md +16 -1
  46. package/docs/report-verifiable-bundle.7.md +123 -0
  47. package/docs/run-registry-control-plane.7.md +6 -0
  48. package/docs/run-retention-reclamation.7.md +6 -0
  49. package/docs/state-explosion-management.7.md +6 -0
  50. package/docs/team-collaboration.7.md +6 -0
  51. package/docs/web-desktop-workbench.7.md +6 -0
  52. package/manifest/plugin.manifest.json +1 -1
  53. package/package.json +1 -1
  54. package/scripts/bump-version.js +9 -1
  55. package/scripts/canonical-apps.js +4 -4
  56. package/scripts/dogfood-release.js +1 -1
  57. package/scripts/golden-path.js +4 -4
  58. package/scripts/parity-check.js +27 -57
  59. package/scripts/release-flow.js +7 -6
  60. package/scripts/sync-project-index.js +1 -1
@@ -0,0 +1,1362 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runCli = runCli;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const orchestrator_1 = require("../orchestrator");
10
+ const capability_core_1 = require("../capability-core");
11
+ const observability_1 = require("../observability");
12
+ const telemetry_demo_1 = require("../telemetry-demo");
13
+ const run_registry_1 = require("../run-registry");
14
+ const daemon_1 = require("../daemon");
15
+ const scheduler_1 = require("../scheduler");
16
+ const triggers_1 = require("../triggers");
17
+ const workbench_1 = require("../workbench");
18
+ const workbench_host_1 = require("../workbench-host");
19
+ const operator_ux_1 = require("../operator-ux");
20
+ const multi_agent_operator_ux_1 = require("../multi-agent-operator-ux");
21
+ const multi_agent_eval_1 = require("../multi-agent-eval");
22
+ const state_explosion_1 = require("../state-explosion");
23
+ const evidence_reasoning_1 = require("../evidence-reasoning");
24
+ const doctor_1 = require("../doctor");
25
+ async function runCli(argv = process.argv.slice(2)) {
26
+ const args = (0, orchestrator_1.parseArgv)(argv);
27
+ const runner = new orchestrator_1.CoolWorkflowRunner({
28
+ pluginRoot: node_path_1.default.resolve(__dirname, "../..")
29
+ });
30
+ const scheduler = new scheduler_1.Scheduler(String(args.options.cwd || process.cwd()));
31
+ const triggers = new triggers_1.RoutineTriggerBridge(String(args.options.cwd || process.cwd()));
32
+ switch (args.command) {
33
+ case "help":
34
+ case undefined:
35
+ process.stdout.write((0, orchestrator_1.formatHelp)());
36
+ return;
37
+ case "list":
38
+ printJson(runner.listWorkflows());
39
+ return;
40
+ case "doctor": {
41
+ const report = (0, doctor_1.runDoctor)(args.options, process.env, String(args.options.cwd || process.cwd()));
42
+ if (wantsJson(args.options))
43
+ printJson(report);
44
+ else
45
+ process.stdout.write(`${(0, doctor_1.formatDoctorReport)(report)}\n`);
46
+ if (!report.ok)
47
+ process.exitCode = 1;
48
+ return;
49
+ }
50
+ case "init": {
51
+ const [workflowId] = args.positionals;
52
+ if (!workflowId)
53
+ throw new Error("Missing workflow id. Example: cw.js init my-workflow");
54
+ printJson(runner.init(workflowId, args.options));
55
+ return;
56
+ }
57
+ case "app": {
58
+ const [subcommand, appIdOrPath] = args.positionals;
59
+ switch (subcommand) {
60
+ case "list":
61
+ printJson(runner.listApps());
62
+ return;
63
+ case "show":
64
+ printJson(runner.showApp(required(appIdOrPath, "app id")));
65
+ return;
66
+ case "validate": {
67
+ const result = runner.validateApp(required(appIdOrPath, "app path or id"));
68
+ printJson(result);
69
+ if (!result.valid)
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+ case "init":
74
+ printJson(runner.initApp(required(appIdOrPath, "app id"), args.options));
75
+ return;
76
+ case "package":
77
+ printJson(runner.packageApp(required(appIdOrPath, "app id"), args.options));
78
+ return;
79
+ case "run":
80
+ printJson((0, capability_core_1.appRun)(runner, { ...args.options, appId: required(appIdOrPath, "app id") }));
81
+ return;
82
+ default:
83
+ throw new Error("Usage: cw.js app list|show|validate|init|package|run [app-id|path]");
84
+ }
85
+ }
86
+ case "quickstart":
87
+ case "audit-run": {
88
+ // ONE-COMMAND first value (v0.1.38+): plan(app) -> run --drive -> report in a
89
+ // single invocation. A thin UX wrapper over the EXISTING drive() pipeline — it
90
+ // DELEGATES worker execution to the operator's configured agent backend and
91
+ // fails closed (status=blocked) when none is set. No new executor/scheduler.
92
+ const [appId] = args.positionals;
93
+ const runId = optionalArg(args.options.run) || optionalArg(args.options.runId);
94
+ const qs = (0, capability_core_1.quickstart)(runner, { ...args.options, ...(appId ? { appId } : {}), ...(runId ? { runId } : {}) });
95
+ printJson(qs);
96
+ // Fail closed: if --bundle produced an artifact that does not self-verify, exit
97
+ // non-zero so `cw quickstart ... --bundle && send-to-client` cannot ship a report
98
+ // whose bundle a client could not verify. Mirrors `report bundle`.
99
+ if (qs.bundle && qs.bundle.ok === false) {
100
+ process.exitCode = 1;
101
+ }
102
+ return;
103
+ }
104
+ case "plan": {
105
+ const [workflowId] = args.positionals;
106
+ if (!workflowId)
107
+ throw new Error("Missing workflow id. Example: cw.js plan architecture-review");
108
+ printJson((0, capability_core_1.planSummary)(runner, workflowId, args.options));
109
+ return;
110
+ }
111
+ case "status":
112
+ if (!args.positionals[0]) {
113
+ const nextActions = (0, operator_ux_1.adviseNoRun)();
114
+ if (wantsJson(args.options))
115
+ printJson({ runId: null, nextActions });
116
+ else
117
+ process.stdout.write(`No run selected\n\nNext Action\n${nextActions.map((action) => ` ${action.command}\n reason: ${action.reason}`).join("\n")}\n`);
118
+ }
119
+ else if (wantsJson(args.options))
120
+ printJson(runner.status(args.positionals[0]));
121
+ else
122
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorStatus)(runner.operatorStatus(args.positionals[0]))}\n`);
123
+ return;
124
+ case "next":
125
+ printJson(runner.next(required(args.positionals[0], "run id"), args.options));
126
+ return;
127
+ case "dispatch":
128
+ printJson(runner.dispatch(required(args.positionals[0], "run id"), args.options));
129
+ return;
130
+ case "result": {
131
+ const [runId, taskId, resultPath] = args.positionals;
132
+ printJson(runner.recordResult(required(runId, "run id"), required(taskId, "task id"), required(resultPath, "result file"), args.options));
133
+ return;
134
+ }
135
+ case "state": {
136
+ const [subcommand, runId] = args.positionals;
137
+ switch (subcommand) {
138
+ case "check": {
139
+ const report = runner.checkState(required(runId, "run id"), args.options);
140
+ printJson(report);
141
+ if (report.status === "unsupported")
142
+ process.exitCode = 1;
143
+ return;
144
+ }
145
+ default:
146
+ throw new Error("Usage: cw.js state check <run-id> [--state PATH] [--write]");
147
+ }
148
+ }
149
+ case "commit":
150
+ if (args.positionals[0] === "summary") {
151
+ const summary = runner.summarizeCommitRecords(required(args.positionals[1], "run id"));
152
+ if (wantsJson(args.options))
153
+ printJson(summary);
154
+ else
155
+ process.stdout.write(`${(0, operator_ux_1.formatCommitSummary)(summary)}\n`);
156
+ return;
157
+ }
158
+ printJson(runner.commit(required(args.positionals[0], "run id"), args.options));
159
+ return;
160
+ case "report": {
161
+ // `report verify-bundle <path>` is the offline self-contained bundle verifier;
162
+ // `report bundle <run-id>` exports a sealed bundle and self-verifies it;
163
+ // every other `report <run-id>` form prints/inspects a local run's report.
164
+ if (args.positionals[0] === "verify-bundle") {
165
+ const result = (0, capability_core_1.runVerifyReportBundle)(runner, { ...args.options, archive: args.positionals[1] || args.options.archive || args.options.path || args.options.file || args.options.bundle });
166
+ printJson(result);
167
+ // Fail closed: a forged/edited/corrupt bundle verifies false — surface it
168
+ // through the exit code so `cw report verify-bundle <file> && ship` cannot
169
+ // pass on a lie. Mirrors run inspect-archive / telemetry verify.
170
+ if (!result.ok)
171
+ process.exitCode = 1;
172
+ return;
173
+ }
174
+ if (args.positionals[0] === "bundle") {
175
+ const result = (0, capability_core_1.reportBundle)(runner, required(args.positionals[1] || optionalArg(args.options.runId || args.options.run), "run id"), args.options);
176
+ printJson(result);
177
+ // Fail closed: never report a "bundle made" success if the artifact does not
178
+ // self-verify — so `cw report bundle <run> && send-to-client` cannot ship an
179
+ // unverifiable report (e.g. no trust key under --strict-signatures).
180
+ if (!result.ok)
181
+ process.exitCode = 1;
182
+ return;
183
+ }
184
+ const runId = required(args.positionals[0], "run id");
185
+ const report = runner.report(runId);
186
+ if (wantsJson(args.options)) {
187
+ printJson(report);
188
+ }
189
+ else if (args.options.show || args.options.summary) {
190
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorReport)(runner.operatorReport(runId))}\n`);
191
+ process.stdout.write(`\n${(0, state_explosion_1.formatStateExplosionReport)(runner.stateExplosionReport(runId))}\n`);
192
+ }
193
+ else {
194
+ process.stdout.write(`${report.path}\n`);
195
+ }
196
+ return;
197
+ }
198
+ case "operator": {
199
+ const [subcommand, runId] = args.positionals;
200
+ switch (subcommand) {
201
+ case "status":
202
+ if (wantsJson(args.options))
203
+ printJson(runner.operatorStatus(required(runId, "run id")));
204
+ else
205
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorStatus)(runner.operatorStatus(required(runId, "run id")))}\n`);
206
+ return;
207
+ case "report":
208
+ if (wantsJson(args.options))
209
+ printJson(runner.operatorReport(required(runId, "run id")));
210
+ else
211
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorReport)(runner.operatorReport(required(runId, "run id")))}\n`);
212
+ return;
213
+ default:
214
+ throw new Error("Usage: cw.js operator status|report <run-id> [--json]");
215
+ }
216
+ }
217
+ case "graph": {
218
+ const graph = runner.operatorGraph(required(args.positionals[0], "run id"));
219
+ if (wantsJson(args.options))
220
+ printJson(graph);
221
+ else
222
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorGraph)(graph)}\n`);
223
+ return;
224
+ }
225
+ case "topology": {
226
+ const [subcommand, first, second] = args.positionals;
227
+ switch (subcommand) {
228
+ case "list":
229
+ printJson(runner.listTopologies());
230
+ return;
231
+ case "show":
232
+ if (second)
233
+ printJson(runner.showTopologyRun(required(first, "run id"), second));
234
+ else
235
+ printJson(runner.showTopology(required(first, "topology id")));
236
+ return;
237
+ case "validate": {
238
+ const result = runner.validateTopology(required(first, "topology id"));
239
+ printJson(result);
240
+ if (!result.valid)
241
+ process.exitCode = 1;
242
+ return;
243
+ }
244
+ case "apply":
245
+ printJson(runner.applyTopology(required(first, "run id"), required(second, "topology id"), args.options));
246
+ return;
247
+ case "summary": {
248
+ const summary = runner.topologySummary(required(first, "run id"));
249
+ if (wantsJson(args.options))
250
+ printJson(summary);
251
+ else
252
+ process.stdout.write(`${(0, operator_ux_1.formatTopologySummary)(summary)}\n`);
253
+ return;
254
+ }
255
+ case "graph": {
256
+ const graph = runner.topologyGraph(required(first, "run id"));
257
+ if (wantsJson(args.options))
258
+ printJson(graph);
259
+ else
260
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorGraph)({ runId: required(first, "run id"), nodes: graph.nodes, edges: graph.edges })}\n`);
261
+ return;
262
+ }
263
+ default:
264
+ throw new Error("Usage: cw.js topology list|show <topology-id>|show <run-id> <topology-run-id>|validate <topology-id>|apply <run-id> <topology-id>|summary <run-id>|graph <run-id>");
265
+ }
266
+ }
267
+ case "summary": {
268
+ const [subcommand, runId] = args.positionals;
269
+ switch (subcommand) {
270
+ case "refresh": {
271
+ const index = runner.summaryRefresh(required(runId, "run id"), args.options);
272
+ if (wantsJson(args.options))
273
+ printJson(index);
274
+ else
275
+ process.stdout.write(`${(0, state_explosion_1.formatStateExplosionReport)(runner.summaryShow(required(runId, "run id")))}\n`);
276
+ return;
277
+ }
278
+ case "show": {
279
+ const report = runner.summaryShow(required(runId, "run id"));
280
+ if (wantsJson(args.options))
281
+ printJson(report);
282
+ else
283
+ process.stdout.write(`${(0, state_explosion_1.formatStateExplosionReport)(report)}\n`);
284
+ return;
285
+ }
286
+ default:
287
+ throw new Error("Usage: cw.js summary refresh|show <run-id> [--json]");
288
+ }
289
+ }
290
+ case "multi-agent": {
291
+ const [subcommand, runId, id] = args.positionals;
292
+ switch (subcommand) {
293
+ case "status":
294
+ if (wantsJson(args.options))
295
+ printJson(runner.hostMultiAgentStatus(required(runId, "run id")));
296
+ else
297
+ process.stdout.write(`${(0, multi_agent_operator_ux_1.formatMultiAgentOperatorStatus)(runner.multiAgentOperatorStatus(required(runId, "run id")))}\n`);
298
+ return;
299
+ case "step":
300
+ printJson(runner.hostMultiAgentStep(required(runId, "run id"), args.options));
301
+ return;
302
+ case "blackboard":
303
+ printJson(runner.hostMultiAgentBlackboard(required(runId, "run id"), id, args.options));
304
+ return;
305
+ case "score":
306
+ printJson(runner.hostMultiAgentScore(required(runId, "run id"), { ...args.options, candidate: args.options.candidate || args.options.candidateId || id }));
307
+ return;
308
+ case "select":
309
+ printJson(runner.hostMultiAgentSelect(required(runId, "run id"), { ...args.options, candidate: args.options.candidate || args.options.candidateId || id }));
310
+ return;
311
+ case "summary": {
312
+ const summary = runner.multiAgentSummary(required(runId, "run id"));
313
+ if (wantsJson(args.options))
314
+ printJson(summary);
315
+ else
316
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentSummary)(summary)}\n`);
317
+ return;
318
+ }
319
+ case "summarize": {
320
+ const report = runner.multiAgentSummarize(required(runId, "run id"));
321
+ if (wantsJson(args.options))
322
+ printJson(report);
323
+ else
324
+ process.stdout.write(`${(0, state_explosion_1.formatStateExplosionReport)(report)}\n`);
325
+ return;
326
+ }
327
+ case "graph": {
328
+ const wantsView = args.options.view || args.options.focus || args.options.depth;
329
+ if (wantsView) {
330
+ const graph = runner.multiAgentGraphView(required(runId, "run id"), args.options);
331
+ if (wantsJson(args.options))
332
+ printJson(graph);
333
+ else
334
+ process.stdout.write(`${(0, state_explosion_1.formatCompactGraph)(graph)}\n`);
335
+ return;
336
+ }
337
+ const graph = runner.multiAgentOperatorGraph(required(runId, "run id"));
338
+ if (wantsJson(args.options))
339
+ printJson(graph);
340
+ else
341
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorGraph)({ runId: required(runId, "run id"), nodes: graph.nodes, edges: graph.edges })}\n`);
342
+ return;
343
+ }
344
+ case "dependencies": {
345
+ const rows = runner.multiAgentDependencies(required(runId, "run id"));
346
+ if (wantsJson(args.options))
347
+ printJson(rows);
348
+ else
349
+ process.stdout.write(`${(0, multi_agent_operator_ux_1.formatMultiAgentDependencies)(rows)}\n`);
350
+ return;
351
+ }
352
+ case "failures": {
353
+ const rows = runner.multiAgentFailures(required(runId, "run id"));
354
+ if (wantsJson(args.options))
355
+ printJson(rows);
356
+ else
357
+ process.stdout.write(`${(0, multi_agent_operator_ux_1.formatMultiAgentFailures)(rows)}\n`);
358
+ return;
359
+ }
360
+ case "evidence": {
361
+ const rows = runner.multiAgentEvidence(required(runId, "run id"));
362
+ if (wantsJson(args.options))
363
+ printJson(rows);
364
+ else
365
+ process.stdout.write(`${(0, multi_agent_operator_ux_1.formatMultiAgentEvidence)(rows)}\n`);
366
+ return;
367
+ }
368
+ case "reasoning": {
369
+ if (args.options.refresh && !args.options.evidence && !args.options.evidenceId) {
370
+ const index = runner.multiAgentReasoningRefresh(required(runId, "run id"));
371
+ printJson(index);
372
+ return;
373
+ }
374
+ const report = runner.multiAgentReasoning(required(runId, "run id"), { ...args.options, evidence: args.options.evidence || args.options.evidenceId || id });
375
+ if (wantsJson(args.options))
376
+ printJson(report);
377
+ else
378
+ process.stdout.write(`${(0, evidence_reasoning_1.formatEvidenceReasoningReport)(report)}\n`);
379
+ return;
380
+ }
381
+ case "run":
382
+ if (!runId ||
383
+ args.options.topology ||
384
+ args.options.topologyId ||
385
+ args.options.app ||
386
+ args.options.appId ||
387
+ args.options.workflow ||
388
+ args.options.workflowId) {
389
+ printJson(runner.hostMultiAgentRun(runId, args.options));
390
+ return;
391
+ }
392
+ if (id && !args.options.id && !args.options.status)
393
+ printJson(runner.showMultiAgentRun(required(runId, "run id"), id));
394
+ else if (id && args.options.status)
395
+ printJson(runner.transitionMultiAgentRun(required(runId, "run id"), id, args.options));
396
+ else
397
+ printJson(runner.createMultiAgentRun(required(runId, "run id"), args.options));
398
+ return;
399
+ case "show":
400
+ printJson(runner.showMultiAgentRun(required(runId, "run id"), required(id, "multi-agent run id")));
401
+ return;
402
+ case "role":
403
+ if (id && !args.options.id && !args.options["multi-agent-run"] && !args.options.multiAgentRun && !args.options.multiAgentRunId) {
404
+ printJson(runner.showAgentRole(required(runId, "run id"), id));
405
+ }
406
+ else {
407
+ printJson(runner.createAgentRole(required(runId, "run id"), { ...args.options, id: args.options.id || id }));
408
+ }
409
+ return;
410
+ case "group":
411
+ if (id && !args.options.id && !args.options["multi-agent-run"] && !args.options.multiAgentRun && !args.options.multiAgentRunId) {
412
+ printJson(runner.showAgentGroup(required(runId, "run id"), id));
413
+ }
414
+ else {
415
+ printJson(runner.createAgentGroup(required(runId, "run id"), { ...args.options, id: args.options.id || id }));
416
+ }
417
+ return;
418
+ case "membership":
419
+ if (id && !args.options.id && !args.options.group && !args.options.groupId && !args.options["multi-agent-group"]) {
420
+ printJson(runner.showAgentMembership(required(runId, "run id"), id));
421
+ }
422
+ else {
423
+ printJson(runner.assignAgentMembership(required(runId, "run id"), { ...args.options, id: args.options.id || id }));
424
+ }
425
+ return;
426
+ case "fanout":
427
+ if (id && !args.options.id && !args.options.group && !args.options.groupId && !args.options["multi-agent-group"]) {
428
+ printJson(runner.showAgentFanout(required(runId, "run id"), id));
429
+ }
430
+ else {
431
+ printJson(runner.createAgentFanout(required(runId, "run id"), { ...args.options, id: args.options.id || id }));
432
+ }
433
+ return;
434
+ case "fanin":
435
+ if (id && !args.options.id && !args.options.group && !args.options.groupId && !args.options["multi-agent-group"] && !args.options.fanout) {
436
+ printJson(runner.showAgentFanin(required(runId, "run id"), id));
437
+ }
438
+ else {
439
+ printJson(runner.collectAgentFanin(required(runId, "run id"), { ...args.options, id: args.options.id || id }));
440
+ }
441
+ return;
442
+ default:
443
+ throw new Error("Usage: cw.js multi-agent run|status|step|blackboard|score|select|summary|summarize|graph|dependencies|failures|evidence|reasoning|show|role|group|membership|fanout|fanin <run-id> [id]");
444
+ }
445
+ }
446
+ case "eval": {
447
+ const [subcommand, first, second] = args.positionals;
448
+ let result;
449
+ switch (subcommand) {
450
+ case "snapshot":
451
+ result = runner.evalSnapshot(required(first, "run id"), args.options);
452
+ break;
453
+ case "replay":
454
+ result = runner.evalReplay(required(first, "snapshot id or path"), args.options);
455
+ break;
456
+ case "compare":
457
+ result = runner.evalCompare(required(first, "baseline id or path"), required(second, "replay id or path"));
458
+ break;
459
+ case "score":
460
+ result = runner.evalScore(required(first, "replay id or path"));
461
+ break;
462
+ case "gate":
463
+ result = runner.evalGate(required(first, "suite id or path"));
464
+ if (!wantsJson(args.options) && result.status === "fail")
465
+ process.exitCode = 1;
466
+ break;
467
+ case "report":
468
+ result = runner.evalReport(required(first, "replay id or path"));
469
+ break;
470
+ default:
471
+ throw new Error("Usage: cw.js eval snapshot <run-id> --id <snapshot-id> | replay <snapshot-id-or-path> | compare <baseline-id-or-path> <replay-id-or-path> | score <replay-id-or-path> | gate <suite-id-or-path> | report <replay-id-or-path>");
472
+ }
473
+ if (wantsJson(args.options))
474
+ printJson(result);
475
+ else
476
+ process.stdout.write(`${(0, multi_agent_eval_1.formatMultiAgentEval)(result)}\n`);
477
+ if (subcommand === "gate" && result.status === "fail")
478
+ process.exitCode = 1;
479
+ return;
480
+ }
481
+ case "blackboard": {
482
+ const [subcommand, action, runId] = args.positionals;
483
+ switch (subcommand) {
484
+ case "summary":
485
+ printJson(runner.blackboardSummary(required(action, "run id"), args.options));
486
+ return;
487
+ case "summarize": {
488
+ const digest = runner.blackboardSummarize(required(action, "run id"), args.options);
489
+ if (wantsJson(args.options))
490
+ printJson(digest);
491
+ else
492
+ process.stdout.write(`${(0, state_explosion_1.formatBlackboardDigest)(digest)}\n`);
493
+ return;
494
+ }
495
+ case "graph":
496
+ printJson(runner.blackboardGraph(required(action, "run id")));
497
+ return;
498
+ case "resolve":
499
+ printJson(runner.resolveRunBlackboard(required(action, "run id"), args.options));
500
+ return;
501
+ case "topic":
502
+ if (action === "create") {
503
+ printJson(runner.createBlackboardTopic(required(runId, "run id"), args.options));
504
+ return;
505
+ }
506
+ break;
507
+ case "message":
508
+ if (action === "post") {
509
+ printJson(runner.postBlackboardMessage(required(runId, "run id"), args.options));
510
+ return;
511
+ }
512
+ if (action === "list") {
513
+ printJson(runner.listBlackboardMessages(required(runId, "run id"), args.options));
514
+ return;
515
+ }
516
+ break;
517
+ case "context":
518
+ if (action === "put") {
519
+ printJson(runner.putBlackboardContext(required(runId, "run id"), args.options));
520
+ return;
521
+ }
522
+ break;
523
+ case "artifact":
524
+ if (action === "add") {
525
+ printJson(runner.addBlackboardArtifact(required(runId, "run id"), args.options));
526
+ return;
527
+ }
528
+ if (action === "list") {
529
+ printJson(runner.listBlackboardArtifacts(required(runId, "run id"), args.options));
530
+ return;
531
+ }
532
+ break;
533
+ case "snapshot":
534
+ printJson(runner.snapshotBlackboard(required(action, "run id"), args.options));
535
+ return;
536
+ default:
537
+ break;
538
+ }
539
+ throw new Error("Usage: cw.js blackboard summary|summarize|graph|resolve <run-id> | topic create <run-id> | message post|list <run-id> | context put <run-id> | artifact add|list <run-id> | snapshot <run-id>");
540
+ }
541
+ case "coordinator": {
542
+ const [subcommand, runId] = args.positionals;
543
+ switch (subcommand) {
544
+ case "summary":
545
+ printJson(runner.coordinatorSummary(required(runId, "run id"), args.options));
546
+ return;
547
+ case "decision":
548
+ printJson(runner.recordCoordinatorDecision(required(runId, "run id"), args.options));
549
+ return;
550
+ default:
551
+ throw new Error("Usage: cw.js coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT");
552
+ }
553
+ }
554
+ case "sandbox": {
555
+ const [subcommand, profileIdOrFile] = args.positionals;
556
+ switch (subcommand) {
557
+ case "list":
558
+ printJson(runner.listSandboxProfiles(args.options));
559
+ return;
560
+ case "show":
561
+ printJson(runner.showSandboxProfile(required(profileIdOrFile, "profile id"), args.options));
562
+ return;
563
+ case "validate": {
564
+ const result = runner.validateSandboxProfile(required(profileIdOrFile, "profile file"), args.options);
565
+ printJson(result);
566
+ if (!result.valid)
567
+ process.exitCode = 1;
568
+ return;
569
+ }
570
+ case "choose":
571
+ case "resolve":
572
+ printJson((0, capability_core_1.sandboxChoose)(runner, { ...args.options, profileId: profileIdOrFile || args.options.profileId }));
573
+ return;
574
+ default:
575
+ throw new Error("Usage: cw.js sandbox list|show|validate|choose|resolve [profile-id|profile-file]");
576
+ }
577
+ }
578
+ case "backend": {
579
+ const [subcommand, backendId] = args.positionals;
580
+ switch (subcommand) {
581
+ case "list":
582
+ printJson(runner.listBackends(args.options));
583
+ return;
584
+ case "show":
585
+ printJson(runner.showBackend(required(backendId, "backend id"), args.options));
586
+ return;
587
+ case "probe":
588
+ printJson(runner.probeBackend(backendId, args.options));
589
+ return;
590
+ case "agent": {
591
+ // `backend agent config [show]` = read-only; `backend agent config set ...` = mutating.
592
+ const [, , action] = args.positionals;
593
+ if (action === "set") {
594
+ printJson((0, capability_core_1.backendAgentConfigSet)(args.options));
595
+ return;
596
+ }
597
+ printJson((0, capability_core_1.backendAgentConfigShow)(args.options));
598
+ return;
599
+ }
600
+ default:
601
+ throw new Error("Usage: cw.js backend list|show|probe [backend-id] | cw.js backend agent config [show|set] [--agent-command ... --agent-endpoint ... --agent-model ...]");
602
+ }
603
+ }
604
+ case "contract": {
605
+ const [subcommand, runId, contractId] = args.positionals;
606
+ switch (subcommand) {
607
+ case "show":
608
+ printJson(runner.showContract(required(runId, "run id"), contractId));
609
+ return;
610
+ default:
611
+ throw new Error("Usage: cw.js contract show <run-id> [contract-id]");
612
+ }
613
+ }
614
+ case "node": {
615
+ const [subcommand, runId, nodeId] = args.positionals;
616
+ switch (subcommand) {
617
+ case "list":
618
+ printJson(runner.listNodes(required(runId, "run id")));
619
+ return;
620
+ case "show":
621
+ printJson(runner.showNode(required(runId, "run id"), required(nodeId, "node id")));
622
+ return;
623
+ case "graph":
624
+ if (wantsJson(args.options))
625
+ printJson(runner.graphNodes(required(runId, "run id")));
626
+ else
627
+ process.stdout.write(`${(0, operator_ux_1.formatOperatorGraph)(runner.operatorGraph(required(runId, "run id")))}\n`);
628
+ return;
629
+ case "snapshot":
630
+ printJson(runner.nodeSnapshot(required(runId, "run id"), required(nodeId, "node id")));
631
+ return;
632
+ case "diff":
633
+ printJson(runner.nodeDiff(required(runId, "run id"), required(nodeId, "baseline snapshot id"), required(args.positionals[3], "candidate snapshot id")));
634
+ return;
635
+ case "replay":
636
+ printJson(runner.nodeReplay(required(runId, "run id"), required(nodeId, "snapshot id")));
637
+ return;
638
+ case "verify": {
639
+ const verdict = runner.nodeReplayVerify(required(runId, "run id"), required(nodeId, "replay id"));
640
+ printJson(verdict);
641
+ if (!verdict.pass)
642
+ process.exitCode = 1;
643
+ return;
644
+ }
645
+ default:
646
+ throw new Error("Usage: cw.js node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]");
647
+ }
648
+ }
649
+ case "migration": {
650
+ const [subcommand, target] = args.positionals;
651
+ switch (subcommand) {
652
+ case "list":
653
+ printJson(runner.migrationList());
654
+ return;
655
+ case "check": {
656
+ const report = runner.migrationCheck(required(target, "target (run-id or state/app file)"), args.options);
657
+ printJson(report);
658
+ if (report.status === "unsupported")
659
+ process.exitCode = 1;
660
+ return;
661
+ }
662
+ case "prove": {
663
+ const proof = runner.migrationProve(required(target, "target (run-id or state/app file)"), args.options);
664
+ printJson(proof);
665
+ if (!proof.pass)
666
+ process.exitCode = 1;
667
+ return;
668
+ }
669
+ default:
670
+ throw new Error("Usage: cw.js migration list|check|prove [target] [--contract run-state|workflow-app]");
671
+ }
672
+ }
673
+ case "feedback": {
674
+ const [subcommand, runId, feedbackId] = args.positionals;
675
+ switch (subcommand) {
676
+ case "list":
677
+ printJson(runner.listFeedback(required(runId, "run id"), args.options));
678
+ return;
679
+ case "show":
680
+ printJson(runner.showFeedback(required(runId, "run id"), required(feedbackId, "feedback id")));
681
+ return;
682
+ case "collect":
683
+ printJson(runner.collectFeedback(required(runId, "run id")));
684
+ return;
685
+ case "summary": {
686
+ const summary = runner.summarizeFeedbackRecords(required(runId, "run id"));
687
+ if (wantsJson(args.options))
688
+ printJson(summary);
689
+ else
690
+ process.stdout.write(`${(0, operator_ux_1.formatFeedbackSummary)(summary)}\n`);
691
+ return;
692
+ }
693
+ case "task":
694
+ printJson(runner.createFeedbackTask(required(runId, "run id"), required(feedbackId, "feedback id"), args.options));
695
+ return;
696
+ case "resolve":
697
+ printJson(runner.resolveFeedback(required(runId, "run id"), required(feedbackId, "feedback id"), args.options));
698
+ return;
699
+ default:
700
+ throw new Error("Usage: cw.js feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]");
701
+ }
702
+ }
703
+ case "worker": {
704
+ const [subcommand, runId, workerId, resultPath] = args.positionals;
705
+ switch (subcommand) {
706
+ case "list":
707
+ printJson(runner.listWorkers(required(runId, "run id"), args.options));
708
+ return;
709
+ case "summary": {
710
+ const summary = runner.summarizeWorkerRecords(required(runId, "run id"));
711
+ if (wantsJson(args.options))
712
+ printJson(summary);
713
+ else
714
+ process.stdout.write(`${(0, operator_ux_1.formatWorkerSummary)(summary)}\n`);
715
+ return;
716
+ }
717
+ case "show":
718
+ printJson(runner.showWorker(required(runId, "run id"), required(workerId, "worker id")));
719
+ return;
720
+ case "manifest":
721
+ printJson(runner.showWorkerManifest(required(runId, "run id"), required(workerId, "worker id")));
722
+ return;
723
+ case "output":
724
+ printJson(runner.recordWorkerOutput(required(runId, "run id"), required(workerId, "worker id"), required(resultPath, "result file"), args.options));
725
+ return;
726
+ case "fail":
727
+ printJson(runner.recordWorkerFailure(required(runId, "run id"), required(workerId, "worker id"), String(args.options.message || required(resultPath, "failure message")), args.options));
728
+ return;
729
+ case "validate": {
730
+ // Non-null = a boundary violation: a validate verb must report an invalid
731
+ // verdict through its exit code, not just print it and exit 0.
732
+ const violation = runner.validateWorker(required(runId, "run id"), required(workerId, "worker id"), resultPath);
733
+ printJson(violation);
734
+ if (violation)
735
+ process.exitCode = 1;
736
+ return;
737
+ }
738
+ default:
739
+ throw new Error("Usage: cw.js worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]");
740
+ }
741
+ }
742
+ case "audit": {
743
+ const [subcommand, runId, id] = args.positionals;
744
+ switch (subcommand) {
745
+ case "summary":
746
+ printJson(runner.auditSummary(required(runId, "run id")));
747
+ return;
748
+ case "verify": {
749
+ const result = (0, capability_core_1.auditVerify)(runner, { ...args.options, runId: required(runId, "run id") });
750
+ printJson(result);
751
+ // Fail-closed: any unverified chain exits non-zero so `cw audit verify
752
+ // <run> && deploy` stops — mirrors the telemetry-verify guard. verifyTrustAudit
753
+ // returns verified:true for a truly absent/empty chain (nothing to prove),
754
+ // so this stays exit 0 there; a FULLY-corrupt log reports present:false but
755
+ // verified:false (corruptLines>0) and must NOT be conflated with absent — the
756
+ // earlier `present && ...` guard let that severe tamper escape (exit 0).
757
+ if (!result.verified)
758
+ process.exitCode = 1;
759
+ return;
760
+ }
761
+ case "worker":
762
+ printJson(runner.workerAudit(required(runId, "run id"), required(id, "worker id")));
763
+ return;
764
+ case "provenance":
765
+ printJson(runner.evidenceProvenance(required(runId, "run id"), args.options));
766
+ return;
767
+ case "multi-agent": {
768
+ const view = runner.auditMultiAgent(required(runId, "run id"));
769
+ if (wantsJson(args.options))
770
+ printJson(view);
771
+ else
772
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentTrustAudit)(view)}\n`);
773
+ return;
774
+ }
775
+ case "policy": {
776
+ const view = runner.auditPolicy(required(runId, "run id"));
777
+ if (wantsJson(args.options))
778
+ printJson(view);
779
+ else
780
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentTrustAudit)(view)}\n`);
781
+ return;
782
+ }
783
+ case "role": {
784
+ const view = runner.auditRole(required(runId, "run id"), required(id, "role id"));
785
+ if (wantsJson(args.options))
786
+ printJson(view);
787
+ else
788
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentTrustAudit)(view)}\n`);
789
+ return;
790
+ }
791
+ case "blackboard": {
792
+ const view = runner.auditBlackboard(required(runId, "run id"));
793
+ if (wantsJson(args.options))
794
+ printJson(view);
795
+ else
796
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentTrustAudit)(view)}\n`);
797
+ return;
798
+ }
799
+ case "judge": {
800
+ const view = runner.auditJudge(required(runId, "run id"));
801
+ if (wantsJson(args.options))
802
+ printJson(view);
803
+ else
804
+ process.stdout.write(`${(0, operator_ux_1.formatMultiAgentTrustAudit)(view)}\n`);
805
+ return;
806
+ }
807
+ case "attest":
808
+ printJson(runner.recordAuditAttestation(required(runId, "run id"), args.options));
809
+ return;
810
+ case "decision":
811
+ printJson(runner.recordAuditDecision(required(runId, "run id"), required(id, "worker id"), args.options));
812
+ return;
813
+ default:
814
+ throw new Error("Usage: cw.js audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]");
815
+ }
816
+ }
817
+ case "candidate": {
818
+ const [subcommand, runId, candidateId, reason] = args.positionals;
819
+ switch (subcommand) {
820
+ case "list":
821
+ printJson(runner.listCandidates(required(runId, "run id"), args.options));
822
+ return;
823
+ case "show":
824
+ printJson(runner.showCandidate(required(runId, "run id"), required(candidateId, "candidate id")));
825
+ return;
826
+ case "register":
827
+ printJson(runner.registerCandidate(required(runId, "run id"), args.options));
828
+ return;
829
+ case "score":
830
+ printJson(runner.scoreCandidate(required(runId, "run id"), required(candidateId, "candidate id"), args.options));
831
+ return;
832
+ case "rank":
833
+ printJson(runner.rankCandidates(required(runId, "run id"), args.options));
834
+ return;
835
+ case "select":
836
+ printJson(runner.selectCandidate(required(runId, "run id"), required(candidateId, "candidate id"), args.options));
837
+ return;
838
+ case "reject":
839
+ printJson(runner.rejectCandidate(required(runId, "run id"), required(candidateId, "candidate id"), String(args.options.reason || args.options.message || reason || "rejected")));
840
+ return;
841
+ case "summary":
842
+ if (wantsJson(args.options))
843
+ printJson(runner.summarizeCandidateOperatorRecords(required(runId, "run id")));
844
+ else
845
+ process.stdout.write(`${(0, operator_ux_1.formatCandidateSummary)(runner.summarizeCandidateOperatorRecords(required(runId, "run id")))}\n`);
846
+ return;
847
+ default:
848
+ throw new Error("Usage: cw.js candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]");
849
+ }
850
+ }
851
+ // ---- Team Collaboration (v0.1.32) ------------------------------------
852
+ case "approve": {
853
+ const [targetKind, runId, targetId] = args.positionals;
854
+ printJson(runner.collaborationApprove(required(runId, "run id"), required(targetKind, "target kind (candidate|commit|selection|run|task|node)"), required(targetId, "target id"), args.options));
855
+ return;
856
+ }
857
+ case "reject": {
858
+ const [targetKind, runId, targetId] = args.positionals;
859
+ printJson(runner.collaborationReject(required(runId, "run id"), required(targetKind, "target kind (candidate|commit|selection|run|task|node)"), required(targetId, "target id"), args.options));
860
+ return;
861
+ }
862
+ case "comment": {
863
+ const [subcommand, ...rest] = args.positionals;
864
+ if (subcommand === "add") {
865
+ const [targetKind, runId, targetId] = rest;
866
+ printJson(runner.collaborationComment(required(runId, "run id"), required(targetKind, "target kind"), required(targetId, "target id"), args.options));
867
+ return;
868
+ }
869
+ if (subcommand === "list") {
870
+ const result = runner.collaborationCommentList(required(rest[0], "run id"), args.options);
871
+ if (wantsJson(args.options))
872
+ printJson(result);
873
+ else
874
+ process.stdout.write(`${runner.formatCommentList(result.comments)}\n`);
875
+ return;
876
+ }
877
+ throw new Error("Usage: cw.js comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]");
878
+ }
879
+ case "handoff": {
880
+ const [targetKind, runId, targetIdRaw] = args.positionals;
881
+ const kind = required(targetKind, "target kind (run|task|candidate|commit|node)");
882
+ const rid = required(runId, "run id");
883
+ const targetId = targetIdRaw || (kind === "run" ? rid : undefined);
884
+ printJson(runner.collaborationHandoff(rid, kind, required(targetId, "target id"), args.options));
885
+ return;
886
+ }
887
+ case "review": {
888
+ const [subcommand, runId] = args.positionals;
889
+ if (subcommand === "status") {
890
+ const report = runner.reviewStatus(required(runId, "run id"), args.options);
891
+ if (wantsJson(args.options))
892
+ printJson(report);
893
+ else
894
+ process.stdout.write(`${runner.formatReviewStatus(report)}\n`);
895
+ return;
896
+ }
897
+ if (subcommand === "policy") {
898
+ printJson(runner.reviewPolicy(required(runId, "run id"), args.options));
899
+ return;
900
+ }
901
+ throw new Error("Usage: cw.js review status <run-id> [--json] | review policy <run-id> --required-approvals N --authorized-roles a,b --applies-to commit,selection");
902
+ }
903
+ case "loop": {
904
+ printJson(scheduler.create({ ...args.options, kind: "loop" }));
905
+ return;
906
+ }
907
+ case "schedule": {
908
+ const [subcommand, id] = args.positionals;
909
+ switch (subcommand) {
910
+ case "create":
911
+ printJson(scheduler.create(args.options));
912
+ return;
913
+ case "list":
914
+ printJson(scheduler.list(args.options.status ? String(args.options.status) : undefined));
915
+ return;
916
+ case "delete":
917
+ printJson(scheduler.delete(required(id, "schedule id")));
918
+ return;
919
+ case "due":
920
+ printJson(scheduler.due());
921
+ return;
922
+ case "complete":
923
+ printJson(scheduler.complete(required(id, "schedule id"), args.options));
924
+ return;
925
+ case "pause":
926
+ printJson(scheduler.pause(required(id, "schedule id")));
927
+ return;
928
+ case "resume":
929
+ printJson(scheduler.resume(required(id, "schedule id")));
930
+ return;
931
+ case "run-now":
932
+ printJson(scheduler.runNow(required(id, "schedule id")));
933
+ return;
934
+ case "history":
935
+ printJson(scheduler.history(id));
936
+ return;
937
+ case "daemon": {
938
+ const daemon = new daemon_1.DesktopSchedulerDaemon({
939
+ cwd: String(args.options.cwd || process.cwd()),
940
+ intervalSeconds: Number(args.options.intervalSeconds || args.options.interval || 60)
941
+ });
942
+ if (args.options.once) {
943
+ printJson(daemon.tick());
944
+ return;
945
+ }
946
+ await daemon.run();
947
+ return;
948
+ }
949
+ default:
950
+ throw new Error("Usage: cw.js schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon");
951
+ }
952
+ }
953
+ case "routine": {
954
+ const [subcommand, idOrKind, payloadPath] = args.positionals;
955
+ switch (subcommand) {
956
+ case "create":
957
+ printJson(triggers.create(args.options));
958
+ return;
959
+ case "list":
960
+ printJson(triggers.list(args.options.kind ? String(args.options.kind) : undefined));
961
+ return;
962
+ case "delete":
963
+ printJson(triggers.delete(required(idOrKind, "trigger id")));
964
+ return;
965
+ case "fire": {
966
+ const kind = required(idOrKind, "trigger kind");
967
+ const payload = payloadPath ? JSON.parse(node_fs_1.default.readFileSync(payloadPath, "utf8")) : args.options;
968
+ printJson(triggers.fire(kind, payload));
969
+ return;
970
+ }
971
+ case "events":
972
+ printJson(triggers.events(idOrKind));
973
+ return;
974
+ default:
975
+ throw new Error("Usage: cw.js routine create|list|delete|fire|events");
976
+ }
977
+ }
978
+ case "registry": {
979
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
980
+ const [subcommand] = args.positionals;
981
+ switch (subcommand) {
982
+ case "refresh": {
983
+ const report = (0, capability_core_1.runRegistryRefresh)(registry, args.options);
984
+ if (wantsJson(args.options))
985
+ printJson(report);
986
+ else
987
+ process.stdout.write(`${(0, run_registry_1.formatRegistryReport)(report)}\n`);
988
+ return;
989
+ }
990
+ case "show": {
991
+ const report = (0, capability_core_1.runRegistryShow)(registry, args.options);
992
+ if (wantsJson(args.options))
993
+ printJson(report);
994
+ else
995
+ process.stdout.write(`${(0, run_registry_1.formatRegistryReport)(report)}\n`);
996
+ return;
997
+ }
998
+ default:
999
+ throw new Error("Usage: cw.js registry refresh|show [--scope repo|home] [--json]");
1000
+ }
1001
+ }
1002
+ case "metrics": {
1003
+ const [subcommand, runId] = args.positionals;
1004
+ switch (subcommand) {
1005
+ case "show": {
1006
+ const report = runner.metricsShow(required(runId, "run id"), args.options);
1007
+ if (wantsJson(args.options))
1008
+ printJson(report);
1009
+ else
1010
+ process.stdout.write(`${(0, observability_1.formatMetricsReport)(report)}\n`);
1011
+ return;
1012
+ }
1013
+ case "summary": {
1014
+ const report = (0, capability_core_1.metricsSummary)((0, capability_core_1.runRegistryFor)(args.options, runner), runner, args.options);
1015
+ if (wantsJson(args.options))
1016
+ printJson(report);
1017
+ else
1018
+ process.stdout.write(`${(0, observability_1.formatMetricsSummary)(report)}\n`);
1019
+ return;
1020
+ }
1021
+ default:
1022
+ throw new Error("Usage: cw.js metrics show <run-id> | metrics summary [--scope repo|home] [--pricing <path>|default] [--json]");
1023
+ }
1024
+ }
1025
+ case "run": {
1026
+ // Agent Delegation Drive (v0.1.38): `cw run <app> --drive [--once]` drives a
1027
+ // run end-to-end by delegating each worker to the agent backend. Distinct from
1028
+ // the run-REGISTRY verbs below. `--preview` (or the `run drive <run-id>` form)
1029
+ // is the read-only, deterministic next-step preview.
1030
+ //
1031
+ // A run-REGISTRY subcommand keyword (resume/show/...) must NOT be intercepted
1032
+ // here just because it carries a --drive flag of its own — e.g.
1033
+ // `run resume <id> --drive` is the resume verb's opt-in continuation, not
1034
+ // `run <app=resume> --drive`. Fall through to the switch for those keywords.
1035
+ const runRegistrySubcommand = new Set([
1036
+ "drive", "search", "list", "show", "resume", "archive", "rerun", "export", "import", "verify-import", "inspect-archive"
1037
+ ]);
1038
+ if (args.options.drive && !runRegistrySubcommand.has(String(args.positionals[0] || ""))) {
1039
+ const target = args.positionals[0];
1040
+ const runId = optionalArg(args.options.run) || optionalArg(args.options.runId);
1041
+ if (args.options.preview) {
1042
+ printJson((0, capability_core_1.runDrivePreview)(runner, { ...args.options, runId: runId || target }));
1043
+ return;
1044
+ }
1045
+ const driveArgs = { ...args.options };
1046
+ if (runId)
1047
+ driveArgs.runId = runId;
1048
+ else
1049
+ driveArgs.appId = target;
1050
+ printJson((0, capability_core_1.runDrive)(runner, driveArgs));
1051
+ return;
1052
+ }
1053
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
1054
+ const [subcommand, id] = args.positionals;
1055
+ switch (subcommand) {
1056
+ case "drive": {
1057
+ // `run drive <run-id>` = read-only preview; `--step [--once]` = mutating drive.
1058
+ if (args.options.step) {
1059
+ const driveArgs = { ...args.options };
1060
+ if (id)
1061
+ driveArgs.runId = id;
1062
+ printJson((0, capability_core_1.runDrive)(runner, driveArgs));
1063
+ return;
1064
+ }
1065
+ printJson((0, capability_core_1.runDrivePreview)(runner, { ...args.options, runId: required(id, "run id") }));
1066
+ return;
1067
+ }
1068
+ case "search": {
1069
+ const result = (0, capability_core_1.runSearch)(registry, args.options);
1070
+ if (wantsJson(args.options))
1071
+ printJson(result);
1072
+ else
1073
+ process.stdout.write(`${(0, run_registry_1.formatRunSearch)(result)}\n`);
1074
+ return;
1075
+ }
1076
+ case "list": {
1077
+ const result = (0, capability_core_1.runList)(registry, args.options);
1078
+ if (wantsJson(args.options))
1079
+ printJson(result);
1080
+ else
1081
+ process.stdout.write(`${(0, run_registry_1.formatRunSearch)(result)}\n`);
1082
+ return;
1083
+ }
1084
+ case "show": {
1085
+ const result = (0, capability_core_1.runShow)(registry, required(id, "run id"), args.options);
1086
+ if (wantsJson(args.options))
1087
+ printJson(result);
1088
+ else
1089
+ process.stdout.write(`${(0, run_registry_1.formatRunShow)(result)}\n`);
1090
+ return;
1091
+ }
1092
+ case "resume": {
1093
+ const result = (0, capability_core_1.runResume)(registry, runner, required(id, "run id"), args.options);
1094
+ if (wantsJson(args.options))
1095
+ printJson(result);
1096
+ else
1097
+ process.stdout.write(`${(0, run_registry_1.formatResume)(result)}\n`);
1098
+ return;
1099
+ }
1100
+ case "archive":
1101
+ printJson((0, capability_core_1.runArchive)(registry, id, args.options));
1102
+ return;
1103
+ case "rerun":
1104
+ printJson((0, capability_core_1.runRerun)(registry, required(id, "run id"), args.options));
1105
+ return;
1106
+ case "export":
1107
+ printJson((0, capability_core_1.runExportArchive)(runner, required(id || optionalArg(args.options.runId || args.options.run), "run id"), args.options));
1108
+ return;
1109
+ case "import":
1110
+ printJson((0, capability_core_1.runImportArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path }));
1111
+ return;
1112
+ case "verify-import": {
1113
+ const result = (0, capability_core_1.runVerifyImport)(runner, required(id || optionalArg(args.options.runId || args.options.run), "run id"), args.options);
1114
+ printJson(result);
1115
+ // Fail-closed ONLY behind --strict, so the default exit stays 0
1116
+ // (byte-identical). With --strict, any failed restore check — including
1117
+ // the new trust-audit row — exits 1 for `verify-import && restore`.
1118
+ if (Boolean(args.options.strict) && !result.ok)
1119
+ process.exitCode = 1;
1120
+ return;
1121
+ }
1122
+ case "inspect-archive": {
1123
+ const result = (0, capability_core_1.runInspectArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path });
1124
+ printJson(result);
1125
+ // Read-only diagnostic: exit 1 when the archive fails any integrity check,
1126
+ // so `cw run inspect-archive <path> && restore` stops on a bad archive.
1127
+ if (!result.ok)
1128
+ process.exitCode = 1;
1129
+ return;
1130
+ }
1131
+ default:
1132
+ throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import|inspect-archive [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--repo R --question Q]");
1133
+ }
1134
+ }
1135
+ case "queue": {
1136
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
1137
+ const [subcommand, id] = args.positionals;
1138
+ switch (subcommand) {
1139
+ case "add":
1140
+ printJson((0, capability_core_1.queueAdd)(registry, args.options));
1141
+ return;
1142
+ case "list": {
1143
+ const result = (0, capability_core_1.queueList)(registry, args.options);
1144
+ if (wantsJson(args.options))
1145
+ printJson(result);
1146
+ else
1147
+ process.stdout.write(`${(0, run_registry_1.formatQueueList)(result)}\n`);
1148
+ return;
1149
+ }
1150
+ case "drain":
1151
+ printJson((0, capability_core_1.queueDrain)(registry, args.options));
1152
+ return;
1153
+ case "show":
1154
+ printJson((0, capability_core_1.queueShow)(registry, required(id, "queue id")));
1155
+ return;
1156
+ default:
1157
+ throw new Error("Usage: cw.js queue add|list|drain|show [queue-id] [--repo PATH] [--priority N]");
1158
+ }
1159
+ }
1160
+ case "sched": {
1161
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
1162
+ const [subcommand, idArg] = args.positionals;
1163
+ switch (subcommand) {
1164
+ case "plan":
1165
+ printJson((0, capability_core_1.schedPlan)(registry, args.options));
1166
+ return;
1167
+ case "lease":
1168
+ printJson((0, capability_core_1.schedLease)(registry, args.options));
1169
+ return;
1170
+ case "release":
1171
+ printJson((0, capability_core_1.schedRelease)(registry, { ...args.options, leaseId: args.options.leaseId || idArg }));
1172
+ return;
1173
+ case "complete":
1174
+ printJson((0, capability_core_1.schedComplete)(registry, { ...args.options, leaseId: args.options.leaseId || idArg }));
1175
+ return;
1176
+ case "reclaim":
1177
+ printJson((0, capability_core_1.schedReclaim)(registry, args.options));
1178
+ return;
1179
+ case "reset":
1180
+ printJson((0, capability_core_1.schedReset)(registry, { ...args.options, id: args.options.id || idArg }));
1181
+ return;
1182
+ case "policy": {
1183
+ const [, action] = args.positionals;
1184
+ if (action === "set") {
1185
+ printJson((0, capability_core_1.schedPolicySet)(registry, args.options));
1186
+ return;
1187
+ }
1188
+ printJson((0, capability_core_1.schedPolicyShow)(registry));
1189
+ return;
1190
+ }
1191
+ default:
1192
+ throw new Error("Usage: cw.js sched plan|lease|release|complete|reclaim|reset|policy [show|set] [id] [--maxConcurrent N --maxAttempts N ...]");
1193
+ }
1194
+ }
1195
+ case "gc": {
1196
+ // Run Retention & Provable Reclamation (v0.1.39). `plan` is a pure dry-run
1197
+ // (frees nothing); `run` executes the write-ahead reclamation transaction;
1198
+ // `verify` re-proves a reclaimed run. CW never reclaims by default.
1199
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
1200
+ const [subcommand, id] = args.positionals;
1201
+ switch (subcommand) {
1202
+ case "plan": {
1203
+ const result = (0, capability_core_1.gcPlan)(registry, id, args.options);
1204
+ if (wantsJson(args.options))
1205
+ printJson(result);
1206
+ else
1207
+ process.stdout.write(`${(0, run_registry_1.formatGcPlan)(result)}\n`);
1208
+ return;
1209
+ }
1210
+ case "run": {
1211
+ const result = (0, capability_core_1.gcRun)(registry, id, args.options);
1212
+ if (wantsJson(args.options))
1213
+ printJson(result);
1214
+ else
1215
+ process.stdout.write(`${(0, run_registry_1.formatGcRun)(result)}\n`);
1216
+ return;
1217
+ }
1218
+ case "verify": {
1219
+ const result = (0, capability_core_1.gcVerify)(registry, required(id, "run id"), args.options);
1220
+ if (wantsJson(args.options))
1221
+ printJson(result);
1222
+ else
1223
+ process.stdout.write(`${(0, run_registry_1.formatGcVerify)(result)}\n`);
1224
+ // Fail closed ONLY on a real integrity failure: a run that WAS reclaimed
1225
+ // but no longer re-proves. A not-reclaimed run has nothing to verify
1226
+ // (reclaimed:false/verified:false) and must not be treated as a failure.
1227
+ // LIMIT (honest): a DELETED reclaimed.json reads as reclaimed:false, so
1228
+ // proof-deletion is indistinguishable from never-reclaimed here without
1229
+ // an independent witness (e.g. a trust-audit reclamation event) — a
1230
+ // follow-up. This guard is still strictly better than the prior exit-0.
1231
+ if (result.reclaimed && !result.verified)
1232
+ process.exitCode = 1;
1233
+ return;
1234
+ }
1235
+ default:
1236
+ throw new Error("Usage: cw.js gc plan|run|verify [run-id] [--reclaimAfterArchiveDays N] [--keep-scratch] [--keep-snapshots] [--limit N] [--json]");
1237
+ }
1238
+ }
1239
+ case "history": {
1240
+ const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
1241
+ const result = (0, capability_core_1.runHistory)(registry, args.options);
1242
+ if (wantsJson(args.options))
1243
+ printJson(result);
1244
+ else
1245
+ process.stdout.write(`${(0, run_registry_1.formatHistory)(result)}\n`);
1246
+ return;
1247
+ }
1248
+ case "telemetry": {
1249
+ const [subcommand, id] = args.positionals;
1250
+ switch (subcommand) {
1251
+ case "verify": {
1252
+ const result = (0, capability_core_1.telemetryVerify)(runner, { ...args.options, runId: id || args.options.runId || args.options.run });
1253
+ if (wantsJson(args.options))
1254
+ printJson(result);
1255
+ else
1256
+ process.stdout.write(`${(0, telemetry_demo_1.formatTelemetryVerify)(result)}\n`);
1257
+ // Fail closed: a forged/edited/corrupt ledger verifies false — report it
1258
+ // through the exit code so `cw telemetry verify <run> && deploy` cannot
1259
+ // pass on a lie. (Absent ledger = present:false/verified:true -> exit 0.)
1260
+ if (!result.verified)
1261
+ process.exitCode = 1;
1262
+ return;
1263
+ }
1264
+ default:
1265
+ throw new Error("Usage: cw.js telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]");
1266
+ }
1267
+ }
1268
+ case "demo": {
1269
+ const [subcommand] = args.positionals;
1270
+ switch (subcommand) {
1271
+ case "tamper": {
1272
+ const result = (0, capability_core_1.demoTamper)(runner, args.options);
1273
+ if (wantsJson(args.options))
1274
+ printJson(result);
1275
+ else
1276
+ process.stdout.write(`${(0, telemetry_demo_1.formatTamperDemo)(result)}\n`);
1277
+ // Fail closed: if the proof did not hold (a tamper went undetected),
1278
+ // exit nonzero so the demo can never green a broken guarantee.
1279
+ if (!result.proven)
1280
+ process.exitCode = 1;
1281
+ return;
1282
+ }
1283
+ case "bundle": {
1284
+ const result = (0, capability_core_1.demoBundle)(runner, args.options);
1285
+ if (wantsJson(args.options))
1286
+ printJson(result);
1287
+ else
1288
+ process.stdout.write(`${(0, telemetry_demo_1.formatBundleDemo)(result)}\n`);
1289
+ // Fail closed: a forged bundle that verified would be a regression in the
1290
+ // bundle guarantee — exit nonzero so the demo can never green it.
1291
+ if (!result.proven)
1292
+ process.exitCode = 1;
1293
+ return;
1294
+ }
1295
+ default:
1296
+ throw new Error("Usage: cw.js demo tamper|bundle [--json]");
1297
+ }
1298
+ }
1299
+ case "workbench": {
1300
+ const [subcommand, runId] = args.positionals;
1301
+ switch (subcommand) {
1302
+ case "view": {
1303
+ // Read-only five-panel view of one run. Same core entry as cw_workbench_view.
1304
+ const view = (0, workbench_1.buildWorkbenchRunView)(runner, required(runId, "run id"));
1305
+ if (wantsJson(args.options))
1306
+ printJson(view);
1307
+ else
1308
+ process.stdout.write(`${formatWorkbenchView(view)}\n`);
1309
+ return;
1310
+ }
1311
+ case "serve": {
1312
+ // The OPTIONAL localhost host. `--once`/`--json` emit the descriptor only
1313
+ // (no server); the default starts the read-only, localhost-only host.
1314
+ if (args.options.once || wantsJson(args.options)) {
1315
+ printJson((0, workbench_1.buildWorkbenchServeDescriptor)(runner, { ...args.options, once: true }));
1316
+ return;
1317
+ }
1318
+ const host = new workbench_host_1.WorkbenchHost({
1319
+ runner,
1320
+ cwd: String(args.options.cwd || process.cwd()),
1321
+ port: Number(args.options.port) || undefined,
1322
+ scope: args.options.scope === "repo" ? "repo" : "home"
1323
+ });
1324
+ await host.run();
1325
+ return;
1326
+ }
1327
+ default:
1328
+ throw new Error("Usage: cw.js workbench serve [--port N] [--once] | view <run-id> [--json]");
1329
+ }
1330
+ }
1331
+ default:
1332
+ throw new Error(`Unknown command: ${args.command}`);
1333
+ }
1334
+ }
1335
+ function required(value, label) {
1336
+ if (!value)
1337
+ throw new Error(`Missing ${label}. Run "cw.js help" for usage.`);
1338
+ return value;
1339
+ }
1340
+ function optionalArg(value) {
1341
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
1342
+ }
1343
+ function printJson(value) {
1344
+ process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
1345
+ }
1346
+ function wantsJson(options) {
1347
+ return Boolean(options.json || options.format === "json");
1348
+ }
1349
+ function formatWorkbenchView(view) {
1350
+ const lines = [
1351
+ `Workbench view ${view.runId} (${view.resolved ? "resolved" : "UNRESOLVED"})`,
1352
+ view.error ? ` error: ${view.error}` : ""
1353
+ ].filter(Boolean);
1354
+ for (const [group, panels] of Object.entries(view.panels)) {
1355
+ lines.push(` ${group}:`);
1356
+ for (const [name, panel] of Object.entries(panels)) {
1357
+ const note = panel.status === "present" ? panel.capability : `absent (${panel.error || "unreadable"})`;
1358
+ lines.push(` ${name}: ${panel.status} — ${note}`);
1359
+ }
1360
+ }
1361
+ return lines.join("\n");
1362
+ }