cool-workflow 0.2.1 → 0.2.3

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 (156) 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 +29 -91
  10. package/dist/cli/entry.js +41 -1
  11. package/dist/cli/io.js +6 -2
  12. package/dist/cli/parseargv.js +6 -2
  13. package/dist/core/capability-data.js +271 -0
  14. package/dist/core/capability-table.js +16 -3504
  15. package/dist/core/format/completion.js +68 -0
  16. package/dist/core/format/help.js +50 -8
  17. package/dist/core/format/safe-json.js +73 -0
  18. package/dist/core/format/state-explosion-text.js +1 -1
  19. package/dist/core/multi-agent/candidate-scoring.js +5 -1
  20. package/dist/core/multi-agent/collaboration.js +6 -5
  21. package/dist/core/multi-agent/coordinator.js +9 -8
  22. package/dist/core/multi-agent/runtime.js +4 -4
  23. package/dist/core/multi-agent/topology.js +3 -3
  24. package/dist/core/pipeline/commit-gate.js +2 -1
  25. package/dist/core/pipeline/dispatch.js +18 -4
  26. package/dist/core/pipeline/drive-decide.js +2 -1
  27. package/dist/core/state/migrations.js +16 -1
  28. package/dist/core/state/state-explosion/digest.js +16 -15
  29. package/dist/core/state/state-explosion/graph.js +26 -19
  30. package/dist/core/state/state-explosion/helpers.js +2 -1
  31. package/dist/core/state/state-explosion/report.js +6 -6
  32. package/dist/core/trust/ledger.js +2 -1
  33. package/dist/core/types/execution-backend.js +18 -0
  34. package/dist/core/types/observability.js +7 -0
  35. package/dist/core/util/collate.js +23 -0
  36. package/dist/core/util/numeric-flag.js +40 -0
  37. package/dist/core/version.js +1 -1
  38. package/dist/mcp/server.js +99 -11
  39. package/dist/shell/audit-cli.js +99 -23
  40. package/dist/shell/commit-summary.js +2 -1
  41. package/dist/shell/coordinator-io.js +73 -13
  42. package/dist/shell/dispatch.js +1 -1
  43. package/dist/shell/doctor.js +80 -1
  44. package/dist/shell/drive.js +269 -59
  45. package/dist/shell/eval-text.js +2 -2
  46. package/dist/shell/evidence-reasoning.js +8 -7
  47. package/dist/shell/execution-backend/agent.js +20 -1
  48. package/dist/shell/execution-backend/container.js +4 -1
  49. package/dist/shell/execution-backend/local.js +4 -1
  50. package/dist/shell/execution-backend/registry.js +2 -1
  51. package/dist/shell/execution-backend/types.js +0 -9
  52. package/dist/shell/feedback-cli.js +6 -6
  53. package/dist/shell/fs-atomic.js +232 -30
  54. package/dist/shell/man-cli.js +6 -0
  55. package/dist/shell/metrics-cli.js +2 -1
  56. package/dist/shell/multi-agent-cli.js +367 -323
  57. package/dist/shell/multi-agent-host.js +9 -9
  58. package/dist/shell/multi-agent-operator-ux.js +82 -39
  59. package/dist/shell/node-store.js +10 -4
  60. package/dist/shell/observability.js +13 -12
  61. package/dist/shell/onramp.js +17 -1
  62. package/dist/shell/operator-ux-text.js +24 -23
  63. package/dist/shell/operator-ux.js +22 -20
  64. package/dist/shell/orchestrator.js +49 -38
  65. package/dist/shell/pipeline-cli.js +168 -111
  66. package/dist/shell/reclamation-io.js +16 -5
  67. package/dist/shell/registry-cli.js +19 -17
  68. package/dist/shell/remote-source.js +13 -8
  69. package/dist/shell/report-cli.js +45 -0
  70. package/dist/shell/report.js +4 -2
  71. package/dist/shell/run-registry-io.js +77 -19
  72. package/dist/shell/run-store.js +91 -2
  73. package/dist/shell/scheduling-io.js +12 -13
  74. package/dist/shell/state-cli.js +2 -7
  75. package/dist/shell/state-explosion-cli.js +19 -10
  76. package/dist/shell/topology-io.js +38 -6
  77. package/dist/shell/trust-audit.js +264 -23
  78. package/dist/shell/trust-policy-io.js +1 -1
  79. package/dist/shell/worker-cli.js +41 -29
  80. package/dist/shell/worker-isolation.js +34 -9
  81. package/dist/shell/workflow-app-loader.js +3 -2
  82. package/dist/wiring/capability-table/basics.js +91 -0
  83. package/dist/wiring/capability-table/exec-backend.js +171 -0
  84. package/dist/wiring/capability-table/index.js +42 -0
  85. package/dist/wiring/capability-table/multi-agent.js +630 -0
  86. package/dist/wiring/capability-table/parity.js +467 -0
  87. package/dist/wiring/capability-table/pipeline.js +292 -0
  88. package/dist/wiring/capability-table/registry-core.js +208 -0
  89. package/dist/wiring/capability-table/reporting.js +435 -0
  90. package/dist/wiring/capability-table/scheduling-registry.js +592 -0
  91. package/dist/wiring/capability-table/state.js +181 -0
  92. package/dist/wiring/capability-table/trust-ledger.js +158 -0
  93. package/dist/wiring/capability-table/workflow-apps.js +381 -0
  94. package/docs/agent-delegation-drive.7.md +4 -0
  95. package/docs/candidate-scoring.7.md +1 -1
  96. package/docs/canonical-workflow-apps.7.md +7 -7
  97. package/docs/cli-mcp-parity.7.md +13 -3
  98. package/docs/contract-migration-tooling.7.md +4 -0
  99. package/docs/control-plane-scheduling.7.md +4 -0
  100. package/docs/coordinator-blackboard.7.md +17 -17
  101. package/docs/dogfood-one-real-repo.7.md +11 -11
  102. package/docs/durable-state-and-locking.7.md +24 -0
  103. package/docs/end-to-end-golden-path.7.md +14 -14
  104. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  105. package/docs/execution-backends.7.md +4 -0
  106. package/docs/getting-started.md +37 -37
  107. package/docs/index.md +1 -0
  108. package/docs/multi-agent-cli-mcp-surface.7.md +21 -17
  109. package/docs/multi-agent-eval-replay-harness.7.md +17 -13
  110. package/docs/multi-agent-operator-ux.7.md +23 -19
  111. package/docs/multi-agent-runtime-core.7.md +22 -22
  112. package/docs/multi-agent-topologies.7.md +6 -6
  113. package/docs/multi-agent-trust-policy-audit.7.md +11 -11
  114. package/docs/node-snapshot-diff-replay.7.md +4 -0
  115. package/docs/observability-cost-accounting.7.md +4 -0
  116. package/docs/operator-ux.7.md +34 -34
  117. package/docs/pipeline-runner.7.md +4 -4
  118. package/docs/project-index.md +48 -5
  119. package/docs/real-execution-backends.7.md +4 -0
  120. package/docs/release-and-migration.7.md +5 -1
  121. package/docs/release-tooling.7.md +4 -0
  122. package/docs/routines.md +4 -4
  123. package/docs/run-registry-control-plane.7.md +23 -19
  124. package/docs/run-retention-reclamation.7.md +4 -0
  125. package/docs/scheduled-tasks.md +14 -14
  126. package/docs/security-trust-hardening.7.md +43 -13
  127. package/docs/state-explosion-management.7.md +14 -10
  128. package/docs/team-collaboration.7.md +4 -0
  129. package/docs/trust-audit-anchor.7.md +71 -0
  130. package/docs/unix-principles.md +3 -1
  131. package/docs/verifier-gated-commit.7.md +1 -1
  132. package/docs/web-desktop-workbench.7.md +4 -0
  133. package/docs/workflow-app-framework.7.md +13 -13
  134. package/manifest/plugin.manifest.json +1 -1
  135. package/package.json +4 -2
  136. package/scripts/agents/claude-p-agent.js +2 -2
  137. package/scripts/block-unapproved-tag.sh +23 -2
  138. package/scripts/bump-version.js +24 -2
  139. package/scripts/canonical-apps.js +4 -4
  140. package/scripts/children/batch-delegate-child.js +52 -2
  141. package/scripts/dogfood-release.js +1 -1
  142. package/scripts/fake-date-for-reproduction.js +44 -0
  143. package/scripts/golden-path.js +4 -4
  144. package/scripts/purity-baseline.json +71 -0
  145. package/scripts/purity-gate.js +239 -0
  146. package/scripts/release-check.js +8 -1
  147. package/scripts/release-flow.js +57 -1
  148. package/scripts/verdict-keygen.js +83 -0
  149. package/scripts/verify-bump-reproduction.sh +148 -0
  150. package/scripts/verify-verdict-signature.js +61 -0
  151. package/scripts/version-sync-check.js +33 -12
  152. package/skills/cool-workflow/SKILL.md +9 -9
  153. package/skills/cool-workflow/references/commands.md +89 -88
  154. package/ui/workbench/app.css +37 -1
  155. package/ui/workbench/app.js +124 -6
  156. package/workflows/README.md +19 -0
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ // wiring/capability-table/workflow-apps.ts — MILESTONE 12 (workflow-apps:
3
+ // app.*, info, man) CLI bindings, plus the `next` capability (a milestone
4
+ // 3/6 placeholder folded in alongside app.* per the file's own history).
5
+ // Split out of core/capability-table.ts, byte-for-byte (extracted with
6
+ // sed, not retyped).
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const registry_core_1 = require("./registry-core");
9
+ const io_1 = require("../../cli/io");
10
+ // This whole module is required unconditionally at startup for EVERY
11
+ // command (see wiring/capability-table/index.ts) — loading `next`'s and
12
+ // `app.run`'s shell modules lazily, inside the handler that actually
13
+ // calls them, keeps other commands from paying their load cost.
14
+ function loadStateCli() {
15
+ return require("../../shell/state-cli");
16
+ }
17
+ function loadAppRunCli() {
18
+ return require("../../shell/app-run-cli");
19
+ }
20
+ // MILESTONE 12 (workflow-apps). Handler BODIES live in
21
+ // shell/workflow-app-loader.ts (impure — they scan apps/*/app.json +
22
+ // workflows/*.workflow.js on disk and `require()` each entrypoint); this
23
+ // table only wires argv/tool-args shape -> handler call, per SPEC/
24
+ // workflow-apps.md's "Exact outputs". `app.validate` is ALWAYS JSON
25
+ // (jsonMode "default") even without --json, and its handler sets
26
+ // exitCode 1 on `valid:false` — both the "not found" id case and a
27
+ // structurally-broken manifest case fail this same way.
28
+ // Loaded lazily so the app.* handlers below pay this module's load cost
29
+ // only when actually invoked, not on every CLI/MCP startup.
30
+ function loadWorkflowAppLoader() {
31
+ return require("../../shell/workflow-app-loader");
32
+ }
33
+ const help_1 = require("../../core/format/help");
34
+ // Loaded lazily so only the `man` handler below pays its load cost.
35
+ function loadManCli() {
36
+ return require("../../shell/man-cli");
37
+ }
38
+ (0, registry_core_1.attachCliBinding)("app.list", {
39
+ path: ["app", "list"],
40
+ jsonMode: "default",
41
+ handler: () => ({ json: loadWorkflowAppLoader().listWorkflowApps() }),
42
+ });
43
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.list").mcp.handler = () => loadWorkflowAppLoader().listWorkflowApps();
44
+ (0, registry_core_1.attachCliBinding)("app.show", {
45
+ path: ["app", "show"],
46
+ jsonMode: "default",
47
+ handler: (args) => ({ json: loadWorkflowAppLoader().showWorkflowApp((0, io_1.required)(args.positionals[0], "workflow app id")) }),
48
+ });
49
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.show").mcp.handler = (args) => loadWorkflowAppLoader().showWorkflowApp((0, io_1.required)((0, io_1.optionalArg)(args.appId), "workflow app id"));
50
+ (0, registry_core_1.attachCliBinding)("app.validate", {
51
+ path: ["app", "validate"],
52
+ jsonMode: "default",
53
+ handler: (args) => {
54
+ const result = loadWorkflowAppLoader().validateWorkflowAppTarget((0, io_1.required)(args.positionals[0], "workflow app path or id"));
55
+ return { json: result, exitCode: result.valid ? undefined : 1 };
56
+ },
57
+ });
58
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.validate").mcp.handler = (args) => loadWorkflowAppLoader().validateWorkflowAppTarget((0, io_1.required)((0, io_1.optionalArg)(args.target ?? args.appId), "workflow app path or id"));
59
+ (0, registry_core_1.attachCliBinding)("app.init", {
60
+ path: ["app", "init"],
61
+ jsonMode: "default",
62
+ handler: (args) => ({ json: loadWorkflowAppLoader().initWorkflowApp((0, io_1.required)(args.positionals[0], "app id"), args.options) }),
63
+ });
64
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.init").mcp.handler = (args) => loadWorkflowAppLoader().initWorkflowApp((0, io_1.required)((0, io_1.optionalArg)(args.appId), "app id"), args);
65
+ // `cw init <id>` — the standalone scaffold verb. v2 folds `init` into
66
+ // `app.init` (the old build's legacy `.workflow.js` scaffold is gone), so
67
+ // both surfaces route through initWorkflowApp, same as `cw app init`. The
68
+ // `init` help token is folded away (declaredCliHelpTokens) — it stays in
69
+ // the frozen "More commands" index line only, matching the parity smoke's
70
+ // HELP_INDEX_ONLY_TOKENS treatment. `workflowId` is the old init arg name.
71
+ (0, registry_core_1.attachCliBinding)("init", {
72
+ path: ["init"],
73
+ jsonMode: "default",
74
+ handler: (args) => ({ json: loadWorkflowAppLoader().initWorkflowApp((0, io_1.required)((0, io_1.optionalArg)(args.positionals[0]), "workflow id"), args.options) }),
75
+ });
76
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("init").mcp.handler = (args) => loadWorkflowAppLoader().initWorkflowApp((0, io_1.required)((0, io_1.optionalArg)(args.workflowId ?? args.appId), "workflow id"), args);
77
+ (0, registry_core_1.attachCliBinding)("app.package", {
78
+ path: ["app", "package"],
79
+ jsonMode: "default",
80
+ handler: (args) => ({ json: loadWorkflowAppLoader().packageWorkflowApp((0, io_1.required)(args.positionals[0], "app id"), args.options) }),
81
+ });
82
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("app.package").mcp.handler = (args) => loadWorkflowAppLoader().packageWorkflowApp((0, io_1.required)((0, io_1.optionalArg)(args.appId), "app id"), args);
83
+ // `cw app run <app-id>` — plan+drive+report an app in one call. 2-token
84
+ // cli.path found before the ["app"] usage catch-all; `appRunCli` reads the
85
+ // app id from `appId`, so the first positional after "run" is forwarded as
86
+ // appId (old build: appRun(runner, { ...options, appId: <positional> })).
87
+ (0, registry_core_1.attachCliBinding)("app.run", {
88
+ path: ["app", "run"],
89
+ jsonMode: "default",
90
+ handler: (args) => ({ json: loadAppRunCli().appRunCli({ ...args.options, appId: (0, io_1.required)(args.positionals[0], "app id") }) }),
91
+ });
92
+ // A 1-token `["app"]` row that exists ONLY to own the fixed usage string
93
+ // for an unrecognized `app` subcommand (`app run` is not yet CLI-wired at
94
+ // this milestone — cw_app_run stays MCP-only — so a bogus or `run`
95
+ // subcommand both fall through to this same usage throw, matching
96
+ // SPEC/cli-surface.md's "Usage strings" table byte-for-byte). Per
97
+ // dispatchTable's reversed-candidate-order contract (cli/dispatch.ts),
98
+ // this 1-token row is only ever reached when no 2-token `app.*` row
99
+ // above matched. `hiddenFromHelp` keeps it off `cw help app`'s own line
100
+ // (see CliBinding.hiddenFromHelp's doc comment).
101
+ (0, registry_core_1.addCliOnlyCapability)("app.usage", "cw app list|show|validate|init|package|run [app-id|path] — the workflow-app framework.", {
102
+ path: ["app"],
103
+ jsonMode: "default",
104
+ hiddenFromHelp: true,
105
+ handler: () => {
106
+ throw new Error("Usage: cw app list|show|validate|init|package|run [app-id|path]");
107
+ },
108
+ }, "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.");
109
+ // ---------------------------------------------------------------------
110
+ // 1-token usage-fallback rows: one per multi-verb family, each existing
111
+ // ONLY to own the fixed usage string for an unrecognized subcommand,
112
+ // same pattern and reasoning as app.usage above (SPEC/cli-surface.md's
113
+ // "Usage strings" table, byte-for-byte). Per dispatchTable's reversed-
114
+ // candidate-order contract (cli/dispatch.ts), each 1-token row here is
115
+ // only ever reached when no 2-token real row for that family matched.
116
+ // `hiddenFromHelp` keeps each off its own `cw help <verb>` line.
117
+ // ---------------------------------------------------------------------
118
+ (0, registry_core_1.addCliOnlyCapability)("sandbox.usage", "cw sandbox list|show|validate|choose|resolve [profile-id|profile-file]", {
119
+ path: ["sandbox"],
120
+ jsonMode: "default",
121
+ hiddenFromHelp: true,
122
+ handler: () => {
123
+ throw new Error("Usage: cw sandbox list|show|validate|choose|resolve [profile-id|profile-file]");
124
+ },
125
+ }, "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.");
126
+ (0, registry_core_1.addCliOnlyCapability)("state.usage", "cw state check <run-id> [--state PATH] [--write]", {
127
+ path: ["state"],
128
+ jsonMode: "default",
129
+ hiddenFromHelp: true,
130
+ handler: () => {
131
+ throw new Error("Usage: cw state check <run-id> [--state PATH] [--write]");
132
+ },
133
+ }, "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.");
134
+ (0, registry_core_1.addCliOnlyCapability)("audit.usage", "cw audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]", {
135
+ path: ["audit"],
136
+ jsonMode: "default",
137
+ hiddenFromHelp: true,
138
+ handler: () => {
139
+ throw new Error("Usage: cw audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]");
140
+ },
141
+ }, "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.");
142
+ (0, registry_core_1.addCliOnlyCapability)("blackboard.usage", "cw 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>", {
143
+ path: ["blackboard"],
144
+ jsonMode: "default",
145
+ hiddenFromHelp: true,
146
+ handler: () => {
147
+ throw new Error("Usage: cw 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>");
148
+ },
149
+ }, "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.");
150
+ (0, registry_core_1.addCliOnlyCapability)("candidate.usage", "cw candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]", {
151
+ path: ["candidate"],
152
+ jsonMode: "default",
153
+ hiddenFromHelp: true,
154
+ handler: () => {
155
+ throw new Error("Usage: cw candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]");
156
+ },
157
+ }, "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.");
158
+ (0, registry_core_1.addCliOnlyCapability)("comment.usage", "cw comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]", {
159
+ path: ["comment"],
160
+ jsonMode: "default",
161
+ hiddenFromHelp: true,
162
+ handler: () => {
163
+ throw new Error("Usage: cw comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]");
164
+ },
165
+ }, "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.");
166
+ (0, registry_core_1.addCliOnlyCapability)("eval.usage", "cw 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>", {
167
+ path: ["eval"],
168
+ jsonMode: "default",
169
+ hiddenFromHelp: true,
170
+ handler: () => {
171
+ throw new Error("Usage: cw 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>");
172
+ },
173
+ }, "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.");
174
+ (0, registry_core_1.addCliOnlyCapability)("telemetry.usage", "cw telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]", {
175
+ path: ["telemetry"],
176
+ jsonMode: "default",
177
+ hiddenFromHelp: true,
178
+ handler: () => {
179
+ throw new Error("Usage: cw telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]");
180
+ },
181
+ }, "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.");
182
+ (0, registry_core_1.addCliOnlyCapability)("demo.usage", "cw demo tamper|bundle [--json]", {
183
+ path: ["demo"],
184
+ jsonMode: "default",
185
+ hiddenFromHelp: true,
186
+ handler: () => {
187
+ throw new Error("Usage: cw demo tamper|bundle [--json]");
188
+ },
189
+ }, "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.");
190
+ (0, registry_core_1.addCliOnlyCapability)("multi-agent.usage", "cw multi-agent run|status|step|blackboard|score|select|summary|summarize|graph|dependencies|failures|evidence|reasoning|show|role|group|membership|fanout|fanin <run-id> [id]", {
191
+ path: ["multi-agent"],
192
+ jsonMode: "default",
193
+ hiddenFromHelp: true,
194
+ handler: () => {
195
+ throw new Error("Usage: cw multi-agent run|status|step|blackboard|score|select|summary|summarize|graph|dependencies|failures|evidence|reasoning|show|role|group|membership|fanout|fanin <run-id> [id]");
196
+ },
197
+ }, "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.");
198
+ (0, registry_core_1.addCliOnlyCapability)("node.usage", "cw node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]", {
199
+ path: ["node"],
200
+ jsonMode: "default",
201
+ hiddenFromHelp: true,
202
+ handler: () => {
203
+ throw new Error("Usage: cw node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]");
204
+ },
205
+ }, "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.");
206
+ (0, registry_core_1.addCliOnlyCapability)("backend.usage", "cw backend list|show|probe [backend-id] | cw backend agent config [show|set] [--agent-command ... --agent-endpoint ... --agent-model ...]", {
207
+ path: ["backend"],
208
+ jsonMode: "default",
209
+ hiddenFromHelp: true,
210
+ handler: () => {
211
+ throw new Error("Usage: cw backend list|show|probe [backend-id] | cw backend agent config [show|set] [--agent-command ... --agent-endpoint ... --agent-model ...]");
212
+ },
213
+ }, "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.");
214
+ (0, registry_core_1.addCliOnlyCapability)("contract.usage", "cw contract show <run-id> [contract-id]", {
215
+ path: ["contract"],
216
+ jsonMode: "default",
217
+ hiddenFromHelp: true,
218
+ handler: () => {
219
+ throw new Error("Usage: cw contract show <run-id> [contract-id]");
220
+ },
221
+ }, "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.");
222
+ (0, registry_core_1.addCliOnlyCapability)("migration.usage", "cw migration list|check|prove [target] [--contract run-state|workflow-app]", {
223
+ path: ["migration"],
224
+ jsonMode: "default",
225
+ hiddenFromHelp: true,
226
+ handler: () => {
227
+ throw new Error("Usage: cw migration list|check|prove [target] [--contract run-state|workflow-app]");
228
+ },
229
+ }, "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.");
230
+ (0, registry_core_1.addCliOnlyCapability)("feedback.usage", "cw feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]", {
231
+ path: ["feedback"],
232
+ jsonMode: "default",
233
+ hiddenFromHelp: true,
234
+ handler: () => {
235
+ throw new Error("Usage: cw feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]");
236
+ },
237
+ }, "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.");
238
+ (0, registry_core_1.addCliOnlyCapability)("metrics.usage", "cw metrics show <run-id> | metrics summary [--scope repo|home] [--pricing <path>|default] [--limit N] [--json]", {
239
+ path: ["metrics"],
240
+ jsonMode: "default",
241
+ hiddenFromHelp: true,
242
+ handler: () => {
243
+ throw new Error("Usage: cw metrics show <run-id> | metrics summary [--scope repo|home] [--pricing <path>|default] [--limit N] [--json]");
244
+ },
245
+ }, "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.");
246
+ (0, registry_core_1.addCliOnlyCapability)("operator.usage", "cw operator status|report <run-id> [--json]", {
247
+ path: ["operator"],
248
+ jsonMode: "default",
249
+ hiddenFromHelp: true,
250
+ handler: () => {
251
+ throw new Error("Usage: cw operator status|report <run-id> [--json]");
252
+ },
253
+ }, "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.");
254
+ (0, registry_core_1.addCliOnlyCapability)("topology.usage", "cw 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>", {
255
+ path: ["topology"],
256
+ jsonMode: "default",
257
+ hiddenFromHelp: true,
258
+ handler: () => {
259
+ throw new Error("Usage: cw 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>");
260
+ },
261
+ }, "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.");
262
+ (0, registry_core_1.addCliOnlyCapability)("summary.usage", "cw summary refresh|show <run-id> [--json]", {
263
+ path: ["summary"],
264
+ jsonMode: "default",
265
+ hiddenFromHelp: true,
266
+ handler: () => {
267
+ throw new Error("Usage: cw summary refresh|show <run-id> [--json]");
268
+ },
269
+ }, "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.");
270
+ (0, registry_core_1.addCliOnlyCapability)("workbench.usage", "cw workbench serve [--port N] [--once] [--require-token] | view <run-id> [--json]", {
271
+ path: ["workbench"],
272
+ jsonMode: "default",
273
+ hiddenFromHelp: true,
274
+ handler: () => {
275
+ throw new Error("Usage: cw workbench serve [--port N] [--once] [--require-token] | view <run-id> [--json]");
276
+ },
277
+ }, "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.");
278
+ (0, registry_core_1.addCliOnlyCapability)("worker.usage", "cw worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]", {
279
+ path: ["worker"],
280
+ jsonMode: "default",
281
+ hiddenFromHelp: true,
282
+ handler: () => {
283
+ throw new Error("Usage: cw worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]");
284
+ },
285
+ }, "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.");
286
+ (0, registry_core_1.addCliOnlyCapability)("review.usage", "cw review status <run-id> [--json] | review policy <run-id> --required-approvals N --authorized-roles a,b --applies-to commit,selection", {
287
+ path: ["review"],
288
+ jsonMode: "default",
289
+ hiddenFromHelp: true,
290
+ handler: () => {
291
+ throw new Error("Usage: cw review status <run-id> [--json] | review policy <run-id> --required-approvals N --authorized-roles a,b --applies-to commit,selection");
292
+ },
293
+ }, "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.");
294
+ (0, registry_core_1.addCliOnlyCapability)("coordinator.usage", "cw coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT", {
295
+ path: ["coordinator"],
296
+ jsonMode: "default",
297
+ hiddenFromHelp: true,
298
+ handler: () => {
299
+ throw new Error("Usage: cw coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT");
300
+ },
301
+ }, "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.");
302
+ // ---- man (CLI-only; raw manual-page bytes to stdout, no MCP peer) -----
303
+ //
304
+ // Writes the resolved doc file's raw bytes directly to stdout and
305
+ // returns an empty result — the generic renderCliResult (cli/dispatch.ts)
306
+ // always appends "\n" to `result.text` when it is missing one, which
307
+ // would violate "no added trailing newline" for any manual page that
308
+ // does not already end in one. A handler performing its own stdout write
309
+ // and returning `{}` is the established escape hatch (see
310
+ // workbench.serve's handler above for the same pattern/reasoning).
311
+ (0, registry_core_1.addCliOnlyCapability)("man", "cw man <topic> — read a manual page from docs/ (raw bytes, no added newline).", {
312
+ path: ["man"],
313
+ jsonMode: "human",
314
+ // core/format/help.ts's COMMAND_HELP_ROWS.man already owns the
315
+ // human-facing "cw man" help line (byte-ported from the old build's
316
+ // orchestrator.ts help table); hiddenFromHelp avoids a duplicate row.
317
+ hiddenFromHelp: true,
318
+ handler: (args) => {
319
+ const topic = args.positionals[0];
320
+ if (!topic) {
321
+ throw new Error("Missing topic.\n Tip: cw man release-tooling for the release tooling manual.");
322
+ }
323
+ process.stdout.write(loadManCli().readManPage(topic));
324
+ return {};
325
+ },
326
+ }, "man is a CLI-only raw-file reader over docs/; the old build never gave it an MCP peer.");
327
+ // ---- info (CLI-only; mirrors app.show with a human card by default) ----
328
+ (0, registry_core_1.addCliOnlyCapability)("info", "Show a workflow app's contract as a human card (or JSON with --json).", {
329
+ path: ["info"],
330
+ jsonMode: "flag",
331
+ handler: (args) => {
332
+ const appId = (0, io_1.required)(args.positionals[0], "workflow app id");
333
+ const data = loadWorkflowAppLoader().showWorkflowApp(appId);
334
+ return { json: data, text: `${(0, help_1.formatInfo)(appId, data)}\n` };
335
+ },
336
+ }, "info is a CLI-only convenience card over app.show; the old build never gave it an MCP peer.");
337
+ // ---- PARITY WIRING -------------------------------------------------------
338
+ //
339
+ // `next` had a raw `case "next"` arm in cli/dispatch.ts (a milestone 3/6
340
+ // PLACEHOLDER that always throws "not implemented in this milestone") but
341
+ // no row in this table's cli binding, so it had no cli-mcp-parity-smoke /
342
+ // cli-jsonmode-parity-smoke coverage. This row makes `next` a real,
343
+ // dual-bound capability (matching the old build's `cli: { path: ["next"],
344
+ // jsonMode: "default" }`) with the SAME placeholder body as the dispatch.ts
345
+ // arm — no new capability logic, just giving the existing placeholder a
346
+ // home in the one data table. dispatchTable() in cli/dispatch.ts tries this
347
+ // row before the switch statement is reached, so the old `case "next"` arm
348
+ // is now dead code for the CLI path (left in place, like the other
349
+ // superseded arms in that file, each with its own "dispatchTable() above
350
+ // always matches first" note).
351
+ (0, registry_core_1.attachCliBinding)("next", {
352
+ path: ["next"],
353
+ jsonMode: "default",
354
+ handler: (args) => ({ json: loadStateCli().nextCli((0, io_1.required)((0, io_1.optionalArg)(args.positionals[0]), "run id"), args.options) }),
355
+ });
356
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("next").mcp.handler = (args) => loadStateCli().nextCli((0, io_1.required)((0, io_1.optionalArg)(args.runId), "run id"), args);
357
+ // `ledger.propose`/`.review`/`.verify`/`.apply`/`.list` are documented
358
+ // payload-probe opt-outs in the old build (each mints a fresh timestamped/
359
+ // digested entry, or reads args that arrive by --file/stdin on the CLI vs
360
+ // a plain `entry` argument over MCP, or reads an on-disk ledger directory
361
+ // the generic probe does not populate) — same reasoning applies here
362
+ // unchanged, since both surfaces still route through the same
363
+ // buildLedgerProposal/buildLedgerReview/verifyLedgerEntry/
364
+ // applyLedgerProposal/listLedgerEntries core. Ported so these rows do not
365
+ // sit unclassified in the payload-identity probe.
366
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.propose").payloadIdentical = false;
367
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.propose").reason =
368
+ "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.";
369
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.review").payloadIdentical = false;
370
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.review").reason =
371
+ "Mints a fresh timestamped/digested verdict each call — non-deterministic output, same reasoning as ledger.propose. Both surfaces call the same buildLedgerReview core.";
372
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.verify").payloadIdentical = false;
373
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.verify").reason =
374
+ "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.";
375
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.apply").payloadIdentical = false;
376
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.apply").reason =
377
+ "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.";
378
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.list").payloadIdentical = false;
379
+ registry_core_1.REGISTRY_BY_CAPABILITY.get("ledger.list").reason =
380
+ "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.";
381
+ // ---------------------------------------------------------------------------
@@ -417,3 +417,7 @@ The one-command `cw -q` headline now routes the question and defaults the repo t
417
417
  0.2.0
