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