cool-workflow 0.2.0 → 0.2.2

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 (141) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +7 -5
  4. package/apps/architecture-review/app.json +2 -2
  5. package/apps/architecture-review/workflow.js +12 -12
  6. package/apps/architecture-review-fast/app.json +1 -1
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/cli/dispatch.js +20 -88
  12. package/dist/cli/parseargv.js +6 -3
  13. package/dist/core/capability-data.js +270 -0
  14. package/dist/core/capability-table.js +15 -3519
  15. package/dist/core/format/help.js +30 -7
  16. package/dist/core/hash.js +1 -1
  17. package/dist/core/multi-agent/candidate-scoring.js +1 -1
  18. package/dist/core/multi-agent/collaboration.js +3 -2
  19. package/dist/core/multi-agent/coordinator.js +4 -3
  20. package/dist/core/multi-agent/eval-replay.js +1 -1
  21. package/dist/core/multi-agent/runtime.js +2 -2
  22. package/dist/core/multi-agent/trust-policy.js +1 -1
  23. package/dist/core/pipeline/commit-gate.js +2 -1
  24. package/dist/core/pipeline/contract.js +1 -1
  25. package/dist/core/pipeline/drive-decide.js +1 -1
  26. package/dist/core/state/contract-migration.js +1 -1
  27. package/dist/core/state/migrations.js +2 -2
  28. package/dist/core/state/node-snapshot.js +1 -1
  29. package/dist/core/state/state-explosion/digest.js +3 -2
  30. package/dist/core/state/state-explosion/graph.js +13 -12
  31. package/dist/core/state/state-explosion/helpers.js +5 -4
  32. package/dist/core/state/state-explosion/report.js +1 -1
  33. package/dist/core/state/state-explosion/size.js +1 -1
  34. package/dist/core/state/state-node.js +2 -2
  35. package/dist/core/state/types.js +1 -1
  36. package/dist/core/trust/ledger.js +3 -2
  37. package/dist/core/trust/telemetry-attestation.js +3 -3
  38. package/dist/core/trust/telemetry-ledger.js +2 -2
  39. package/dist/core/types/execution-backend.js +18 -0
  40. package/dist/core/types/observability.js +7 -0
  41. package/dist/core/util/collate.js +23 -0
  42. package/dist/core/version.js +1 -1
  43. package/dist/core/workflow-apps/app-schema.js +1 -1
  44. package/dist/mcp/dispatch.js +1 -1
  45. package/dist/mcp/server.js +1 -1
  46. package/dist/shell/agent-config.js +1 -1
  47. package/dist/shell/audit-cli.js +46 -2
  48. package/dist/shell/commit-summary.js +2 -1
  49. package/dist/shell/doctor.js +17 -4
  50. package/dist/shell/drive.js +47 -19
  51. package/dist/shell/evidence-reasoning.js +4 -3
  52. package/dist/shell/execution-backend/agent.js +42 -10
  53. package/dist/shell/execution-backend/ci.js +1 -1
  54. package/dist/shell/execution-backend/container.js +1 -1
  55. package/dist/shell/execution-backend/envelopes.js +1 -1
  56. package/dist/shell/execution-backend/local.js +1 -1
  57. package/dist/shell/execution-backend/probes.js +1 -1
  58. package/dist/shell/execution-backend/registry.js +3 -2
  59. package/dist/shell/execution-backend/remote.js +1 -1
  60. package/dist/shell/execution-backend/types.js +0 -9
  61. package/dist/shell/fs-atomic.js +15 -2
  62. package/dist/shell/ledger-io.js +1 -1
  63. package/dist/shell/metrics-cli.js +4 -2
  64. package/dist/shell/multi-agent-host.js +1 -1
  65. package/dist/shell/multi-agent-operator-ux.js +4 -3
  66. package/dist/shell/observability.js +12 -11
  67. package/dist/shell/onramp.js +17 -1
  68. package/dist/shell/operator-ux-text.js +2 -1
  69. package/dist/shell/operator-ux.js +7 -6
  70. package/dist/shell/pipeline-cli.js +82 -72
  71. package/dist/shell/reclamation-io.js +3 -2
  72. package/dist/shell/registry-cli.js +15 -0
  73. package/dist/shell/report.js +2 -1
  74. package/dist/shell/run-registry-io.js +1 -1
  75. package/dist/shell/run-store.js +17 -0
  76. package/dist/shell/sandbox-profile.js +1 -1
  77. package/dist/shell/scheduler-io.js +46 -37
  78. package/dist/shell/scheduling-io.js +32 -22
  79. package/dist/shell/state-explosion-cli.js +2 -1
  80. package/dist/shell/telemetry-ledger-io.js +1 -1
  81. package/dist/shell/term.js +1 -1
  82. package/dist/shell/topology-io.js +2 -1
  83. package/dist/shell/trust-audit.js +45 -5
  84. package/dist/shell/workbench-host.js +9 -1
  85. package/dist/shell/workbench.js +6 -11
  86. package/dist/shell/worker-cli.js +9 -1
  87. package/dist/shell/worker-isolation.js +34 -9
  88. package/dist/shell/workflow-app-loader.js +3 -2
  89. package/dist/wiring/capability-table/basics.js +66 -0
  90. package/dist/wiring/capability-table/exec-backend.js +162 -0
  91. package/dist/wiring/capability-table/index.js +42 -0
  92. package/dist/wiring/capability-table/multi-agent.js +623 -0
  93. package/dist/wiring/capability-table/parity.js +466 -0
  94. package/dist/wiring/capability-table/pipeline.js +280 -0
  95. package/dist/wiring/capability-table/registry-core.js +189 -0
  96. package/dist/wiring/capability-table/reporting.js +394 -0
  97. package/dist/wiring/capability-table/scheduling-registry.js +558 -0
  98. package/dist/wiring/capability-table/state.js +173 -0
  99. package/dist/wiring/capability-table/trust-ledger.js +134 -0
  100. package/dist/wiring/capability-table/workflow-apps.js +366 -0
  101. package/docs/agent-delegation-drive.7.md +4 -0
  102. package/docs/cli-mcp-parity.7.md +9 -2
  103. package/docs/contract-migration-tooling.7.md +4 -0
  104. package/docs/control-plane-scheduling.7.md +4 -0
  105. package/docs/durable-state-and-locking.7.md +24 -0
  106. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  107. package/docs/execution-backends.7.md +4 -0
  108. package/docs/index.md +1 -0
  109. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  110. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  111. package/docs/multi-agent-operator-ux.7.md +4 -0
  112. package/docs/node-snapshot-diff-replay.7.md +4 -0
  113. package/docs/observability-cost-accounting.7.md +6 -1
  114. package/docs/project-index.md +30 -5
  115. package/docs/real-execution-backends.7.md +4 -0
  116. package/docs/release-and-migration.7.md +4 -0
  117. package/docs/release-tooling.7.md +4 -0
  118. package/docs/remote-source-review.7.md +4 -4
  119. package/docs/report-verifiable-bundle.7.md +1 -1
  120. package/docs/run-registry-control-plane.7.md +4 -0
  121. package/docs/run-retention-reclamation.7.md +4 -0
  122. package/docs/security-trust-hardening.7.md +33 -1
  123. package/docs/state-explosion-management.7.md +4 -0
  124. package/docs/team-collaboration.7.md +4 -0
  125. package/docs/trust-audit-anchor.7.md +69 -0
  126. package/docs/web-desktop-workbench.7.md +15 -1
  127. package/manifest/plugin.manifest.json +1 -1
  128. package/package.json +3 -1
  129. package/scripts/agents/agent-adapter-core.js +22 -2
  130. package/scripts/agents/claude-p-agent.js +8 -3
  131. package/scripts/agents/gemini-agent.js +5 -1
  132. package/scripts/agents/opencode-agent.js +5 -1
  133. package/scripts/bump-version.js +24 -2
  134. package/scripts/canonical-apps.js +4 -4
  135. package/scripts/dogfood-release.js +1 -1
  136. package/scripts/golden-path.js +4 -4
  137. package/scripts/purity-baseline.json +68 -0
  138. package/scripts/purity-gate.js +239 -0
  139. package/scripts/release-check.js +8 -1
  140. package/scripts/version-sync-check.js +33 -12
  141. package/workflows/README.md +19 -0
@@ -1,39 +1,14 @@
1
1
  "use strict";
2
- // core/capability-table.ts — THE one data table: one row per capability.
2
+ // core/capability-table.ts — re-export shim.
3
3
  //
4
- // MILESTONE 2 (v2/PLAN.md build order, step 2). Replaces the old build's
5
- // `capability-registry.ts` (940 lines) + 40 CLI handler files + the
6
- // 196-arm MCP switch + the 1000-line tool-definitions array with ONE data
7
- // table plus two generic front-door readers (`cli/dispatch.ts`,
8
- // `mcp/dispatch.ts`).
9
- //
10
- // Per PLAN.md's build order note, this milestone wires only a HANDFUL of
11
- // capabilities end to end (version, help, list, status, sandbox.list —
12
- // exactly what conformance/cases/mcp-basic.case.js and the milestone-1
13
- // carry-over cases need). Every later milestone adds capabilities as table
14
- // ROWS ONLY; this file's shape (and cli/dispatch.ts + mcp/dispatch.ts) is
15
- // not touched again — see v2/PLAN.md's Revision note.
16
- //
17
- // Byte-compat item 5 (v2/PLAN.md): 12 capabilities have CLI and MCP call
18
- // DIFFERENT functions with DIFFERENT payloads. So a row carries a SEPARATE
19
- // `cli.handler` and `mcp.handler`, never one shared "handler" — even
20
- // though every row landed so far happens to share one function, the type
21
- // itself must not collapse the two fields into one, or a later milestone
22
- // would need a breaking shape change to add the first real divergent row.
23
- //
24
- // `MCP_TOOL_DATA` below is the full, literal 196-tool surface transcribed
25
- // from SPEC/mcp.md's "All 196 MCP tools" table (name, capability id,
26
- // required-argument groups, input property names, description) — this is
27
- // exactly the kind of declarative surface data this table exists to hold.
28
- // `tools/list` must report the full 196-tool set NOW (mcp-basic.case.js
29
- // asserts `tools.length >= 100` and checks specific names/order), even
30
- // though only a few of those 196 capabilities have a real, working
31
- // `tools/call` handler at this milestone. Every other tool's `mcp.handler`
32
- // is `notYetImplemented(capability)`, which throws a clean, typed error
33
- // if ever actually called — safe, because no case in this milestone's
34
- // filter calls an unimplemented tool. Each later milestone replaces the
35
- // placeholder handler for the rows it implements; the row's name,
36
- // schema, and position in the array do not change.
4
+ // The full capability table (the shared machinery + every domain slice)
5
+ // now lives under wiring/capability-table/ (see that directory's index.ts
6
+ // for the composition order REGISTRY order is a pinned behavior). This
7
+ // file stays so every existing import site (cli/dispatch.ts,
8
+ // mcp/dispatch.ts, shell/workbench.ts, the captable-*.test.js unit tests,
9
+ // scripts/parity-check.js, scripts/gen-parity-doc.js) keeps working
10
+ // unchanged, whether they import a value (REGISTRY, findCapability,
11
+ // CAPABILITY_REGISTRY, ...) or a pure type (Capability, CliBinding, ...).
37
12
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
38
13
  if (k2 === undefined) k2 = k;
39
14
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -45,3490 +20,11 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
45
20
  if (k2 === undefined) k2 = k;
46
21
  o[k2] = m[k];
47
22
  }));
48
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
49
- Object.defineProperty(o, "default", { enumerable: true, value: v });
50
- }) : function(o, v) {
51
- o["default"] = v;
52
- });
53
- var __importStar = (this && this.__importStar) || (function () {
54
- var ownKeys = function(o) {
55
- ownKeys = Object.getOwnPropertyNames || function (o) {
56
- var ar = [];
57
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
58
- return ar;
59
- };
60
- return ownKeys(o);
61
- };
62
- return function (mod) {
63
- if (mod && mod.__esModule) return mod;
64
- var result = {};
65
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
66
- __setModuleDefault(result, mod);
67
- return result;
68
- };
69
- })();
70
- var __importDefault = (this && this.__importDefault) || function (mod) {
71
- return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
24
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
72
25
  };
73
26
  Object.defineProperty(exports, "__esModule", { value: true });