418
418
 
419
419
  0.2.1
420
+
421
+ 0.2.2
422
+
423
+ 0.2.3
@@ -80,7 +80,7 @@ Operators can record an unverified selection only with a clear option. That
80
80
  records selection state but does not make the candidate into committed state.
81
81
 
82
82
  Committed state has a harder rule. A candidate can be moved up by
83
- `cw.js commit --candidate` or `cw.js commit --selection` only when it has score
83
+ `cw commit --candidate` or `cw commit --selection` only when it has score
84
84
  evidence, a verified selection, and a linked verifier node with evidence.
85
85
  Rejected, failed, unscored, unselected, and unverified candidates are stopped
86
86
  and produce ErrorFeedback.
@@ -21,7 +21,7 @@ Map out a repository architecture, weigh the risks, check the important
21
21
  findings, and put together an evidence-backed verdict.
22
22
 
23
23
  ```bash
24
- node scripts/cw.js plan architecture-review \
24
+ cw plan architecture-review \
25
25
  --repo /path/to/repo \
26
26
  --question "Is this architecture sound?" \
27
27
  --invariant "public API stays stable" \
@@ -72,7 +72,7 @@ you can act on, patch when `--mode fix` is allowed, check the outcomes, and
72
72
  give a short account with evidence.
73
73
 
74
74
  ```bash
75
- node scripts/cw.js plan pr-review-fix-ci \
75
+ cw plan pr-review-fix-ci \
76
76
  --repo /path/to/repo \
77
77
  --pr 123 \
78
78
  --base main \
@@ -86,7 +86,7 @@ Get a release ready with checklist discipline: version checks, changelog, tests,
86
86
  packaging, release notes, and a last verification.
87
87
 
88
88
  ```bash
89
- node scripts/cw.js plan release-cut \
89
+ cw plan release-cut \
90
90
  --repo /path/to/repo \
91
91
  --version 0.1.13 \
92
92
  --previousVersion 0.1.11 \
@@ -104,7 +104,7 @@ papers — not only a git code repo. The working directory is the corpus,
104
104
  so the agent can back its answer with your own files.
105
105
 
106
106
  ```bash
107
- node scripts/cw.js plan research-synthesis \
107
+ cw plan research-synthesis \
108
108
  --cwd /tmp/research-run \
109
109
  --question "What does the evidence support?" \
110
110
  --source "official-docs" \
@@ -179,8 +179,8 @@ easy to inspect, and useful.
179
179
  Use the Operator UX commands to look at any canonical app run:
180
180
 
181
181
  ```bash
182
- node scripts/cw.js status <run-id>
183
- node scripts/cw.js graph <run-id>
184
- node scripts/cw.js report <run-id> --summary
182
+ cw status <run-id>
183
+ cw graph <run-id>
184
+ cw report <run-id> --summary
185
185
  ```