74
- exports.CAPABILITY_REGISTRY = exports.REGISTRY = exports.CapabilityNotImplementedError = void 0;
75
- exports.listBundledWorkflows = listBundledWorkflows;
76
- exports.listBundledSandboxProfiles = listBundledSandboxProfiles;
77
- exports.statusPayload = statusPayload;
78
- exports.findCapability = findCapability;
79
- exports.findCapabilityByCliPath = findCapabilityByCliPath;
80
- exports.cliCapabilities = cliCapabilities;
81
- exports.mcpToolDefinitions = mcpToolDefinitions;
82
- exports.declaredMcpTools = declaredMcpTools;
83
- exports.findCapabilityByMcpTool = findCapabilityByMcpTool;
84
- exports.declaredMcpToolsList = declaredMcpToolsList;
85
- exports.mcpRequiredArgsForTool = mcpRequiredArgsForTool;
86
- exports.declaredCliTokens = declaredCliTokens;
87
- exports.declaredCliHelpTokens = declaredCliHelpTokens;
88
- exports.requiresReason = requiresReason;
89
- exports.isPayloadProbeOptOut = isPayloadProbeOptOut;
90
- exports.payloadIdenticalCapabilities = payloadIdenticalCapabilities;
91
- exports.payloadProbeTargets = payloadProbeTargets;
92
- exports.deferredPayloadProbeCapabilities = deferredPayloadProbeCapabilities;
93
- exports.buildPayloadProbePlan = buildPayloadProbePlan;
94
- exports.payloadProbePlan = payloadProbePlan;
95
- exports.buildParityReport = buildParityReport;
96
- /** Thrown by every not-yet-wired MCP tool handler. Never hit by this
97
- * milestone's conformance filter — every tool mcp-basic.case.js actually
98
- * calls (`cw_list`, `cw_sandbox_list`) has a real handler below. */
99
- class CapabilityNotImplementedError extends Error {
100
- constructor(capability) {
101
- super(`${capability} is not implemented in this milestone`);
102
- this.name = "CapabilityNotImplementedError";
103
- }
104
- }
105
- exports.CapabilityNotImplementedError = CapabilityNotImplementedError;
106
- function notYetImplemented(capability) {
107
- return () => {
108
- throw new CapabilityNotImplementedError(capability);
109
- };
110
- }
111
- function stringProperty(name) {
112
- return { type: "string", description: name };
113
- }
114
- /** SPEC/mcp.md's two hand-written property-shape exceptions (see that
115
- * file's "All 196 MCP tools" section header note): every OTHER property
116
- * on every OTHER tool is the plain string form above. */
117
- const PROPERTY_OVERRIDES = {
118
- cw_commit: {
119
- allowUnverifiedCheckpoint: {
120
- type: "boolean",
121
- description: "Write a non-gated checkpoint instead of committed state",
122
- },
123
- },
124
- cw_routine_fire: {
125
- payload: { type: "object", description: "Event payload" },
126
- },
127
- };
128
- const MCP_TOOL_DATA = [
129
- { tool: "cw_list", capability: "list", requiredArgs: [], properties: [], description: "List bundled CW workflows." },
130
- { tool: "cw_plan", capability: "plan", requiredArgs: ["workflowId"], properties: ["workflowId", "repo", "question"], description: "Create a CW run and return its canonical plan summary." },
131
- { tool: "cw_app_run", capability: "app.run", requiredArgs: ["appId"], properties: ["cwd", "appId", "inputs", "sandbox", "sandboxProfile", "sandboxProfileId"], description: "Create a run from an app id + structured inputs." },
132
- { tool: "cw_status", capability: "status", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read run checkpoint status." },
133
- { tool: "cw_init", capability: "init", requiredArgs: ["workflowId"], properties: ["workflowId", "title", "output"], description: "Scaffold a new workflow definition." },
134
- { tool: "cw_next", capability: "next", requiredArgs: ["runId"], properties: ["runId", "cwd", "limit"], description: "Read the next recommended tasks for a run." },
135
- { tool: "cw_state_check", capability: "state.check", requiredArgs: ["runId"], properties: ["runId", "cwd", "state", "write"], description: "Check run-state schema compatibility." },
136
- { tool: "cw_contract_show", capability: "contract.show", requiredArgs: ["runId"], properties: ["runId", "cwd", "contractId"], description: "Show a run's pipeline contract." },
137
- { tool: "cw_node_list", capability: "node.list", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "List state nodes for a run." },
138
- { tool: "cw_node_show", capability: "node.show", requiredArgs: ["runId, nodeId"], properties: ["runId", "cwd", "nodeId"], description: "Show one state node for a run." },
139
- { tool: "cw_node_graph", capability: "node.graph", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the state-node graph for a run." },
140
- { tool: "cw_node_snapshot", capability: "node.snapshot", requiredArgs: [], properties: ["runId", "cwd", "nodeId"], description: "Snapshot one state node (derived + fingerprinted)." },
141
- { tool: "cw_node_diff", capability: "node.diff", requiredArgs: [], properties: ["runId", "cwd", "baselineSnapshotId", "candidateSnapshotId"], description: "Structurally diff two node snapshots." },
142
- { tool: "cw_node_replay", capability: "node.replay", requiredArgs: [], properties: ["runId", "cwd", "snapshotId"], description: "Deterministically replay one node from a snapshot." },
143
- { tool: "cw_node_replay_verify", capability: "node.replay.verify", requiredArgs: [], properties: ["runId", "cwd", "replayId"], description: "Verify a node replay against its source." },
144
- { tool: "cw_migration_list", capability: "migration.list", requiredArgs: [], properties: [], description: "List the declared migration registry." },
145
- { tool: "cw_migration_check", capability: "migration.check", requiredArgs: [], properties: ["target", "contract", "cwd"], description: "Dry-run migration verdict for a target." },
146
- { tool: "cw_migration_prove", capability: "migration.prove", requiredArgs: [], properties: ["target", "contract", "cwd"], description: "Round-trip / non-destruction migration proof for a target." },
147
- { tool: "cw_operator_status", capability: "operator.status", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured Operator UX run status." },
148
- { tool: "cw_operator_graph", capability: "graph", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured Operator UX run graph." },
149
- { tool: "cw_operator_report", capability: "operator.report", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Refresh and read the structured Operator UX report summary." },
150
- { tool: "cw_worker_summary", capability: "worker.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured worker summary for a run." },
151
- { tool: "cw_workbench_view", capability: "workbench.view", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the read-only five-panel Workbench view of one run (graph, blackboard, worker, candidate, audit)." },
152
- { tool: "cw_workbench_serve", capability: "workbench.serve", requiredArgs: [], properties: ["cwd", "port", "scope"], description: "Describe/serve the optional localhost-only, read-only Workbench host." },
153
- { tool: "cw_candidate_summary", capability: "candidate.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured candidate summary for a run." },
154
- { tool: "cw_feedback_summary", capability: "feedback.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured feedback summary for a run." },
155
- { tool: "cw_commit_summary", capability: "commit.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured commit summary for a run." },
156
- { tool: "cw_multi_agent_summary", capability: "multi-agent.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured multi-agent runtime summary for a run." },
157
- { tool: "cw_multi_agent_graph", capability: "multi-agent.graph", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the structured multi-agent operator graph for a run." },
158
- { tool: "cw_multi_agent_dependencies", capability: "multi-agent.dependencies", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read derived multi-agent dependency edges for operator inspection." },
159
- { tool: "cw_multi_agent_failures", capability: "multi-agent.failures", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read failed, blocked, rejected, and ambiguous multi-agent records." },
160
- { tool: "cw_multi_agent_evidence", capability: "multi-agent.evidence", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read evidence adoption status from worker output through selection and commit. Each row carries a derived rationaleStatus (explained|unexplained|not-applicable)." },
161
- { tool: "cw_evidence_reasoning", capability: "multi-agent.reasoning", requiredArgs: ["runId"], properties: ["runId", "cwd", "evidence", "refresh"], description: "Explain why each evidence item was adopted/rejected." },
162
- { tool: "cw_evidence_reasoning_refresh", capability: "multi-agent.reasoning.refresh", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Refresh the durable evidence-reasoning index." },
163
- { tool: "cw_summary_refresh", capability: "summary.refresh", requiredArgs: ["runId"], properties: ["runId", "cwd", "view"], description: "Refresh state-explosion summaries." },
164
- { tool: "cw_summary_show", capability: "summary.show", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the persisted state-explosion report." },
165
- { tool: "cw_blackboard_summarize", capability: "blackboard.summarize", requiredArgs: ["runId"], properties: ["runId", "cwd", "blackboardId"], description: "Read a blackboard digest with conflicts/evidence." },
166
- { tool: "cw_multi_agent_summarize", capability: "multi-agent.summarize", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the combined state-explosion report." },
167
- { tool: "cw_multi_agent_graph_compact", capability: "multi-agent.graph.compact", requiredArgs: ["runId"], properties: ["runId", "cwd", "view", "focus", "depth"], description: "Read a compact/focused multi-agent graph view." },
168
- { tool: "cw_multi_agent_run", capability: "multi-agent.run", requiredArgs: [], properties: ["runId", "cwd", "app", "appId", "workflow", "workflowId", "topology", "topologyId", "task", "mapperCount", "judgeCount", "debateRounds"], description: "Create or attach a topology-backed multi-agent run." },
169
- { tool: "cw_multi_agent_status", capability: "multi-agent.status", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read combined topology/blackboard/worker status." },
170
- { tool: "cw_multi_agent_step", capability: "multi-agent.step", requiredArgs: ["runId"], properties: ["runId", "cwd", "sandbox", "backend", "limit"], description: "Perform one safe deterministic host step." },
171
- { tool: "cw_multi_agent_blackboard", capability: "multi-agent.blackboard", requiredArgs: ["runId"], properties: ["runId", "cwd", "action", "blackboardId", "topicId", "body", "kind", "path", "evidence"], description: "Operate on the active multi-agent blackboard." },
172
- { tool: "cw_multi_agent_score", capability: "multi-agent.score", requiredArgs: ["runId"], properties: ["runId", "cwd", "candidate", "candidateId", "worker", "criterion", "criteria", "evidence", "maxTotal"], description: "Score a candidate with evidence." },
173
- { tool: "cw_multi_agent_select", capability: "multi-agent.select", requiredArgs: ["runId"], properties: ["runId", "cwd", "candidate", "candidateId", "score", "scoreId", "reason", "allowUnverified"], description: "Select a candidate with the verifier gate." },
174
- { tool: "cw_eval_snapshot", capability: "eval.snapshot", requiredArgs: ["runId"], properties: ["runId", "cwd", "id"], description: "Create a deterministic replay snapshot." },
175
- { tool: "cw_eval_replay", capability: "eval.replay", requiredArgs: ["snapshot|snapshotId|path"], properties: ["cwd", "snapshot", "snapshotId", "path", "id"], description: "Replay a snapshot without live agents." },
176
- { tool: "cw_eval_compare", capability: "eval.compare", requiredArgs: ["baseline|baselinePath, replay|replayPath"], properties: ["cwd", "baseline", "baselinePath", "replay", "replayPath"], description: "Compare baseline and replay deterministically." },
177
- { tool: "cw_eval_score", capability: "eval.score", requiredArgs: ["replay|replayPath|path"], properties: ["cwd", "replay", "replayPath", "path"], description: "Score replay quality." },
178
- { tool: "cw_eval_gate", capability: "eval.gate", requiredArgs: ["suite|suiteId|path"], properties: ["cwd", "suite", "suiteId", "path"], description: "Run the eval/replay regression gate." },
179
- { tool: "cw_eval_report", capability: "eval.report", requiredArgs: ["replay|replayPath|path"], properties: ["cwd", "replay", "replayPath", "path"], description: "Render an eval/replay report." },
180
- { tool: "cw_multi_agent_run_create", capability: "multi-agent.run.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "title", "objective"], description: "Create a MultiAgentRun state record." },
181
- { tool: "cw_multi_agent_run_transition", capability: "multi-agent.run.transition", requiredArgs: ["runId"], properties: ["runId", "cwd", "multiAgentRunId", "id", "status", "reason"], description: "Transition a MultiAgentRun lifecycle." },
182
- { tool: "cw_multi_agent_run_show", capability: "multi-agent.run.show", requiredArgs: ["runId"], properties: ["runId", "cwd", "multiAgentRunId", "id"], description: "Show one MultiAgentRun record." },
183
- { tool: "cw_multi_agent_role_create", capability: "multi-agent.role.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "multiAgentRunId", "multiAgentRun", "title", "responsibility", "requiredEvidence", "sandboxProfileHint", "expectedArtifact", "faninObligation"], description: "Create an AgentRole record." },
184
- { tool: "cw_multi_agent_role_show", capability: "multi-agent.role.show", requiredArgs: ["runId, roleId"], properties: ["runId", "cwd", "roleId", "id"], description: "Show one AgentRole record." },
185
- { tool: "cw_multi_agent_group_create", capability: "multi-agent.group.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "multiAgentRunId", "multiAgentRun", "title", "phase", "task"], description: "Create an AgentGroup record." },
186
- { tool: "cw_multi_agent_group_show", capability: "multi-agent.group.show", requiredArgs: ["runId, groupId"], properties: ["runId", "cwd", "groupId", "id"], description: "Show one AgentGroup record." },
187
- { tool: "cw_multi_agent_membership_create", capability: "multi-agent.membership.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "groupId", "roleId", "taskId", "workerId", "dispatchId", "fanoutId"], description: "Create an AgentMembership record." },
188
- { tool: "cw_multi_agent_membership_show", capability: "multi-agent.membership.show", requiredArgs: ["runId, membershipId"], properties: ["runId", "cwd", "membershipId", "id"], description: "Show one AgentMembership record." },
189
- { tool: "cw_multi_agent_fanout_create", capability: "multi-agent.fanout.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "groupId", "reason", "role", "task", "limit", "sandboxChoice"], description: "Create an AgentFanout record." },
190
- { tool: "cw_multi_agent_fanout_show", capability: "multi-agent.fanout.show", requiredArgs: ["runId, fanoutId"], properties: ["runId", "cwd", "fanoutId", "id"], description: "Show one AgentFanout record." },
191
- { tool: "cw_multi_agent_fanin_collect", capability: "multi-agent.fanin.collect", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "groupId", "fanoutId", "requiredRole", "strategy"], description: "Collect an AgentFanin with evidence coverage." },
192
- { tool: "cw_multi_agent_fanin_show", capability: "multi-agent.fanin.show", requiredArgs: ["runId, faninId"], properties: ["runId", "cwd", "faninId", "id"], description: "Show one AgentFanin record." },
193
- { tool: "cw_topology_list", capability: "topology.list", requiredArgs: [], properties: [], description: "List official topology definitions." },
194
- { tool: "cw_topology_show", capability: "topology.show", requiredArgs: ["topologyId|id"], properties: ["runId", "cwd", "topologyId", "topologyRunId", "id"], description: "Show a topology definition or run." },
195
- { tool: "cw_topology_validate", capability: "topology.validate", requiredArgs: ["topologyId|id"], properties: ["topologyId", "id"], description: "Validate a topology definition." },
196
- { tool: "cw_topology_apply", capability: "topology.apply", requiredArgs: ["runId, topologyId|id"], properties: ["runId", "cwd", "topologyId", "id", "task", "mapperCount", "judgeCount", "debateRounds", "blackboardId", "multiAgentRunId", "collectInitialFanin"], description: "Apply a topology to a run." },
197
- { tool: "cw_topology_summary", capability: "topology.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read topology progress and next actions." },
198
- { tool: "cw_topology_graph", capability: "topology.graph", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read topology graph nodes and edges." },
199
- { tool: "cw_blackboard_summary", capability: "blackboard.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the blackboard/coordinator summary." },
200
- { tool: "cw_blackboard_graph", capability: "blackboard.graph", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read blackboard graph nodes and edges." },
201
- { tool: "cw_blackboard_resolve", capability: "blackboard.resolve", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "title", "multiAgentRunId", "groupId", "roleId", "membershipId"], description: "Create or resolve a run blackboard." },
202
- { tool: "cw_blackboard_topic_create", capability: "blackboard.topic.create", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "title", "description", "blackboardId", "tag"], description: "Create a blackboard topic." },
203
- { tool: "cw_blackboard_message_post", capability: "blackboard.message.post", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "topic", "topicId", "body", "replyTo", "visibility", "evidence", "artifact"], description: "Post a blackboard message." },
204
- { tool: "cw_blackboard_message_list", capability: "blackboard.message.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "topic", "topicId", "blackboardId"], description: "List blackboard messages." },
205
- { tool: "cw_blackboard_context_put", capability: "blackboard.context.put", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "topic", "topicId", "kind", "key", "value", "supersedes", "evidence", "artifact"], description: "Publish a shared context frame." },
206
- { tool: "cw_blackboard_artifact_add", capability: "blackboard.artifact.add", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "topic", "kind", "path", "locator", "source", "evidence"], description: "Index an artifact in the blackboard." },
207
- { tool: "cw_blackboard_artifact_list", capability: "blackboard.artifact.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "topic", "blackboardId"], description: "List blackboard artifact refs." },
208
- { tool: "cw_blackboard_snapshot", capability: "blackboard.snapshot", requiredArgs: ["runId"], properties: ["runId", "cwd", "blackboardId"], description: "Create a durable blackboard snapshot." },
209
- { tool: "cw_coordinator_summary", capability: "coordinator.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the coordinator summary." },
210
- { tool: "cw_coordinator_decision", capability: "coordinator.decision", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "kind", "outcome", "reason", "subject", "evidence", "artifact", "message"], description: "Record a coordinator decision." },
211
- { tool: "cw_audit_summary", capability: "audit.summary", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the trust/audit summary." },
212
- { tool: "cw_audit_verify", capability: "audit.verify", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Re-prove a run's trust-audit hash chain (fail-closed exit)." },
213
- { tool: "cw_audit_worker", capability: "audit.worker", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId"], description: "Read trust/audit for one worker." },
214
- { tool: "cw_audit_provenance", capability: "audit.provenance", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "worker", "candidateId", "candidate", "commitId", "commit"], description: "Inspect evidence provenance." },
215
- { tool: "cw_audit_multi_agent", capability: "audit.multi-agent", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the multi-agent trust/policy/provenance audit." },
216
- { tool: "cw_audit_policy", capability: "audit.policy", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read role policies and permission decisions." },
217
- { tool: "cw_audit_role", capability: "audit.role", requiredArgs: ["runId"], properties: ["runId", "cwd", "roleId", "id"], description: "Read policy/audit for one role." },
218
- { tool: "cw_audit_blackboard", capability: "audit.blackboard", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read the blackboard write audit." },
219
- { tool: "cw_audit_judge", capability: "audit.judge", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Read judge rationale/panel decision audit." },
220
- { tool: "cw_audit_attest", capability: "audit.attest", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "worker", "actor", "hostEnforced", "env", "note"], description: "Record a host/operator sandbox attestation." },
221
- { tool: "cw_audit_decision", capability: "audit.decision", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "path", "command", "network", "env", "kind"], description: "Validate and record a sandbox decision." },
222
- { tool: "cw_dispatch", capability: "dispatch", requiredArgs: ["runId"], properties: ["runId", "cwd", "limit", "sandbox", "sandboxProfile", "sandboxProfileId", "backend", "backendId"], description: "Create a subagent dispatch manifest." },
223
- { tool: "cw_sandbox_list", capability: "sandbox.list", requiredArgs: [], properties: ["cwd"], description: "List bundled sandbox profiles." },
224
- { tool: "cw_sandbox_show", capability: "sandbox.show", requiredArgs: ["profileId"], properties: ["cwd", "profileId"], description: "Show a resolved sandbox profile." },
225
- { tool: "cw_sandbox_validate", capability: "sandbox.validate", requiredArgs: ["profileFile"], properties: ["cwd", "profileFile"], description: "Validate a sandbox profile JSON file." },
226
- { tool: "cw_sandbox_choose", capability: "sandbox.choose", requiredArgs: [], properties: ["cwd", "profileId", "sandbox", "sandboxProfile", "sandboxProfileId"], description: "Resolve and validate a sandbox profile choice." },
227
- { tool: "cw_sandbox_resolve", capability: "sandbox.resolve", requiredArgs: [], properties: ["cwd", "profileId", "sandbox", "sandboxProfile", "sandboxProfileId"], description: "Alias of sandbox.choose." },
228
- { tool: "cw_backend_list", capability: "backend.list", requiredArgs: [], properties: ["cwd"], description: "List available execution backends and their capabilities." },
229
- { tool: "cw_backend_show", capability: "backend.show", requiredArgs: [], properties: ["cwd", "backendId"], description: "Show one execution backend descriptor." },
230
- { tool: "cw_backend_probe", capability: "backend.probe", requiredArgs: [], properties: ["cwd", "backendId"], description: "Probe execution backend readiness (live, deterministic)." },
231
- { tool: "cw_backend_agent_config_show", capability: "backend.agent.config.show", requiredArgs: [], properties: ["cwd", "agentCommand", "agentEndpoint", "agentModel"], description: "Show the effective agent delegation config (flags>env>file, secret-stripped, host-stable)." },
232
- { tool: "cw_backend_agent_config_set", capability: "backend.agent.config.set", requiredArgs: [], properties: ["cwd", "agentCommand", "agentEndpoint", "agentModel"], description: "Set the durable agent delegation config (command-template/endpoint/model; API keys never written)." },
233
- { tool: "cw_result", capability: "result", requiredArgs: ["runId"], properties: ["runId", "taskId", "resultPath", "cwd"], description: "Record a subagent result file against a task." },
234
- { tool: "cw_commit", capability: "commit", requiredArgs: ["runId"], properties: ["runId", "reason", "verifier", "verifierNode", "candidate", "selection", "allowUnverifiedCheckpoint", "cwd"], description: "Create a verifier-gated commit or checkpoint." },
235
- { tool: "cw_report", capability: "report", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Render a run report and return its canonical descriptor." },
236
- { tool: "cw_app_list", capability: "app.list", requiredArgs: [], properties: ["cwd"], description: "List CW workflow apps." },
237
- { tool: "cw_app_show", capability: "app.show", requiredArgs: [], properties: ["cwd", "appId"], description: "Show a CW workflow app contract." },
238
- { tool: "cw_app_validate", capability: "app.validate", requiredArgs: [], properties: ["cwd", "target"], description: "Validate an app by path or id." },
239
- { tool: "cw_app_init", capability: "app.init", requiredArgs: [], properties: ["cwd", "appId", "title", "directory"], description: "Create a CW workflow app directory." },
240
- { tool: "cw_app_package", capability: "app.package", requiredArgs: [], properties: ["cwd", "appId", "output"], description: "Package an app as a JSON artifact." },
241
- { tool: "cw_worker_list", capability: "worker.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "status"], description: "List worker isolation scopes." },
242
- { tool: "cw_worker_show", capability: "worker.show", requiredArgs: ["runId, workerId"], properties: ["runId", "cwd", "workerId"], description: "Show one worker isolation scope." },
243
- { tool: "cw_worker_manifest", capability: "worker.manifest", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId"], description: "Write and return a worker manifest." },
244
- { tool: "cw_worker_output", capability: "worker.output", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "resultPath"], description: "Record worker output." },
245
- { tool: "cw_worker_fail", capability: "worker.fail", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "message", "code", "path", "retryable"], description: "Record a structured worker failure." },
246
- { tool: "cw_worker_validate", capability: "worker.validate", requiredArgs: ["runId"], properties: ["runId", "cwd", "workerId", "path", "resultPath"], description: "Validate a worker output boundary." },
247
- { tool: "cw_candidate_list", capability: "candidate.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "status", "kind"], description: "List candidates for a run." },
248
- { tool: "cw_candidate_show", capability: "candidate.show", requiredArgs: ["runId, candidateId"], properties: ["runId", "cwd", "candidateId"], description: "Show one candidate." },
249
- { tool: "cw_candidate_register", capability: "candidate.register", requiredArgs: ["runId"], properties: ["runId", "cwd", "id", "kind", "worker", "task", "resultNode", "verifierNode", "resultPath"], description: "Register a candidate from evidence." },
250
- { tool: "cw_candidate_score", capability: "candidate.score", requiredArgs: ["runId"], properties: ["runId", "cwd", "candidateId", "criteria", "criterion", "evidence", "maxTotal", "max", "verdict", "notes", "scorer"], description: "Score a candidate with criteria/evidence." },
251
- { tool: "cw_candidate_rank", capability: "candidate.rank", requiredArgs: ["runId"], properties: ["runId", "cwd", "includeRejected", "minNormalized", "requireEvidence", "requireVerifierGate", "tieBreaker"], description: "Rank candidates with gates." },
252
- { tool: "cw_candidate_select", capability: "candidate.select", requiredArgs: ["runId"], properties: ["runId", "cwd", "candidateId", "reason", "selectedBy", "by", "score", "allowUnverified", "minNormalized", "requireVerifierGate"], description: "Select a candidate with the verifier gate." },
253
- { tool: "cw_candidate_reject", capability: "candidate.reject", requiredArgs: ["runId"], properties: ["runId", "cwd", "candidateId", "reason"], description: "Reject a candidate with a reason." },
254
- { tool: "cw_approve", capability: "approve", requiredArgs: ["runId", "targetKind|kind", "targetId|target"], properties: ["runId", "cwd", "targetKind", "targetId", "actor", "actorKind", "role", "displayName", "attested", "attestation", "rationale", "supersedes"], description: "Append a host-attested approval of a candidate/commit/selection." },
255
- { tool: "cw_reject", capability: "reject", requiredArgs: ["runId", "targetKind|kind", "targetId|target"], properties: ["runId", "cwd", "targetKind", "targetId", "actor", "actorKind", "role", "displayName", "attested", "attestation", "rationale"], description: "Append a host-attested rejection (blocking veto) of a candidate/commit/selection." },
256
- { tool: "cw_comment_add", capability: "comment.add", requiredArgs: ["runId", "targetKind|kind", "targetId|target", "body|message|text"], properties: ["runId", "cwd", "targetKind", "targetId", "actor", "actorKind", "role", "displayName", "attested", "attestation", "body", "thread", "parent"], description: "Append a comment to a durable target." },
257
- { tool: "cw_comment_list", capability: "comment.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "targetKind", "target"], description: "List append-only comments for a run (optionally one target)." },
258
- { tool: "cw_handoff", capability: "handoff", requiredArgs: ["runId", "targetKind|kind", "targetId|target", "to|toActor"], properties: ["runId", "cwd", "targetKind", "targetId", "actor", "actorKind", "role", "displayName", "attested", "attestation", "to", "toRole", "from", "reason"], description: "Record an ownership transfer (from-actor → to-actor) of a run/task." },
259
- { tool: "cw_ledger_propose", capability: "ledger.propose", requiredArgs: ["from", "to", "title", "rationale"], properties: ["from", "to", "title", "rationale", "files", "diff"], description: "Build a verifiable cross-agent change proposal entry (printed as JSON)." },
260
- { tool: "cw_ledger_review", capability: "ledger.review", requiredArgs: ["from", "to", "target", "verdict"], properties: ["from", "to", "target", "verdict", "findings"], description: "Build a verifiable cross-agent review verdict entry (printed as JSON)." },
261
- { tool: "cw_ledger_verify", capability: "ledger.verify", requiredArgs: ["entry"], properties: ["entry"], description: "Verify a ledger entry against its content digest (fail-closed on tampering)." },
262
- { tool: "cw_ledger_apply", capability: "ledger.apply", requiredArgs: ["entry"], properties: ["entry"], description: "Verify a proposal entry and return its suggestedDiff for `git apply` (fail-closed: no diff unless the entry verifies as a proposal)." },
263
- { tool: "cw_ledger_list", capability: "ledger.list", requiredArgs: ["dir|dirs"], properties: ["dir", "dirs"], description: "Read + verify every entry in one or more shared ledger directories (fail-closed inbox; 2+ dirs union-verify mirrors)." },
264
- { tool: "cw_review_status", capability: "review.status", requiredArgs: ["runId"], properties: ["runId", "cwd", "targetKind", "target", "now"], description: "Read the derived per-target review state + collaboration timeline for a run." },
265
- { tool: "cw_review_policy", capability: "review.policy", requiredArgs: ["runId"], properties: ["runId", "cwd", "requiredApprovals", "authorizedRoles", "allowSelfApproval", "requireAttestedActor", "appliesTo"], description: "Set the run's review-gate policy (required approvals, authorized roles, self-approval rule)." },
266
- { tool: "cw_feedback_list", capability: "feedback.list", requiredArgs: ["runId"], properties: ["runId", "cwd", "status"], description: "List run feedback records." },
267
- { tool: "cw_feedback_show", capability: "feedback.show", requiredArgs: ["runId, feedbackId"], properties: ["runId", "feedbackId", "cwd"], description: "Show a run feedback record." },
268
- { tool: "cw_feedback_collect", capability: "feedback.collect", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Collect feedback from failed nodes." },
269
- { tool: "cw_feedback_task", capability: "feedback.task", requiredArgs: ["runId"], properties: ["runId", "feedbackId", "cwd", "verify"], description: "Create a correction task for feedback." },
270
- { tool: "cw_feedback_resolve", capability: "feedback.resolve", requiredArgs: ["runId"], properties: ["runId", "feedbackId", "cwd", "node", "status"], description: "Resolve or reject feedback." },
271
- { tool: "cw_schedule_create", capability: "schedule.create", requiredArgs: [], properties: ["cwd", "kind", "prompt", "intervalMinutes", "cron", "delayMinutes"], description: "Create a scheduled CW task." },
272
- { tool: "cw_schedule_list", capability: "schedule.list", requiredArgs: [], properties: ["cwd", "status"], description: "List scheduled CW tasks." },
273
- { tool: "cw_schedule_due", capability: "schedule.due", requiredArgs: [], properties: ["cwd"], description: "List due scheduled CW tasks." },
274
- { tool: "cw_schedule_complete", capability: "schedule.complete", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Mark a scheduled task complete." },
275
- { tool: "cw_schedule_pause", capability: "schedule.pause", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Pause a scheduled CW task." },
276
- { tool: "cw_schedule_resume", capability: "schedule.resume", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Resume a scheduled CW task." },
277
- { tool: "cw_schedule_run_now", capability: "schedule.run-now", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Create an immediate scheduled-task run record." },
278
- { tool: "cw_schedule_history", capability: "schedule.history", requiredArgs: [], properties: ["cwd", "id"], description: "List scheduled-task run history." },
279
- { tool: "cw_schedule_delete", capability: "schedule.delete", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Delete a scheduled CW task." },
280
- { tool: "cw_routine_create", capability: "routine.create", requiredArgs: [], properties: ["cwd", "kind", "prompt", "match"], description: "Create a routine-style API/GitHub trigger." },
281
- { tool: "cw_routine_list", capability: "routine.list", requiredArgs: [], properties: ["cwd", "kind"], description: "List routine-style triggers." },
282
- { tool: "cw_routine_fire", capability: "routine.fire", requiredArgs: ["kind"], properties: ["cwd", "kind", "payload"], description: "Record an API/GitHub trigger event." },
283
- { tool: "cw_routine_events", capability: "routine.events", requiredArgs: [], properties: ["cwd", "id"], description: "List routine trigger events." },
284
- { tool: "cw_routine_delete", capability: "routine.delete", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Delete a routine-style trigger." },
285
- { tool: "cw_registry_refresh", capability: "registry.refresh", requiredArgs: [], properties: ["cwd", "scope"], description: "Recompute and persist the derived run registry index." },
286
- { tool: "cw_registry_show", capability: "registry.show", requiredArgs: [], properties: ["cwd", "scope"], description: "Read the run registry index with valid|stale|absent freshness." },
287
- { tool: "cw_metrics_show", capability: "metrics.show", requiredArgs: ["runId"], properties: ["runId", "cwd", "pricing", "now"], description: "Read the derived per-run observability + attested-cost report (durations, failure/verifier/acceptance rates with sample counts, attested usage, cost, coverage)." },
288
- { tool: "cw_metrics_summary", capability: "metrics.summary", requiredArgs: [], properties: ["cwd", "scope", "pricing", "now"], description: "Read the cross-repo observability + cost rollup over the v0.1.28 run registry, with per-app and per-backend breakdowns." },
289
- { tool: "cw_run_search", capability: "run.search", requiredArgs: [], properties: ["cwd", "scope", "text", "app", "status", "repo", "since", "until", "includeArchived", "limit", "offset"], description: "Search runs by app/status/time/repo/free-text, deterministic + paginated." },
290
- { tool: "cw_run_list", capability: "run.list", requiredArgs: [], properties: ["cwd", "scope", "includeArchived", "limit", "offset"], description: "List indexed runs across repos (search with no filters)." },
291
- { tool: "cw_run_show", capability: "run.show", requiredArgs: ["runId"], properties: ["runId", "cwd", "scope"], description: "Resolve one run by id across the registry; fail closed on missing source." },
292
- { tool: "cw_run_resume", capability: "run.resume", requiredArgs: ["runId"], properties: ["runId", "cwd", "scope", "limit"], description: "Resolve a run by id and return its next runnable tasks/actions (read-only by default; the opt-in --drive/--once mode hands it to the shared agent-drive core, which mutates and is covered by run.drive.step)." },
293
- { tool: "cw_run_archive", capability: "run.archive", requiredArgs: ["runId|olderThanDays"], properties: ["runId", "cwd", "scope", "reason", "unarchive", "olderThanDays", "state"], description: "Archive/unarchive a run (overlay mark; never deletes source)." },
294
- { tool: "cw_run_rerun", capability: "run.rerun", requiredArgs: ["runId"], properties: ["runId", "cwd", "scope", "reason"], description: "Re-run a failed run as a NEW run linked to the original by provenance." },
295
- { tool: "cw_run_export", capability: "run.export", requiredArgs: ["runId"], properties: ["runId", "cwd", "output", "path", "archive", "trustKey", "withTrustKey"], description: "Export a run to a portable archive with run-local files and digest integrity." },
296
- { tool: "cw_run_import", capability: "run.import", requiredArgs: ["archive|path|file"], properties: ["archive", "path", "file", "target", "repo", "cwd"], description: "Restore a portable run archive into a target repo and verify restored file digests." },
297
- { tool: "cw_run_verify_import", capability: "run.verify-import", requiredArgs: ["runId"], properties: ["runId", "cwd"], description: "Verify an imported run against its restore manifest and telemetry chain." },
298
- { tool: "cw_run_inspect_archive", capability: "run.inspect-archive", requiredArgs: ["archive|path|file"], properties: ["archive", "path", "file", "cwd"], description: "Read-only integrity inspection of a portable run archive without importing it." },
299
- { tool: "cw_run_restore", capability: "run.restore", requiredArgs: ["archive|path|file"], properties: ["archive", "path", "file", "target", "repo", "cwd"], description: "Fail-closed restore of a portable run archive: integrity-inspect, import, and verify in one step; refuses anything that does not verify." },
300
- { tool: "cw_report_verify_bundle", capability: "report.verify-bundle", requiredArgs: ["archive|path|file|bundle"], properties: ["archive", "path", "file", "bundle", "pubkey", "extractReport", "strictSignatures", "cwd"], description: "Offline self-contained verify of a portable run bundle: archive bytes + telemetry chain + trust-audit chain + embedded-key signatures." },
301
- { tool: "cw_report_bundle", capability: "report.bundle", requiredArgs: ["runId"], properties: ["runId", "cwd", "output", "path", "trustKey", "withTrustKey", "extractReport", "strictSignatures"], description: "Produce-and-prove: export a run to a portable bundle sealed with the trust key, then self-verify it offline (fail-closed) so the producer knows it is verifiable before shipping." },
302
- { tool: "cw_run_drive", capability: "run.drive", requiredArgs: [], properties: ["runId", "cwd"], description: "Preview the next agent-delegation drive step for a run (read-only, deterministic)." },
303
- { tool: "cw_run_drive_step", capability: "run.drive.step", requiredArgs: [], properties: ["runId", "appId", "repo", "question", "once", "now", "concurrency", "cwd"], description: "Drive a run by delegating each worker to the agent backend (plan->dispatch->fulfill->accept->commit; --once for one step)." },
304
- { tool: "cw_queue_add", capability: "queue.add", requiredArgs: [], properties: ["cwd", "runId", "appId", "workflowId", "repo", "priority", "note"], description: "Enqueue a pending/planned run with explicit ordering policy." },
305
- { tool: "cw_queue_list", capability: "queue.list", requiredArgs: [], properties: ["cwd", "status", "repo"], description: "List the durable run queue in policy order." },
306
- { tool: "cw_queue_drain", capability: "queue.drain", requiredArgs: [], properties: ["cwd", "limit", "repo"], description: "Mark the next ready queue entries drained (the host still executes)." },
307
- { tool: "cw_queue_show", capability: "queue.show", requiredArgs: ["id"], properties: ["cwd", "id"], description: "Show one durable queue entry." },
308
- { tool: "cw_sched_plan", capability: "sched.plan", requiredArgs: [], properties: ["cwd"], description: "Read-only control-plane lease plan for the queue+policy+now." },
309
- { tool: "cw_sched_lease", capability: "sched.lease", requiredArgs: [], properties: ["cwd", "limit"], description: "Claim eligible queue entries as leases (concurrency-bounded)." },
310
- { tool: "cw_sched_release", capability: "sched.release", requiredArgs: [], properties: ["cwd", "leaseId", "failed", "reason"], description: "Release a held lease (failed -> retry/backoff or park)." },
311
- { tool: "cw_sched_complete", capability: "sched.complete", requiredArgs: [], properties: ["cwd", "leaseId"], description: "Complete a held lease (terminal success)." },
312
- { tool: "cw_sched_reclaim", capability: "sched.reclaim", requiredArgs: [], properties: ["cwd"], description: "Reclaim expired leases (each counts a failed attempt)." },
313
- { tool: "cw_sched_reset", capability: "sched.reset", requiredArgs: [], properties: ["cwd", "id"], description: "Reset a parked entry to ready (operator recovery)." },
314
- { tool: "cw_sched_policy_show", capability: "sched.policy.show", requiredArgs: [], properties: ["cwd"], description: "Show the scheduling policy (file or default)." },
315
- { tool: "cw_sched_policy_set", capability: "sched.policy.set", requiredArgs: [], properties: ["cwd", "maxConcurrent", "maxAttempts", "leaseTtlMs", "backoffBaseMs", "backoffFactor", "backoffCapMs"], description: "Set scheduling policy fields (concurrency/attempts/backoff/TTL)." },
316
- { tool: "cw_gc_plan", capability: "gc.plan", requiredArgs: [], properties: ["cwd", "scope", "runId", "reclaimAfterArchiveDays", "keepScratch", "keepSnapshots"], description: "Dry-run plan of run reclamation (per-kind bytes + capability downgrade); frees nothing." },
317
- { tool: "cw_gc_run", capability: "gc.run", requiredArgs: [], properties: ["cwd", "scope", "runId", "reclaimAfterArchiveDays", "keepScratch", "keepSnapshots", "limit", "actor"], description: "Execute the write-ahead reclamation transaction (skeleton -> tombstone -> fsync -> free)." },
318
- { tool: "cw_gc_verify", capability: "gc.verify", requiredArgs: ["runId"], properties: ["cwd", "scope", "runId"], description: "Re-prove a reclaimed run: skeleton-complete, tombstone chain untampered, artifacts reconstructable." },
319
- { tool: "cw_clones_list", capability: "clones.list", requiredArgs: [], properties: [], description: "List the cached remote-source checkouts that --link/URL reviews populate (origin URL, kind, commit, age, bytes). Read-only." },
320
- { tool: "cw_clones_gc", capability: "clones.gc", requiredArgs: [], properties: ["olderThanDays", "all"], description: "Reclaim cached remote-source checkouts: a TTL sweep (--older-than-days, default 30) or --all. Deletes only inside the clones cache." },
321
- { tool: "cw_orphans_list", capability: "orphans.list", requiredArgs: [], properties: ["cwd", "scope"], description: "List run directories under .cw/runs/ that the run registry cannot see (no state.json — a killed/interrupted process never wrote one), with age + bytes. Read-only." },
322
- { tool: "cw_orphans_gc", capability: "orphans.gc", requiredArgs: [], properties: ["cwd", "scope", "minAgeMinutes", "all"], description: "Reclaim orphan run directories (no state.json): an age sweep (--min-age-minutes, default 60) or --all. Deletes only inside a scanned repo's .cw/runs/, never a run the registry knows about." },
323
- { tool: "cw_telemetry_verify", capability: "telemetry.verify", requiredArgs: ["runId"], properties: ["cwd", "runId", "pubkey"], description: "Re-prove a run's telemetry attestation ledger offline: chain linkage + independent hash recompute, and (with --pubkey / CW_AGENT_ATTEST_PUBKEY) re-verify each attested hop's ed25519 signature against the public key." },
324
- { tool: "cw_history", capability: "history", requiredArgs: [], properties: ["cwd", "scope", "app", "status", "limit", "offset"], description: "Read a cross-repo unified run timeline (newest first)." },
325
- ];
326
- /** Real handlers implemented at THIS milestone, keyed by capability id.
327
- * Every tool row not listed here gets `notYetImplemented`. Kept as a
328
- * small side table (rather than inlined into MCP_TOOL_DATA above) so the
329
- * 196-row literal above stays a pure, mechanically-checkable transcript
330
- * of the spec table — handler wiring is a separate, obviously-later-
331
- * editable concern. */
332
- const MCP_REAL_HANDLERS = {
333
- list: () => listBundledWorkflows(),
334
- "sandbox.list": () => listBundledSandboxProfiles(),
335
- status: (args) => statusPayload(optionalString(args.runId)),
336
- "summary.refresh": (args) => (0, state_explosion_cli_1.summaryRefreshCli)((0, io_1.required)(optionalString(args.runId), "run id"), args),
337
- "summary.show": (args) => (0, state_explosion_cli_1.summaryShowCli)((0, io_1.required)(optionalString(args.runId), "run id"), args),
338
- };
339
- function optionalString(value) {
340
- return typeof value === "string" && value.trim() ? value.trim() : undefined;
341
- }
342
- /** `cw list` / `cw_list` (MILESTONE 12) — the real discovery over every
343
- * `apps/*\/app.json` + legacy `workflows/*.workflow.js` on disk, per
344
- * `listWorkflowsShallow` (shell/workflow-app-loader.ts). */
345
- function listBundledWorkflows() {
346
- return (0, workflow_app_loader_1.listWorkflowsShallow)();
347
- }
348
- /** PLACEHOLDER (milestone 5, execution-backend/sandbox) — the real
349
- * `sandbox.list` resolves and stamps each of the 4 bundled profiles
350
- * (default/readonly/workspace-write/locked-down) with real path lists
351
- * via `resolveSandboxProfile` (SPEC/execution-backend.md). This
352
- * milestone reproduces only the id/title/schemaVersion subset that
353
- * mcp-basic.case.js checks. */
354
- function listBundledSandboxProfiles() {
355
- return [
356
- { schemaVersion: 1, id: "default", title: "Default Worker Boundary" },
357
- { schemaVersion: 1, id: "readonly", title: "Readonly Workspace" },
358
- { schemaVersion: 1, id: "workspace-write", title: "Workspace Write" },
359
- { schemaVersion: 1, id: "locked-down", title: "Locked Down" },
360
- ];
361
- }
362
- /** `cw status` / `cw_status` — SPEC/cli-surface.md pins the no-id JSON
363
- * shape exactly (`{runId:null, nextActions}`); a real run id resolves to
364
- * `summarizeRun`'s payload (MILESTONE 11, reporting/observability). */
365
- function statusPayload(runId, cwd) {
366
- if (!runId) {
367
- return { runId: null, nextActions: (0, operator_ux_1.adviseNoRun)() };
368
- }
369
- const run = (0, run_store_1.loadRunFromCwd)(runId, cwd || process.cwd());
370
- return (0, operator_ux_1.summarizeRun)(run);
371
- }
372
- // Aliased on import so this milestone-3 placeholder's own local names
373
- // (adviseNoRun/loadRunFromCwd/summarizeRun) don't collide with any later
374
- // milestone section importing the same symbols under their own name.
375
- const run_store_1 = require("../shell/run-store");
376
- const operator_ux_1 = require("../shell/operator-ux");
377
- const workflow_app_loader_1 = require("../shell/workflow-app-loader");
378
- // ---------------------------------------------------------------------
379
- // Public table-derived API
380
- // ---------------------------------------------------------------------
381
- function buildMcpBinding(row) {
382
- const handler = MCP_REAL_HANDLERS[row.capability] ?? notYetImplemented(row.capability);
383
- // A transcript entry like "runId, workerId" is TWO AND-required args (the
384
- // spec table's comma form), while "topicId|id" is one OR-group. mcp/dispatch's
385
- // validator only splits on `|`, so expand each comma-joined transcript entry
386
- // into its separate AND-groups here (the one place the row shape is turned
387
- // into the runtime McpBinding.requiredArgs contract).
388
- const requiredArgs = row.requiredArgs.flatMap((group) => group.split(",").map((entry) => entry.trim()).filter(Boolean));
389
- return {
390
- tool: row.tool,
391
- requiredArgs: requiredArgs.length ? requiredArgs : undefined,
392
- properties: row.properties,
393
- description: row.description,
394
- handler,
395
- };
396
- }
397
- /** The full capability table: one row per MCP tool (196, per SPEC/mcp.md),
398
- * in the exact source order `tools/list` must report. CLI bindings are
399
- * layered on top for the small set of capabilities this milestone also
400
- * exposes on the CLI front door (see `CLI_ROWS` below); every other row
401
- * is MCP-only AT THIS MILESTONE (not a permanent `mcp-only` declaration —
402
- * just not yet CLI-wired; later milestones add the `cli` binding without
403
- * touching this array's mcp side). */
404
- exports.REGISTRY = MCP_TOOL_DATA.map((row) => ({
405
- capability: row.capability,
406
- summary: row.description,
407
- surface: "both",
408
- mcp: buildMcpBinding(row),
409
- }));
410
- const REGISTRY_BY_CAPABILITY = new Map(exports.REGISTRY.map((row) => [row.capability, row]));
411
- /** Attach (or replace) a CLI binding for an already-declared MCP capability.
412
- * Used once below to wire `list`/`status`/`sandbox.list` onto the CLI
413
- * front door too, without duplicating their row data. */
414
- function attachCliBinding(capability, cli) {
415
- const row = REGISTRY_BY_CAPABILITY.get(capability);
416
- if (!row)
417
- throw new Error(`capability-table: cannot attach cli binding to undeclared capability ${capability}`);
418
- row.cli = cli;
419
- }
420
- /** Declare a capability that is CLI-only at this milestone (`help`,
421
- * `version` — both are permanently `cli-only` per SPEC/mcp.md's
422
- * declared one-surface list, so no mcp row is created for them). */
423
- function addCliOnlyCapability(capability, summary, cli, reason, entry) {
424
- const row = { capability, summary, surface: "cli-only", cli, reason, ...(entry ? { entry } : {}) };
425
- exports.REGISTRY.push(row);
426
- REGISTRY_BY_CAPABILITY.set(capability, row);
427
- }
428
- /** Returns the declared row for a capability id, or undefined. */
429
- function findCapability(capability) {
430
- return REGISTRY_BY_CAPABILITY.get(capability);
431
- }
432
- /** Returns the declared row whose `cli.path` matches `path` exactly
433
- * (path[0] is the verb). Used by cli/dispatch.ts's generic executor.
434
- * A single-token command also matches a row's `caseTokens` alias list, so
435
- * an alias (e.g. `audit-run`) dispatches to the same handler as its verb. */
436
- function findCapabilityByCliPath(path) {
437
- for (const row of exports.REGISTRY) {
438
- if (row.cli && row.cli.path.length === path.length && row.cli.path.every((p, i) => p === path[i])) {
439
- return row;
440
- }
441
- }
442
- if (path.length === 1) {
443
- for (const row of exports.REGISTRY) {
444
- if (row.cli && row.cli.caseTokens && row.cli.caseTokens.includes(path[0]))
445
- return row;
446
- }
447
- }
448
- return undefined;
449
- }
450
- /** Every capability row that declares a `cli` binding, in registry order.
451
- * Used to derive `formatCommandHelp`'s per-verb subcommand rows. */
452
- function cliCapabilities() {
453
- return exports.REGISTRY.filter((row) => Boolean(row.cli));
454
- }
455
- /** `tools/list`'s exact array, in the pinned source order. */
456
- function mcpToolDefinitions() {
457
- const definitions = [];
458
- for (const row of exports.REGISTRY) {
459
- if (!row.mcp)
460
- continue;
461
- const overrides = PROPERTY_OVERRIDES[row.mcp.tool] ?? {};
462
- const properties = {};
463
- for (const propName of row.mcp.properties) {
464
- properties[propName] = overrides[propName] ?? stringProperty(propName);
465
- }
466
- definitions.push({
467
- name: row.mcp.tool,
468
- description: row.mcp.description,
469
- inputSchema: { type: "object", properties, additionalProperties: true },
470
- });
471
- }
472
- return definitions;
473
- }
474
- /** Every declared MCP tool name, in `tools/list` order. */
475
- function declaredMcpTools() {
476
- return exports.REGISTRY.filter((row) => row.mcp).map((row) => row.mcp.tool);
477
- }
478
- /** Look up a capability row by its MCP tool name. */
479
- function findCapabilityByMcpTool(tool) {
480
- return exports.REGISTRY.find((row) => row.mcp && row.mcp.tool === tool);
481
- }
482
- // ---------------------------------------------------------------------
483
- // CLI bindings wired at THIS milestone (version, list, status,
484
- // sandbox.list). `version` is cli-only per SPEC/mcp.md's declared
485
- // one-surface list (`help` is handled directly by cli/entry.ts's
486
- // top-level flag redirect, same as milestone 1 — it is not itself a
487
- // dispatchable command row); `list`/`status`/`sandbox.list` reuse the mcp
488
- // row's capability id and get a cli binding layered on top. Every handler
489
- // below returns a `CliHandlerResult`; core/ never touches process.stdout
490
- // or process.exitCode directly (see v2/PLAN.md's core/shell split) —
491
- // cli/dispatch.ts's generic executor performs the actual write.
492
- // ---------------------------------------------------------------------
493
- const version_1 = require("./version");
494
- addCliOnlyCapability("version", "Print the current cool-workflow version.", {
495
- path: ["version"],
496
- jsonMode: "default",
497
- handler: () => ({ text: `${version_1.CURRENT_COOL_WORKFLOW_VERSION}\n` }),
498
- }, "version is a local, no-run-state print; the old build never gave it an MCP peer.");
499
- attachCliBinding("list", {
500
- path: ["list"],
501
- jsonMode: "default",
502
- handler: () => ({ json: listBundledWorkflows() }),
503
- });
504
- attachCliBinding("status", {
505
- path: ["status"],
506
- jsonMode: "flag",
507
- handler: (args) => ({ json: statusPayload(args.positionals[0]) }),
508
- });
509
- attachCliBinding("sandbox.list", {
510
- path: ["sandbox", "list"],
511
- jsonMode: "default",
512
- handler: () => ({ json: listBundledSandboxProfiles() }),
513
- });
514
- // ---------------------------------------------------------------------
515
- // MILESTONE 3 (state kernel) CLI bindings: state.check, migration.list|
516
- // check|prove, node.list|show|graph|snapshot|diff|replay|replay.verify.
517
- // Handler BODIES live in shell/state-cli.ts (impure — they read/write
518
- // run state on disk); this table only wires argv shape -> handler call
519
- // and the row's own exit-code rule, per cli/dispatch.ts's generic
520
- // executor contract. `required`/`optionalArg` are cli/io.ts's shared
521
- // coercion helpers, imported here so the wiring stays a thin adapter
522
- // (Usage-error strings copied byte-for-byte from the old build's
523
- // handlers/*.ts).
524
- // ---------------------------------------------------------------------
525
- const io_1 = require("../cli/io");
526
- const state_cli_1 = require("../shell/state-cli");
527
- attachCliBinding("state.check", {
528
- path: ["state", "check"],
529
- jsonMode: "default",
530
- handler: (args) => {
531
- const runId = (0, io_1.required)(args.positionals[0], "run id");
532
- const report = (0, state_cli_1.checkState)(runId, args.options);
533
- return { json: report, exitCode: report.status === "unsupported" ? 1 : undefined };
534
- },
535
- });
536
- attachCliBinding("migration.list", {
537
- path: ["migration", "list"],
538
- jsonMode: "default",
539
- handler: () => ({ json: (0, state_cli_1.migrationList)() }),
540
- });
541
- attachCliBinding("migration.check", {
542
- path: ["migration", "check"],
543
- jsonMode: "default",
544
- handler: (args) => {
545
- const target = (0, io_1.required)(args.positionals[0], "target (run-id or state/app file)");
546
- const report = (0, state_cli_1.migrationCheck)(target, args.options);
547
- return { json: report, exitCode: report.status === "unsupported" ? 1 : undefined };
548
- },
549
- });
550
- attachCliBinding("migration.prove", {
551
- path: ["migration", "prove"],
552
- jsonMode: "default",
553
- handler: (args) => {
554
- const target = (0, io_1.required)(args.positionals[0], "target (run-id or state/app file)");
555
- const proof = (0, state_cli_1.migrationProve)(target, args.options);
556
- return { json: proof, exitCode: proof.pass ? undefined : 1 };
557
- },
558
- });
559
- attachCliBinding("node.list", {
560
- path: ["node", "list"],
561
- jsonMode: "default",
562
- handler: (args) => ({ json: (0, state_cli_1.listNodes)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
563
- });
564
- attachCliBinding("node.show", {
565
- path: ["node", "show"],
566
- jsonMode: "default",
567
- handler: (args) => {
568
- const runId = (0, io_1.required)(args.positionals[0], "run id");
569
- const nodeId = (0, io_1.required)(args.positionals[1], "node id");
570
- return { json: (0, state_cli_1.showNode)(runId, nodeId, args.options) };
571
- },
572
- });
573
- // jsonMode "flag": `--json` prints the node array (graphNodes); the bare
574
- // verb prints the operator run-graph text, byte-for-byte the old build's
575
- // `node graph` render (formatOperatorGraph over runner.operatorGraph).
576
- attachCliBinding("node.graph", {
577
- path: ["node", "graph"],
578
- jsonMode: "flag",
579
- handler: (args) => {
580
- const runId = (0, io_1.required)(args.positionals[0], "run id");
581
- return { json: (0, state_cli_1.graphNodes)(runId, args.options), text: `${(0, report_view_cli_1.graphText)(runId, args.options)}\n` };
582
- },
583
- });
584
- attachCliBinding("node.snapshot", {
585
- path: ["node", "snapshot"],
586
- jsonMode: "default",
587
- handler: (args) => {
588
- const runId = (0, io_1.required)(args.positionals[0], "run id");
589
- const nodeId = (0, io_1.required)(args.positionals[1], "node id");
590
- return { json: (0, state_cli_1.nodeSnapshotCli)(runId, nodeId, args.options) };
591
- },
592
- });
593
- attachCliBinding("node.diff", {
594
- path: ["node", "diff"],
595
- jsonMode: "default",
596
- handler: (args) => {
597
- const runId = (0, io_1.required)(args.positionals[0], "run id");
598
- const baselineSnapshotId = (0, io_1.required)(args.positionals[1], "baseline snapshot id");
599
- const candidateSnapshotId = (0, io_1.required)(args.positionals[2], "candidate snapshot id");
600
- return { json: (0, state_cli_1.nodeDiffCli)(runId, baselineSnapshotId, candidateSnapshotId, args.options) };
601
- },
602
- });
603
- attachCliBinding("node.replay", {
604
- path: ["node", "replay"],
605
- jsonMode: "default",
606
- handler: (args) => {
607
- const runId = (0, io_1.required)(args.positionals[0], "run id");
608
- const snapshotId = (0, io_1.required)(args.positionals[1], "snapshot id");
609
- return { json: (0, state_cli_1.nodeReplayCli)(runId, snapshotId, args.options) };
610
- },
611
- });
612
- attachCliBinding("node.replay.verify", {
613
- path: ["node", "verify"],
614
- jsonMode: "default",
615
- handler: (args) => {
616
- const runId = (0, io_1.required)(args.positionals[0], "run id");
617
- const replayId = (0, io_1.required)(args.positionals[1], "replay id");
618
- const verdict = (0, state_cli_1.nodeReplayVerifyCli)(runId, replayId, args.options);
619
- return { json: verdict, exitCode: verdict.pass ? undefined : 1 };
620
- },
621
- });
622
- // GAP #24: mirror the state-kernel CLI shell fns as MCP handlers (they were
623
- // declared MCP tool rows but left on notYetImplemented). Arg-name reads copied
624
- // byte-for-byte from the old build's mcp/tool-call.ts switch arms.
625
- REGISTRY_BY_CAPABILITY.get("state.check").mcp.handler = (args) => (0, state_cli_1.checkState)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
626
- REGISTRY_BY_CAPABILITY.get("migration.list").mcp.handler = () => (0, state_cli_1.migrationList)();
627
- REGISTRY_BY_CAPABILITY.get("migration.check").mcp.handler = (args) => (0, state_cli_1.migrationCheck)((0, io_1.required)((0, io_3.optionalArg)(args.target ?? args.runId), "target (run-id or state/app file)"), args);
628
- REGISTRY_BY_CAPABILITY.get("migration.prove").mcp.handler = (args) => (0, state_cli_1.migrationProve)((0, io_1.required)((0, io_3.optionalArg)(args.target ?? args.runId), "target (run-id or state/app file)"), args);
629
- REGISTRY_BY_CAPABILITY.get("node.list").mcp.handler = (args) => (0, state_cli_1.listNodes)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
630
- REGISTRY_BY_CAPABILITY.get("node.show").mcp.handler = (args) => (0, state_cli_1.showNode)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.nodeId), "node id"), args);
631
- REGISTRY_BY_CAPABILITY.get("node.graph").mcp.handler = (args) => (0, state_cli_1.graphNodes)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
632
- REGISTRY_BY_CAPABILITY.get("node.snapshot").mcp.handler = (args) => (0, state_cli_1.nodeSnapshotCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.nodeId), "node id"), args);
633
- REGISTRY_BY_CAPABILITY.get("node.diff").mcp.handler = (args) => (0, state_cli_1.nodeDiffCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.baselineSnapshotId ?? args.baseline), "baseline snapshot id"), (0, io_1.required)((0, io_3.optionalArg)(args.candidateSnapshotId ?? args.candidate), "candidate snapshot id"), args);
634
- REGISTRY_BY_CAPABILITY.get("node.replay").mcp.handler = (args) => (0, state_cli_1.nodeReplayCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.snapshotId), "snapshot id"), args);
635
- REGISTRY_BY_CAPABILITY.get("node.replay.verify").mcp.handler = (args) => (0, state_cli_1.nodeReplayVerifyCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.replayId), "replay id"), args);
636
- // `contract.show` is not yet a declared MCP_TOOL_DATA row with a CLI peer
637
- // wired here (it IS in MCP_TOOL_DATA already); no milestone-3 conformance
638
- // case reaches it, so it is intentionally left on its placeholder handler
639
- // until a case demands it — avoids speculative, untested wiring.
640
- // ---------------------------------------------------------------------
641
- // MILESTONE 4 (state-explosion summaries) CLI bindings: summary.refresh,
642
- // summary.show. Handler BODIES live in shell/state-explosion-cli.ts
643
- // (impure — disk reads/writes summaries under the run dir); this table
644
- // only wires argv shape -> handler call, per cli/dispatch.ts's generic
645
- // executor contract. Per SPEC/state-core.md's CLI verbs section: without
646
- // `--json` both print `formatStateExplosionReport` text (jsonMode
647
- // "flag" — text by default, JSON under --json/--format json).
648
- // ---------------------------------------------------------------------
649
- const state_explosion_text_1 = require("./format/state-explosion-text");
650
- const state_explosion_cli_1 = require("../shell/state-explosion-cli");
651
- const io_2 = require("../cli/io");
652
- attachCliBinding("summary.refresh", {
653
- path: ["summary", "refresh"],
654
- jsonMode: "flag",
655
- handler: (args) => {
656
- const runId = (0, io_1.required)(args.positionals[0], "run id");
657
- const index = (0, state_explosion_cli_1.summaryRefreshCli)(runId, args.options);
658
- // Byte-exact port of the old build's handleSummary "refresh": the
659
- // human-text branch re-reads via a fresh summaryShow call rather than
660
- // formatting the refresh's own index record (src/cli/handlers/
661
- // operator.ts:118-127); only computed when actually needed, so a
662
- // --json call does exactly the one read the old build's if/else did.
663
- if ((0, io_2.wantsJson)(args.options))
664
- return { json: index };
665
- return { json: index, text: (0, state_explosion_text_1.formatStateExplosionReport)((0, state_explosion_cli_1.summaryShowCli)(runId, args.options)) };
666
- },
667
- });
668
- attachCliBinding("summary.show", {
669
- path: ["summary", "show"],
670
- jsonMode: "flag",
671
- handler: (args) => {
672
- const runId = (0, io_1.required)(args.positionals[0], "run id");
673
- const report = (0, state_explosion_cli_1.summaryShowCli)(runId, args.options);
674
- return { json: report, text: (0, state_explosion_text_1.formatStateExplosionReport)(report) };
675
- },
676
- });
677
- // ---------------------------------------------------------------------
678
- // MILESTONE 5 (execution backend, agent spawn, sandbox) CLI bindings:
679
- // sandbox.list|show|validate, backend.list|show|probe,
680
- // backend.agent.config.show|set, doctor, fix. Handler BODIES live in
681
- // shell/exec-backend-cli.ts / shell/doctor.ts (impure — env/fs reads);
682
- // this table only wires argv shape -> handler call, per cli/dispatch.ts's
683
- // generic executor contract. `sandbox.list`/`backend.list` are ALREADY
684
- // declared MCP-only rows from milestone 2 (MCP_TOOL_DATA above) — this
685
- // section layers a `cli` binding onto them (attachCliBinding) and replaces
686
- // their milestone-2 placeholder `mcp.handler` with the real body, exactly
687
- // as milestones 3/4 did for their own rows.
688
- // ---------------------------------------------------------------------
689
- const exec_backend_cli_1 = require("../shell/exec-backend-cli");
690
- const doctor_1 = require("../shell/doctor");
691
- const io_3 = require("../cli/io");
692
- const app_run_cli_1 = require("../shell/app-run-cli");
693
- attachCliBinding("sandbox.list", {
694
- path: ["sandbox", "list"],
695
- jsonMode: "default",
696
- handler: (args) => ({ json: (0, exec_backend_cli_1.listSandboxProfilesCli)(args.options) }),
697
- });
698
- REGISTRY_BY_CAPABILITY.get("sandbox.list").mcp.handler = (args) => (0, exec_backend_cli_1.listSandboxProfilesCli)(args);
699
- // GAP #24: cw_sandbox_choose / cw_sandbox_resolve + cw_app_run were declared
700
- // MCP-only rows with the notYetImplemented placeholder handler. Wire them to
701
- // the ported shell bodies (both are MCP-only in the old build — no CLI path).
702
- REGISTRY_BY_CAPABILITY.get("sandbox.choose").mcp.handler = (args) => (0, app_run_cli_1.sandboxChooseCli)(args);
703
- REGISTRY_BY_CAPABILITY.get("sandbox.resolve").mcp.handler = (args) => (0, app_run_cli_1.sandboxChooseCli)(args);
704
- REGISTRY_BY_CAPABILITY.get("app.run").mcp.handler = (args) => (0, app_run_cli_1.appRunCli)(args);
705
- attachCliBinding("sandbox.show", {
706
- path: ["sandbox", "show"],
707
- jsonMode: "default",
708
- handler: (args) => ({ json: (0, exec_backend_cli_1.showSandboxProfileCli)((0, io_1.required)(args.positionals[0], "profile id"), args.options) }),
709
- });
710
- REGISTRY_BY_CAPABILITY.get("sandbox.show").mcp.handler = (args) => (0, exec_backend_cli_1.showSandboxProfileCli)((0, io_1.required)((0, io_3.optionalArg)(args.profileId), "profile id"), args);
711
- attachCliBinding("sandbox.validate", {
712
- path: ["sandbox", "validate"],
713
- jsonMode: "default",
714
- handler: (args) => {
715
- const result = (0, exec_backend_cli_1.validateSandboxProfileCli)((0, io_1.required)(args.positionals[0], "profile file"), args.options);
716
- return { json: result, exitCode: result.valid ? undefined : 1 };
717
- },
718
- });
719
- REGISTRY_BY_CAPABILITY.get("sandbox.validate").mcp.handler = (args) => (0, exec_backend_cli_1.validateSandboxProfileCli)((0, io_1.required)((0, io_3.optionalArg)(args.profileFile), "profile file"), args);
720
- // PARITY: `sandbox.choose`/`sandbox.resolve` are BOTH-surface capabilities
721
- // per SPEC/mcp.md (old build cli.path ["sandbox","choose"]/["sandbox",
722
- // "resolve"]) — they were left MCP-only at GAP #24 (see the comment
723
- // above sandboxChooseCli's mcp.handler wiring). Attach the same, already-
724
- // working shell body as the cli.handler too, so the CLI front door and
725
- // the parity payload probe both reach it (no new business logic, same
726
- // function both surfaces already call over MCP).
727
- attachCliBinding("sandbox.choose", {
728
- path: ["sandbox", "choose"],
729
- jsonMode: "default",
730
- handler: (args) => ({ json: (0, app_run_cli_1.sandboxChooseCli)(args.options) }),
731
- });
732
- attachCliBinding("sandbox.resolve", {
733
- path: ["sandbox", "resolve"],
734
- jsonMode: "default",
735
- handler: (args) => ({ json: (0, app_run_cli_1.sandboxChooseCli)(args.options) }),
736
- });
737
- attachCliBinding("backend.list", {
738
- path: ["backend", "list"],
739
- jsonMode: "default",
740
- handler: () => ({ json: (0, exec_backend_cli_1.listBackendsCli)() }),
741
- });
742
- REGISTRY_BY_CAPABILITY.get("backend.list").mcp.handler = () => (0, exec_backend_cli_1.listBackendsCli)();
743
- attachCliBinding("backend.show", {
744
- path: ["backend", "show"],
745
- jsonMode: "default",
746
- handler: (args) => ({ json: (0, exec_backend_cli_1.showBackendCli)((0, io_1.required)(args.positionals[0], "backend id")) }),
747
- });
748
- REGISTRY_BY_CAPABILITY.get("backend.show").mcp.handler = (args) => (0, exec_backend_cli_1.showBackendCli)((0, io_1.required)((0, io_3.optionalArg)(args.backendId), "backend id"));
749
- attachCliBinding("backend.probe", {
750
- path: ["backend", "probe"],
751
- jsonMode: "default",
752
- handler: (args) => ({ json: (0, exec_backend_cli_1.probeBackendCli)(args.positionals[0], args.options) }),
753
- });
754
- REGISTRY_BY_CAPABILITY.get("backend.probe").mcp.handler = (args) => (0, exec_backend_cli_1.probeBackendCli)((0, io_3.optionalArg)(args.backendId), args);
755
- // `backend agent config [show]` = read-only; `backend agent config set
756
- // ...` = mutating. CLI path is ["backend", "agent"] (2 tokens, matching
757
- // dispatchTable's supported path lengths); the remaining positionals
758
- // ("config", "show"/"set") are read inside the handler, byte-exact to the
759
- // old build's handleBackend "agent" case (src/cli/handlers/
760
- // operational.ts:52-62).
761
- attachCliBinding("backend.agent.config.show", {
762
- path: ["backend", "agent"],
763
- helpPath: ["backend", "agent", "config"],
764
- jsonMode: "default",
765
- handler: (args) => {
766
- const action = args.positionals[1];
767
- if (action === "set")
768
- return { json: (0, exec_backend_cli_1.backendAgentConfigSet)(args.options) };
769
- return { json: (0, exec_backend_cli_1.backendAgentConfigShow)(args.options) };
770
- },
771
- });
772
- // `backend.agent.config.set` shares the SAME dispatch path/handler as
773
- // `.show` above (dispatchTable only supports 2-token paths, and the
774
- // show-vs-set branch lives inside that one handler on positionals[1] —
775
- // byte-exact to the old build's handleBackend "agent" case). This second
776
- // attachCliBinding call exists ONLY so `cw help backend` lists both rows
777
- // (cliCommandHelpRows iterates cliCapabilities(), one row per capability),
778
- // matching the old registry's two declared rows sharing one caseTokens
779
- // group; dispatchTable itself never reaches this row a second time because
780
- // `backend.agent.config.show`'s row is found first by
781
- // findCapabilityByCliPath's linear scan and its handler already covers
782
- // both actions.
783
- attachCliBinding("backend.agent.config.set", {
784
- path: ["backend", "agent"],
785
- helpPath: ["backend", "agent", "config"],
786
- jsonMode: "default",
787
- handler: (args) => {
788
- const action = args.positionals[1];
789
- if (action === "set")
790
- return { json: (0, exec_backend_cli_1.backendAgentConfigSet)(args.options) };
791
- return { json: (0, exec_backend_cli_1.backendAgentConfigShow)(args.options) };
792
- },
793
- });
794
- REGISTRY_BY_CAPABILITY.get("backend.agent.config.show").mcp.handler = (args) => (0, exec_backend_cli_1.backendAgentConfigShow)(args);
795
- REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").mcp.handler = (args) => (0, exec_backend_cli_1.backendAgentConfigSet)(args);
796
- // PARITY: `backend.agent.config.set` mutates $CW_HOME/agent-config.json
797
- // (secret-stripped) before returning the effective config; both surfaces
798
- // perform the same write, so it is a documented opt-out from the
799
- // read-payload probe, not an undocumented divergence.
800
- REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").payloadIdentical = false;
801
- REGISTRY_BY_CAPABILITY.get("backend.agent.config.set").reason =
802
- "Mutating: persists $CW_HOME/agent-config.json (secret-stripped) before returning the effective config; both surfaces perform the same write — it is a surface-mutating verb, not a read probe.";
803
- addCliOnlyCapability("doctor", "Diagnose the host for setup problems (Node version, agent backend, agent binary on PATH, git, writable home/repo state) and print an actionable fix per check.", {
804
- path: ["doctor"],
805
- jsonMode: "flag",
806
- handler: (args) => {
807
- const report = (0, doctor_1.runDoctor)(args.options, process.env, String(args.options.cwd || process.cwd()));
808
- // Byte-exact port of src/cli/command-surface.ts:170-176: both text
809
- // branches are written as `${formatX(report)}\n` UNCONDITIONALLY —
810
- // formatDoctorFixes already ends in its own "\n" (its last joined
811
- // element is ""), so its case needs one MORE explicit "\n" here to
812
- // reproduce that unconditional append; cli/dispatch.ts's generic
813
- // renderer only appends "\n" when the text does NOT already end in
814
- // one, so a bare `formatDoctorFixes(report)` here would silently
815
- // drop the old build's trailing blank line.
816
- const text = (0, io_2.wantsJson)(args.options) ? undefined : args.options.fix ? `${(0, doctor_1.formatDoctorFixes)(report)}\n` : (0, doctor_1.formatDoctorReport)(report);
817
- return { json: report, text, exitCode: report.ok ? undefined : 1 };
818
- },
819
- }, "Environment diagnostics are inherently local to the CLI host — Node version, $PATH, $CW_HOME/cwd writability. An MCP client diagnosing the server process's environment is not meaningful; agents already receive the same readiness facts in their typed results (e.g. status: blocked, agentConfigured). Inspired by `brew doctor`.");
820
- addCliOnlyCapability("fix", "Print consolidated fix commands for CW setup issues.", {
821
- path: ["fix"],
822
- jsonMode: "human",
823
- handler: (args) => {
824
- const report = (0, doctor_1.runDoctor)(args.options, process.env, String(args.options.cwd || process.cwd()));
825
- // See the "doctor" handler's comment above: formatDoctorFixes
826
- // already ends in "\n", so one more explicit "\n" here reproduces
827
- // src/cli/command-surface.ts:126-130's unconditional
828
- // `${formatDoctorFixes(report)}\n` write.
829
- return { text: `${(0, doctor_1.formatDoctorFixes)(report)}\n`, exitCode: report.ok ? undefined : 1 };
830
- },
831
- }, "Environment fix commands are local diagnostics, same reasoning as doctor.");
832
- // ---------------------------------------------------------------------
833
- // MILESTONE 6+7 (combined; see v2/PLAN.md Open risk 10) CLI bindings:
834
- // plan, quickstart, run --drive, run drive (preview), dispatch, result,
835
- // commit. Handler BODIES live in shell/pipeline-cli.ts (impure — they
836
- // plan/drive/dispatch/commit real run state on disk); this table only
837
- // wires argv shape -> handler call, per cli/dispatch.ts's generic
838
- // executor contract.
839
- // ---------------------------------------------------------------------
840
- const pipeline_cli_1 = require("../shell/pipeline-cli");
841
- const commit_summary_1 = require("../shell/commit-summary");
842
- attachCliBinding("plan", {
843
- path: ["plan"],
844
- jsonMode: "default",
845
- handler: (args) => {
846
- const workflowId = (0, io_3.optionalArg)(args.positionals[0]);
847
- if (!workflowId) {
848
- throw new Error('Missing workflow id.\n Tip: plan an architecture review with "cw plan architecture-review"');
849
- }
850
- return { json: (0, pipeline_cli_1.planRun)({ ...args.options, workflowId }) };
851
- },
852
- });
853
- // `cw run <app> --drive [--once]` and `cw run drive <run-id> [--step]`
854
- // share the single `run` dispatch path (byte-exact to the old build's
855
- // handleRun: a run-REGISTRY subcommand keyword is never hijacked by the
856
- // bare `--drive` intercept just because it carries its own --drive/--step
857
- // flag). Both rows below dispatch on `["run"]`; the FIRST one registered
858
- // (run.drive.step) is found first by findCapabilityByCliPath's linear
859
- // scan, so its handler carries the full branch — the second row exists
860
- // only so `cw help run` lists both capabilities.
861
- attachCliBinding("run.drive.step", {
862
- path: ["run"],
863
- helpPath: ["run", "drive"],
864
- jsonMode: "default",
865
- handler: (args) => {
866
- const registrySubcommands = new Set(["drive", "search", "list", "show", "resume", "archive", "rerun", "export", "import", "verify-import", "inspect-archive", "restore"]);
867
- const target = args.positionals[0];
868
- if (args.options.drive && !registrySubcommands.has(String(target || ""))) {
869
- const runId = (0, io_3.optionalArg)(args.options.run) || (0, io_3.optionalArg)(args.options.runId);
870
- if (args.options.preview)
871
- return { json: (0, pipeline_cli_1.runDrivePreview)({ ...args.options, runId: runId || target }) };
872
- const driveArgs = { ...args.options };
873
- if (runId)
874
- driveArgs.runId = runId;
875
- else
876
- driveArgs.appId = target;
877
- return { json: (0, pipeline_cli_1.runDriveStep)(driveArgs) };
878
- }
879
- const [subcommand, id] = args.positionals;
880
- if (subcommand === "drive") {
881
- if (args.options.step) {
882
- const driveArgs = { ...args.options };
883
- if (id)
884
- driveArgs.runId = id;
885
- return { json: (0, pipeline_cli_1.runDriveStep)(driveArgs) };
886
- }
887
- return { json: (0, pipeline_cli_1.runDrivePreview)({ ...args.options, runId: (0, io_1.required)(id, "run id") }) };
888
- }
889
- // MILESTONE 11 (reporting/run-export) — the archive family. Handler
890
- // bodies live in shell/run-export-cli.ts; this arm only wires argv
891
- // shape -> handler call.
892
- if (subcommand === "export") {
893
- const result = (0, run_export_cli_1.runExportCli)((0, io_1.required)(id, "run id"), args.options);
894
- return { json: result };
895
- }
896
- if (subcommand === "import") {
897
- const result = (0, run_export_cli_1.runImportCli)((0, io_1.required)(id, "archive path"), args.options);
898
- return { json: result };
899
- }
900
- if (subcommand === "verify-import") {
901
- const result = (0, run_export_cli_1.runVerifyImportCli)((0, io_1.required)(id, "run id"), args.options);
902
- return { json: result, exitCode: args.options.strict && !result.ok ? 1 : undefined };
903
- }
904
- if (subcommand === "inspect-archive") {
905
- const result = (0, run_export_cli_1.runInspectArchiveCli)((0, io_1.required)(id, "archive path"), args.options);
906
- return { json: result, exitCode: result.ok ? undefined : 1 };
907
- }
908
- if (subcommand === "restore") {
909
- const result = (0, run_export_cli_1.runRestoreCli)((0, io_1.required)(id, "archive path"), args.options);
910
- return { json: result, exitCode: result.ok ? undefined : 1 };
911
- }
912
- throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import|inspect-archive|restore [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--incremental] [--repo R --question Q]");
913
- },
914
- });
915
- // PARITY: `run.drive` (the read-only MCP preview tool) now ALSO carries
916
- // its own two-token `cli.path` ["run","drive"], same as the old build's
917
- // registry row (cli.path ["run","drive"]) and the same reversed-
918
- // candidate-order pattern already used for run.search/run.list/etc.
919
- // (see those rows' own comment below): findCapabilityByCliPath tries the
920
- // 2-token candidate BEFORE the 1-token ["run"] row, so this row — not
921
- // run.drive.step's combined switch — now serves `cw run drive <run-id>`
922
- // [--step]. Behavior is unchanged (same runDrivePreview/runDriveStep
923
- // calls, same --step branch run.drive.step's switch already used); only
924
- // WHICH row answers the dispatch changes, so run.drive becomes a real
925
- // both-surface, dual-bound capability for the payload-identity probe.
926
- attachCliBinding("run.drive", {
927
- path: ["run", "drive"],
928
- jsonMode: "default",
929
- handler: (args) => {
930
- const id = args.positionals[0];
931
- if (args.options.step) {
932
- const driveArgs = { ...args.options };
933
- if (id)
934
- driveArgs.runId = id;
935
- return { json: (0, pipeline_cli_1.runDriveStep)(driveArgs) };
936
- }
937
- return { json: (0, pipeline_cli_1.runDrivePreview)({ ...args.options, runId: (0, io_1.required)(id, "run id") }) };
938
- },
939
- });
940
- REGISTRY_BY_CAPABILITY.get("run.drive").mcp.handler = (args) => (0, pipeline_cli_1.runDrivePreview)(args);
941
- REGISTRY_BY_CAPABILITY.get("run.drive.step").mcp.handler = (args) => (0, pipeline_cli_1.runDriveStep)(args);
942
- // PARITY: `run.drive.step` advances the run by spawning the external
943
- // agent per worker and recording attested output — not a read probe.
944
- // CLI (--drive/--step) and MCP route through the same drive() core; the
945
- // opt-out is the documented divergence, not undocumented drift.
946
- REGISTRY_BY_CAPABILITY.get("run.drive.step").payloadIdentical = false;
947
- REGISTRY_BY_CAPABILITY.get("run.drive.step").reason =
948
- "Mutating: advances the run by spawning the external agent per worker and recording attested output — not a read probe. CLI (--drive/--step) and MCP route through the same drive() core.";
949
- REGISTRY_BY_CAPABILITY.get("plan").mcp.handler = (args) => (0, pipeline_cli_1.planRun)(args);
950
- // GAP #24: dispatchRun reads the sandbox profile from `args.sandbox` only
951
- // (the CLI's --sandbox flag). The cw_dispatch MCP tool also accepts the
952
- // `sandboxProfile`/`sandboxProfileId` aliases (its declared properties), so
953
- // normalize them onto `sandbox` here — mirrors the old build's
954
- // sandboxProfileIdFrom() alias set — before handing off.
955
- REGISTRY_BY_CAPABILITY.get("dispatch").mcp.handler = (args) => (0, pipeline_cli_1.dispatchRun)({ ...args, sandbox: args.sandbox ?? args.sandboxProfile ?? args.sandboxProfileId });
956
- REGISTRY_BY_CAPABILITY.get("result").mcp.handler = (args) => (0, pipeline_cli_1.recordResultRun)(args);
957
- // `cw_commit` returns the FLAT commit envelope (verifierGated/checkpoint/
958
- // selectionId/… at the top level, plus a nested `commit`), matching the old
959
- // build's commitEnvelope. `commitRun` (CLI shape) returns `{ runId, commit }`;
960
- // lift the commit's key fields to the top for the MCP surface.
961
- REGISTRY_BY_CAPABILITY.get("commit").mcp.handler = (args) => {
962
- const result = (0, pipeline_cli_1.commitRun)(args);
963
- const commit = result.commit || {};
964
- return {
965
- runId: result.runId,
966
- commitId: commit.id,
967
- verifierGated: commit.verifierGated,
968
- checkpoint: commit.checkpoint,
969
- verifierNodeId: commit.verifierNodeId,
970
- candidateId: commit.candidateId,
971
- selectionId: commit.selectionId,
972
- evidenceCount: Array.isArray(commit.evidence) ? commit.evidence.length : 0,
973
- snapshotPath: commit.snapshotPath,
974
- commit,
975
- };
976
- };
977
- // PARITY: `commit` is the one declared payload projection (byte-compat
978
- // item 5 above). Both surfaces route through the single core entry
979
- // runner.commit (commitRun); the CLI keeps the raw StateCommitResult for
980
- // scripting while cw_commit lifts an operator-facing envelope on top (see
981
- // the mcp.handler just above). Marked here, not silently let drift, so
982
- // the parity payload probe (core/capability-table.ts's
983
- // payloadIdenticalCapabilities) skips it with a paper trail instead of
984
- // tripping on an undocumented divergence.
985
- REGISTRY_BY_CAPABILITY.get("commit").payloadIdentical = false;
986
- REGISTRY_BY_CAPABILITY.get("commit").reason =
987
- "Both surfaces route through the single core entry runner.commit. The CLI emits the raw StateCommitResult for scripting (commit.id, commit.evidence, commit.gate); cw_commit emits the operator commit envelope (commitId, verifierGated, checkpoint, evidenceCount, snapshotPath, nextActions, plus the raw result under `commit`). Declared projection, not drift.";
988
- // MILESTONE 11 — run.export/import/verify-import/inspect-archive/restore
989
- // MCP handlers (the CLI side is served by run.drive.step's combined
990
- // handler above; these tools are called directly by name over MCP, so
991
- // each needs its own mcp.handler per byte-compat item 5's two-field
992
- // row shape).
993
- const run_export_cli_1 = require("../shell/run-export-cli");
994
- REGISTRY_BY_CAPABILITY.get("run.export").mcp.handler = (args) => (0, run_export_cli_1.runExportCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
995
- REGISTRY_BY_CAPABILITY.get("run.import").mcp.handler = (args) => (0, run_export_cli_1.runImportCli)((0, io_1.required)((0, io_3.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
996
- REGISTRY_BY_CAPABILITY.get("run.verify-import").mcp.handler = (args) => (0, run_export_cli_1.runVerifyImportCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
997
- REGISTRY_BY_CAPABILITY.get("run.inspect-archive").mcp.handler = (args) => (0, run_export_cli_1.runInspectArchiveCli)((0, io_1.required)((0, io_3.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
998
- REGISTRY_BY_CAPABILITY.get("run.restore").mcp.handler = (args) => (0, run_export_cli_1.runRestoreCli)((0, io_1.required)((0, io_3.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
999
- // `run export|import|verify-import|inspect-archive|restore` each carry their
1000
- // own two-token cli.path (found before the ["run"] run.drive.step catch-all
1001
- // per the reversed candidate order), calling the same shell fns with the
1002
- // same [subcommand, id] positional mapping and exit-code shape the catch-all
1003
- // switch already used. `hiddenFromHelp` keeps the byte-pinned `cw help run`
1004
- // fixture's rows coming from the single literal COMMAND_HELP_ROWS.run block.
1005
- attachCliBinding("run.export", {
1006
- path: ["run", "export"],
1007
- jsonMode: "default",
1008
- hiddenFromHelp: true,
1009
- handler: (args) => ({ json: (0, run_export_cli_1.runExportCli)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
1010
- });
1011
- attachCliBinding("run.import", {
1012
- path: ["run", "import"],
1013
- jsonMode: "default",
1014
- hiddenFromHelp: true,
1015
- handler: (args) => ({ json: (0, run_export_cli_1.runImportCli)((0, io_1.required)(args.positionals[0], "archive path"), args.options) }),
1016
- });
1017
- attachCliBinding("run.verify-import", {
1018
- path: ["run", "verify-import"],
1019
- jsonMode: "default",
1020
- hiddenFromHelp: true,
1021
- handler: (args) => {
1022
- const result = (0, run_export_cli_1.runVerifyImportCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
1023
- return { json: result, exitCode: args.options.strict && !result.ok ? 1 : undefined };
1024
- },
1025
- });
1026
- attachCliBinding("run.inspect-archive", {
1027
- path: ["run", "inspect-archive"],
1028
- jsonMode: "default",
1029
- hiddenFromHelp: true,
1030
- handler: (args) => {
1031
- const result = (0, run_export_cli_1.runInspectArchiveCli)((0, io_1.required)(args.positionals[0], "archive path"), args.options);
1032
- return { json: result, exitCode: result.ok ? undefined : 1 };
1033
- },
1034
- });
1035
- attachCliBinding("run.restore", {
1036
- path: ["run", "restore"],
1037
- jsonMode: "default",
1038
- hiddenFromHelp: true,
1039
- handler: (args) => {
1040
- const result = (0, run_export_cli_1.runRestoreCli)((0, io_1.required)(args.positionals[0], "archive path"), args.options);
1041
- return { json: result, exitCode: result.ok ? undefined : 1 };
1042
- },
1043
- });
1044
- addCliOnlyCapability("quickstart", "ONE-COMMAND quickstart: --check preflights without writes; otherwise plan(app, default architecture-review) -> run --drive -> report in a single invocation (--preview for a read-only dry run; --bundle [--with-trust-key K] seals a completed run into a self-verified portable bundle).", {
1045
- path: ["quickstart"],
1046
- // `audit-run` is a CLI-only alias that dispatches to the same quickstart
1047
- // wrapper (byte-behavior port of the old build's caseTokens).
1048
- caseTokens: ["quickstart", "audit-run"],
1049
- jsonMode: "default",
1050
- handler: (args) => {
1051
- const appId = (0, io_3.optionalArg)(args.positionals[0]);
1052
- const result = (0, pipeline_cli_1.quickstartRun)({ ...args.options, appId });
1053
- // Fail closed on both known bad outcomes: a --check preflight that
1054
- // found a blocking gap, OR a --bundle that did not self-verify.
1055
- const bundle = result.bundle;
1056
- const bundleFailed = Boolean(bundle && bundle.ok === false);
1057
- const exitCode = (result.mode === "check" && result.ok === false) || bundleFailed ? 1 : undefined;
1058
- return { json: result, exitCode };
1059
- },
1060
- }, "quickstart composes plan/runDrive/report; SPEC/mcp.md's declared cli-only list names it explicitly (no MCP peer). `audit-run` is a CLI-only alias of the same wrapper.", "quickstart");
1061
- attachCliBinding("dispatch", {
1062
- path: ["dispatch"],
1063
- jsonMode: "default",
1064
- handler: (args) => {
1065
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
1066
- return { json: (0, pipeline_cli_1.dispatchRun)({ ...args.options, runId }) };
1067
- },
1068
- });
1069
- attachCliBinding("result", {
1070
- path: ["result"],
1071
- jsonMode: "default",
1072
- handler: (args) => {
1073
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
1074
- const taskId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[1]), "task id");
1075
- const resultPath = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[2]), "result file path");
1076
- return { json: (0, pipeline_cli_1.recordResultRun)({ ...args.options, runId, taskId, resultPath }) };
1077
- },
1078
- });
1079
- attachCliBinding("commit", {
1080
- path: ["commit"],
1081
- jsonMode: "default",
1082
- handler: (args) => {
1083
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
1084
- return { json: (0, pipeline_cli_1.commitRun)({ ...args.options, runId }) };
1085
- },
1086
- });
1087
- // GAP #26: restore `cw commit summary <run-id>` (CLI + help row). The old
1088
- // build had commit.summary with cli path ["commit","summary"] surface "both"
1089
- // (capability-registry.ts:260-266); v2 kept only the cw_commit_summary MCP
1090
- // tool and dropped both the CLI binding and the COMMAND_HELP_ROWS entry, so
1091
- // `cw commit summary` mis-read "summary" as the run id. Path ["commit","summary"]
1092
- // is 2 tokens; dispatch consumes 1, so positionals[0] is the run id.
1093
- attachCliBinding("commit.summary", {
1094
- path: ["commit", "summary"],
1095
- jsonMode: "flag",
1096
- handler: (args) => {
1097
- const summary = (0, commit_summary_1.commitSummaryCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") });
1098
- return { json: summary, text: `${(0, commit_summary_1.formatCommitSummaryText)(summary)}\n` };
1099
- },
1100
- });
1101
- REGISTRY_BY_CAPABILITY.get("commit.summary").mcp.handler = (args) => (0, commit_summary_1.commitSummaryCli)(args);
1102
- // ---------------------------------------------------------------------
1103
- // MILESTONE 8 (ledger, telemetry, trust-audit, tamper/bundle demos) CLI
1104
- // bindings: ledger propose|review|verify|apply|list, telemetry verify,
1105
- // audit verify, demo tamper|bundle, report bundle|verify-bundle. Handler
1106
- // BODIES live in shell/ledger-cli.ts, shell/telemetry-cli.ts, shell/
1107
- // audit-cli.ts, shell/demo-cli.ts, shell/report-cli.ts (impure — file/
1108
- // stdin reads, run-state loads, archive IO); this table only wires argv
1109
- // shape -> handler call, per cli/dispatch.ts's generic executor
1110
- // contract. `ledger` is intentionally absent from KNOWN_COMMANDS (see
1111
- // cli/parseargv.ts) even though dispatchTable now handles it as a real
1112
- // row — a known, preserved wart.
1113
- // ---------------------------------------------------------------------
1114
- const ledger_cli_1 = require("../shell/ledger-cli");
1115
- const telemetry_cli_1 = require("../shell/telemetry-cli");
1116
- const audit_cli_1 = require("../shell/audit-cli");
1117
- const demo_cli_1 = require("../shell/demo-cli");
1118
- const telemetry_demo_1 = require("../shell/telemetry-demo");
1119
- const report_cli_1 = require("../shell/report-cli");
1120
- attachCliBinding("ledger.propose", {
1121
- path: ["ledger", "propose"],
1122
- jsonMode: "default",
1123
- handler: (args) => ({ json: (0, ledger_cli_1.ledgerProposeCli)(args.options) }),
1124
- });
1125
- REGISTRY_BY_CAPABILITY.get("ledger.propose").mcp.handler = (args) => (0, ledger_cli_1.ledgerProposeMcp)(args);
1126
- attachCliBinding("ledger.review", {
1127
- path: ["ledger", "review"],
1128
- jsonMode: "default",
1129
- handler: (args) => ({ json: (0, ledger_cli_1.ledgerReviewCli)(args.options) }),
1130
- });
1131
- REGISTRY_BY_CAPABILITY.get("ledger.review").mcp.handler = (args) => (0, ledger_cli_1.ledgerReviewMcp)(args);
1132
- attachCliBinding("ledger.verify", {
1133
- path: ["ledger", "verify"],
1134
- jsonMode: "default",
1135
- handler: (args) => {
1136
- const result = (0, ledger_cli_1.ledgerVerifyCli)(args.options);
1137
- return { json: result, exitCode: result.ok ? undefined : 1 };
1138
- },
1139
- });
1140
- REGISTRY_BY_CAPABILITY.get("ledger.verify").mcp.handler = (args) => (0, ledger_cli_1.ledgerVerifyEntry)(args.entry);
1141
- attachCliBinding("ledger.apply", {
1142
- path: ["ledger", "apply"],
1143
- jsonMode: "default",
1144
- handler: (args) => {
1145
- const result = (0, ledger_cli_1.ledgerApplyCli)(args.options);
1146
- return { json: result, exitCode: result.ok ? undefined : 1 };
1147
- },
1148
- });
1149
- REGISTRY_BY_CAPABILITY.get("ledger.apply").mcp.handler = (args) => (0, ledger_cli_1.ledgerApplyEntry)(args.entry);
1150
- attachCliBinding("ledger.list", {
1151
- path: ["ledger", "list"],
1152
- jsonMode: "default",
1153
- handler: (args) => {
1154
- const result = (0, ledger_cli_1.ledgerListCli)(args.options);
1155
- return { json: result, exitCode: result.allOk ? undefined : 1 };
1156
- },
1157
- });
1158
- REGISTRY_BY_CAPABILITY.get("ledger.list").mcp.handler = (args) => (0, ledger_cli_1.ledgerListMcp)(args);
1159
- attachCliBinding("telemetry.verify", {
1160
- path: ["telemetry", "verify"],
1161
- jsonMode: "flag",
1162
- handler: (args) => {
1163
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]) || (0, io_3.optionalArg)(args.options.runId) || (0, io_3.optionalArg)(args.options.run), "run id");
1164
- const result = (0, telemetry_cli_1.telemetryVerifyCli)(runId, args.options);
1165
- return { json: result, text: (0, telemetry_demo_1.formatTelemetryVerify)(result), exitCode: result.verified ? undefined : 1 };
1166
- },
1167
- });
1168
- REGISTRY_BY_CAPABILITY.get("telemetry.verify").mcp.handler = (args) => (0, telemetry_cli_1.telemetryVerifyCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
1169
- attachCliBinding("audit.verify", {
1170
- path: ["audit", "verify"],
1171
- jsonMode: "default",
1172
- handler: (args) => {
1173
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
1174
- const result = (0, audit_cli_1.auditVerifyCli)(runId, args.options);
1175
- return { json: result, exitCode: result.verified ? undefined : 1 };
1176
- },
1177
- });
1178
- REGISTRY_BY_CAPABILITY.get("audit.verify").mcp.handler = (args) => (0, audit_cli_1.auditVerifyCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
1179
- addCliOnlyCapability("demo.tamper", "Prove tamper-evidence: build a signed telemetry ledger, forge it, watch verification fail offline.", {
1180
- path: ["demo", "tamper"],
1181
- jsonMode: "flag",
1182
- handler: (args) => {
1183
- const result = (0, demo_cli_1.demoTamperCli)();
1184
- return { json: result, text: (0, telemetry_demo_1.formatTamperDemo)(result), exitCode: result.proven ? undefined : 1 };
1185
- },
1186
- }, "Human-facing demonstration (operator/newcomer onboarding); the underlying integrity check is exposed programmatically as the both-surface telemetry.verify. No agent or MCP client needs to invoke a demo.");
1187
- addCliOnlyCapability("demo.bundle", "Prove portable-bundle verification: export a sealed report bundle, forge it two ways, watch report verify-bundle catch both offline with only the embedded public key.", {
1188
- path: ["demo", "bundle"],
1189
- jsonMode: "flag",
1190
- handler: (args) => {
1191
- const result = (0, demo_cli_1.demoBundleCli)();
1192
- return { json: result, text: (0, telemetry_demo_1.formatBundleDemo)(result), exitCode: result.proven ? undefined : 1 };
1193
- },
1194
- }, "Human-facing demonstration (operator/newcomer onboarding); the underlying integrity check is exposed programmatically as the both-surface report.verify-bundle. No agent or MCP client needs to invoke a demo.");
1195
- attachCliBinding("report.bundle", {
1196
- path: ["report", "bundle"],
1197
- jsonMode: "default",
1198
- handler: (args) => {
1199
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
1200
- const result = (0, report_cli_1.reportBundleCli)(runId, args.options);
1201
- return { json: result, exitCode: result.ok ? undefined : 1 };
1202
- },
1203
- });
1204
- REGISTRY_BY_CAPABILITY.get("report.bundle").mcp.handler = (args) => (0, report_cli_1.reportBundleCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
1205
- attachCliBinding("report.verify-bundle", {
1206
- path: ["report", "verify-bundle"],
1207
- jsonMode: "default",
1208
- handler: (args) => {
1209
- const archivePath = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "bundle path");
1210
- const result = (0, report_cli_1.reportVerifyBundleCli)({ ...args.options, archive: archivePath });
1211
- return { json: result, exitCode: result.ok ? undefined : 1 };
1212
- },
1213
- });
1214
- REGISTRY_BY_CAPABILITY.get("report.verify-bundle").mcp.handler = (args) => {
1215
- const result = (0, report_cli_1.reportVerifyBundleCli)(args);
1216
- return result;
1217
- };
1218
- // ---------------------------------------------------------------------
1219
- // MILESTONE 9 (multi-agent, topology, coordinator/blackboard, candidate
1220
- // scoring, collaboration, eval replay) CLI bindings. Handler BODIES live
1221
- // in shell/multi-agent-cli.ts (impure — they read/write multi-agent/
1222
- // blackboard/candidate/collaboration/eval state on disk); this table
1223
- // only wires argv shape -> handler call, per cli/dispatch.ts's generic
1224
- // executor contract.
1225
- // ---------------------------------------------------------------------
1226
- const multi_agent_cli_1 = require("../shell/multi-agent-cli");
1227
- const collaboration_io_1 = require("../shell/collaboration-io");
1228
- const topology_io_1 = require("../shell/topology-io");
1229
- attachCliBinding("topology.list", { path: ["topology", "list"], jsonMode: "default", handler: () => ({ json: (0, multi_agent_cli_1.topologyList)() }) });
1230
- REGISTRY_BY_CAPABILITY.get("topology.list").mcp.handler = () => (0, multi_agent_cli_1.topologyList)();
1231
- attachCliBinding("topology.show", {
1232
- path: ["topology", "show"],
1233
- jsonMode: "default",
1234
- handler: (args) => ({ json: (0, multi_agent_cli_1.topologyShowCli)((0, io_1.required)(args.positionals[0], "topology id")) }),
1235
- });
1236
- REGISTRY_BY_CAPABILITY.get("topology.show").mcp.handler = (args) => (0, multi_agent_cli_1.topologyShowCli)((0, io_1.required)((0, io_3.optionalArg)(args.topologyId ?? args.id), "topology id"));
1237
- attachCliBinding("topology.validate", {
1238
- path: ["topology", "validate"],
1239
- jsonMode: "default",
1240
- handler: (args) => {
1241
- const result = (0, multi_agent_cli_1.topologyValidateCli)((0, io_1.required)(args.positionals[0], "topology id"));
1242
- return { json: result, exitCode: result.valid ? undefined : 1 };
1243
- },
1244
- });
1245
- REGISTRY_BY_CAPABILITY.get("topology.validate").mcp.handler = (args) => (0, multi_agent_cli_1.topologyValidateCli)((0, io_1.required)((0, io_3.optionalArg)(args.topologyId ?? args.id), "topology id"));
1246
- attachCliBinding("topology.apply", {
1247
- path: ["topology", "apply"],
1248
- jsonMode: "default",
1249
- handler: (args) => ({
1250
- json: (0, multi_agent_cli_1.topologyApplyCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), topologyId: (0, io_1.required)(args.positionals[1], "topology id") }),
1251
- }),
1252
- });
1253
- REGISTRY_BY_CAPABILITY.get("topology.apply").mcp.handler = (args) => (0, multi_agent_cli_1.topologyApplyCli)({ ...args, topologyId: args.topologyId ?? args.id });
1254
- // jsonMode "flag": human `Topologies` panel by default, canonical JSON
1255
- // under --json (old build's topology.summary was flag).
1256
- attachCliBinding("topology.summary", {
1257
- path: ["topology", "summary"],
1258
- jsonMode: "flag",
1259
- handler: (args) => {
1260
- const summary = (0, multi_agent_cli_1.topologySummaryCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1261
- return { json: summary, text: `${(0, topology_io_1.formatTopologySummaryText)(summary)}\n` };
1262
- },
1263
- });
1264
- REGISTRY_BY_CAPABILITY.get("topology.summary").mcp.handler = (args) => (0, multi_agent_cli_1.topologySummaryCli)(args);
1265
- // jsonMode "flag": human `Run Graph:` render by default, canonical JSON
1266
- // under --json (old build's topology.graph was flag).
1267
- attachCliBinding("topology.graph", {
1268
- path: ["topology", "graph"],
1269
- jsonMode: "flag",
1270
- handler: (args) => {
1271
- const runId = (0, io_1.required)(args.positionals[0], "run id");
1272
- const graph = (0, multi_agent_cli_1.topologyGraphCli)({ runId, ...args.options });
1273
- return { json: graph, text: `${(0, topology_io_1.formatTopologyGraphText)(runId, graph)}\n` };
1274
- },
1275
- });
1276
- REGISTRY_BY_CAPABILITY.get("topology.graph").mcp.handler = (args) => (0, multi_agent_cli_1.topologyGraphCli)(args);
1277
- // ---- multi-agent kernel + host -----------------------------------------
1278
- attachCliBinding("multi-agent.run", {
1279
- path: ["multi-agent", "run"],
1280
- jsonMode: "default",
1281
- // positionals[1] is the MultiAgentRun entity id for the transition/show
1282
- // arms (`cw multi-agent run <run> <id> --status …`); it must NOT collide
1283
- // with the create arm's `--id`, so it is forwarded as `multiAgentRunId`
1284
- // only when no `--id` create flag was passed (old handler took `id` from
1285
- // the 3rd positional token).
1286
- handler: (args) => ({
1287
- json: (0, multi_agent_cli_1.multiAgentRunCli)({
1288
- ...args.options,
1289
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1290
- multiAgentRunId: args.options.id === undefined ? (args.positionals[1] ?? args.options.multiAgentRunId) : args.options.multiAgentRunId,
1291
- }),
1292
- }),
1293
- });
1294
- REGISTRY_BY_CAPABILITY.get("multi-agent.run").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentRunCli)(args);
1295
- attachCliBinding("multi-agent.status", {
1296
- path: ["multi-agent", "status"],
1297
- jsonMode: "flag",
1298
- handler: (args) => ({
1299
- json: (0, multi_agent_cli_1.multiAgentStatusCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1300
- text: (0, multi_agent_cli_1.multiAgentStatusText)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1301
- }),
1302
- });
1303
- REGISTRY_BY_CAPABILITY.get("multi-agent.status").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentStatusCli)(args);
1304
- attachCliBinding("multi-agent.step", {
1305
- path: ["multi-agent", "step"],
1306
- jsonMode: "default",
1307
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentStepCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1308
- });
1309
- REGISTRY_BY_CAPABILITY.get("multi-agent.step").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentStepCli)(args);
1310
- attachCliBinding("multi-agent.blackboard", {
1311
- path: ["multi-agent", "blackboard"],
1312
- jsonMode: "default",
1313
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentBlackboardCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }, args.positionals[1]) }),
1314
- });
1315
- REGISTRY_BY_CAPABILITY.get("multi-agent.blackboard").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentBlackboardCli)(args, args.action);
1316
- attachCliBinding("multi-agent.score", {
1317
- path: ["multi-agent", "score"],
1318
- jsonMode: "default",
1319
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentScoreCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), candidate: args.options.candidate ?? args.positionals[1] }) }),
1320
- });
1321
- REGISTRY_BY_CAPABILITY.get("multi-agent.score").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentScoreCli)(args);
1322
- attachCliBinding("multi-agent.select", {
1323
- path: ["multi-agent", "select"],
1324
- jsonMode: "default",
1325
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentSelectCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), candidate: args.options.candidate ?? args.positionals[1] }) }),
1326
- });
1327
- REGISTRY_BY_CAPABILITY.get("multi-agent.select").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentSelectCli)(args);
1328
- // jsonMode "flag": human `Multi-Agent` panel by default, canonical JSON
1329
- // under --json (old build's multi-agent.summary was flag).
1330
- attachCliBinding("multi-agent.summary", {
1331
- path: ["multi-agent", "summary"],
1332
- jsonMode: "flag",
1333
- handler: (args) => {
1334
- const summary = (0, multi_agent_cli_1.multiAgentSummaryCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1335
- return { json: summary, text: `${(0, operator_ux_text_1.formatMultiAgentSummaryText)(summary)}\n` };
1336
- },
1337
- });
1338
- REGISTRY_BY_CAPABILITY.get("multi-agent.summary").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentSummaryCli)(args);
1339
- // `cw multi-agent graph <run>` is one dispatch path served by two capability
1340
- // rows (multi-agent.graph — the operator graph — and multi-agent.graph.compact
1341
- // — the state-explosion view under --view/--focus/--depth), exactly like
1342
- // blackboard.message.post/list. One shared handler answers both; the
1343
- // second row exists so both capabilities carry a cli binding (the
1344
- // both-surface pairing) and `cw help multi-agent` can list both forms.
1345
- function multiAgentGraphHandler(args) {
1346
- const call = { runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options };
1347
- if (args.options.view !== undefined || args.options.focus !== undefined || args.options.depth !== undefined) {
1348
- const compact = (0, multi_agent_cli_1.multiAgentGraphCompactCli)(call);
1349
- return { json: compact, text: (0, state_explosion_text_1.formatCompactGraph)(compact) };
1350
- }
1351
- return { json: (0, multi_agent_cli_1.multiAgentGraphCli)(call), text: (0, multi_agent_cli_1.multiAgentGraphText)(call) };
1352
- }
1353
- attachCliBinding("multi-agent.graph", { path: ["multi-agent", "graph"], helpPath: ["multi-agent", "graph"], jsonMode: "flag", handler: multiAgentGraphHandler });
1354
- attachCliBinding("multi-agent.graph.compact", { path: ["multi-agent", "graph"], helpPath: ["multi-agent", "graph"], jsonMode: "flag", handler: multiAgentGraphHandler });
1355
- REGISTRY_BY_CAPABILITY.get("multi-agent.graph").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentGraphCli)(args);
1356
- // GAP: `cw multi-agent dependencies|failures|evidence` — the MCP tool rows
1357
- // (cw_multi_agent_dependencies/failures/evidence) were declared but had no
1358
- // CLI path binding and their mcp.handler was still notYetImplemented. Wire
1359
- // both surfaces to the same operator-ux derivation the CLI text render uses
1360
- // (port of the old handler's dependencies/failures/evidence arms).
1361
- attachCliBinding("multi-agent.dependencies", {
1362
- path: ["multi-agent", "dependencies"],
1363
- jsonMode: "flag",
1364
- handler: (args) => ({
1365
- json: (0, multi_agent_cli_1.multiAgentDependenciesCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1366
- text: (0, multi_agent_cli_1.multiAgentDependenciesText)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1367
- }),
1368
- });
1369
- REGISTRY_BY_CAPABILITY.get("multi-agent.dependencies").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentDependenciesCli)(args);
1370
- attachCliBinding("multi-agent.failures", {
1371
- path: ["multi-agent", "failures"],
1372
- jsonMode: "flag",
1373
- handler: (args) => ({
1374
- json: (0, multi_agent_cli_1.multiAgentFailuresCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1375
- text: (0, multi_agent_cli_1.multiAgentFailuresText)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1376
- }),
1377
- });
1378
- REGISTRY_BY_CAPABILITY.get("multi-agent.failures").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentFailuresCli)(args);
1379
- attachCliBinding("multi-agent.evidence", {
1380
- path: ["multi-agent", "evidence"],
1381
- jsonMode: "flag",
1382
- handler: (args) => ({
1383
- json: (0, multi_agent_cli_1.multiAgentEvidenceCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1384
- text: (0, multi_agent_cli_1.multiAgentEvidenceText)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }),
1385
- }),
1386
- });
1387
- REGISTRY_BY_CAPABILITY.get("multi-agent.evidence").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentEvidenceCli)(args);
1388
- // GAP: `cw multi-agent reasoning <run> [--refresh|--evidence <id>]` — the
1389
- // evidence-adoption reasoning chain (cw_evidence_reasoning /
1390
- // cw_evidence_reasoning_refresh MCP tools were declared but notYetImplemented,
1391
- // and no CLI verb was bound). `--refresh` prints the durable index (JSON only,
1392
- // matching the old handler's printJson refresh arm); otherwise it prints the
1393
- // report (text, or JSON under --json).
1394
- function multiAgentReasoningHandler(args) {
1395
- const call = { runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options };
1396
- if (args.options.refresh && args.options.evidence === undefined && args.options.evidenceId === undefined) {
1397
- return { json: (0, multi_agent_cli_1.multiAgentReasoningRefreshCli)(call) };
1398
- }
1399
- return { json: (0, multi_agent_cli_1.multiAgentReasoningCli)(call), text: (0, multi_agent_cli_1.multiAgentReasoningText)(call) };
1400
- }
1401
- attachCliBinding("multi-agent.reasoning", { path: ["multi-agent", "reasoning"], helpPath: ["multi-agent", "reasoning"], jsonMode: "flag", handler: multiAgentReasoningHandler });
1402
- // `multi-agent.reasoning.refresh` (the durable evidence-adoption index) shares
1403
- // the ["multi-agent","reasoning"] dispatch path — `cw multi-agent reasoning
1404
- // <run> --refresh` is served by the reasoning binding above (first row wins).
1405
- // This row exists so the refresh capability also carries a cli binding (the
1406
- // both-surface pairing) and `cw help multi-agent` lists it. Same handler.
1407
- attachCliBinding("multi-agent.reasoning.refresh", { path: ["multi-agent", "reasoning"], helpPath: ["multi-agent", "reasoning"], jsonMode: "default", handler: multiAgentReasoningHandler });
1408
- REGISTRY_BY_CAPABILITY.get("multi-agent.reasoning").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentReasoningCli)(args);
1409
- REGISTRY_BY_CAPABILITY.get("multi-agent.reasoning.refresh").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentReasoningRefreshCli)(args);
1410
- // GAP: the state-explosion / contract read views (cw_multi_agent_summarize /
1411
- // cw_blackboard_summarize / cw_multi_agent_graph_compact / cw_contract_show)
1412
- // were declared MCP tools left on notYetImplemented, and their CLI verbs were
1413
- // unbound. Wire both surfaces to the ported read fns.
1414
- attachCliBinding("multi-agent.summarize", {
1415
- path: ["multi-agent", "summarize"],
1416
- jsonMode: "flag",
1417
- handler: (args) => {
1418
- const result = (0, multi_agent_cli_1.multiAgentSummarizeCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1419
- return { json: result, text: (0, state_explosion_text_1.formatStateExplosionReport)(result) };
1420
- },
1421
- });
1422
- REGISTRY_BY_CAPABILITY.get("multi-agent.summarize").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentSummarizeCli)(args);
1423
- REGISTRY_BY_CAPABILITY.get("multi-agent.graph.compact").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentGraphCompactCli)(args);
1424
- attachCliBinding("blackboard.summarize", {
1425
- path: ["blackboard", "summarize"],
1426
- jsonMode: "flag",
1427
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardSummarizeCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1428
- });
1429
- REGISTRY_BY_CAPABILITY.get("blackboard.summarize").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardSummarizeCli)(args);
1430
- attachCliBinding("contract.show", {
1431
- path: ["contract", "show"],
1432
- jsonMode: "default",
1433
- handler: (args) => ({ json: (0, multi_agent_cli_1.contractShowCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }, args.positionals[1]) }),
1434
- });
1435
- REGISTRY_BY_CAPABILITY.get("contract.show").mcp.handler = (args) => (0, multi_agent_cli_1.contractShowCli)(args);
1436
- attachCliBinding("multi-agent.run.create", {
1437
- path: ["multi-agent", "role"],
1438
- helpPath: ["multi-agent", "role"],
1439
- jsonMode: "default",
1440
- handler: (args) => ({
1441
- json: (0, multi_agent_cli_1.multiAgentRoleCli)({
1442
- ...args.options,
1443
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1444
- roleId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.roleId,
1445
- }),
1446
- }),
1447
- });
1448
- attachCliBinding("multi-agent.group.create", {
1449
- path: ["multi-agent", "group"],
1450
- helpPath: ["multi-agent", "group"],
1451
- jsonMode: "default",
1452
- handler: (args) => ({
1453
- json: (0, multi_agent_cli_1.multiAgentGroupCli)({
1454
- ...args.options,
1455
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1456
- groupId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.groupId,
1457
- }),
1458
- }),
1459
- });
1460
- attachCliBinding("multi-agent.membership.create", {
1461
- path: ["multi-agent", "membership"],
1462
- helpPath: ["multi-agent", "membership"],
1463
- jsonMode: "default",
1464
- handler: (args) => ({
1465
- json: (0, multi_agent_cli_1.multiAgentMembershipCli)({
1466
- ...args.options,
1467
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1468
- membershipId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.membershipId,
1469
- }),
1470
- }),
1471
- });
1472
- attachCliBinding("multi-agent.fanout.create", {
1473
- path: ["multi-agent", "fanout"],
1474
- helpPath: ["multi-agent", "fanout"],
1475
- jsonMode: "default",
1476
- handler: (args) => ({
1477
- json: (0, multi_agent_cli_1.multiAgentFanoutCli)({
1478
- ...args.options,
1479
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1480
- fanoutId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.fanoutId,
1481
- }),
1482
- }),
1483
- });
1484
- attachCliBinding("multi-agent.fanin.collect", {
1485
- path: ["multi-agent", "fanin"],
1486
- helpPath: ["multi-agent", "fanin"],
1487
- jsonMode: "default",
1488
- handler: (args) => ({
1489
- json: (0, multi_agent_cli_1.multiAgentFaninCli)({
1490
- ...args.options,
1491
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1492
- faninId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.faninId,
1493
- }),
1494
- }),
1495
- });
1496
- REGISTRY_BY_CAPABILITY.get("multi-agent.run.create").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentRoleCli)(args);
1497
- REGISTRY_BY_CAPABILITY.get("multi-agent.role.create").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentRoleCli)(args);
1498
- REGISTRY_BY_CAPABILITY.get("multi-agent.group.create").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentGroupCli)(args);
1499
- REGISTRY_BY_CAPABILITY.get("multi-agent.membership.create").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentMembershipCli)(args);
1500
- REGISTRY_BY_CAPABILITY.get("multi-agent.fanout.create").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentFanoutCli)(args);
1501
- REGISTRY_BY_CAPABILITY.get("multi-agent.fanin.collect").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentFaninCli)(args);
1502
- // GAP: the *.show MCP tools were declared but left notYetImplemented. Route
1503
- // each to its create CLI fn's read arm (id-only args return the record).
1504
- REGISTRY_BY_CAPABILITY.get("multi-agent.role.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentRoleCli)({ ...args, roleId: args.roleId ?? args.id });
1505
- REGISTRY_BY_CAPABILITY.get("multi-agent.group.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentGroupCli)({ ...args, groupId: args.groupId ?? args.id });
1506
- REGISTRY_BY_CAPABILITY.get("multi-agent.membership.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentMembershipCli)({ ...args, membershipId: args.membershipId ?? args.id });
1507
- REGISTRY_BY_CAPABILITY.get("multi-agent.fanout.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentFanoutCli)({ ...args, fanoutId: args.fanoutId ?? args.id });
1508
- REGISTRY_BY_CAPABILITY.get("multi-agent.fanin.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentFaninCli)({ ...args, faninId: args.faninId ?? args.id });
1509
- // The create/show pairs for role/group/membership/fanout/fanin each SHARE
1510
- // one dispatch path (["multi-agent","role"] etc.); `cw multi-agent role
1511
- // <run> [id]` is served by the create binding declared above (first row
1512
- // wins findCapabilityByCliPath), and an id-only invocation returns the
1513
- // existing record (the read arm). These extra rows exist so each show
1514
- // capability — and multi-agent.role.create, distinct from the
1515
- // multi-agent.run.create binding that already owns the ["multi-agent",
1516
- // "role"] path — also carries a cli binding (the both-surface pairing),
1517
- // exactly like blackboard.message.post/list. Same handler, same shell fn.
1518
- function multiAgentRoleHandler(args) {
1519
- return {
1520
- json: (0, multi_agent_cli_1.multiAgentRoleCli)({
1521
- ...args.options,
1522
- runId: (0, io_1.required)(args.positionals[0], "run id"),
1523
- roleId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.roleId,
1524
- }),
1525
- };
1526
- }
1527
- attachCliBinding("multi-agent.role.create", { path: ["multi-agent", "role"], helpPath: ["multi-agent", "role"], jsonMode: "default", handler: multiAgentRoleHandler });
1528
- attachCliBinding("multi-agent.role.show", { path: ["multi-agent", "role"], helpPath: ["multi-agent", "role"], jsonMode: "default", handler: multiAgentRoleHandler });
1529
- attachCliBinding("multi-agent.group.show", {
1530
- path: ["multi-agent", "group"],
1531
- helpPath: ["multi-agent", "group"],
1532
- jsonMode: "default",
1533
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentGroupCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), groupId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.groupId }) }),
1534
- });
1535
- attachCliBinding("multi-agent.membership.show", {
1536
- path: ["multi-agent", "membership"],
1537
- helpPath: ["multi-agent", "membership"],
1538
- jsonMode: "default",
1539
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentMembershipCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), membershipId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.membershipId }) }),
1540
- });
1541
- attachCliBinding("multi-agent.fanout.show", {
1542
- path: ["multi-agent", "fanout"],
1543
- helpPath: ["multi-agent", "fanout"],
1544
- jsonMode: "default",
1545
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentFanoutCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), fanoutId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.fanoutId }) }),
1546
- });
1547
- attachCliBinding("multi-agent.fanin.show", {
1548
- path: ["multi-agent", "fanin"],
1549
- helpPath: ["multi-agent", "fanin"],
1550
- jsonMode: "default",
1551
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentFaninCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id"), faninId: args.options.id === undefined && args.positionals.length >= 2 ? args.positionals[1] : args.options.faninId }) }),
1552
- });
1553
- attachCliBinding("multi-agent.run.transition", {
1554
- path: ["multi-agent", "transition"],
1555
- jsonMode: "default",
1556
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentRunCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1557
- });
1558
- REGISTRY_BY_CAPABILITY.get("multi-agent.run.transition").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentRunCli)(args);
1559
- attachCliBinding("multi-agent.run.show", {
1560
- path: ["multi-agent", "show"],
1561
- jsonMode: "default",
1562
- handler: (args) => ({ json: (0, multi_agent_cli_1.multiAgentShowCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }, (0, io_1.required)(args.positionals[1], "id")) }),
1563
- });
1564
- REGISTRY_BY_CAPABILITY.get("multi-agent.run.show").mcp.handler = (args) => (0, multi_agent_cli_1.multiAgentShowCli)(args, (0, io_1.required)((0, io_3.optionalArg)(args.multiAgentRunId ?? args.id), "id"));
1565
- // ---- blackboard / coordinator -------------------------------------------
1566
- attachCliBinding("blackboard.summary", {
1567
- path: ["blackboard", "summary"],
1568
- jsonMode: "default",
1569
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardSummaryCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1570
- });
1571
- REGISTRY_BY_CAPABILITY.get("blackboard.summary").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardSummaryCli)(args);
1572
- attachCliBinding("blackboard.graph", {
1573
- path: ["blackboard", "graph"],
1574
- jsonMode: "default",
1575
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardGraphCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1576
- });
1577
- REGISTRY_BY_CAPABILITY.get("blackboard.graph").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardGraphCli)(args);
1578
- attachCliBinding("blackboard.resolve", {
1579
- path: ["blackboard", "resolve"],
1580
- jsonMode: "default",
1581
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardResolveCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1582
- });
1583
- REGISTRY_BY_CAPABILITY.get("blackboard.resolve").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardResolveCli)(args);
1584
- // GAP: the blackboard write/read verbs accept the sub-verb's ACTION word
1585
- // ("create"/"post"/"put"/"add"/"list") in EITHER of two slots around the run
1586
- // id, per the smokes' varied spellings:
1587
- // blackboard topic <run> (create, run first)
1588
- // blackboard topic create <run> (create action FIRST)
1589
- // blackboard message <run> (post, run first)
1590
- // blackboard message <run> list (list action AFTER run)
1591
- // blackboard message list <run> (list action FIRST)
1592
- // blackboard message post <run> (post action FIRST)
1593
- // dispatchTable already consumed the sub-verb ("topic"/"message"/…), so the
1594
- // handler's positionals begin at the token AFTER it. `blackboardRunAndAction`
1595
- // strips a leading action word (if present) so the run id is found wherever it
1596
- // sits, and reports the effective action word for the post/list split.
1597
- const BLACKBOARD_ACTION_WORDS = new Set(["create", "post", "put", "add", "list", "show"]);
1598
- function blackboardRunAndAction(args) {
1599
- const [first, second] = args.positionals;
1600
- if (first !== undefined && BLACKBOARD_ACTION_WORDS.has(first)) {
1601
- return { runId: (0, io_1.required)(second, "run id"), action: first };
1602
- }
1603
- return { runId: (0, io_1.required)(first, "run id"), action: second };
1604
- }
1605
- attachCliBinding("blackboard.topic.create", {
1606
- path: ["blackboard", "topic"],
1607
- helpPath: ["blackboard", "topic", "create"],
1608
- jsonMode: "default",
1609
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardTopicCreateCli)({ ...args.options, runId: blackboardRunAndAction(args).runId }) }),
1610
- });
1611
- REGISTRY_BY_CAPABILITY.get("blackboard.topic.create").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardTopicCreateCli)(args);
1612
- function blackboardMessageHandler(args) {
1613
- const { runId, action } = blackboardRunAndAction(args);
1614
- if (action === "list")
1615
- return { json: (0, multi_agent_cli_1.blackboardMessageListCli)({ ...args.options, runId }) };
1616
- return { json: (0, multi_agent_cli_1.blackboardMessagePostCli)({ ...args.options, runId }) };
1617
- }
1618
- attachCliBinding("blackboard.message.post", { path: ["blackboard", "message"], helpPath: ["blackboard", "message", "post"], jsonMode: "default", handler: blackboardMessageHandler });
1619
- attachCliBinding("blackboard.message.list", { path: ["blackboard", "message"], helpPath: ["blackboard", "message", "list"], jsonMode: "default", handler: blackboardMessageHandler });
1620
- REGISTRY_BY_CAPABILITY.get("blackboard.message.post").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardMessagePostCli)(args);
1621
- REGISTRY_BY_CAPABILITY.get("blackboard.message.list").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardMessageListCli)(args);
1622
- attachCliBinding("blackboard.context.put", {
1623
- path: ["blackboard", "context"],
1624
- helpPath: ["blackboard", "context", "put"],
1625
- jsonMode: "default",
1626
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardContextPutCli)({ ...args.options, runId: blackboardRunAndAction(args).runId }) }),
1627
- });
1628
- REGISTRY_BY_CAPABILITY.get("blackboard.context.put").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardContextPutCli)(args);
1629
- function blackboardArtifactHandler(args) {
1630
- const { runId, action } = blackboardRunAndAction(args);
1631
- if (action === "list")
1632
- return { json: (0, multi_agent_cli_1.blackboardArtifactListCli)({ ...args.options, runId }) };
1633
- return { json: (0, multi_agent_cli_1.blackboardArtifactAddCli)({ ...args.options, runId }) };
1634
- }
1635
- attachCliBinding("blackboard.artifact.add", { path: ["blackboard", "artifact"], helpPath: ["blackboard", "artifact", "add"], jsonMode: "default", handler: blackboardArtifactHandler });
1636
- attachCliBinding("blackboard.artifact.list", { path: ["blackboard", "artifact"], helpPath: ["blackboard", "artifact", "list"], jsonMode: "default", handler: blackboardArtifactHandler });
1637
- REGISTRY_BY_CAPABILITY.get("blackboard.artifact.add").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardArtifactAddCli)(args);
1638
- REGISTRY_BY_CAPABILITY.get("blackboard.artifact.list").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardArtifactListCli)(args);
1639
- attachCliBinding("blackboard.snapshot", {
1640
- path: ["blackboard", "snapshot"],
1641
- jsonMode: "default",
1642
- handler: (args) => ({ json: (0, multi_agent_cli_1.blackboardSnapshotCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1643
- });
1644
- REGISTRY_BY_CAPABILITY.get("blackboard.snapshot").mcp.handler = (args) => (0, multi_agent_cli_1.blackboardSnapshotCli)(args);
1645
- attachCliBinding("coordinator.summary", {
1646
- path: ["coordinator", "summary"],
1647
- jsonMode: "default",
1648
- handler: (args) => ({ json: (0, multi_agent_cli_1.coordinatorSummaryCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1649
- });
1650
- REGISTRY_BY_CAPABILITY.get("coordinator.summary").mcp.handler = (args) => (0, multi_agent_cli_1.coordinatorSummaryCli)(args);
1651
- attachCliBinding("coordinator.decision", {
1652
- path: ["coordinator", "decision"],
1653
- jsonMode: "default",
1654
- handler: (args) => ({ json: (0, multi_agent_cli_1.coordinatorDecisionCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1655
- });
1656
- REGISTRY_BY_CAPABILITY.get("coordinator.decision").mcp.handler = (args) => (0, multi_agent_cli_1.coordinatorDecisionCli)(args);
1657
- // ---- candidate scoring ----------------------------------------------------
1658
- attachCliBinding("candidate.list", {
1659
- path: ["candidate", "list"],
1660
- jsonMode: "default",
1661
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateListCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1662
- });
1663
- REGISTRY_BY_CAPABILITY.get("candidate.list").mcp.handler = (args) => (0, multi_agent_cli_1.candidateListCli)(args);
1664
- attachCliBinding("candidate.show", {
1665
- path: ["candidate", "show"],
1666
- jsonMode: "default",
1667
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateShowCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }, (0, io_1.required)(args.positionals[1], "candidate id")) }),
1668
- });
1669
- REGISTRY_BY_CAPABILITY.get("candidate.show").mcp.handler = (args) => (0, multi_agent_cli_1.candidateShowCli)(args, (0, io_1.required)((0, io_3.optionalArg)(args.candidateId), "candidate id"));
1670
- attachCliBinding("candidate.register", {
1671
- path: ["candidate", "register"],
1672
- jsonMode: "default",
1673
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateRegisterCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1674
- });
1675
- REGISTRY_BY_CAPABILITY.get("candidate.register").mcp.handler = (args) => (0, multi_agent_cli_1.candidateRegisterCli)(args);
1676
- attachCliBinding("candidate.score", {
1677
- path: ["candidate", "score"],
1678
- jsonMode: "default",
1679
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateScoreCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }, (0, io_1.required)(args.positionals[1], "candidate id")) }),
1680
- });
1681
- REGISTRY_BY_CAPABILITY.get("candidate.score").mcp.handler = (args) => (0, multi_agent_cli_1.candidateScoreCli)(args, (0, io_1.required)((0, io_3.optionalArg)(args.candidateId), "candidate id"));
1682
- attachCliBinding("candidate.rank", {
1683
- path: ["candidate", "rank"],
1684
- jsonMode: "default",
1685
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateRankCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options }) }),
1686
- });
1687
- REGISTRY_BY_CAPABILITY.get("candidate.rank").mcp.handler = (args) => (0, multi_agent_cli_1.candidateRankCli)(args);
1688
- attachCliBinding("candidate.select", {
1689
- path: ["candidate", "select"],
1690
- jsonMode: "default",
1691
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateSelectCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }, (0, io_1.required)(args.positionals[1], "candidate id")) }),
1692
- });
1693
- REGISTRY_BY_CAPABILITY.get("candidate.select").mcp.handler = (args) => (0, multi_agent_cli_1.candidateSelectCli)(args, (0, io_1.required)((0, io_3.optionalArg)(args.candidateId), "candidate id"));
1694
- attachCliBinding("candidate.reject", {
1695
- path: ["candidate", "reject"],
1696
- jsonMode: "default",
1697
- handler: (args) => ({ json: (0, multi_agent_cli_1.candidateRejectCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }, (0, io_1.required)(args.positionals[1], "candidate id")) }),
1698
- });
1699
- REGISTRY_BY_CAPABILITY.get("candidate.reject").mcp.handler = (args) => (0, multi_agent_cli_1.candidateRejectCli)(args, (0, io_1.required)((0, io_3.optionalArg)(args.candidateId), "candidate id"));
1700
- // jsonMode "flag": human `Candidates` panel by default, canonical JSON under
1701
- // --json (old build's candidate.summary was flag).
1702
- attachCliBinding("candidate.summary", {
1703
- path: ["candidate", "summary"],
1704
- jsonMode: "flag",
1705
- handler: (args) => {
1706
- const summary = (0, multi_agent_cli_1.candidateSummaryCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1707
- return { json: summary, text: `${(0, operator_ux_text_1.formatCandidateSummaryText)(summary)}\n` };
1708
- },
1709
- });
1710
- REGISTRY_BY_CAPABILITY.get("candidate.summary").mcp.handler = (args) => (0, multi_agent_cli_1.candidateSummaryCli)(args);
1711
- // ---- collaboration ---------------------------------------------------------
1712
- attachCliBinding("approve", {
1713
- path: ["approve"],
1714
- jsonMode: "default",
1715
- handler: (args) => ({ json: (0, multi_agent_cli_1.approveCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[1], "run id"), body: args.positionals[3] }, args.positionals[0], args.positionals[2]) }),
1716
- });
1717
- REGISTRY_BY_CAPABILITY.get("approve").mcp.handler = (args) => (0, multi_agent_cli_1.approveCli)(args);
1718
- attachCliBinding("reject", {
1719
- path: ["reject"],
1720
- jsonMode: "default",
1721
- handler: (args) => ({ json: (0, multi_agent_cli_1.rejectCollabCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[1], "run id") }, args.positionals[0], args.positionals[2]) }),
1722
- });
1723
- REGISTRY_BY_CAPABILITY.get("reject").mcp.handler = (args) => (0, multi_agent_cli_1.rejectCollabCli)(args);
1724
- attachCliBinding("comment.add", {
1725
- path: ["comment", "add"],
1726
- jsonMode: "default",
1727
- handler: (args) => ({ json: (0, multi_agent_cli_1.commentAddCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[1], "run id"), body: args.options.body ?? args.positionals[3] }, args.positionals[0], args.positionals[2]) }),
1728
- });
1729
- REGISTRY_BY_CAPABILITY.get("comment.add").mcp.handler = (args) => (0, multi_agent_cli_1.commentAddCli)(args);
1730
- // jsonMode "flag": human comment list by default, canonical JSON under
1731
- // --json (old build's comment.list was flag).
1732
- attachCliBinding("comment.list", {
1733
- path: ["comment", "list"],
1734
- jsonMode: "flag",
1735
- handler: (args) => {
1736
- const report = (0, multi_agent_cli_1.commentListCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1737
- return { json: report, text: `${(0, collaboration_io_1.formatCommentList)(report)}\n` };
1738
- },
1739
- });
1740
- REGISTRY_BY_CAPABILITY.get("comment.list").mcp.handler = (args) => (0, multi_agent_cli_1.commentListCli)(args);
1741
- attachCliBinding("handoff", {
1742
- path: ["handoff"],
1743
- jsonMode: "default",
1744
- // `cw handoff <kind> <run-id> [target-id]` (byte-behavior port of the old
1745
- // build's handleHandoff): the FIRST required() is on the target-kind
1746
- // positional, so a bare `cw handoff` fails with "Missing target kind" — not
1747
- // "Missing run id". The kind check must fire before the run-id read.
1748
- handler: (args) => {
1749
- const kind = (0, io_1.required)(args.positionals[0], "target kind");
1750
- const runId = (0, io_1.required)(args.positionals[1], "run id");
1751
- return { json: (0, multi_agent_cli_1.handoffCli)({ ...args.options, runId }, kind, args.positionals[2]) };
1752
- },
1753
- });
1754
- REGISTRY_BY_CAPABILITY.get("handoff").mcp.handler = (args) => (0, multi_agent_cli_1.handoffCli)(args);
1755
- // jsonMode "flag": human review-status report by default, canonical JSON
1756
- // under --json (old build's review.status was flag).
1757
- attachCliBinding("review.status", {
1758
- path: ["review", "status"],
1759
- jsonMode: "flag",
1760
- handler: (args) => {
1761
- const report = (0, multi_agent_cli_1.reviewStatusCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1762
- return { json: report, text: `${(0, collaboration_io_1.formatReviewStatus)(report)}\n` };
1763
- },
1764
- });
1765
- REGISTRY_BY_CAPABILITY.get("review.status").mcp.handler = (args) => (0, multi_agent_cli_1.reviewStatusCli)(args);
1766
- attachCliBinding("review.policy", {
1767
- path: ["review", "policy"],
1768
- jsonMode: "default",
1769
- handler: (args) => ({ json: (0, multi_agent_cli_1.reviewPolicyCli)({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") }) }),
1770
- });
1771
- REGISTRY_BY_CAPABILITY.get("review.policy").mcp.handler = (args) => (0, multi_agent_cli_1.reviewPolicyCli)(args);
1772
- // ---- eval replay harness ---------------------------------------------------
1773
- // eval snapshot|replay|compare|score|gate|report — `jsonMode: flag` so a bare
1774
- // call renders the human eval report (formatMultiAgentEval) and `--json`
1775
- // prints the result object, matching the old build's eval handler.
1776
- attachCliBinding("eval.snapshot", {
1777
- path: ["eval", "snapshot"],
1778
- jsonMode: "flag",
1779
- handler: (args) => {
1780
- const result = (0, multi_agent_cli_1.evalSnapshotCli)({ runId: (0, io_1.required)(args.positionals[0], "run id"), ...args.options });
1781
- return { json: result, text: (0, eval_text_1.formatMultiAgentEval)(result) };
1782
- },
1783
- });
1784
- REGISTRY_BY_CAPABILITY.get("eval.snapshot").mcp.handler = (args) => (0, multi_agent_cli_1.evalSnapshotCli)(args);
1785
- attachCliBinding("eval.replay", {
1786
- path: ["eval", "replay"],
1787
- jsonMode: "flag",
1788
- handler: (args) => {
1789
- const result = (0, multi_agent_cli_1.evalReplayCli)({ snapshot: args.positionals[0], ...args.options });
1790
- return { json: result, text: (0, eval_text_1.formatMultiAgentEval)(result) };
1791
- },
1792
- });
1793
- REGISTRY_BY_CAPABILITY.get("eval.replay").mcp.handler = (args) => (0, multi_agent_cli_1.evalReplayCli)(args);
1794
- attachCliBinding("eval.compare", {
1795
- path: ["eval", "compare"],
1796
- jsonMode: "flag",
1797
- handler: (args) => {
1798
- const result = (0, multi_agent_cli_1.evalCompareCli)({ baseline: args.positionals[0], replay: args.positionals[1], ...args.options });
1799
- return { json: result, text: (0, eval_text_1.formatMultiAgentEval)(result) };
1800
- },
1801
- });
1802
- REGISTRY_BY_CAPABILITY.get("eval.compare").mcp.handler = (args) => (0, multi_agent_cli_1.evalCompareCli)(args);
1803
- attachCliBinding("eval.score", {
1804
- path: ["eval", "score"],
1805
- jsonMode: "flag",
1806
- handler: (args) => {
1807
- const result = (0, multi_agent_cli_1.evalScoreCli)({ replay: args.positionals[0], ...args.options });
1808
- return { json: result, text: (0, eval_text_1.formatMultiAgentEval)(result) };
1809
- },
1810
- });
1811
- REGISTRY_BY_CAPABILITY.get("eval.score").mcp.handler = (args) => (0, multi_agent_cli_1.evalScoreCli)(args);
1812
- attachCliBinding("eval.gate", {
1813
- path: ["eval", "gate"],
1814
- jsonMode: "flag",
1815
- handler: (args) => {
1816
- const gate = (0, multi_agent_cli_1.evalGateCli)({ suite: args.positionals[0], ...args.options });
1817
- return { json: gate, text: (0, eval_text_1.formatMultiAgentEval)(gate), exitCode: gate.verdict === "ship" ? undefined : 1 };
1818
- },
1819
- });
1820
- REGISTRY_BY_CAPABILITY.get("eval.gate").mcp.handler = (args) => (0, multi_agent_cli_1.evalGateCli)(args);
1821
- attachCliBinding("eval.report", {
1822
- path: ["eval", "report"],
1823
- jsonMode: "flag",
1824
- handler: (args) => {
1825
- const result = (0, multi_agent_cli_1.evalReportCli)({ replay: args.positionals[0], ...args.options });
1826
- return { json: result, text: (0, eval_text_1.formatMultiAgentEval)(result) };
1827
- },
1828
- });
1829
- REGISTRY_BY_CAPABILITY.get("eval.report").mcp.handler = (args) => (0, multi_agent_cli_1.evalReportCli)(args);
1830
- // ---------------------------------------------------------------------
1831
- // MILESTONE 10 (scheduling, registry, gc/reclamation, orphans, clones)
1832
- // CLI bindings: schedule *, cw loop, routine *, sched *, registry *,
1833
- // queue *, gc *, orphans *, clones *, run search|list|show|resume|
1834
- // archive|rerun, history. Handler BODIES live in shell/registry-cli.ts,
1835
- // shell/scheduler-io.ts, shell/scheduling-io.ts, shell/reclamation-io.ts,
1836
- // shell/run-registry-io.ts (impure — disk-scanning IO); this table only
1837
- // wires argv shape -> handler call, per cli/dispatch.ts's generic
1838
- // executor contract. Usage-error strings are copied byte-for-byte from
1839
- // the old build's handlers/{scheduling,registry,maintenance,orphans,
1840
- // clones}.ts.
1841
- // ---------------------------------------------------------------------
1842
- const registry_cli_1 = require("../shell/registry-cli");
1843
- const reclamation_io_1 = require("../shell/reclamation-io");
1844
- const run_registry_io_1 = require("../shell/run-registry-io");
1845
- const scheduling_io_1 = require("../shell/scheduling-io");
1846
- const node_fs_1 = __importDefault(require("node:fs"));
1847
- function firstPositionalArg(args, index = 0) {
1848
- return args.positionals[index];
1849
- }
1850
- // ---- schedule (+ cw loop) ----------------------------------------------
1851
- addCliOnlyCapability("loop", 'cw loop — sugar for "schedule create --kind loop".', {
1852
- path: ["loop"],
1853
- jsonMode: "default",
1854
- handler: (args) => ({ json: (0, registry_cli_1.scheduleCreateCli)({ ...args.options, kind: "loop" }) }),
1855
- }, "loop is CLI-only sugar over schedule.create; the old build never gave it an MCP tool of its own (SPEC/scheduling-registry.md section I).");
1856
- addCliOnlyCapability("schedule", "cw schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon — the wall-clock scheduler.", {
1857
- path: ["schedule"],
1858
- jsonMode: "default",
1859
- hiddenFromHelp: true,
1860
- handler: (args) => {
1861
- const [subcommand, id] = args.positionals;
1862
- switch (subcommand) {
1863
- case "create":
1864
- return { json: (0, registry_cli_1.scheduleCreateCli)(args.options) };
1865
- case "list":
1866
- return { json: (0, registry_cli_1.scheduleListCli)(args.options) };
1867
- case "delete":
1868
- return { json: (0, registry_cli_1.scheduleDeleteCli)((0, io_1.required)(id, "schedule id"), args.options) };
1869
- case "due":
1870
- return { json: (0, registry_cli_1.scheduleDueCli)(args.options) };
1871
- case "complete":
1872
- return { json: (0, registry_cli_1.scheduleCompleteCli)((0, io_1.required)(id, "schedule id"), args.options) };
1873
- case "pause":
1874
- return { json: (0, registry_cli_1.schedulePauseCli)((0, io_1.required)(id, "schedule id"), args.options) };
1875
- case "resume":
1876
- return { json: (0, registry_cli_1.scheduleResumeCli)((0, io_1.required)(id, "schedule id"), args.options) };
1877
- case "run-now":
1878
- return { json: (0, registry_cli_1.scheduleRunNowCli)((0, io_1.required)(id, "schedule id"), args.options) };
1879
- case "history":
1880
- return { json: (0, registry_cli_1.scheduleHistoryCli)(id, args.options) };
1881
- case "daemon": {
1882
- if (args.options.once)
1883
- return { json: (0, registry_cli_1.scheduleDaemonTickCli)(args.options) };
1884
- // Never returns (matches the old build's forever daemon loop);
1885
- // the process stays alive via the DesktopSchedulerDaemon's own
1886
- // setInterval, printing one tick line per interval.
1887
- void (0, registry_cli_1.scheduleDaemonRunForever)(args.options);
1888
- return {};
1889
- }
1890
- default:
1891
- throw new Error("Usage: cw.js schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon");
1892
- }
1893
- },
1894
- }, "cw schedule is the desktop wall-clock scheduler; SPEC/mcp.md declares its MCP peers per verb (cw_schedule_*), each wired below.");
1895
- // GAP #24: the cw_schedule_* MCP peers were declared but left on the
1896
- // notYetImplemented placeholder (the "each wired below" comment was never
1897
- // satisfied). Mirror the CLI switch's shell fns; arg-name reads (id/status)
1898
- // copied from the old build's mcp/tool-call.ts scheduler arms.
1899
- REGISTRY_BY_CAPABILITY.get("schedule.create").mcp.handler = (args) => (0, registry_cli_1.scheduleCreateCli)(args);
1900
- REGISTRY_BY_CAPABILITY.get("schedule.list").mcp.handler = (args) => (0, registry_cli_1.scheduleListCli)(args);
1901
- REGISTRY_BY_CAPABILITY.get("schedule.due").mcp.handler = (args) => (0, registry_cli_1.scheduleDueCli)(args);
1902
- REGISTRY_BY_CAPABILITY.get("schedule.complete").mcp.handler = (args) => (0, registry_cli_1.scheduleCompleteCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "schedule id"), args);
1903
- REGISTRY_BY_CAPABILITY.get("schedule.pause").mcp.handler = (args) => (0, registry_cli_1.schedulePauseCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "schedule id"), args);
1904
- REGISTRY_BY_CAPABILITY.get("schedule.resume").mcp.handler = (args) => (0, registry_cli_1.scheduleResumeCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "schedule id"), args);
1905
- REGISTRY_BY_CAPABILITY.get("schedule.run-now").mcp.handler = (args) => (0, registry_cli_1.scheduleRunNowCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "schedule id"), args);
1906
- REGISTRY_BY_CAPABILITY.get("schedule.history").mcp.handler = (args) => (0, registry_cli_1.scheduleHistoryCli)((0, io_3.optionalArg)(args.id), args);
1907
- REGISTRY_BY_CAPABILITY.get("schedule.delete").mcp.handler = (args) => (0, registry_cli_1.scheduleDeleteCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "schedule id"), args);
1908
- // Each `schedule <verb>` sub-action is its own two-token cli row (found
1909
- // before the ["schedule"] catch-all per the reversed candidate order), so
1910
- // each capability is a real both-surface dual-bound row. Same shell fns and
1911
- // [subcommand, id] positional mapping as the catch-all switch above.
1912
- // `hiddenFromHelp` keeps `cw help schedule`'s rows coming from the single
1913
- // literal COMMAND_HELP_ROWS.schedule block.
1914
- attachCliBinding("schedule.create", { path: ["schedule", "create"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleCreateCli)(args.options) }) });
1915
- attachCliBinding("schedule.list", { path: ["schedule", "list"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleListCli)(args.options) }) });
1916
- attachCliBinding("schedule.delete", { path: ["schedule", "delete"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleDeleteCli)((0, io_1.required)(args.positionals[0], "schedule id"), args.options) }) });
1917
- attachCliBinding("schedule.due", { path: ["schedule", "due"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleDueCli)(args.options) }) });
1918
- attachCliBinding("schedule.complete", { path: ["schedule", "complete"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleCompleteCli)((0, io_1.required)(args.positionals[0], "schedule id"), args.options) }) });
1919
- attachCliBinding("schedule.pause", { path: ["schedule", "pause"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.schedulePauseCli)((0, io_1.required)(args.positionals[0], "schedule id"), args.options) }) });
1920
- attachCliBinding("schedule.resume", { path: ["schedule", "resume"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleResumeCli)((0, io_1.required)(args.positionals[0], "schedule id"), args.options) }) });
1921
- attachCliBinding("schedule.run-now", { path: ["schedule", "run-now"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleRunNowCli)((0, io_1.required)(args.positionals[0], "schedule id"), args.options) }) });
1922
- attachCliBinding("schedule.history", { path: ["schedule", "history"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.scheduleHistoryCli)(args.positionals[0], args.options) }) });
1923
- // ---- routine ------------------------------------------------------------
1924
- addCliOnlyCapability("routine", "cw routine create|list|delete|fire|events — API/GitHub-style triggers.", {
1925
- path: ["routine"],
1926
- jsonMode: "default",
1927
- hiddenFromHelp: true,
1928
- handler: (args) => {
1929
- const [subcommand, idOrKind, payloadPath] = args.positionals;
1930
- switch (subcommand) {
1931
- case "create":
1932
- return { json: (0, registry_cli_1.routineCreateCli)(args.options) };
1933
- case "list":
1934
- return { json: (0, registry_cli_1.routineListCli)(args.options) };
1935
- case "delete":
1936
- return { json: (0, registry_cli_1.routineDeleteCli)((0, io_1.required)(idOrKind, "trigger id"), args.options) };
1937
- case "fire": {
1938
- const kind = (0, io_1.required)(idOrKind, "trigger kind");
1939
- let payload;
1940
- try {
1941
- payload = payloadPath ? JSON.parse(node_fs_1.default.readFileSync(payloadPath, "utf8")) : args.options;
1942
- }
1943
- catch (e) {
1944
- throw new Error(`Failed to parse payload${payloadPath ? ` file "${payloadPath}"` : ""}: ${String((e && e.message) || e)}`);
1945
- }
1946
- return { json: (0, registry_cli_1.routineFireCli)(kind, payload, args.options) };
1947
- }
1948
- case "events":
1949
- return { json: (0, registry_cli_1.routineEventsCli)(idOrKind, args.options) };
1950
- default:
1951
- throw new Error("Usage: cw.js routine create|list|delete|fire|events");
1952
- }
1953
- },
1954
- }, "cw routine is the API/GitHub-style trigger bridge; SPEC/mcp.md declares its MCP peers per verb (cw_routine_*), each wired below.");
1955
- REGISTRY_BY_CAPABILITY.get("routine.create").mcp.handler = (args) => (0, registry_cli_1.routineCreateCli)(args);
1956
- REGISTRY_BY_CAPABILITY.get("routine.list").mcp.handler = (args) => (0, registry_cli_1.routineListCli)(args);
1957
- REGISTRY_BY_CAPABILITY.get("routine.delete").mcp.handler = (args) => (0, registry_cli_1.routineDeleteCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "trigger id"), args);
1958
- REGISTRY_BY_CAPABILITY.get("routine.fire").mcp.handler = (args) => (0, registry_cli_1.routineFireCli)((0, io_1.required)((0, io_3.optionalArg)(args.kind), "trigger kind"), args.payload, args);
1959
- REGISTRY_BY_CAPABILITY.get("routine.events").mcp.handler = (args) => (0, registry_cli_1.routineEventsCli)((0, io_3.optionalArg)(args.id), args);
1960
- // Each `routine <verb>` sub-action is its own two-token cli row. The
1961
- // catch-all read [subcommand, idOrKind, payloadPath], so after the
1962
- // dispatcher consumes the sub-verb positionals[0]=idOrKind,
1963
- // positionals[1]=payloadPath. `hiddenFromHelp` keeps `cw help routine`'s
1964
- // rows coming from the single literal COMMAND_HELP_ROWS.routine block.
1965
- attachCliBinding("routine.create", { path: ["routine", "create"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.routineCreateCli)(args.options) }) });
1966
- attachCliBinding("routine.list", { path: ["routine", "list"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.routineListCli)(args.options) }) });
1967
- attachCliBinding("routine.delete", { path: ["routine", "delete"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.routineDeleteCli)((0, io_1.required)(args.positionals[0], "trigger id"), args.options) }) });
1968
- attachCliBinding("routine.fire", {
1969
- path: ["routine", "fire"],
1970
- jsonMode: "default",
1971
- hiddenFromHelp: true,
1972
- handler: (args) => {
1973
- const kind = (0, io_1.required)(args.positionals[0], "trigger kind");
1974
- const payloadPath = args.positionals[1];
1975
- let payload;
1976
- try {
1977
- payload = payloadPath ? JSON.parse(node_fs_1.default.readFileSync(payloadPath, "utf8")) : args.options;
1978
- }
1979
- catch (e) {
1980
- throw new Error(`Failed to parse payload${payloadPath ? ` file "${payloadPath}"` : ""}: ${String((e && e.message) || e)}`);
1981
- }
1982
- return { json: (0, registry_cli_1.routineFireCli)(kind, payload, args.options) };
1983
- },
1984
- });
1985
- attachCliBinding("routine.events", { path: ["routine", "events"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, registry_cli_1.routineEventsCli)(args.positionals[0], args.options) }) });
1986
- // ---- sched (control-plane leases over the durable queue) ---------------
1987
- addCliOnlyCapability("sched", "cw sched plan|lease|release|complete|reclaim|reset|policy [show|set] — control-plane lease scheduling over the durable queue.", {
1988
- path: ["sched"],
1989
- jsonMode: "default",
1990
- hiddenFromHelp: true,
1991
- handler: (args) => {
1992
- const [subcommand, idArg] = args.positionals;
1993
- switch (subcommand) {
1994
- case "plan":
1995
- return { json: (0, scheduling_io_1.schedPlanCli)(args.options) };
1996
- case "lease":
1997
- return { json: (0, scheduling_io_1.schedLeaseCli)(args.options) };
1998
- case "release":
1999
- return { json: (0, scheduling_io_1.schedReleaseCli)(String(args.options.leaseId || idArg || ""), args.options) };
2000
- case "complete":
2001
- return { json: (0, scheduling_io_1.schedCompleteCli)(String(args.options.leaseId || idArg || ""), args.options) };
2002
- case "reclaim":
2003
- return { json: (0, scheduling_io_1.schedReclaimCli)(args.options) };
2004
- case "reset":
2005
- return { json: (0, scheduling_io_1.schedResetCli)(String(args.options.id || idArg || ""), args.options) };
2006
- case "policy": {
2007
- const action = args.positionals[1];
2008
- if (action === "set")
2009
- return { json: (0, scheduling_io_1.schedPolicySetCli)(args.options) };
2010
- return { json: (0, scheduling_io_1.schedPolicyShowCli)(args.options) };
2011
- }
2012
- default:
2013
- throw new Error("Usage: cw.js sched plan|lease|release|complete|reclaim|reset|policy [show|set] [id] [--maxConcurrent N --maxAttempts N ...]");
2014
- }
2015
- },
2016
- }, "cw sched is the durable-queue lease scheduler; SPEC/mcp.md declares its MCP peers per verb (cw_sched_*), each wired below.");
2017
- REGISTRY_BY_CAPABILITY.get("sched.plan").mcp.handler = (args) => (0, scheduling_io_1.schedPlanCli)(args);
2018
- REGISTRY_BY_CAPABILITY.get("sched.lease").mcp.handler = (args) => (0, scheduling_io_1.schedLeaseCli)(args);
2019
- REGISTRY_BY_CAPABILITY.get("sched.release").mcp.handler = (args) => (0, scheduling_io_1.schedReleaseCli)(String(args.leaseId || ""), args);
2020
- REGISTRY_BY_CAPABILITY.get("sched.complete").mcp.handler = (args) => (0, scheduling_io_1.schedCompleteCli)(String(args.leaseId || ""), args);
2021
- REGISTRY_BY_CAPABILITY.get("sched.reclaim").mcp.handler = (args) => (0, scheduling_io_1.schedReclaimCli)(args);
2022
- REGISTRY_BY_CAPABILITY.get("sched.reset").mcp.handler = (args) => (0, scheduling_io_1.schedResetCli)(String(args.id || ""), args);
2023
- REGISTRY_BY_CAPABILITY.get("sched.policy.show").mcp.handler = (args) => (0, scheduling_io_1.schedPolicyShowCli)(args);
2024
- REGISTRY_BY_CAPABILITY.get("sched.policy.set").mcp.handler = (args) => (0, scheduling_io_1.schedPolicySetCli)(args);
2025
- // Each `sched <verb>` sub-action is its own two-token cli row. The
2026
- // catch-all read [subcommand, idArg]; after the dispatcher consumes the
2027
- // sub-verb, positionals[0]=idArg (release/complete read --leaseId or that
2028
- // positional; reset reads --id or that positional). `sched.policy.show`/
2029
- // `.set` share the ["sched","policy"] path with the [show|set] action read
2030
- // from the first positional (like blackboard.message.post/list).
2031
- // `hiddenFromHelp` keeps `cw help sched`'s rows coming from the single
2032
- // literal COMMAND_HELP_ROWS.sched block.
2033
- attachCliBinding("sched.plan", { path: ["sched", "plan"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedPlanCli)(args.options) }) });
2034
- attachCliBinding("sched.lease", { path: ["sched", "lease"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedLeaseCli)(args.options) }) });
2035
- attachCliBinding("sched.release", { path: ["sched", "release"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedReleaseCli)(String(args.options.leaseId || args.positionals[0] || ""), args.options) }) });
2036
- attachCliBinding("sched.complete", { path: ["sched", "complete"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedCompleteCli)(String(args.options.leaseId || args.positionals[0] || ""), args.options) }) });
2037
- attachCliBinding("sched.reclaim", { path: ["sched", "reclaim"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedReclaimCli)(args.options) }) });
2038
- attachCliBinding("sched.reset", { path: ["sched", "reset"], jsonMode: "default", hiddenFromHelp: true, handler: (args) => ({ json: (0, scheduling_io_1.schedResetCli)(String(args.options.id || args.positionals[0] || ""), args.options) }) });
2039
- function schedPolicyHandler(args) {
2040
- const action = args.positionals[0];
2041
- if (action === "set")
2042
- return { json: (0, scheduling_io_1.schedPolicySetCli)(args.options) };
2043
- return { json: (0, scheduling_io_1.schedPolicyShowCli)(args.options) };
2044
- }
2045
- attachCliBinding("sched.policy.show", { path: ["sched", "policy"], helpPath: ["sched", "policy"], jsonMode: "default", hiddenFromHelp: true, handler: schedPolicyHandler });
2046
- attachCliBinding("sched.policy.set", { path: ["sched", "policy"], helpPath: ["sched", "policy"], jsonMode: "default", hiddenFromHelp: true, handler: schedPolicyHandler });
2047
- // ---- registry (refresh|show) --------------------------------------------
2048
- addCliOnlyCapability("registry", "cw registry refresh|show [--scope repo|home] [--json] — the derived run registry index.", {
2049
- path: ["registry"],
2050
- jsonMode: "flag",
2051
- hiddenFromHelp: true,
2052
- handler: (args) => {
2053
- const subcommand = firstPositionalArg(args);
2054
- let report;
2055
- if (subcommand === "refresh")
2056
- report = (0, registry_cli_1.registryRefreshCli)(args.options);
2057
- else if (subcommand === "show")
2058
- report = (0, registry_cli_1.registryShowCli)(args.options);
2059
- else
2060
- throw new Error("Usage: cw.js registry refresh|show [--scope repo|home] [--json]");
2061
- return { json: report, text: (0, run_registry_io_1.formatRegistryReport)(report) };
2062
- },
2063
- }, "cw registry is the derived run-registry index; SPEC/mcp.md declares its MCP peers (cw_registry_refresh|show), each wired below.");
2064
- REGISTRY_BY_CAPABILITY.get("registry.refresh").mcp.handler = (args) => (0, registry_cli_1.registryRefreshCli)(args);
2065
- REGISTRY_BY_CAPABILITY.get("registry.show").mcp.handler = (args) => (0, registry_cli_1.registryShowCli)(args);
2066
- // `registry.refresh`/`registry.show` each carry their own two-token
2067
- // cli.path (found before the ["registry"] catch-all). `hiddenFromHelp`
2068
- // keeps `cw help registry`'s rows coming from the single literal
2069
- // COMMAND_HELP_ROWS.registry block. Both are read/derive verbs, so they
2070
- // stay in the payload-identity probe (classified deferred until a
2071
- // bootstrap fixture seeds a registry index).
2072
- attachCliBinding("registry.refresh", {
2073
- path: ["registry", "refresh"],
2074
- jsonMode: "flag",
2075
- hiddenFromHelp: true,
2076
- handler: (args) => {
2077
- const report = (0, registry_cli_1.registryRefreshCli)(args.options);
2078
- return (0, io_2.wantsJson)(args.options) ? { json: report } : { json: report, text: (0, run_registry_io_1.formatRegistryReport)(report) };
2079
- },
2080
- });
2081
- attachCliBinding("registry.show", {
2082
- path: ["registry", "show"],
2083
- jsonMode: "flag",
2084
- hiddenFromHelp: true,
2085
- handler: (args) => {
2086
- const report = (0, registry_cli_1.registryShowCli)(args.options);
2087
- return (0, io_2.wantsJson)(args.options) ? { json: report } : { json: report, text: (0, run_registry_io_1.formatRegistryReport)(report) };
2088
- },
2089
- });
2090
- // ---- queue (add|list|drain|show) ----------------------------------------
2091
- addCliOnlyCapability("queue", "cw queue add|list|drain|show [queue-id] [--repo PATH] [--priority N] — the durable run queue.", {
2092
- path: ["queue"],
2093
- jsonMode: "flag",
2094
- hiddenFromHelp: true,
2095
- handler: (args) => {
2096
- const [subcommand, id] = args.positionals;
2097
- switch (subcommand) {
2098
- case "add":
2099
- return { json: (0, registry_cli_1.queueAddCli)(args.options) };
2100
- case "list": {
2101
- const result = (0, registry_cli_1.queueListCli)(args.options);
2102
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, run_registry_io_1.formatQueueList)(result) };
2103
- }
2104
- case "drain":
2105
- return { json: (0, registry_cli_1.queueDrainCli)(args.options) };
2106
- case "show":
2107
- return { json: (0, registry_cli_1.queueShowCli)((0, io_1.required)(id, "queue id"), args.options) };
2108
- default:
2109
- throw new Error("Usage: cw.js queue add|list|drain|show [queue-id] [--repo PATH] [--priority N]");
2110
- }
2111
- },
2112
- }, "cw queue is the durable run queue; SPEC/mcp.md declares its MCP peers (cw_queue_add|list|drain|show), each wired below.");
2113
- REGISTRY_BY_CAPABILITY.get("queue.add").mcp.handler = (args) => (0, registry_cli_1.queueAddCli)(args);
2114
- REGISTRY_BY_CAPABILITY.get("queue.list").mcp.handler = (args) => (0, registry_cli_1.queueListCli)(args);
2115
- REGISTRY_BY_CAPABILITY.get("queue.drain").mcp.handler = (args) => (0, registry_cli_1.queueDrainCli)(args);
2116
- REGISTRY_BY_CAPABILITY.get("queue.show").mcp.handler = (args) => (0, registry_cli_1.queueShowCli)((0, io_1.required)((0, io_3.optionalArg)(args.id), "queue id"), args);
2117
- // `queue add|list|drain|show` each carry their own two-token cli.path
2118
- // (found before the ["queue"] catch-all). `hiddenFromHelp` keeps `cw help
2119
- // queue`'s rows coming from the single literal COMMAND_HELP_ROWS.queue
2120
- // block. `queue.list` is jsonMode "flag" (human table by default); the
2121
- // others are always-JSON "default", matching the old build's registry.
2122
- attachCliBinding("queue.add", {
2123
- path: ["queue", "add"],
2124
- jsonMode: "default",
2125
- hiddenFromHelp: true,
2126
- handler: (args) => ({ json: (0, registry_cli_1.queueAddCli)(args.options) }),
2127
- });
2128
- attachCliBinding("queue.list", {
2129
- path: ["queue", "list"],
2130
- jsonMode: "flag",
2131
- hiddenFromHelp: true,
2132
- handler: (args) => {
2133
- const result = (0, registry_cli_1.queueListCli)(args.options);
2134
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, run_registry_io_1.formatQueueList)(result) };
2135
- },
2136
- });
2137
- attachCliBinding("queue.drain", {
2138
- path: ["queue", "drain"],
2139
- jsonMode: "default",
2140
- hiddenFromHelp: true,
2141
- handler: (args) => ({ json: (0, registry_cli_1.queueDrainCli)(args.options) }),
2142
- });
2143
- attachCliBinding("queue.show", {
2144
- path: ["queue", "show"],
2145
- jsonMode: "default",
2146
- hiddenFromHelp: true,
2147
- handler: (args) => ({ json: (0, registry_cli_1.queueShowCli)((0, io_1.required)(args.positionals[0], "queue id"), args.options) }),
2148
- });
2149
- // ---- gc (plan|run|verify) ------------------------------------------------
2150
- addCliOnlyCapability("gc", "cw gc plan|run|verify [run-id] [--reclaimAfterArchiveDays N] [--keep-scratch] [--keep-snapshots] [--limit N] [--json] — run retention & provable reclamation.", {
2151
- path: ["gc"],
2152
- jsonMode: "flag",
2153
- hiddenFromHelp: true,
2154
- handler: (args) => {
2155
- const [subcommand, id] = args.positionals;
2156
- switch (subcommand) {
2157
- case "plan": {
2158
- const result = (0, registry_cli_1.gcPlanCli)(id, args.options);
2159
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatGcPlan)(result) };
2160
- }
2161
- case "run": {
2162
- const result = (0, registry_cli_1.gcRunCli)(id, args.options);
2163
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatGcRun)(result) };
2164
- }
2165
- case "verify": {
2166
- const result = (0, registry_cli_1.gcVerifyCli)((0, io_1.required)(id, "run id"), args.options);
2167
- const text = (0, reclamation_io_1.formatGcVerify)(result);
2168
- return { json: result, text, exitCode: result.reclaimed && !result.verified ? 1 : undefined };
2169
- }
2170
- default:
2171
- throw new Error("Usage: cw.js gc plan|run|verify [run-id] [--reclaimAfterArchiveDays N] [--keep-scratch] [--keep-snapshots] [--limit N] [--json]");
2172
- }
2173
- },
2174
- }, "cw gc is run retention & provable reclamation; SPEC/mcp.md declares its MCP peers (cw_gc_plan|run|verify), each wired below.");
2175
- REGISTRY_BY_CAPABILITY.get("gc.plan").mcp.handler = (args) => (0, registry_cli_1.gcPlanCli)((0, io_3.optionalArg)(args.runId), args);
2176
- REGISTRY_BY_CAPABILITY.get("gc.run").mcp.handler = (args) => (0, registry_cli_1.gcRunCli)((0, io_3.optionalArg)(args.runId), args);
2177
- REGISTRY_BY_CAPABILITY.get("gc.verify").mcp.handler = (args) => (0, registry_cli_1.gcVerifyCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2178
- // PARITY: `gc.run` frees disk and appends a tombstone; both surfaces run
2179
- // the identical transaction but the payload reports now-derived
2180
- // bytesFreed/tombstone, so it is a documented opt-out, not drift.
2181
- REGISTRY_BY_CAPABILITY.get("gc.run").payloadIdentical = false;
2182
- REGISTRY_BY_CAPABILITY.get("gc.run").reason =
2183
- "Mutating: frees disk and appends a tombstone; both surfaces perform the identical transaction but the payload reports now-derived bytesFreed/tombstone.";
2184
- // PARITY: `gc.plan`/`gc.verify` now ALSO carry their own two-token
2185
- // cli.path ["gc","plan"]/["gc","verify"], same as the old build's
2186
- // registry rows and the same reversed-candidate-order pattern used for
2187
- // run.drive/run.search above: findCapabilityByCliPath tries the 2-token
2188
- // candidate before the 1-token ["gc"] catch-all row, so these rows — not
2189
- // the "gc" capability's combined switch — now serve `cw gc plan`/`cw gc
2190
- // verify`. Same functions, same output; only which row answers the
2191
- // dispatch changes, so both become real both-surface, dual-bound
2192
- // capabilities for the payload-identity probe. `gc.run` stays reachable
2193
- // only via the ["gc"] catch-all (it is a documented payload-probe
2194
- // opt-out above, so it does not need its own dual-bound row).
2195
- attachCliBinding("gc.plan", {
2196
- path: ["gc", "plan"],
2197
- jsonMode: "flag",
2198
- handler: (args) => {
2199
- const result = (0, registry_cli_1.gcPlanCli)(args.positionals[0], args.options);
2200
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatGcPlan)(result) };
2201
- },
2202
- });
2203
- attachCliBinding("gc.verify", {
2204
- path: ["gc", "verify"],
2205
- jsonMode: "flag",
2206
- handler: (args) => {
2207
- const result = (0, registry_cli_1.gcVerifyCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
2208
- const text = (0, reclamation_io_1.formatGcVerify)(result);
2209
- return { json: result, text, exitCode: result.reclaimed && !result.verified ? 1 : undefined };
2210
- },
2211
- });
2212
- // `gc.run` also carries its own two-token cli.path ["gc","run"], same
2213
- // reversed-candidate-order pattern as gc.plan/gc.verify. It stays a
2214
- // documented payload-probe opt-out (mutating reclamation), so this row
2215
- // only satisfies the both-surface "cli + mcp" pairing — it does not join
2216
- // the payload-identity probe. `hiddenFromHelp` keeps `cw help gc`'s row
2217
- // coming from the single literal COMMAND_HELP_ROWS.gc entry.
2218
- attachCliBinding("gc.run", {
2219
- path: ["gc", "run"],
2220
- jsonMode: "flag",
2221
- hiddenFromHelp: true,
2222
- handler: (args) => {
2223
- const result = (0, registry_cli_1.gcRunCli)(args.positionals[0], args.options);
2224
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatGcRun)(result) };
2225
- },
2226
- });
2227
- // ---- orphans (list|gc) ---------------------------------------------------
2228
- addCliOnlyCapability("orphans", "cw orphans list|gc — reclaim run directories a killed process never registered (no state.json).", {
2229
- path: ["orphans"],
2230
- jsonMode: "flag",
2231
- hiddenFromHelp: true,
2232
- handler: (args) => {
2233
- const subcommand = firstPositionalArg(args);
2234
- switch (subcommand) {
2235
- case "list": {
2236
- const result = (0, registry_cli_1.orphansListCli)(args.options);
2237
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatOrphanRunsList)(result) };
2238
- }
2239
- case "gc": {
2240
- const result = (0, registry_cli_1.orphansGcCli)(args.options);
2241
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatOrphanRunsGc)(result) };
2242
- }
2243
- default:
2244
- throw new Error("Usage: cw.js orphans list [--scope repo|home] [--json] | orphans gc [--scope repo|home] [--min-age-minutes N] [--all] [--json] (scope defaults to home: every registered repo)");
2245
- }
2246
- },
2247
- }, "cw orphans reclaims killed-process run dirs with no state.json; SPEC/mcp.md declares its MCP peers (cw_orphans_list|gc), each wired below.");
2248
- REGISTRY_BY_CAPABILITY.get("orphans.list").mcp.handler = (args) => (0, registry_cli_1.orphansListCli)(args);
2249
- REGISTRY_BY_CAPABILITY.get("orphans.gc").mcp.handler = (args) => (0, registry_cli_1.orphansGcCli)(args);
2250
- // `orphans.list`/`orphans.gc` each carry their own two-token cli.path
2251
- // (found before the ["orphans"] catch-all per the reversed-candidate
2252
- // order), so both are real both-surface dual-bound rows. `hiddenFromHelp`
2253
- // keeps `cw help orphans`'s rows coming from the single literal
2254
- // COMMAND_HELP_ROWS.orphans block. `orphans.gc` is a documented
2255
- // payload-probe opt-out (mutating sweep, now-derived freedBytes/removed),
2256
- // same as gc.run/clones.gc.
2257
- attachCliBinding("orphans.list", {
2258
- path: ["orphans", "list"],
2259
- jsonMode: "flag",
2260
- hiddenFromHelp: true,
2261
- handler: (args) => {
2262
- const result = (0, registry_cli_1.orphansListCli)(args.options);
2263
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatOrphanRunsList)(result) };
2264
- },
2265
- });
2266
- attachCliBinding("orphans.gc", {
2267
- path: ["orphans", "gc"],
2268
- jsonMode: "flag",
2269
- hiddenFromHelp: true,
2270
- handler: (args) => {
2271
- const result = (0, registry_cli_1.orphansGcCli)(args.options);
2272
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatOrphanRunsGc)(result) };
2273
- },
2274
- });
2275
- REGISTRY_BY_CAPABILITY.get("orphans.gc").payloadIdentical = false;
2276
- REGISTRY_BY_CAPABILITY.get("orphans.gc").reason =
2277
- "Mutating: removes orphan run directories and reports now-derived freedBytes/removed; both surfaces perform the identical sweep.";
2278
- // ---- clones (list|gc) ------------------------------------------------------
2279
- addCliOnlyCapability("clones", "cw clones list|gc [--older-than-days N] [--all] — the cached remote-source checkout cache.", {
2280
- path: ["clones"],
2281
- jsonMode: "flag",
2282
- hiddenFromHelp: true,
2283
- handler: (args) => {
2284
- const subcommand = firstPositionalArg(args);
2285
- switch (subcommand) {
2286
- case "list": {
2287
- const result = (0, registry_cli_1.clonesListCli)();
2288
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatClonesList)(result) };
2289
- }
2290
- case "gc": {
2291
- const result = (0, registry_cli_1.clonesGcCli)(args.options);
2292
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatClonesGc)(result) };
2293
- }
2294
- default:
2295
- throw new Error("Usage: cw.js clones list [--json] | clones gc [--older-than-days N] [--all] [--json]");
2296
- }
2297
- },
2298
- }, "cw clones is the cached remote-source checkout cache; SPEC/mcp.md declares its MCP peers (cw_clones_list|gc), each wired below.");
2299
- REGISTRY_BY_CAPABILITY.get("clones.list").mcp.handler = () => (0, registry_cli_1.clonesListCli)();
2300
- REGISTRY_BY_CAPABILITY.get("clones.gc").mcp.handler = (args) => (0, registry_cli_1.clonesGcCli)(args);
2301
- // `clones.list`/`clones.gc` each carry their own two-token cli.path (found
2302
- // before the ["clones"] catch-all). `hiddenFromHelp` keeps the byte-pinned
2303
- // `cw help clones` fixture's rows coming from the single literal
2304
- // COMMAND_HELP_ROWS.clones block. `clones.gc` is a documented payload-probe
2305
- // opt-out (mutating sweep), same as gc.run/orphans.gc.
2306
- attachCliBinding("clones.list", {
2307
- path: ["clones", "list"],
2308
- jsonMode: "flag",
2309
- hiddenFromHelp: true,
2310
- handler: (args) => {
2311
- const result = (0, registry_cli_1.clonesListCli)();
2312
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatClonesList)(result) };
2313
- },
2314
- });
2315
- attachCliBinding("clones.gc", {
2316
- path: ["clones", "gc"],
2317
- jsonMode: "flag",
2318
- hiddenFromHelp: true,
2319
- handler: (args) => {
2320
- const result = (0, registry_cli_1.clonesGcCli)(args.options);
2321
- return (0, io_2.wantsJson)(args.options) ? { json: result } : { json: result, text: (0, reclamation_io_1.formatClonesGc)(result) };
2322
- },
2323
- });
2324
- REGISTRY_BY_CAPABILITY.get("clones.gc").payloadIdentical = false;
2325
- REGISTRY_BY_CAPABILITY.get("clones.gc").reason =
2326
- "Mutating: removes cache directories and reports now-derived freedBytes/removed; both surfaces perform the identical reclamation.";
2327
- // ---- run search|list|show|resume|archive|rerun (2-token rows, found
2328
- // BEFORE the 1-token run.drive.step row per dispatchTable's reversed
2329
- // candidate order — see that row's own comment for why the run-registry
2330
- // keyword guard set still lists these words) --------------------------
2331
- attachCliBinding("run.search", {
2332
- path: ["run", "search"],
2333
- jsonMode: "flag",
2334
- handler: (args) => {
2335
- const result = (0, registry_cli_1.runSearchCli)(args.options);
2336
- return { json: result, text: (0, run_registry_io_1.formatRunSearch)(result) };
2337
- },
2338
- });
2339
- REGISTRY_BY_CAPABILITY.get("run.search").mcp.handler = (args) => (0, registry_cli_1.runSearchCli)(args);
2340
- attachCliBinding("run.list", {
2341
- path: ["run", "list"],
2342
- jsonMode: "flag",
2343
- handler: (args) => {
2344
- const result = (0, registry_cli_1.runListCli)(args.options);
2345
- return { json: result, text: (0, run_registry_io_1.formatRunSearch)(result) };
2346
- },
2347
- });
2348
- REGISTRY_BY_CAPABILITY.get("run.list").mcp.handler = (args) => (0, registry_cli_1.runListCli)(args);
2349
- attachCliBinding("run.show", {
2350
- path: ["run", "show"],
2351
- jsonMode: "flag",
2352
- handler: (args) => {
2353
- const runId = (0, io_1.required)(args.positionals[0], "run id");
2354
- const result = (0, registry_cli_1.runShowCli)(runId, args.options);
2355
- return { json: result, text: (0, run_registry_io_1.formatRunShow)(result) };
2356
- },
2357
- });
2358
- REGISTRY_BY_CAPABILITY.get("run.show").mcp.handler = (args) => (0, registry_cli_1.runShowCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2359
- attachCliBinding("run.resume", {
2360
- path: ["run", "resume"],
2361
- jsonMode: "flag",
2362
- handler: (args) => {
2363
- const runId = (0, io_1.required)(args.positionals[0], "run id");
2364
- const result = (0, registry_cli_1.runResumeCli)(runId, args.options);
2365
- return { json: result, text: (0, run_registry_io_1.formatResume)(result) };
2366
- },
2367
- });
2368
- REGISTRY_BY_CAPABILITY.get("run.resume").mcp.handler = (args) => (0, registry_cli_1.runResumeCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2369
- attachCliBinding("run.archive", {
2370
- path: ["run", "archive"],
2371
- jsonMode: "default",
2372
- handler: (args) => ({ json: (0, registry_cli_1.runArchiveCli)((0, io_3.optionalArg)(args.positionals[0]), args.options) }),
2373
- });
2374
- REGISTRY_BY_CAPABILITY.get("run.archive").mcp.handler = (args) => (0, registry_cli_1.runArchiveCli)((0, io_3.optionalArg)(args.runId), args);
2375
- attachCliBinding("run.rerun", {
2376
- path: ["run", "rerun"],
2377
- jsonMode: "default",
2378
- handler: (args) => ({ json: (0, registry_cli_1.runRerunCli)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
2379
- });
2380
- REGISTRY_BY_CAPABILITY.get("run.rerun").mcp.handler = (args) => (0, registry_cli_1.runRerunCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2381
- // ---- history ---------------------------------------------------------
2382
- attachCliBinding("history", {
2383
- path: ["history"],
2384
- jsonMode: "flag",
2385
- handler: (args) => {
2386
- const result = (0, registry_cli_1.historyCli)(args.options);
2387
- return { json: result, text: (0, run_registry_io_1.formatHistory)(result) };
2388
- },
2389
- });
2390
- REGISTRY_BY_CAPABILITY.get("history").mcp.handler = (args) => (0, registry_cli_1.historyCli)(args);
2391
- // ---------------------------------------------------------------------
2392
- // MILESTONE 11 (reporting, observability, doctor/fix, workbench, run
2393
- // export/bundle) CLI bindings: report, status (real run id), graph,
2394
- // operator.status|report|graph. Handler bodies live in shell/report-
2395
- // view-cli.ts (impure — they load run state and, for `report`/`operator
2396
- // report`, re-write report.md); this table only wires argv shape ->
2397
- // handler call, per cli/dispatch.ts's generic executor contract.
2398
- // ---------------------------------------------------------------------
2399
- const report_view_cli_1 = require("../shell/report-view-cli");
2400
- const operator_ux_text_1 = require("../shell/operator-ux-text");
2401
- attachCliBinding("report", {
2402
- path: ["report"],
2403
- jsonMode: "flag",
2404
- handler: (args) => {
2405
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2406
- const result = (0, report_view_cli_1.reportWriteCli)(runId, args.options);
2407
- if (args.options.show || args.options.summary) {
2408
- const stateExplosion = (0, state_explosion_text_1.formatStateExplosionReport)((0, state_explosion_cli_1.summaryShowCli)(runId, args.options));
2409
- return { json: result, text: `${(0, report_view_cli_1.operatorReportText)(runId, args.options)}\n\n${stateExplosion}\n` };
2410
- }
2411
- return { json: result, text: `${result.path}\n` };
2412
- },
2413
- });
2414
- REGISTRY_BY_CAPABILITY.get("report").mcp.handler = (args) => (0, report_view_cli_1.reportWriteCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2415
- // `status` already carries a milestone-2 CLI binding (`attachCliBinding("status", ...)`
2416
- // above); replace its handler here with the real run-id-aware body while
2417
- // keeping the same row/path (no reshape needed — see byte-compat item 5).
2418
- REGISTRY_BY_CAPABILITY.get("status").cli = {
2419
- path: ["status"],
2420
- jsonMode: "flag",
2421
- handler: (args) => {
2422
- const runId = (0, io_3.optionalArg)(args.positionals[0]);
2423
- if (!runId)
2424
- return { json: (0, report_view_cli_1.statusCli)(undefined, args.options), text: `No run selected\n\nNext Action\n${adviseNoRunLines()}` };
2425
- if (args.options.summary || args.options.brief) {
2426
- return { json: (0, report_view_cli_1.statusCli)(runId, args.options), text: `${(0, report_view_cli_1.statusSummaryText)(runId, args.options)}\n` };
2427
- }
2428
- return { json: (0, report_view_cli_1.statusCli)(runId, args.options), text: `${(0, report_view_cli_1.statusFullText)(runId, args.options)}\n` };
2429
- },
2430
- };
2431
- REGISTRY_BY_CAPABILITY.get("status").mcp.handler = (args) => (0, report_view_cli_1.statusCli)((0, io_3.optionalArg)(args.runId), args);
2432
- function adviseNoRunLines() {
2433
- return " node scripts/cw.js plan <workflow-id> --repo <path>\n reason: No run id is available yet; create a workflow run before dispatching or recording evidence.\n";
2434
- }
2435
- attachCliBinding("graph", {
2436
- path: ["graph"],
2437
- jsonMode: "flag",
2438
- handler: (args) => {
2439
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2440
- return { json: (0, report_view_cli_1.graphCli)(runId, args.options), text: `${(0, report_view_cli_1.graphText)(runId, args.options)}\n` };
2441
- },
2442
- });
2443
- REGISTRY_BY_CAPABILITY.get("graph").mcp.handler = (args) => (0, report_view_cli_1.graphCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2444
- attachCliBinding("operator.status", {
2445
- path: ["operator", "status"],
2446
- jsonMode: "flag",
2447
- handler: (args) => {
2448
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2449
- if (args.options.summary || args.options.brief) {
2450
- return { json: (0, report_view_cli_1.operatorStatusCli)(runId, args.options), text: `${(0, report_view_cli_1.statusSummaryText)(runId, args.options)}\n` };
2451
- }
2452
- return { json: (0, report_view_cli_1.operatorStatusCli)(runId, args.options), text: `${(0, report_view_cli_1.statusFullText)(runId, args.options)}\n` };
2453
- },
2454
- });
2455
- REGISTRY_BY_CAPABILITY.get("operator.status").mcp.handler = (args) => (0, report_view_cli_1.operatorStatusCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2456
- attachCliBinding("operator.report", {
2457
- path: ["operator", "report"],
2458
- jsonMode: "flag",
2459
- handler: (args) => {
2460
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2461
- return { json: (0, report_view_cli_1.operatorReportCli)(runId, args.options), text: `${(0, report_view_cli_1.operatorReportText)(runId, args.options)}\n` };
2462
- },
2463
- });
2464
- REGISTRY_BY_CAPABILITY.get("operator.report").mcp.handler = (args) => (0, report_view_cli_1.operatorReportCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2465
- // ---- metrics.show / metrics.summary -----------------------------------
2466
- const metrics_cli_1 = require("../shell/metrics-cli");
2467
- const observability_1 = require("../shell/observability");
2468
- attachCliBinding("metrics.show", {
2469
- path: ["metrics", "show"],
2470
- jsonMode: "flag",
2471
- handler: (args) => {
2472
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2473
- const report = (0, metrics_cli_1.metricsShowCli)(runId, args.options);
2474
- return { json: report, text: `${(0, observability_1.formatMetricsReport)(report)}\n` };
2475
- },
2476
- });
2477
- REGISTRY_BY_CAPABILITY.get("metrics.show").mcp.handler = (args) => (0, metrics_cli_1.metricsShowCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2478
- attachCliBinding("metrics.summary", {
2479
- path: ["metrics", "summary"],
2480
- jsonMode: "flag",
2481
- handler: (args) => {
2482
- const report = (0, metrics_cli_1.metricsSummaryCli)(args.options);
2483
- return { json: report, text: `${(0, observability_1.formatMetricsSummary)(report)}\n` };
2484
- },
2485
- });
2486
- REGISTRY_BY_CAPABILITY.get("metrics.summary").mcp.handler = (args) => (0, metrics_cli_1.metricsSummaryCli)(args);
2487
- // ---- worker.summary (the workbench worker panel + `cw worker summary`) ----
2488
- const worker_isolation_1 = require("../shell/worker-isolation");
2489
- const workerPath = __importStar(require("node:path"));
2490
- function workerSummaryCli(args) {
2491
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id");
2492
- const run = (0, run_store_1.loadRunFromCwd)(runId, invocationCwdFor(args));
2493
- return (0, worker_isolation_1.summarizeWorkers)(run);
2494
- }
2495
- function workerSummaryText(args) {
2496
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id");
2497
- const run = (0, run_store_1.loadRunFromCwd)(runId, invocationCwdFor(args));
2498
- return (0, worker_isolation_1.formatWorkerSummaryText)(run);
2499
- }
2500
- function invocationCwdFor(args) {
2501
- return typeof args.cwd === "string" && args.cwd.trim() ? workerPath.resolve(args.cwd) : process.cwd();
2502
- }
2503
- // jsonMode "flag": human `Workers` panel by default, canonical JSON under
2504
- // --json (old build's worker.summary was flag, cli/handlers/worker.ts).
2505
- attachCliBinding("worker.summary", {
2506
- path: ["worker", "summary"],
2507
- jsonMode: "flag",
2508
- handler: (args) => ({
2509
- json: workerSummaryCli({ ...args.options, runId: args.positionals[0] }),
2510
- text: `${workerSummaryText({ ...args.options, runId: args.positionals[0] })}\n`,
2511
- }),
2512
- });
2513
- REGISTRY_BY_CAPABILITY.get("worker.summary").mcp.handler = (args) => workerSummaryCli(args);
2514
- // ---- worker list|show|manifest|output|fail|validate (CLI + MCP) ----------
2515
- // Each worker lifecycle verb over a run. The old build routed all of these
2516
- // via src/cli/handlers/worker.ts; v2 shipped only worker.summary bound, so the
2517
- // rest fell through to the worker.usage error. positionals: [runId, workerId,
2518
- // resultFile].
2519
- const worker_cli_1 = require("../shell/worker-cli");
2520
- attachCliBinding("worker.list", {
2521
- path: ["worker", "list"],
2522
- jsonMode: "default",
2523
- handler: (args) => ({ json: (0, worker_cli_1.workerListCli)({ ...args.options, runId: args.positionals[0] }) }),
2524
- });
2525
- REGISTRY_BY_CAPABILITY.get("worker.list").mcp.handler = (args) => (0, worker_cli_1.workerListCli)(args);
2526
- attachCliBinding("worker.show", {
2527
- path: ["worker", "show"],
2528
- jsonMode: "default",
2529
- handler: (args) => ({ json: (0, worker_cli_1.workerShowCli)({ ...args.options, runId: args.positionals[0], workerId: args.positionals[1] }) }),
2530
- });
2531
- REGISTRY_BY_CAPABILITY.get("worker.show").mcp.handler = (args) => (0, worker_cli_1.workerShowCli)(args);
2532
- attachCliBinding("worker.manifest", {
2533
- path: ["worker", "manifest"],
2534
- jsonMode: "default",
2535
- handler: (args) => ({ json: (0, worker_cli_1.workerManifestCli)({ ...args.options, runId: args.positionals[0], workerId: args.positionals[1] }) }),
2536
- });
2537
- REGISTRY_BY_CAPABILITY.get("worker.manifest").mcp.handler = (args) => (0, worker_cli_1.workerManifestCli)(args);
2538
- attachCliBinding("worker.output", {
2539
- path: ["worker", "output"],
2540
- jsonMode: "default",
2541
- handler: (args) => ({ json: (0, worker_cli_1.workerOutputCli)({ ...args.options, runId: args.positionals[0], workerId: args.positionals[1], resultPath: args.positionals[2] }) }),
2542
- });
2543
- REGISTRY_BY_CAPABILITY.get("worker.output").mcp.handler = (args) => (0, worker_cli_1.workerOutputCli)(args);
2544
- attachCliBinding("worker.fail", {
2545
- path: ["worker", "fail"],
2546
- jsonMode: "default",
2547
- handler: (args) => ({ json: (0, worker_cli_1.workerFailCli)({ ...args.options, runId: args.positionals[0], workerId: args.positionals[1], resultPath: args.positionals[2] }) }),
2548
- });
2549
- REGISTRY_BY_CAPABILITY.get("worker.fail").mcp.handler = (args) => (0, worker_cli_1.workerFailCli)(args);
2550
- attachCliBinding("worker.validate", {
2551
- path: ["worker", "validate"],
2552
- jsonMode: "default",
2553
- handler: (args) => {
2554
- const { violation, exitCode } = (0, worker_cli_1.workerValidateCli)({ ...args.options, runId: args.positionals[0], workerId: args.positionals[1], resultPath: args.positionals[2] });
2555
- return { json: violation, exitCode };
2556
- },
2557
- });
2558
- REGISTRY_BY_CAPABILITY.get("worker.validate").mcp.handler = (args) => (0, worker_cli_1.workerValidateCli)(args).violation;
2559
- // ---- feedback list|show|summary|collect|task|resolve (CLI + MCP) ---------
2560
- // The operator feedback lifecycle. MCP rows were declared but stubbed
2561
- // (notYetImplemented) and no CLI verb was bound; the old build routed all of
2562
- // these. positionals: [runId, feedbackId].
2563
- const feedback_cli_1 = require("../shell/feedback-cli");
2564
- // jsonMode "flag": human `Feedback` panel by default, canonical JSON under
2565
- // --json (old build's feedback.summary was flag).
2566
- attachCliBinding("feedback.summary", {
2567
- path: ["feedback", "summary"],
2568
- jsonMode: "flag",
2569
- handler: (args) => {
2570
- const summary = (0, feedback_cli_1.feedbackSummaryCli)({ ...args.options, runId: args.positionals[0] });
2571
- return { json: summary, text: `${(0, operator_ux_text_1.formatFeedbackSummaryText)(summary)}\n` };
2572
- },
2573
- });
2574
- REGISTRY_BY_CAPABILITY.get("feedback.summary").mcp.handler = (args) => (0, feedback_cli_1.feedbackSummaryCli)(args);
2575
- attachCliBinding("feedback.list", {
2576
- path: ["feedback", "list"],
2577
- jsonMode: "default",
2578
- handler: (args) => ({ json: (0, feedback_cli_1.feedbackListCli)({ ...args.options, runId: args.positionals[0] }) }),
2579
- });
2580
- REGISTRY_BY_CAPABILITY.get("feedback.list").mcp.handler = (args) => (0, feedback_cli_1.feedbackListCli)(args);
2581
- attachCliBinding("feedback.show", {
2582
- path: ["feedback", "show"],
2583
- jsonMode: "default",
2584
- handler: (args) => ({ json: (0, feedback_cli_1.feedbackShowCli)({ ...args.options, runId: args.positionals[0], feedbackId: args.positionals[1] }) }),
2585
- });
2586
- REGISTRY_BY_CAPABILITY.get("feedback.show").mcp.handler = (args) => (0, feedback_cli_1.feedbackShowCli)(args);
2587
- attachCliBinding("feedback.collect", {
2588
- path: ["feedback", "collect"],
2589
- jsonMode: "default",
2590
- handler: (args) => ({ json: (0, feedback_cli_1.feedbackCollectCli)({ ...args.options, runId: args.positionals[0] }) }),
2591
- });
2592
- REGISTRY_BY_CAPABILITY.get("feedback.collect").mcp.handler = (args) => (0, feedback_cli_1.feedbackCollectCli)(args);
2593
- attachCliBinding("feedback.task", {
2594
- path: ["feedback", "task"],
2595
- jsonMode: "default",
2596
- handler: (args) => ({ json: (0, feedback_cli_1.feedbackTaskCli)({ ...args.options, runId: args.positionals[0], feedbackId: args.positionals[1] }) }),
2597
- });
2598
- REGISTRY_BY_CAPABILITY.get("feedback.task").mcp.handler = (args) => (0, feedback_cli_1.feedbackTaskCli)(args);
2599
- attachCliBinding("feedback.resolve", {
2600
- path: ["feedback", "resolve"],
2601
- jsonMode: "default",
2602
- handler: (args) => ({ json: (0, feedback_cli_1.feedbackResolveCli)({ ...args.options, runId: args.positionals[0], feedbackId: args.positionals[1] }) }),
2603
- });
2604
- REGISTRY_BY_CAPABILITY.get("feedback.resolve").mcp.handler = (args) => (0, feedback_cli_1.feedbackResolveCli)(args);
2605
- // ---- workbench.view / workbench.serve ---------------------------------
2606
- const workbench_1 = require("../shell/workbench");
2607
- const workbench_text_1 = require("../shell/workbench-text");
2608
- const workbench_host_1 = require("../shell/workbench-host");
2609
- attachCliBinding("workbench.view", {
2610
- path: ["workbench", "view"],
2611
- jsonMode: "flag",
2612
- handler: (args) => {
2613
- const runId = (0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id");
2614
- const view = (0, workbench_1.buildWorkbenchRunView)(runId, args.options);
2615
- return { json: view, text: `${(0, workbench_text_1.formatWorkbenchView)(view)}\n` };
2616
- },
2617
- });
2618
- // The MCP path is CLI-facing byte-identical (buildWorkbenchRunView takes
2619
- // the same args shape either way) — required here since `.cli` and
2620
- // `.mcp` never share a handler object per byte-compat item 5.
2621
- REGISTRY_BY_CAPABILITY.get("workbench.view").mcp.handler = (args) => (0, workbench_1.buildWorkbenchRunView)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2622
- attachCliBinding("workbench.serve", {
2623
- path: ["workbench", "serve"],
2624
- jsonMode: "flag",
2625
- handler: (args) => {
2626
- const host = new workbench_host_1.WorkbenchHost(args.options);
2627
- if (args.options.once || (0, io_2.wantsJson)(args.options)) {
2628
- return { json: host.descriptor(true) };
2629
- }
2630
- // The default (no --once, no --json) actually binds and blocks — this
2631
- // returns a promise the generic dispatcher does not await today, so
2632
- // instead we run it directly here and never return (matching the old
2633
- // build's own blocking `serve` behavior). See cli/dispatch.ts's
2634
- // renderCliResult: it is synchronous, so a genuinely blocking serve
2635
- // must perform its own stdout write and keep the event loop alive
2636
- // rather than returning a CliHandlerResult at all.
2637
- void host.run();
2638
- return { json: undefined };
2639
- },
2640
- });
2641
- // `cw_workbench_serve` NEVER starts the server — the MCP path forces
2642
- // `once: true` unconditionally, per SPEC/reporting-ux.md's "one declared
2643
- // divergence": an MCP client must never be able to make the server
2644
- // process open a persistent listening socket.
2645
- REGISTRY_BY_CAPABILITY.get("workbench.serve").mcp.handler = (args) => new workbench_host_1.WorkbenchHost(args).descriptor(true);
2646
- // PARITY: both surfaces route through the single core entry
2647
- // buildWorkbenchServeDescriptor and return the IDENTICAL serve
2648
- // descriptor under `cw workbench serve --json`/`--once` and
2649
- // `cw_workbench_serve`. They diverge only in side effect, not payload:
2650
- // the CLI's default `cw workbench serve` (no --once) additionally
2651
- // STARTS the blocking localhost host, which an MCP stdio host cannot do,
2652
- // so cw_workbench_serve only ever returns the descriptor. Declared
2653
- // divergence, not drift.
2654
- REGISTRY_BY_CAPABILITY.get("workbench.serve").payloadIdentical = false;
2655
- REGISTRY_BY_CAPABILITY.get("workbench.serve").reason =
2656
- "Both surfaces route through the single core entry buildWorkbenchServeDescriptor and return the IDENTICAL serve descriptor under `cw workbench serve --json`/`--once` and `cw_workbench_serve`. They diverge only in side effect, not payload: the CLI's default `cw workbench serve` (no --once) additionally STARTS the blocking localhost host, which an MCP stdio host cannot do, so cw_workbench_serve only ever returns the descriptor. Declared divergence, not drift.";
2657
- // ---- audit.summary / audit.multi-agent / audit.policy / audit.judge ----
2658
- const audit_cli_2 = require("../shell/audit-cli");
2659
- const operator_ux_text_2 = require("../shell/operator-ux-text");
2660
- const eval_text_1 = require("../shell/eval-text");
2661
- attachCliBinding("audit.summary", {
2662
- path: ["audit", "summary"],
2663
- jsonMode: "default",
2664
- handler: (args) => ({ json: (0, audit_cli_2.auditSummaryCli)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
2665
- });
2666
- REGISTRY_BY_CAPABILITY.get("audit.summary").mcp.handler = (args) => (0, audit_cli_2.auditSummaryCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2667
- attachCliBinding("audit.multi-agent", {
2668
- path: ["audit", "multi-agent"],
2669
- jsonMode: "flag",
2670
- handler: (args) => {
2671
- const view = (0, audit_cli_2.auditMultiAgentCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
2672
- return { json: view, text: (0, operator_ux_text_2.formatMultiAgentTrustAudit)(view) };
2673
- },
2674
- });
2675
- REGISTRY_BY_CAPABILITY.get("audit.multi-agent").mcp.handler = (args) => (0, audit_cli_2.auditMultiAgentCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2676
- attachCliBinding("audit.policy", {
2677
- path: ["audit", "policy"],
2678
- jsonMode: "flag",
2679
- handler: (args) => {
2680
- const view = (0, audit_cli_2.auditPolicyCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
2681
- return { json: view, text: (0, operator_ux_text_2.formatMultiAgentTrustAudit)(view) };
2682
- },
2683
- });
2684
- REGISTRY_BY_CAPABILITY.get("audit.policy").mcp.handler = (args) => (0, audit_cli_2.auditPolicyCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2685
- attachCliBinding("audit.judge", {
2686
- path: ["audit", "judge"],
2687
- jsonMode: "flag",
2688
- handler: (args) => {
2689
- const view = (0, audit_cli_2.auditJudgeCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
2690
- return { json: view, text: (0, operator_ux_text_2.formatMultiAgentTrustAudit)(view) };
2691
- },
2692
- });
2693
- REGISTRY_BY_CAPABILITY.get("audit.judge").mcp.handler = (args) => (0, audit_cli_2.auditJudgeCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2694
- // GAP: `cw audit worker|provenance|role|blackboard|attest|decision` — the MCP
2695
- // tool rows (cw_audit_worker/provenance/role/blackboard/attest/decision) were
2696
- // declared but had no CLI path binding and their mcp.handler was still
2697
- // notYetImplemented. Wire both surfaces (port of the old cli/handlers/audit.ts
2698
- // arms). `audit worker`/`role`/`decision` read positionals[1] as the entity id.
2699
- attachCliBinding("audit.worker", {
2700
- path: ["audit", "worker"],
2701
- jsonMode: "default",
2702
- handler: (args) => ({ json: (0, audit_cli_2.auditWorkerCli)((0, io_1.required)(args.positionals[0], "run id"), (0, io_1.required)(args.positionals[1], "worker id"), args.options) }),
2703
- });
2704
- REGISTRY_BY_CAPABILITY.get("audit.worker").mcp.handler = (args) => (0, audit_cli_2.auditWorkerCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.workerId ?? args.worker), "worker id"), args);
2705
- attachCliBinding("audit.provenance", {
2706
- path: ["audit", "provenance"],
2707
- jsonMode: "default",
2708
- handler: (args) => ({ json: (0, audit_cli_2.auditProvenanceCli)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
2709
- });
2710
- REGISTRY_BY_CAPABILITY.get("audit.provenance").mcp.handler = (args) => (0, audit_cli_2.auditProvenanceCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2711
- attachCliBinding("audit.role", {
2712
- path: ["audit", "role"],
2713
- jsonMode: "flag",
2714
- handler: (args) => {
2715
- const view = (0, audit_cli_2.auditRoleCli)((0, io_1.required)(args.positionals[0], "run id"), (0, io_1.required)(args.positionals[1], "role id"), args.options);
2716
- return { json: view, text: (0, operator_ux_text_2.formatMultiAgentTrustAudit)(view) };
2717
- },
2718
- });
2719
- REGISTRY_BY_CAPABILITY.get("audit.role").mcp.handler = (args) => (0, audit_cli_2.auditRoleCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.roleId ?? args.id), "role id"), args);
2720
- attachCliBinding("audit.blackboard", {
2721
- path: ["audit", "blackboard"],
2722
- jsonMode: "flag",
2723
- handler: (args) => {
2724
- const view = (0, audit_cli_2.auditBlackboardCli)((0, io_1.required)(args.positionals[0], "run id"), args.options);
2725
- return { json: view, text: (0, operator_ux_text_2.formatMultiAgentTrustAudit)(view) };
2726
- },
2727
- });
2728
- REGISTRY_BY_CAPABILITY.get("audit.blackboard").mcp.handler = (args) => (0, audit_cli_2.auditBlackboardCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2729
- attachCliBinding("audit.attest", {
2730
- path: ["audit", "attest"],
2731
- jsonMode: "default",
2732
- handler: (args) => ({ json: (0, audit_cli_2.auditAttestCli)((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
2733
- });
2734
- REGISTRY_BY_CAPABILITY.get("audit.attest").mcp.handler = (args) => (0, audit_cli_2.auditAttestCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
2735
- attachCliBinding("audit.decision", {
2736
- path: ["audit", "decision"],
2737
- jsonMode: "default",
2738
- handler: (args) => ({ json: (0, audit_cli_2.auditDecisionCli)((0, io_1.required)(args.positionals[0], "run id"), (0, io_1.required)(args.positionals[1], "worker id"), args.options) }),
2739
- });
2740
- REGISTRY_BY_CAPABILITY.get("audit.decision").mcp.handler = (args) => (0, audit_cli_2.auditDecisionCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), (0, io_1.required)((0, io_3.optionalArg)(args.workerId), "worker id"), args);
2741
- // ---- app.list / app.show / app.validate / app.init / app.package -------
2742
- // MILESTONE 12 (workflow-apps). Handler BODIES live in
2743
- // shell/workflow-app-loader.ts (impure — they scan apps/*/app.json +
2744
- // workflows/*.workflow.js on disk and `require()` each entrypoint); this
2745
- // table only wires argv/tool-args shape -> handler call, per SPEC/
2746
- // workflow-apps.md's "Exact outputs". `app.validate` is ALWAYS JSON
2747
- // (jsonMode "default") even without --json, and its handler sets
2748
- // exitCode 1 on `valid:false` — both the "not found" id case and a
2749
- // structurally-broken manifest case fail this same way.
2750
- const workflow_app_loader_2 = require("../shell/workflow-app-loader");
2751
- const help_1 = require("./format/help");
2752
- const man_cli_1 = require("../shell/man-cli");
2753
- attachCliBinding("app.list", {
2754
- path: ["app", "list"],
2755
- jsonMode: "default",
2756
- handler: () => ({ json: (0, workflow_app_loader_2.listWorkflowApps)() }),
2757
- });
2758
- REGISTRY_BY_CAPABILITY.get("app.list").mcp.handler = () => (0, workflow_app_loader_2.listWorkflowApps)();
2759
- attachCliBinding("app.show", {
2760
- path: ["app", "show"],
2761
- jsonMode: "default",
2762
- handler: (args) => ({ json: (0, workflow_app_loader_2.showWorkflowApp)((0, io_1.required)(args.positionals[0], "workflow app id")) }),
2763
- });
2764
- REGISTRY_BY_CAPABILITY.get("app.show").mcp.handler = (args) => (0, workflow_app_loader_2.showWorkflowApp)((0, io_1.required)((0, io_3.optionalArg)(args.appId), "workflow app id"));
2765
- attachCliBinding("app.validate", {
2766
- path: ["app", "validate"],
2767
- jsonMode: "default",
2768
- handler: (args) => {
2769
- const result = (0, workflow_app_loader_2.validateWorkflowAppTarget)((0, io_1.required)(args.positionals[0], "workflow app path or id"));
2770
- return { json: result, exitCode: result.valid ? undefined : 1 };
2771
- },
2772
- });
2773
- REGISTRY_BY_CAPABILITY.get("app.validate").mcp.handler = (args) => (0, workflow_app_loader_2.validateWorkflowAppTarget)((0, io_1.required)((0, io_3.optionalArg)(args.target ?? args.appId), "workflow app path or id"));
2774
- attachCliBinding("app.init", {
2775
- path: ["app", "init"],
2776
- jsonMode: "default",
2777
- handler: (args) => ({ json: (0, workflow_app_loader_2.initWorkflowApp)((0, io_1.required)(args.positionals[0], "app id"), args.options) }),
2778
- });
2779
- REGISTRY_BY_CAPABILITY.get("app.init").mcp.handler = (args) => (0, workflow_app_loader_2.initWorkflowApp)((0, io_1.required)((0, io_3.optionalArg)(args.appId), "app id"), args);
2780
- // `cw init <id>` — the standalone scaffold verb. v2 folds `init` into
2781
- // `app.init` (the old build's legacy `.workflow.js` scaffold is gone), so
2782
- // both surfaces route through initWorkflowApp, same as `cw app init`. The
2783
- // `init` help token is folded away (declaredCliHelpTokens) — it stays in
2784
- // the frozen "More commands" index line only, matching the parity smoke's
2785
- // HELP_INDEX_ONLY_TOKENS treatment. `workflowId` is the old init arg name.
2786
- attachCliBinding("init", {
2787
- path: ["init"],
2788
- jsonMode: "default",
2789
- handler: (args) => ({ json: (0, workflow_app_loader_2.initWorkflowApp)((0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "workflow id"), args.options) }),
2790
- });
2791
- REGISTRY_BY_CAPABILITY.get("init").mcp.handler = (args) => (0, workflow_app_loader_2.initWorkflowApp)((0, io_1.required)((0, io_3.optionalArg)(args.workflowId ?? args.appId), "workflow id"), args);
2792
- attachCliBinding("app.package", {
2793
- path: ["app", "package"],
2794
- jsonMode: "default",
2795
- handler: (args) => ({ json: (0, workflow_app_loader_2.packageWorkflowApp)((0, io_1.required)(args.positionals[0], "app id"), args.options) }),
2796
- });
2797
- REGISTRY_BY_CAPABILITY.get("app.package").mcp.handler = (args) => (0, workflow_app_loader_2.packageWorkflowApp)((0, io_1.required)((0, io_3.optionalArg)(args.appId), "app id"), args);
2798
- // `cw app run <app-id>` — plan+drive+report an app in one call. 2-token
2799
- // cli.path found before the ["app"] usage catch-all; `appRunCli` reads the
2800
- // app id from `appId`, so the first positional after "run" is forwarded as
2801
- // appId (old build: appRun(runner, { ...options, appId: <positional> })).
2802
- attachCliBinding("app.run", {
2803
- path: ["app", "run"],
2804
- jsonMode: "default",
2805
- handler: (args) => ({ json: (0, app_run_cli_1.appRunCli)({ ...args.options, appId: (0, io_1.required)(args.positionals[0], "app id") }) }),
2806
- });
2807
- // A 1-token `["app"]` row that exists ONLY to own the fixed usage string
2808
- // for an unrecognized `app` subcommand (`app run` is not yet CLI-wired at
2809
- // this milestone — cw_app_run stays MCP-only — so a bogus or `run`
2810
- // subcommand both fall through to this same usage throw, matching
2811
- // SPEC/cli-surface.md's "Usage strings" table byte-for-byte). Per
2812
- // dispatchTable's reversed-candidate-order contract (cli/dispatch.ts),
2813
- // this 1-token row is only ever reached when no 2-token `app.*` row
2814
- // above matched. `hiddenFromHelp` keeps it off `cw help app`'s own line
2815
- // (see CliBinding.hiddenFromHelp's doc comment).
2816
- addCliOnlyCapability("app.usage", "cw app list|show|validate|init|package|run [app-id|path] — the workflow-app framework.", {
2817
- path: ["app"],
2818
- jsonMode: "default",
2819
- hiddenFromHelp: true,
2820
- handler: () => {
2821
- throw new Error("Usage: cw.js app list|show|validate|init|package|run [app-id|path]");
2822
- },
2823
- }, "app.usage exists only to own the fixed usage-error text for an unrecognized app subcommand; every real app.* action is its own capability row above.");
2824
- // ---------------------------------------------------------------------
2825
- // 1-token usage-fallback rows: one per multi-verb family, each existing
2826
- // ONLY to own the fixed usage string for an unrecognized subcommand,
2827
- // same pattern and reasoning as app.usage above (SPEC/cli-surface.md's
2828
- // "Usage strings" table, byte-for-byte). Per dispatchTable's reversed-
2829
- // candidate-order contract (cli/dispatch.ts), each 1-token row here is
2830
- // only ever reached when no 2-token real row for that family matched.
2831
- // `hiddenFromHelp` keeps each off its own `cw help <verb>` line.
2832
- // ---------------------------------------------------------------------
2833
- addCliOnlyCapability("sandbox.usage", "cw.js sandbox list|show|validate|choose|resolve [profile-id|profile-file]", {
2834
- path: ["sandbox"],
2835
- jsonMode: "default",
2836
- hiddenFromHelp: true,
2837
- handler: () => {
2838
- throw new Error("Usage: cw.js sandbox list|show|validate|choose|resolve [profile-id|profile-file]");
2839
- },
2840
- }, "sandbox.usage exists only to own the fixed usage-error text for an unrecognized sandbox subcommand; every real sandbox.* action is its own capability row above.");
2841
- addCliOnlyCapability("state.usage", "cw.js state check <run-id> [--state PATH] [--write]", {
2842
- path: ["state"],
2843
- jsonMode: "default",
2844
- hiddenFromHelp: true,
2845
- handler: () => {
2846
- throw new Error("Usage: cw.js state check <run-id> [--state PATH] [--write]");
2847
- },
2848
- }, "state.usage exists only to own the fixed usage-error text for an unrecognized state subcommand; every real state.* action is its own capability row above.");
2849
- addCliOnlyCapability("audit.usage", "cw.js audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]", {
2850
- path: ["audit"],
2851
- jsonMode: "default",
2852
- hiddenFromHelp: true,
2853
- handler: () => {
2854
- throw new Error("Usage: cw.js audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]");
2855
- },
2856
- }, "audit.usage exists only to own the fixed usage-error text for an unrecognized audit subcommand; every real audit.* action is its own capability row above.");
2857
- addCliOnlyCapability("blackboard.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>", {
2858
- path: ["blackboard"],
2859
- jsonMode: "default",
2860
- hiddenFromHelp: true,
2861
- handler: () => {
2862
- 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>");
2863
- },
2864
- }, "blackboard.usage exists only to own the fixed usage-error text for an unrecognized blackboard subcommand; every real blackboard.* action is its own capability row above.");
2865
- addCliOnlyCapability("candidate.usage", "cw.js candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]", {
2866
- path: ["candidate"],
2867
- jsonMode: "default",
2868
- hiddenFromHelp: true,
2869
- handler: () => {
2870
- throw new Error("Usage: cw.js candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]");
2871
- },
2872
- }, "candidate.usage exists only to own the fixed usage-error text for an unrecognized candidate subcommand; every real candidate.* action is its own capability row above.");
2873
- addCliOnlyCapability("comment.usage", "cw.js comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]", {
2874
- path: ["comment"],
2875
- jsonMode: "default",
2876
- hiddenFromHelp: true,
2877
- handler: () => {
2878
- throw new Error("Usage: cw.js comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]");
2879
- },
2880
- }, "comment.usage exists only to own the fixed usage-error text for an unrecognized comment subcommand; every real comment.* action is its own capability row above.");
2881
- addCliOnlyCapability("eval.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>", {
2882
- path: ["eval"],
2883
- jsonMode: "default",
2884
- hiddenFromHelp: true,
2885
- handler: () => {
2886
- 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>");
2887
- },
2888
- }, "eval.usage exists only to own the fixed usage-error text for an unrecognized eval subcommand; every real eval.* action is its own capability row above.");
2889
- addCliOnlyCapability("telemetry.usage", "cw.js telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]", {
2890
- path: ["telemetry"],
2891
- jsonMode: "default",
2892
- hiddenFromHelp: true,
2893
- handler: () => {
2894
- throw new Error("Usage: cw.js telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]");
2895
- },
2896
- }, "telemetry.usage exists only to own the fixed usage-error text for an unrecognized telemetry subcommand; every real telemetry.* action is its own capability row above.");
2897
- addCliOnlyCapability("demo.usage", "cw.js demo tamper|bundle [--json]", {
2898
- path: ["demo"],
2899
- jsonMode: "default",
2900
- hiddenFromHelp: true,
2901
- handler: () => {
2902
- throw new Error("Usage: cw.js demo tamper|bundle [--json]");
2903
- },
2904
- }, "demo.usage exists only to own the fixed usage-error text for an unrecognized demo subcommand; every real demo.* action is its own capability row above.");
2905
- addCliOnlyCapability("multi-agent.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]", {
2906
- path: ["multi-agent"],
2907
- jsonMode: "default",
2908
- hiddenFromHelp: true,
2909
- handler: () => {
2910
- 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]");
2911
- },
2912
- }, "multi-agent.usage exists only to own the fixed usage-error text for an unrecognized multi-agent subcommand; every real multi-agent.* action is its own capability row above.");
2913
- addCliOnlyCapability("node.usage", "cw.js node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]", {
2914
- path: ["node"],
2915
- jsonMode: "default",
2916
- hiddenFromHelp: true,
2917
- handler: () => {
2918
- throw new Error("Usage: cw.js node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]");
2919
- },
2920
- }, "node.usage exists only to own the fixed usage-error text for an unrecognized node subcommand; every real node.* action is its own capability row above.");
2921
- addCliOnlyCapability("backend.usage", "cw.js backend list|show|probe [backend-id] | cw.js backend agent config [show|set] [--agent-command ... --agent-endpoint ... --agent-model ...]", {
2922
- path: ["backend"],
2923
- jsonMode: "default",
2924
- hiddenFromHelp: true,
2925
- handler: () => {
2926
- 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 ...]");
2927
- },
2928
- }, "backend.usage exists only to own the fixed usage-error text for an unrecognized backend subcommand; every real backend.* action is its own capability row above.");
2929
- addCliOnlyCapability("contract.usage", "cw.js contract show <run-id> [contract-id]", {
2930
- path: ["contract"],
2931
- jsonMode: "default",
2932
- hiddenFromHelp: true,
2933
- handler: () => {
2934
- throw new Error("Usage: cw.js contract show <run-id> [contract-id]");
2935
- },
2936
- }, "contract.usage exists only to own the fixed usage-error text for an unrecognized contract subcommand; every real contract.* action is its own capability row above.");
2937
- addCliOnlyCapability("migration.usage", "cw.js migration list|check|prove [target] [--contract run-state|workflow-app]", {
2938
- path: ["migration"],
2939
- jsonMode: "default",
2940
- hiddenFromHelp: true,
2941
- handler: () => {
2942
- throw new Error("Usage: cw.js migration list|check|prove [target] [--contract run-state|workflow-app]");
2943
- },
2944
- }, "migration.usage exists only to own the fixed usage-error text for an unrecognized migration subcommand; every real migration.* action is its own capability row above.");
2945
- addCliOnlyCapability("feedback.usage", "cw.js feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]", {
2946
- path: ["feedback"],
2947
- jsonMode: "default",
2948
- hiddenFromHelp: true,
2949
- handler: () => {
2950
- throw new Error("Usage: cw.js feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]");
2951
- },
2952
- }, "feedback.usage exists only to own the fixed usage-error text for an unrecognized feedback subcommand; every real feedback.* action is its own capability row above.");
2953
- addCliOnlyCapability("metrics.usage", "cw.js metrics show <run-id> | metrics summary [--scope repo|home] [--pricing <path>|default] [--json]", {
2954
- path: ["metrics"],
2955
- jsonMode: "default",
2956
- hiddenFromHelp: true,
2957
- handler: () => {
2958
- throw new Error("Usage: cw.js metrics show <run-id> | metrics summary [--scope repo|home] [--pricing <path>|default] [--json]");
2959
- },
2960
- }, "metrics.usage exists only to own the fixed usage-error text for an unrecognized metrics subcommand; every real metrics.* action is its own capability row above.");
2961
- addCliOnlyCapability("operator.usage", "cw.js operator status|report <run-id> [--json]", {
2962
- path: ["operator"],
2963
- jsonMode: "default",
2964
- hiddenFromHelp: true,
2965
- handler: () => {
2966
- throw new Error("Usage: cw.js operator status|report <run-id> [--json]");
2967
- },
2968
- }, "operator.usage exists only to own the fixed usage-error text for an unrecognized operator subcommand; every real operator.* action is its own capability row above.");
2969
- addCliOnlyCapability("topology.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>", {
2970
- path: ["topology"],
2971
- jsonMode: "default",
2972
- hiddenFromHelp: true,
2973
- handler: () => {
2974
- 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>");
2975
- },
2976
- }, "topology.usage exists only to own the fixed usage-error text for an unrecognized topology subcommand; every real topology.* action is its own capability row above.");
2977
- addCliOnlyCapability("summary.usage", "cw.js summary refresh|show <run-id> [--json]", {
2978
- path: ["summary"],
2979
- jsonMode: "default",
2980
- hiddenFromHelp: true,
2981
- handler: () => {
2982
- throw new Error("Usage: cw.js summary refresh|show <run-id> [--json]");
2983
- },
2984
- }, "summary.usage exists only to own the fixed usage-error text for an unrecognized summary subcommand; every real summary.* action is its own capability row above.");
2985
- addCliOnlyCapability("workbench.usage", "cw.js workbench serve [--port N] [--once] | view <run-id> [--json]", {
2986
- path: ["workbench"],
2987
- jsonMode: "default",
2988
- hiddenFromHelp: true,
2989
- handler: () => {
2990
- throw new Error("Usage: cw.js workbench serve [--port N] [--once] | view <run-id> [--json]");
2991
- },
2992
- }, "workbench.usage exists only to own the fixed usage-error text for an unrecognized workbench subcommand; every real workbench.* action is its own capability row above.");
2993
- addCliOnlyCapability("worker.usage", "cw.js worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]", {
2994
- path: ["worker"],
2995
- jsonMode: "default",
2996
- hiddenFromHelp: true,
2997
- handler: () => {
2998
- throw new Error("Usage: cw.js worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]");
2999
- },
3000
- }, "worker.usage exists only to own the fixed usage-error text for an unrecognized worker subcommand; every real worker.* action is its own capability row above.");
3001
- addCliOnlyCapability("review.usage", "cw.js review status <run-id> [--json] | review policy <run-id> --required-approvals N --authorized-roles a,b --applies-to commit,selection", {
3002
- path: ["review"],
3003
- jsonMode: "default",
3004
- hiddenFromHelp: true,
3005
- handler: () => {
3006
- 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");
3007
- },
3008
- }, "review.usage exists only to own the fixed usage-error text for an unrecognized review subcommand; every real review.* action is its own capability row above.");
3009
- addCliOnlyCapability("coordinator.usage", "cw.js coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT", {
3010
- path: ["coordinator"],
3011
- jsonMode: "default",
3012
- hiddenFromHelp: true,
3013
- handler: () => {
3014
- throw new Error("Usage: cw.js coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT");
3015
- },
3016
- }, "coordinator.usage exists only to own the fixed usage-error text for an unrecognized coordinator subcommand; every real coordinator.* action is its own capability row above.");
3017
- // ---- man (CLI-only; raw manual-page bytes to stdout, no MCP peer) -----
3018
- //
3019
- // Writes the resolved doc file's raw bytes directly to stdout and
3020
- // returns an empty result — the generic renderCliResult (cli/dispatch.ts)
3021
- // always appends "\n" to `result.text` when it is missing one, which
3022
- // would violate "no added trailing newline" for any manual page that
3023
- // does not already end in one. A handler performing its own stdout write
3024
- // and returning `{}` is the established escape hatch (see
3025
- // workbench.serve's handler above for the same pattern/reasoning).
3026
- addCliOnlyCapability("man", "cw man <topic> — read a manual page from docs/ (raw bytes, no added newline).", {
3027
- path: ["man"],
3028
- jsonMode: "human",
3029
- // core/format/help.ts's COMMAND_HELP_ROWS.man already owns the
3030
- // human-facing "cw man" help line (byte-ported from the old build's
3031
- // orchestrator.ts help table); hiddenFromHelp avoids a duplicate row.
3032
- hiddenFromHelp: true,
3033
- handler: (args) => {
3034
- const topic = args.positionals[0];
3035
- if (!topic) {
3036
- throw new Error("Missing topic.\n Tip: cw man release-tooling for the release tooling manual.");
3037
- }
3038
- process.stdout.write((0, man_cli_1.readManPage)(topic));
3039
- return {};
3040
- },
3041
- }, "man is a CLI-only raw-file reader over docs/; the old build never gave it an MCP peer.");
3042
- // ---- info (CLI-only; mirrors app.show with a human card by default) ----
3043
- addCliOnlyCapability("info", "Show a workflow app's contract as a human card (or JSON with --json).", {
3044
- path: ["info"],
3045
- jsonMode: "flag",
3046
- handler: (args) => {
3047
- const appId = (0, io_1.required)(args.positionals[0], "workflow app id");
3048
- const data = (0, workflow_app_loader_2.showWorkflowApp)(appId);
3049
- return { json: data, text: `${(0, help_1.formatInfo)(appId, data)}\n` };
3050
- },
3051
- }, "info is a CLI-only convenience card over app.show; the old build never gave it an MCP peer.");
3052
- // ---- PARITY WIRING -------------------------------------------------------
3053
- //
3054
- // `next` had a raw `case "next"` arm in cli/dispatch.ts (a milestone 3/6
3055
- // PLACEHOLDER that always throws "not implemented in this milestone") but
3056
- // no row in this table's cli binding, so it had no cli-mcp-parity-smoke /
3057
- // cli-jsonmode-parity-smoke coverage. This row makes `next` a real,
3058
- // dual-bound capability (matching the old build's `cli: { path: ["next"],
3059
- // jsonMode: "default" }`) with the SAME placeholder body as the dispatch.ts
3060
- // arm — no new capability logic, just giving the existing placeholder a
3061
- // home in the one data table. dispatchTable() in cli/dispatch.ts tries this
3062
- // row before the switch statement is reached, so the old `case "next"` arm
3063
- // is now dead code for the CLI path (left in place, like the other
3064
- // superseded arms in that file, each with its own "dispatchTable() above
3065
- // always matches first" note).
3066
- attachCliBinding("next", {
3067
- path: ["next"],
3068
- jsonMode: "default",
3069
- handler: (args) => ({ json: (0, state_cli_1.nextCli)((0, io_1.required)((0, io_3.optionalArg)(args.positionals[0]), "run id"), args.options) }),
3070
- });
3071
- REGISTRY_BY_CAPABILITY.get("next").mcp.handler = (args) => (0, state_cli_1.nextCli)((0, io_1.required)((0, io_3.optionalArg)(args.runId), "run id"), args);
3072
- // `ledger.propose`/`.review`/`.verify`/`.apply`/`.list` are documented
3073
- // payload-probe opt-outs in the old build (each mints a fresh timestamped/
3074
- // digested entry, or reads args that arrive by --file/stdin on the CLI vs
3075
- // a plain `entry` argument over MCP, or reads an on-disk ledger directory
3076
- // the generic probe does not populate) — same reasoning applies here
3077
- // unchanged, since both surfaces still route through the same
3078
- // buildLedgerProposal/buildLedgerReview/verifyLedgerEntry/
3079
- // applyLedgerProposal/listLedgerEntries core. Ported so these rows do not
3080
- // sit unclassified in the payload-identity probe.
3081
- REGISTRY_BY_CAPABILITY.get("ledger.propose").payloadIdentical = false;
3082
- REGISTRY_BY_CAPABILITY.get("ledger.propose").reason =
3083
- "Mints a fresh entry each call: createdAt is the wall-clock instant and the id/digest are derived from it, so the output is inherently non-deterministic and a byte-identity probe does not apply. Both surfaces call the same buildLedgerProposal core; round-trip + fail-closed behavior is covered by ledger-verify-smoke.";
3084
- REGISTRY_BY_CAPABILITY.get("ledger.review").payloadIdentical = false;
3085
- REGISTRY_BY_CAPABILITY.get("ledger.review").reason =
3086
- "Mints a fresh timestamped/digested verdict each call — non-deterministic output, same reasoning as ledger.propose. Both surfaces call the same buildLedgerReview core.";
3087
- REGISTRY_BY_CAPABILITY.get("ledger.verify").payloadIdentical = false;
3088
- REGISTRY_BY_CAPABILITY.get("ledger.verify").reason =
3089
- "The entry arrives by --file/stdin on the CLI and as an `entry` argument over MCP; there is no shared arg-bag the byte-identity probe can feed both. Both surfaces call the same verifyLedgerEntry core; ledger-verify-smoke proves the fail-closed contract.";
3090
- REGISTRY_BY_CAPABILITY.get("ledger.apply").payloadIdentical = false;
3091
- REGISTRY_BY_CAPABILITY.get("ledger.apply").reason =
3092
- "The entry arrives by --file/stdin on the CLI and as an `entry` argument over MCP; there is no shared arg-bag the byte-identity probe can feed both. Both surfaces call the same applyLedgerProposal core (a fail-closed wrapper over verifyLedgerEntry); ledger-apply-smoke proves the diff only escapes a verified proposal.";
3093
- REGISTRY_BY_CAPABILITY.get("ledger.list").payloadIdentical = false;
3094
- REGISTRY_BY_CAPABILITY.get("ledger.list").reason =
3095
- "Output depends on the on-disk contents of the named ledger directory/directories, which the generic payload probe does not populate. Both surfaces call the same listLedgerEntries/unionLedgerEntries core; ledger-verify-smoke covers the fail-closed inbox and the multi-mirror union.";
3096
- // ---------------------------------------------------------------------------
3097
- // CLI <-> MCP parity planning + report. Ported from the old flat build's
3098
- // src/capability-registry.ts (its single source of parity data) onto this
3099
- // table's row shape. Same rule as that file's header: a capability marked
3100
- // `payloadIdentical` (the default for `surface: "both"`) MUST return a
3101
- // byte-for-byte equal JSON payload from `cw <cmd> --json` and from the
3102
- // `cw_<tool>` MCP result (whitespace aside); any divergence is drift. A
3103
- // capability reachable on one surface but absent on the other, or an
3104
- // undeclared payload divergence, is a release-blocking fail-closed error —
3105
- // see scripts/parity-check.js.
3106
- //
3107
- // `CAPABILITY_REGISTRY` is an alias so callers written against the old
3108
- // name (and the two smokes that import this module) find the same array
3109
- // under either name; `REGISTRY` stays the primary export other v2 modules
3110
- // already use.
3111
- exports.CAPABILITY_REGISTRY = exports.REGISTRY;
3112
- /** Read-only, run-less global reads: safe with just `cwd`. */
3113
- const GLOBAL_PAYLOAD_PROBE_CAPABILITIES = [
3114
- "list",
3115
- "app.list",
3116
- "topology.list",
3117
- "sandbox.list",
3118
- "backend.list",
3119
- "backend.agent.config.show",
3120
- "metrics.summary",
3121
- ];
3122
- /** Read-only reads that need only a planned run id. */
3123
- const RUN_PAYLOAD_PROBE_CAPABILITIES = [
3124
- "status",
3125
- "operator.status",
3126
- "operator.report",
3127
- "graph",
3128
- "report",
3129
- "next",
3130
- "state.check",
3131
- "contract.show",
3132
- "node.list",
3133
- "node.graph",
3134
- "worker.summary",
3135
- "candidate.summary",
3136
- "feedback.summary",
3137
- "commit.summary",
3138
- "audit.summary",
3139
- "multi-agent.summary",
3140
- "workbench.view",
3141
- "metrics.show",
3142
- "review.status",
3143
- "comment.list",
3144
- "run.drive",
3145
- "gc.plan",
3146
- "gc.verify",
3147
- ];
3148
- /** Capabilities that need bespoke scenario setup (extra args, seeded state,
3149
- * a dispatched worker, ...) beyond a bare `cwd`/`runId` — see
3150
- * scripts/parity-check.js's `prepareScenarioCli`/`prepareScenarioMcp` and
3151
- * `runScenarioCli`/`runScenarioMcp` for the setup + invocation each one
3152
- * actually runs. */
3153
- const SCENARIO_PAYLOAD_PROBE_CAPABILITIES = [
3154
- "plan",
3155
- "app.show",
3156
- "app.validate",
3157
- "app.package",
3158
- "topology.show",
3159
- "topology.validate",
3160
- "topology.apply",
3161
- "topology.summary",
3162
- "topology.graph",
3163
- "summary.refresh",
3164
- "summary.show",
3165
- "sandbox.show",
3166
- "sandbox.validate",
3167
- "sandbox.choose",
3168
- "sandbox.resolve",
3169
- "approve",
3170
- "reject",
3171
- "comment.add",
3172
- "handoff",
3173
- "review.policy",
3174
- "worker.list",
3175
- "worker.show",
3176
- "worker.manifest",
3177
- "worker.output",
3178
- "worker.fail",
3179
- "worker.validate",
3180
- "candidate.list",
3181
- "candidate.show",
3182
- "candidate.register",
3183
- "candidate.score",
3184
- "candidate.rank",
3185
- "candidate.select",
3186
- "candidate.reject",
3187
- "feedback.list",
3188
- "feedback.show",
3189
- "feedback.collect",
3190
- "feedback.task",
3191
- "feedback.resolve",
3192
- "node.show",
3193
- "node.snapshot",
3194
- "node.diff",
3195
- "node.replay",
3196
- "node.replay.verify",
3197
- ];
3198
- /** Payload-identical, both-surface, dual-bound capabilities that are not
3199
- * yet safe for the deterministic bootstrap parity probe — each needs
3200
- * extra target ids/files, mutates durable state, depends on external
3201
- * state, or needs a dedicated fixture beyond cwd/runId. Every entry here
3202
- * must actually be a dual-bound (`cli` + `mcp`) row in `REGISTRY` without
3203
- * a declared opt-out, or it never reaches the candidate set this list is
3204
- * deferring — `buildPayloadProbePlan`'s `invalidClassifications` fails
3205
- * closed on a stale entry left behind after a row later grows a real
3206
- * probe target or an explicit opt-out. */
3207
- const PAYLOAD_PROBE_DEFERRED_GROUPS = [
3208
- {
3209
- reason: "Not safe for the deterministic bootstrap parity probe yet: this capability needs extra target ids/files, mutates durable state, depends on external state, or needs a dedicated fixture beyond cwd/runId.",
3210
- capabilities: [
3211
- "dispatch",
3212
- "result",
3213
- "app.init",
3214
- "migration.list",
3215
- "migration.check",
3216
- "migration.prove",
3217
- "multi-agent.run",
3218
- "multi-agent.status",
3219
- "multi-agent.step",
3220
- "multi-agent.blackboard",
3221
- "multi-agent.score",
3222
- "multi-agent.select",
3223
- "multi-agent.summarize",
3224
- "multi-agent.graph",
3225
- "multi-agent.dependencies",
3226
- "multi-agent.failures",
3227
- "multi-agent.evidence",
3228
- "multi-agent.reasoning",
3229
- "multi-agent.run.create",
3230
- "multi-agent.run.transition",
3231
- "multi-agent.run.show",
3232
- "multi-agent.group.create",
3233
- "multi-agent.membership.create",
3234
- "multi-agent.fanout.create",
3235
- "multi-agent.fanin.collect",
3236
- "eval.snapshot",
3237
- "eval.replay",
3238
- "eval.compare",
3239
- "eval.score",
3240
- "eval.gate",
3241
- "eval.report",
3242
- "blackboard.summary",
3243
- "blackboard.summarize",
3244
- "blackboard.graph",
3245
- "blackboard.resolve",
3246
- "blackboard.topic.create",
3247
- "blackboard.message.post",
3248
- "blackboard.message.list",
3249
- "blackboard.context.put",
3250
- "blackboard.artifact.add",
3251
- "blackboard.artifact.list",
3252
- "blackboard.snapshot",
3253
- "coordinator.summary",
3254
- "coordinator.decision",
3255
- "audit.verify",
3256
- "audit.worker",
3257
- "audit.provenance",
3258
- "audit.multi-agent",
3259
- "audit.policy",
3260
- "audit.role",
3261
- "audit.blackboard",
3262
- "audit.judge",
3263
- "audit.attest",
3264
- "audit.decision",
3265
- "backend.show",
3266
- "backend.probe",
3267
- "run.search",
3268
- "run.list",
3269
- "run.show",
3270
- "run.resume",
3271
- "run.archive",
3272
- "run.rerun",
3273
- "report.verify-bundle",
3274
- "report.bundle",
3275
- "telemetry.verify",
3276
- "history",
3277
- ],
3278
- },
3279
- {
3280
- // Phase B: the CLI bindings just layered onto these previously
3281
- // MCP-only rows make each a real both-surface dual-bound capability, so
3282
- // the payload probe now sees them. Each needs a seeded fixture beyond a
3283
- // bare cwd/runId — a scheduled task / routine trigger / durable queue
3284
- // entry / lease / portable archive on disk, a target entity id
3285
- // (role/group/membership/fanout/fanin/schedule/lease id), a workflow-app
3286
- // id to scaffold or drive, or a registry index to refresh — so each is
3287
- // deferred until a bootstrap fixture is added, exactly like the
3288
- // scenario/deferred split the older batches use. `init` also folds into
3289
- // app.init on both surfaces (scaffold), so it defers with the app family.
3290
- reason: "Not safe for the deterministic bootstrap parity probe yet: this capability needs a seeded fixture beyond cwd/runId (a scheduled task / routine trigger / queue entry / lease / portable archive on disk, a target entity id, or a workflow-app id to scaffold or drive). Both surfaces route through the same shell fn; each defers until a bootstrap fixture seeds its state.",
3291
- capabilities: [
3292
- "app.run",
3293
- "init",
3294
- "registry.refresh",
3295
- "registry.show",
3296
- "queue.add",
3297
- "queue.list",
3298
- "queue.drain",
3299
- "queue.show",
3300
- "clones.list",
3301
- "orphans.list",
3302
- "schedule.create",
3303
- "schedule.list",
3304
- "schedule.delete",
3305
- "schedule.due",
3306
- "schedule.complete",
3307
- "schedule.pause",
3308
- "schedule.resume",
3309
- "schedule.run-now",
3310
- "schedule.history",
3311
- "routine.create",
3312
- "routine.list",
3313
- "routine.delete",
3314
- "routine.fire",
3315
- "routine.events",
3316
- "sched.plan",
3317
- "sched.lease",
3318
- "sched.release",
3319
- "sched.complete",
3320
- "sched.reclaim",
3321
- "sched.reset",
3322
- "sched.policy.show",
3323
- "sched.policy.set",
3324
- "run.export",
3325
- "run.import",
3326
- "run.verify-import",
3327
- "run.inspect-archive",
3328
- "run.restore",
3329
- "multi-agent.reasoning.refresh",
3330
- "multi-agent.graph.compact",
3331
- "multi-agent.role.create",
3332
- "multi-agent.role.show",
3333
- "multi-agent.group.show",
3334
- "multi-agent.membership.show",
3335
- "multi-agent.fanout.show",
3336
- "multi-agent.fanin.show",
3337
- ],
3338
- },
3339
- ];
3340
- /** The MCP tool names this registry declares. */
3341
- function declaredMcpToolsList() {
3342
- return declaredMcpTools();
3343
- }
3344
- /** Required MCP argument groups for a registry-declared tool. */
3345
- function mcpRequiredArgsForTool(tool) {
3346
- return findCapabilityByMcpTool(tool)?.mcp?.requiredArgs ?? [];
3347
- }
3348
- /** The CLI `case` tokens this registry declares (deduped). */
3349
- function declaredCliTokens() {
3350
- const tokens = new Set();
3351
- for (const cap of exports.REGISTRY) {
3352
- if (!cap.cli)
3353
- continue;
3354
- for (const token of cap.cli.caseTokens ?? cap.cli.path)
3355
- tokens.add(token);
3356
- }
3357
- return [...tokens].sort();
3358
- }
3359
- /** The top-level CLI commands that should be visible in `cw help`.
3360
- * Subcommands are collapsed to their first token; alias tokens (e.g.
3361
- * `audit-run`) stay visible alongside the verb they alias. */
3362
- function declaredCliHelpTokens() {
3363
- const tokens = new Set();
3364
- for (const cap of exports.REGISTRY) {
3365
- if (!cap.cli)
3366
- continue;
3367
- const subcommandTokens = new Set(cap.cli.path.slice(1));
3368
- tokens.add(cap.cli.path[0]);
3369
- for (const token of cap.cli.caseTokens || []) {
3370
- if (!subcommandTokens.has(token))
3371
- tokens.add(token);
3372
- }
3373
- }
3374
- tokens.delete("help");
3375
- // `init` is a help-index-only token: v2 folds the standalone `init`
3376
- // capability into `app.init` (its cli.path is ["init"] only so the
3377
- // dispatcher can still run `cw init`, but `cw help` lists it in the
3378
- // frozen "More commands" index line, never as its own per-command help
3379
- // row). Mirrors the parity smoke's HELP_INDEX_ONLY_TOKENS set so the
3380
- // help-token parity stays balanced.
3381
- tokens.delete("init");
3382
- return [...tokens].sort();
3383
- }
3384
- /** Whether a row MUST carry a reason (surface-specific or payload-divergent). */
3385
- function requiresReason(cap) {
3386
- if (cap.surface !== "both")
3387
- return true;
3388
- if (cap.payloadIdentical === false)
3389
- return true;
3390
- return false;
3391
- }
3392
- /**
3393
- * Whether a `surface:"both"` capability is DOCUMENTED out of the payload-identity
3394
- * probe. The probe defaults capabilities IN (every both-surface, dual-bound verb —
3395
- * including write/complex-arg verbs) and requires an EXPLICIT, REASONED opt-out to
3396
- * fall out of scope. A capability escapes the probe only when it carries BOTH
3397
- * `payloadIdentical: false` AND a non-empty `reason`. A bare `payloadIdentical:
3398
- * false` with no recorded reason does NOT silently escape — it stays in the probe
3399
- * set so the undocumented divergence trips the gate (FAIL CLOSED).
3400
- */
3401
- function isPayloadProbeOptOut(cap) {
3402
- return cap.payloadIdentical === false && !!(cap.reason && cap.reason.trim());
3403
- }
3404
- /** Rows for the payload-identity probe. Defaults to EVERY both-surface,
3405
- * dual-bound capability (read OR write); a row is excluded only by a
3406
- * documented opt-out (`payloadIdentical: false` + a non-empty `reason`) —
3407
- * see `isPayloadProbeOptOut`. Fail-closed: an undocumented `payloadIdentical:
3408
- * false` stays in scope so its divergence is caught, not silently excused. */
3409
- function payloadIdenticalCapabilities() {
3410
- return exports.REGISTRY.filter((cap) => cap.surface === "both" && cap.cli && cap.mcp && !isPayloadProbeOptOut(cap));
3411
- }
3412
- function payloadProbeTargets() {
3413
- return [
3414
- ...GLOBAL_PAYLOAD_PROBE_CAPABILITIES.map((capability) => ({ capability, kind: "global" })),
3415
- ...RUN_PAYLOAD_PROBE_CAPABILITIES.map((capability) => ({ capability, kind: "run" })),
3416
- ...SCENARIO_PAYLOAD_PROBE_CAPABILITIES.map((capability) => ({ capability, kind: "scenario" })),
3417
- ];
3418
- }
3419
- function deferredPayloadProbeCapabilities() {
3420
- return PAYLOAD_PROBE_DEFERRED_GROUPS.flatMap((group) => group.capabilities.map((capability) => ({ capability, reason: group.reason })));
3421
- }
3422
- function buildPayloadProbePlan(targets, deferred) {
3423
- const candidateIds = new Set(payloadIdenticalCapabilities().map((cap) => cap.capability));
3424
- const counts = new Map();
3425
- const classified = [...targets.map((entry) => entry.capability), ...deferred.map((entry) => entry.capability)];
3426
- for (const capability of classified)
3427
- counts.set(capability, (counts.get(capability) || 0) + 1);
3428
- const classifiedIds = new Set(classified);
3429
- return {
3430
- targets,
3431
- deferred,
3432
- unclassified: [...candidateIds].filter((capability) => !classifiedIds.has(capability)).sort(),
3433
- duplicateClassifications: [...counts.entries()]
3434
- .filter(([, count]) => count > 1)
3435
- .map(([capability]) => capability)
3436
- .sort(),
3437
- invalidClassifications: [...classifiedIds].filter((capability) => !candidateIds.has(capability)).sort(),
3438
- };
3439
- }
3440
- function payloadProbePlan() {
3441
- return buildPayloadProbePlan(payloadProbeTargets(), deferredPayloadProbeCapabilities());
3442
- }
3443
- function lintRegistry() {
3444
- const issues = [];
3445
- const seenCaps = new Set();
3446
- const seenTools = new Set();
3447
- for (const cap of exports.REGISTRY) {
3448
- if (seenCaps.has(cap.capability))
3449
- issues.push(`duplicate capability id: ${cap.capability}`);
3450
- seenCaps.add(cap.capability);
3451
- if (cap.mcp) {
3452
- if (seenTools.has(cap.mcp.tool))
3453
- issues.push(`duplicate MCP tool: ${cap.mcp.tool}`);
3454
- seenTools.add(cap.mcp.tool);
3455
- }
3456
- // NOTE (v2 build-order difference from the old flat registry): the old
3457
- // build's registry was written all at once, so a "both" row ALWAYS had
3458
- // both bindings the moment it was declared. This table is built up
3459
- // MILESTONE BY MILESTONE (this file's header note): `REGISTRY` starts
3460
- // from the full, literal 196-tool `mcp` surface (SPEC/mcp.md) and each
3461
- // milestone LAYERS a `cli` binding onto the rows it wires next — so a
3462
- // "both" row with an `mcp` binding but no `cli` binding YET is the
3463
- // expected, honest mid-rollout state, not a lint error. `cli` bindings
3464
- // are added without ever touching `surface`, so the lint only fails
3465
- // closed on what is actually impossible: a `mcp` binding must always
3466
- // exist for "both" (every row starts from `MCP_TOOL_DATA`), and
3467
- // `cli-only`/`mcp-only` rows must carry exactly the one binding their
3468
- // name promises.
3469
- if (cap.surface === "both" && !cap.mcp) {
3470
- issues.push(`${cap.capability}: surface "both" requires an mcp binding`);
3471
- }
3472
- if (cap.surface === "cli-only" && (cap.mcp || !cap.cli)) {
3473
- issues.push(`${cap.capability}: surface "cli-only" requires a cli binding and no mcp binding`);
3474
- }
3475
- if (cap.surface === "mcp-only" && (cap.cli || !cap.mcp)) {
3476
- issues.push(`${cap.capability}: surface "mcp-only" requires an mcp binding and no cli binding`);
3477
- }
3478
- }
3479
- return issues;
3480
- }
3481
- /**
3482
- * Compare the declared registry against the ACTUAL surfaces and report every
3483
- * fail-closed gap. `mcpTools` is the live `tools/list` result; `cliTokens` is the
3484
- * set of `case "<token>"` strings parsed from the CLI source.
3485
- */
3486
- function buildParityReport(input) {
3487
- const declaredTools = new Set(declaredMcpTools());
3488
- const actualTools = new Set(input.mcpTools);
3489
- const declaredTokens = new Set(declaredCliTokens());
3490
- const actualTokens = new Set(input.cliTokens);
3491
- const declaredHelpTokens = new Set(declaredCliHelpTokens());
3492
- const actualHelpTokens = new Set(input.helpTokens || []);
3493
- const missingMcpTools = [...declaredTools].filter((tool) => !actualTools.has(tool)).sort();
3494
- const undeclaredMcpTools = [...actualTools].filter((tool) => !declaredTools.has(tool)).sort();
3495
- const missingCliTokens = [...declaredTokens].filter((token) => !actualTokens.has(token)).sort();
3496
- const undeclaredCliTokens = [...actualTokens].filter((token) => !declaredTokens.has(token)).sort();
3497
- const helpMissingCliTokens = input.helpTokens
3498
- ? [...declaredHelpTokens].filter((token) => !actualHelpTokens.has(token)).sort()
3499
- : [];
3500
- const helpUndeclaredCliTokens = input.helpTokens
3501
- ? [...actualHelpTokens].filter((token) => !declaredHelpTokens.has(token)).sort()
3502
- : [];
3503
- const reasonlessExceptions = exports.REGISTRY.filter((cap) => requiresReason(cap) && !(cap.reason && cap.reason.trim()))
3504
- .map((cap) => cap.capability)
3505
- .sort();
3506
- const payloadPlan = payloadProbePlan();
3507
- const registryLint = lintRegistry();
3508
- const ok = missingMcpTools.length === 0 &&
3509
- undeclaredMcpTools.length === 0 &&
3510
- missingCliTokens.length === 0 &&
3511
- undeclaredCliTokens.length === 0 &&
3512
- helpMissingCliTokens.length === 0 &&
3513
- helpUndeclaredCliTokens.length === 0 &&
3514
- reasonlessExceptions.length === 0 &&
3515
- payloadPlan.unclassified.length === 0 &&
3516
- payloadPlan.duplicateClassifications.length === 0 &&
3517
- payloadPlan.invalidClassifications.length === 0 &&
3518
- registryLint.length === 0;
3519
- return {
3520
- ok,
3521
- registrySize: exports.REGISTRY.length,
3522
- missingMcpTools,
3523
- undeclaredMcpTools,
3524
- missingCliTokens,
3525
- undeclaredCliTokens,
3526
- helpMissingCliTokens,
3527
- helpUndeclaredCliTokens,
3528
- reasonlessExceptions,
3529
- payloadProbeUnclassified: payloadPlan.unclassified,
3530
- payloadProbeDuplicateClassifications: payloadPlan.duplicateClassifications,
3531
- payloadProbeInvalidClassifications: payloadPlan.invalidClassifications,
3532
- registryLint,
3533
- };
3534
- }
27
+ exports.CapabilityNotImplementedError = void 0;
28
+ __exportStar(require("../wiring/capability-table"), exports);
29
+ var capability_data_1 = require("./capability-data");
30
+ Object.defineProperty(exports, "CapabilityNotImplementedError", { enumerable: true, get: function () { return capability_data_1.CapabilityNotImplementedError; } });