186
186
  0.1.51
@@ -1,7 +1,7 @@
1
1
  # CLI ↔ MCP Parity
2
2
 
3
3
  CW v0.1.27 adds CLI ↔ MCP Parity. CW has two front doors. The CLI
4
- (`node scripts/cw.js ...`, `dist/cli.js`) is built for human speed: short,
4
+ (`cw ...`, `dist/cli.js`) is built for human speed: short,
5
5
  easy-to-read text with exit codes that have clear sense. The MCP server
6
6
  (`cw_*` JSON-RPC tools) is built for machine context: full, fixed, ordered JSON.
7
7
  This release makes the two doors two views of one body of data — named, made from
@@ -82,7 +82,7 @@ relationship. `identical` means `cw <cmd> --json` is equal to the `cw_<tool>`
82
82
  payload; `projected` means a declared divergence with a reason; `cli-only` marks
83
83
  a surface-specific capability with a recorded reason. The matrix is
84
84
  <!-- gen:parity:count -->
85
- machine-complete by design: 237 capabilities, 196 MCP tools.
85
+ machine-complete by design: 241 capabilities, 198 MCP tools.
86
86
  <!-- /gen:parity:count -->
87
87
 
88
88
  <!-- gen:parity:table -->
@@ -172,6 +172,7 @@ machine-complete by design: 237 capabilities, 196 MCP tools.
172
172
  | `coordinator.decision` | `cw coordinator decision` | `cw_coordinator_decision` | `coordinator.decision` | both | identical |
173
173
  | `audit.summary` | `cw audit summary` | `cw_audit_summary` | `audit.summary` | both | identical |
174
174
  | `audit.verify` | `cw audit verify` | `cw_audit_verify` | `audit.verify` | both | identical |
175
+ | `audit.repair` | `cw audit repair` | `cw_audit_repair` | `audit.repair` | both | identical |
175
176
  | `audit.worker` | `cw audit worker` | `cw_audit_worker` | `audit.worker` | both | identical |
176
177
  | `audit.provenance` | `cw audit provenance` | `cw_audit_provenance` | `audit.provenance` | both | identical |
177
178
  | `audit.multi-agent` | `cw audit multi-agent` | `cw_audit_multi_agent` | `audit.multi-agent` | both | identical |
@@ -284,7 +285,10 @@ machine-complete by design: 237 capabilities, 196 MCP tools.
284
285
  | `orphans.gc` | `cw orphans gc` | `cw_orphans_gc` | `orphans.gc` | both | projected |
285
286
  | `telemetry.verify` | `cw telemetry verify` | `cw_telemetry_verify` | `telemetry.verify` | both | identical |
286
287
  | `history` | `cw history` | `cw_history` | `history` | both | identical |
288
+ | `audit.head` | `cw audit head` | `cw_audit_head` | `audit.head` | both | identical |
287
289
  | `version` | `cw version` | `—` | `version` | cli-only | cli-only |
290
+ | `completion` | `cw completion` | `—` | `completion` | cli-only | cli-only |
291
+ | `search` | `cw search` | `—` | `search` | cli-only | cli-only |
288
292
  | `doctor` | `cw doctor` | `—` | `doctor` | cli-only | cli-only |
289
293
  | `fix` | `cw fix` | `—` | `fix` | cli-only | cli-only |
290
294
  | `quickstart` | `cw quickstart` | `—` | `quickstart` | cli-only | cli-only |
@@ -339,9 +343,11 @@ A capability may be on one surface only, but never without word of it — it mus
339
343
  carry a recorded reason in the registry.
340
344
 
341
345
  <!-- gen:parity:cliOnly -->
342
- 41 capabilities are CLI-only:
346
+ 43 capabilities are CLI-only:
343
347
 
344
348
  - `version` — version is a local, no-run-state print; the old build never gave it an MCP peer.
349
+ - `completion` — shell-completion output is a script for the user's OWN shell to source, not data an MCP client could use — CLI-only, same reasoning as doctor/fix.
350
+ - `search` — CLI-only discovery helper over the same real app data cw list shows; no MCP client needs a free-text search tool alongside cw_list's structured output.
345
351
  - `doctor` — 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`.
346
352
  - `fix` — Environment fix commands are local diagnostics, same reasoning as doctor.
347
353
  - `quickstart` — 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.
@@ -628,3 +634,7 @@ CLI golden-path fixes: `cw -q "…"` routes the question (was read as an app id
628
634
  0.2.0
629
635
 
630
636
  0.2.1
637
+
638
+ 0.2.2
639
+
640
+ 0.2.3
@@ -177,3 +177,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
177
177
  0.2.0
178
178
 
179
179
  0.2.1
180
+
181
+ 0.2.2
182
+
183
+ 0.2.3
@@ -161,3 +161,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
161
161
  0.2.0
162
162
 
163
163
  0.2.1
164
+
165
+ 0.2.2
166
+
167
+ 0.2.3
@@ -119,18 +119,18 @@ required role memberships have no blackboard message or artifact refs.
119
119
  ## CLI
120
120
 
121
121
  ```bash
122
- node scripts/cw.js blackboard summary <run-id>
123
- node scripts/cw.js blackboard graph <run-id>
124
- node scripts/cw.js blackboard resolve <run-id> --id bb --title "Shared state"
125
- node scripts/cw.js blackboard topic create <run-id> --id topic --title "Synthesis"
126
- node scripts/cw.js blackboard message post <run-id> --topic topic --body "..."
127
- node scripts/cw.js blackboard message list <run-id> [--topic topic]
128
- node scripts/cw.js blackboard context put <run-id> --topic topic --kind fact --key k --value v
129
- node scripts/cw.js blackboard artifact add <run-id> --topic topic --path result.md --kind worker-result
130
- node scripts/cw.js blackboard artifact list <run-id>
131
- node scripts/cw.js blackboard snapshot <run-id>
132
- node scripts/cw.js coordinator summary <run-id>
133
- node scripts/cw.js coordinator decision <run-id> --kind conflict-resolution --outcome accepted --reason "..."
122
+ cw blackboard summary <run-id>
123
+ cw blackboard graph <run-id>
124
+ cw blackboard resolve <run-id> --id bb --title "Shared state"
125
+ cw blackboard topic create <run-id> --id topic --title "Synthesis"
126
+ cw blackboard message post <run-id> --topic topic --body "..."
127
+ cw blackboard message list <run-id> [--topic topic]
128
+ cw blackboard context put <run-id> --topic topic --kind fact --key k --value v
129
+ cw blackboard artifact add <run-id> --topic topic --path result.md --kind worker-result
130
+ cw blackboard artifact list <run-id>
131
+ cw blackboard snapshot <run-id>
132
+ cw coordinator summary <run-id>
133
+ cw coordinator decision <run-id> --kind conflict-resolution --outcome accepted --reason "..."
134
134
  ```
135
135
 
136
136
  The CLI gives JSON by default for focused blackboard and coordinator
@@ -167,11 +167,11 @@ suggested action.
167
167
  Use:
168
168
 
169
169
  ```bash
170
- node scripts/cw.js status <run-id>
171
- node scripts/cw.js graph <run-id>
172
- node scripts/cw.js report <run-id> --show
173
- node scripts/cw.js audit summary <run-id>
174
- node scripts/cw.js audit provenance <run-id>
170
+ cw status <run-id>
171
+ cw graph <run-id>
172
+ cw report <run-id> --show
173
+ cw audit summary <run-id>
174
+ cw audit provenance <run-id>
175
175
  ```
176
176
 
177
177
  ## Migration
@@ -54,22 +54,22 @@ commit/checkpoint provenance.
54
54
  Use the standard operator commands:
55
55
 
56
56
  ```bash
57
- node scripts/cw.js status <run-id>
58
- node scripts/cw.js graph <run-id>
59
- node scripts/cw.js report <run-id> --show
60
- node scripts/cw.js worker summary <run-id>
61
- node scripts/cw.js candidate summary <run-id>
62
- node scripts/cw.js feedback summary <run-id>
63
- node scripts/cw.js commit summary <run-id>
57
+ cw status <run-id>
58
+ cw graph <run-id>
59
+ cw report <run-id> --show
60
+ cw worker summary <run-id>
61
+ cw candidate summary <run-id>
62
+ cw feedback summary <run-id>
63
+ cw commit summary <run-id>
64
64
  ```
65
65
 
66
66
  Inspect trust records:
67
67
 
68
68
  ```bash
69
- node scripts/cw.js audit summary <run-id>
70
- node scripts/cw.js audit provenance <run-id>
71
- node scripts/cw.js audit provenance <run-id> --candidate dogfood-release-0.1.18
72
- node scripts/cw.js audit provenance <run-id> --commit <commit-id>
69
+ cw audit summary <run-id>
70
+ cw audit provenance <run-id>
71
+ cw audit provenance <run-id> --candidate dogfood-release-0.1.18
72
+ cw audit provenance <run-id> --commit <commit-id>
73
73
  ```
74
74
 
75
75
  The report tells why the candidate is trusted by showing sandbox profiles,
@@ -45,6 +45,26 @@ not just within one: a newly-added queue task can no longer go missing under a
45
45
  concurrent drain, and two reclaimers can no longer lose a tombstone
46
46
  (freed-without-proof).
47
47
 
48
+ ### The whole-cycle run-state lock (unreleased)
49
+
50
+ `saveCheckpoint` locks only the WRITE of `state.json`. A verb that does
51
+ load → change → save on its own left a window where two processes both
52
+ load the same state and the later save silently drops the earlier change
53
+ — the same lost-update class the v0.2.1 fix closed for `queue.json`
54
+ and `triggers.json`. Two additions close it for the run state itself:
55
+
56
+ - **`withRunStateLock(runId, cwd, fn)`** (run-store) holds the
57
+ `state.json` lock over the whole load → change → save cycle. `fn` gets
58
+ the run loaded UNDER the lock. `cw dispatch` and `cw result` go
59
+ through it, so two `cw result` calls for two tasks of the same run can
60
+ no longer lose a completion. Keep `fn` short: a critical section past
61
+ the 30 s steal window can be stolen.
62
+ - **`withFileLock` is now re-entrant inside one process**: a nested call
63
+ on the same target runs its `fn` under the already-held lock instead
64
+ of waiting on its own lockfile until the tries run out. Save paths
65
+ inside `fn` (`saveCheckpoint`, worker-failure persists) keep their own
66
+ lock calls unchanged. Cross-process behavior is untouched.
67
+
48
68
  ## Reclamation durability (the write-ahead seam, v0.1.40)
49
69
 
50
70
  The v0.1.39 reclamation transaction proved the *tombstone* crash-safe, but the
@@ -160,3 +180,7 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
160
180
  0.2.0
161
181
 
162
182
  0.2.1
183
+
184
+ 0.2.2
185
+
186
+ 0.2.3