cool-workflow 0.1.92 → 0.1.93

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 (73) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +104 -129
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/architecture-review-fast/workflow.js +15 -2
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/capability-core.js +47 -0
  12. package/dist/capability-registry.js +2 -0
  13. package/dist/cli/command-surface.js +165 -1352
  14. package/dist/cli/format.js +56 -0
  15. package/dist/cli/handlers/audit.js +82 -0
  16. package/dist/cli/handlers/blackboard.js +81 -0
  17. package/dist/cli/handlers/candidate.js +40 -0
  18. package/dist/cli/handlers/clones.js +34 -0
  19. package/dist/cli/handlers/collaboration.js +61 -0
  20. package/dist/cli/handlers/eval.js +40 -0
  21. package/dist/cli/handlers/maintenance.js +107 -0
  22. package/dist/cli/handlers/multi-agent.js +165 -0
  23. package/dist/cli/handlers/node.js +41 -0
  24. package/dist/cli/handlers/operational.js +155 -0
  25. package/dist/cli/handlers/operator.js +146 -0
  26. package/dist/cli/handlers/registry.js +68 -0
  27. package/dist/cli/handlers/run.js +153 -0
  28. package/dist/cli/handlers/scheduling.js +126 -0
  29. package/dist/cli/handlers/workbench.js +41 -0
  30. package/dist/cli/handlers/worker.js +45 -0
  31. package/dist/cli/io.js +27 -0
  32. package/dist/cli/run-summary.js +45 -0
  33. package/dist/commit.js +0 -5
  34. package/dist/execution-backend.js +0 -11
  35. package/dist/mcp/tool-call.js +2 -0
  36. package/dist/mcp/tool-definitions.js +8 -0
  37. package/dist/orchestrator/app-operations.js +205 -0
  38. package/dist/orchestrator.js +41 -153
  39. package/dist/state-explosion.js +0 -7
  40. package/dist/term.js +0 -18
  41. package/dist/validation.js +0 -21
  42. package/dist/version.js +1 -1
  43. package/docs/agent-delegation-drive.7.md +1 -1
  44. package/docs/cli-mcp-parity.7.md +17 -2
  45. package/docs/contract-migration-tooling.7.md +1 -1
  46. package/docs/control-plane-scheduling.7.md +1 -1
  47. package/docs/durable-state-and-locking.7.md +1 -1
  48. package/docs/evidence-adoption-reasoning-chain.7.md +1 -1
  49. package/docs/execution-backends.7.md +1 -1
  50. package/docs/mcp-app-surface.7.md +12 -0
  51. package/docs/multi-agent-cli-mcp-surface.7.md +1 -1
  52. package/docs/multi-agent-eval-replay-harness.7.md +1 -1
  53. package/docs/multi-agent-operator-ux.7.md +1 -1
  54. package/docs/node-snapshot-diff-replay.7.md +1 -1
  55. package/docs/observability-cost-accounting.7.md +1 -1
  56. package/docs/project-index.md +13 -3
  57. package/docs/real-execution-backends.7.md +1 -1
  58. package/docs/release-and-migration.7.md +1 -1
  59. package/docs/release-tooling.7.md +1 -1
  60. package/docs/run-registry-control-plane.7.md +25 -3
  61. package/docs/run-retention-reclamation.7.md +1 -1
  62. package/docs/state-explosion-management.7.md +1 -1
  63. package/docs/team-collaboration.7.md +1 -1
  64. package/docs/web-desktop-workbench.7.md +1 -1
  65. package/manifest/plugin.manifest.json +1 -1
  66. package/package.json +1 -1
  67. package/scripts/architecture-review-fast.js +19 -5
  68. package/scripts/bump-version.js +16 -0
  69. package/scripts/canonical-apps.js +4 -4
  70. package/scripts/dogfood-release.js +1 -1
  71. package/scripts/golden-path.js +4 -4
  72. package/scripts/parity-check.js +9 -1
  73. package/scripts/version-sync-check.js +5 -0
@@ -232,4 +232,16 @@ The CLI is still the easiest way for people to drive a run. MCP is the steady
232
232
  tool surface for agent hosts. New runtime powers should come up in both
233
233
  surfaces, keep old names as aliases or wrappers, and use clear JSON
234
234
  contracts in place of host-specific policy hidden in the bridge.
235
+
236
+ ## Implementation
237
+
238
+ The app-management surface (`listWorkflows`, `listApps`, `showApp`,
239
+ `validateApp`, `initApp`, `packageApp`) lives on the `CoolWorkflowRunner`
240
+ facade as thin delegators with no logic of their own. Their bodies sit in
241
+ `src/orchestrator/app-operations.ts` as pure functions — the same v0.1.40
242
+ router pattern used by the other `src/orchestrator/*-operations.ts` modules.
243
+ The runner-owned calls (`resolveFromBase`, `validateApp`) are passed in as
244
+ callbacks so the moved bodies stay byte-for-byte the same. The public method
245
+ names, signatures, and return types do not change, so the CLI/MCP parity gate
246
+ stays green.
235
247
  0.1.51
@@ -304,4 +304,4 @@ The host-facing surface tracks the CLI golden-path fixes (`cw -q` routing + repo
304
304
 
305
305
  0.1.91
306
306
 
307
- 0.1.92
307
+ 0.1.93
@@ -338,4 +338,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
338
338
 
339
339
  0.1.91
340
340
 
341
- 0.1.92
341
+ 0.1.93
@@ -350,4 +350,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
350
350
 
351
351
  0.1.91
352
352
 
353
- 0.1.92
353
+ 0.1.93
@@ -171,4 +171,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
171
171
 
172
172
  0.1.91
173
173
 
174
- 0.1.92
174
+ 0.1.93
@@ -230,4 +230,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
230
230
 
231
231
  0.1.91
232
232
 
233
- 0.1.92
233
+ 0.1.93
@@ -1,15 +1,15 @@
1
1
  # Cool Workflow Project Index
2
2
 
3
- Generated from the current repository code on 2026-06-21 by `npm run sync:project-index`.
3
+ Generated from the current repository code on 2026-06-25 by `npm run sync:project-index`.
4
4
 
5
5
  ## Snapshot
6
6
 
7
7
  - Package: `cool-workflow`
8
- - Version: `0.1.92`
8
+ - Version: `0.1.93`
9
9
  - Source modules: `68`
10
10
  - Workflow apps: `7`
11
11
  - Docs: `53`
12
- - Smoke tests: `139`
12
+ - Smoke tests: `149`
13
13
  - Repository: https://github.com/coo1white/cool-workflow
14
14
 
15
15
  ## Architecture
@@ -196,6 +196,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
196
196
  - [agent-delegation-drive-smoke.js](../test/agent-delegation-drive-smoke.js)
197
197
  - [append-run-node-no-realloc-smoke.js](../test/append-run-node-no-realloc-smoke.js)
198
198
  - [architecture-review-fast-automation-smoke.js](../test/architecture-review-fast-automation-smoke.js)
199
+ - [architecture-review-fast-phase-cache-smoke.js](../test/architecture-review-fast-phase-cache-smoke.js)
199
200
  - [architecture-review-fast-smoke.js](../test/architecture-review-fast-smoke.js)
200
201
  - [artifact-integrity-smoke.js](../test/artifact-integrity-smoke.js)
201
202
  - [audit-verify-smoke.js](../test/audit-verify-smoke.js)
@@ -209,6 +210,12 @@ Smoke tests mirror the public contracts. The high-signal suites are:
209
210
  - [claude-p-agent-wrapper-smoke.js](../test/claude-p-agent-wrapper-smoke.js)
210
211
  - [cli-arg-parsing-smoke.js](../test/cli-arg-parsing-smoke.js)
211
212
  - [cli-command-surface-smoke.js](../test/cli-command-surface-smoke.js)
213
+ - [cli-format-smoke.js](../test/cli-format-smoke.js)
214
+ - [cli-handler-clones-smoke.js](../test/cli-handler-clones-smoke.js)
215
+ - [cli-handler-eval-node-smoke.js](../test/cli-handler-eval-node-smoke.js)
216
+ - [cli-handler-maintenance-smoke.js](../test/cli-handler-maintenance-smoke.js)
217
+ - [cli-handler-workbench-smoke.js](../test/cli-handler-workbench-smoke.js)
218
+ - [cli-io-smoke.js](../test/cli-io-smoke.js)
212
219
  - [cli-jsonmode-parity-smoke.js](../test/cli-jsonmode-parity-smoke.js)
213
220
  - [cli-mcp-parity-smoke.js](../test/cli-mcp-parity-smoke.js)
214
221
  - [cli-progress-summary-smoke.js](../test/cli-progress-summary-smoke.js)
@@ -222,6 +229,8 @@ Smoke tests mirror the public contracts. The high-signal suites are:
222
229
  - [contract-migration-tooling-smoke.js](../test/contract-migration-tooling-smoke.js)
223
230
  - [control-plane-scheduling-smoke.js](../test/control-plane-scheduling-smoke.js)
224
231
  - [coordinator-blackboard-smoke.js](../test/coordinator-blackboard-smoke.js)
232
+ - [cw-help-per-command-smoke.js](../test/cw-help-per-command-smoke.js)
233
+ - [dead-export-removal-guard-smoke.js](../test/dead-export-removal-guard-smoke.js)
225
234
  - [demo-bundle-smoke.js](../test/demo-bundle-smoke.js)
226
235
  - [det-ids-b-smoke.js](../test/det-ids-b-smoke.js)
227
236
  - [doctor-smoke.js](../test/doctor-smoke.js)
@@ -301,6 +310,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
301
310
  - [run-import-tamper-failclosed-smoke.js](../test/run-import-tamper-failclosed-smoke.js)
302
311
  - [run-inspect-archive-smoke.js](../test/run-inspect-archive-smoke.js)
303
312
  - [run-registry-control-plane-smoke.js](../test/run-registry-control-plane-smoke.js)
313
+ - [run-restore-failclosed-smoke.js](../test/run-restore-failclosed-smoke.js)
304
314
  - [run-resume-drive-smoke.js](../test/run-resume-drive-smoke.js)
305
315
  - [run-retention-reclamation-smoke.js](../test/run-retention-reclamation-smoke.js)
306
316
  - [sample-determinism-smoke.js](../test/sample-determinism-smoke.js)
@@ -178,4 +178,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
178
178
 
179
179
  0.1.91
180
180
 
181
- 0.1.92
181
+ 0.1.93
@@ -318,4 +318,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
318
318
 
319
319
  0.1.91
320
320
 
321
- 0.1.92
321
+ 0.1.93
@@ -265,4 +265,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
265
265
 
266
266
  0.1.91
267
267
 
268
- 0.1.92
268
+ 0.1.93
@@ -216,9 +216,30 @@ before importing a bad archive. It is a true preview of import: under
216
216
  turn away) also inspects as `ok:false`; with the env unset (default) an absent integrity
217
217
  block is only reported, not failed.
218
218
 
219
+ **Restore in one fail-closed step.** `run restore PATH --target DIR [--json]`
220
+ does the whole move-a-run-to-another-machine flow as ONE atomic, fail-closed
221
+ step: it integrity-**inspects** the bundle first (writing nothing), **imports**
222
+ it, then reuses the verification `import` already ran — and reports `ok:true`
223
+ ONLY when that verify passes. This closes a real gap: `run import` runs a
224
+ verification (it re-proves restored file digests, the **telemetry ledger**, and
225
+ the **trust-audit hash chain**) and reports it, but does NOT fail on it — it
226
+ exits `0` even when that chain does not verify. So a run whose telemetry or
227
+ trust-audit chain was tampered (yet whose file digests are intact) imports with a
228
+ made-up success. `run restore` refuses exactly that: it fails closed on the same
229
+ verification `import` only reports. A bundle that fails the up-front integrity
230
+ inspect is refused **before any import**, so nothing is written and the run is
231
+ never left part-restored; the result carries `imported:null` and `verify:null`.
232
+ A bundle that imports but fails post-import verification is reported with
233
+ `ok:false` too. It exits `1` whenever `ok:false`, so `cw run restore <path>` is a
234
+ single command that either lands a fully-proven run or refuses with a non-zero
235
+ exit — never a made-up success. The result is structured
236
+ (`{ schemaVersion, ok, target, inspect, imported, verify, registry }`) so it is
237
+ scriptable. `run import` and `run inspect-archive` are unchanged; restore is a
238
+ thin composition of `inspectArchive` + `importRun` (reusing its verification).
239
+
219
240
  MCP gives the same mechanisms as `cw_run_export`, `cw_run_import`,
220
- `cw_run_verify_import`, and `cw_run_inspect_archive`; the CLI and MCP paths share
221
- the same runtime functions.
241
+ `cw_run_verify_import`, `cw_run_inspect_archive`, and `cw_run_restore`; the CLI
242
+ and MCP paths share the same runtime functions.
222
243
 
223
244
  ## Cross-repo history
224
245
 
@@ -243,6 +264,7 @@ node scripts/cw.js run export <run-id> --output PATH
243
264
  node scripts/cw.js run import PATH --target DIR
244
265
  node scripts/cw.js run verify-import <run-id> [--cwd DIR]
245
266
  node scripts/cw.js run inspect-archive PATH [--json]
267
+ node scripts/cw.js run restore PATH --target DIR [--json]
246
268
  node scripts/cw.js queue add [--app ID|--workflow ID|--runId ID] [--repo PATH] [--priority N] [--note TEXT]
247
269
  node scripts/cw.js queue list [--status STATE] [--repo PATH] [--json]
248
270
  node scripts/cw.js queue show <queue-id>
@@ -439,4 +461,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
439
461
 
440
462
  0.1.91
441
463
 
442
- 0.1.92
464
+ 0.1.93
@@ -229,4 +229,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
229
229
 
230
230
  0.1.91
231
231
 
232
- 0.1.92
232
+ 0.1.93
@@ -307,4 +307,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
307
307
 
308
308
  0.1.91
309
309
 
310
- 0.1.92
310
+ 0.1.93
@@ -243,4 +243,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
243
243
 
244
244
  0.1.91
245
245
 
246
- 0.1.92
246
+ 0.1.93
@@ -251,4 +251,4 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
251
251
 
252
252
  0.1.91
253
253
 
254
- 0.1.92
254
+ 0.1.93
@@ -2,7 +2,7 @@
2
2
  "_comment": "SINGLE SOURCE OF TRUTH for every vendor manifest. Edit THIS file, then run `npm run gen:manifests`. Do NOT hand-edit the generated vendor manifests (.claude-plugin/, .codex-plugin/, .agents/, .mcp.json) — `npm run gen:manifests -- --check` (run by release:check) will fail if they drift from this source.",
3
3
  "identity": {
4
4
  "name": "cool-workflow",
5
- "version": "0.1.92",
5
+ "version": "0.1.93",
6
6
  "license": "BSD-2-Clause",
7
7
  "homepage": "https://github.com/coo1white/cool-workflow",
8
8
  "author": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cool-workflow",
3
- "version": "0.1.92",
3
+ "version": "0.1.93",
4
4
  "bin": {
5
5
  "cool-workflow": "scripts/cw.js",
6
6
  "cw": "scripts/cw.js"
@@ -38,13 +38,20 @@ function main() {
38
38
  const fastModel = stringArg(args.fastModel || args["fast-model"]);
39
39
  const strongModel = stringArg(args.strongModel || args["strong-model"]);
40
40
  const modelEnv = modelPolicyEnv(fastModel, strongModel);
41
+ // Opt-in incremental overlay: scope the exported source context to files
42
+ // changed since REF (e.g. origin/main). The source-context export resolves
43
+ // the ref, keys its cache separately, and records the base. The fast review
44
+ // then runs over the narrower context; the scheduled full review stays a
45
+ // complete audit (see scheduleFullReview).
46
+ const changedFrom = stringArg(args.changedFrom || args["changed-from"]);
41
47
 
42
48
  const contextExport = timed(() => exportSourceContext({
43
49
  repo,
44
50
  profile,
45
51
  ref,
46
52
  profileFile,
47
- cacheDir
53
+ cacheDir,
54
+ changedFrom
48
55
  }));
49
56
  const contextText = contextExport.value;
50
57
  assertNonEmptySourceContext(contextText, profile, repo);
@@ -87,7 +94,8 @@ function main() {
87
94
  digest,
88
95
  profile,
89
96
  ref,
90
- cacheDir
97
+ cacheDir,
98
+ ...(changedFrom ? { changedFrom } : {})
91
99
  };
92
100
  const fullReviewScheduleRun = truthy(args.scheduleFull || args["schedule-full"])
93
101
  ? timed(() => scheduleFullReview(repo, question, args, fastReview, sourceContextMeta))
@@ -101,7 +109,7 @@ function main() {
101
109
  fastReview,
102
110
  ...(fastModel || strongModel ? { modelPolicy: { ...(fastModel ? { fastModel } : {}), ...(strongModel ? { strongModel } : {}) } } : {}),
103
111
  ...(fullReviewSchedule ? { fullReviewSchedule } : {}),
104
- ...(includeMetrics ? { metrics: buildMetrics(started, contextText, contextExport.elapsedMs, fastReview, fastReviewRun.elapsedMs, fullReviewScheduleRun?.elapsedMs) } : {})
112
+ ...(includeMetrics ? { metrics: buildMetrics(started, contextText, contextExport.elapsedMs, fastReview, fastReviewRun.elapsedMs, fullReviewScheduleRun?.elapsedMs, changedFrom) } : {})
105
113
  });
106
114
  }
107
115
 
@@ -119,6 +127,7 @@ function exportSourceContext(options) {
119
127
  options.cacheDir
120
128
  ];
121
129
  if (options.profileFile) argv.push("--profile-file", path.resolve(options.profileFile));
130
+ if (options.changedFrom) argv.push("--changed-from", options.changedFrom);
122
131
  const result = spawnSync(node, argv, {
123
132
  cwd: repoRoot,
124
133
  encoding: "utf8",
@@ -194,6 +203,9 @@ function scheduleFullReview(repo, question, args, fastReview, sourceContextMeta)
194
203
  fastReview?.reportPath ? `Fast review report: ${fastReview.reportPath}.` : "",
195
204
  `Fast review status: ${fastReview?.status || "unknown"} (${fastReview?.completedWorkers || 0}/${fastReview?.plannedWorkers || 0} workers completed).`,
196
205
  `Source context: ${sourceContextMeta.path} (${sourceContextMeta.digest}, profile ${sourceContextMeta.profile}, ref ${sourceContextMeta.ref}).`,
206
+ sourceContextMeta.changedFrom
207
+ ? `Fast review used an incremental overlay (changed-from ${sourceContextMeta.changedFrom}); this full review must audit the complete source, not only the changed files.`
208
+ : "",
197
209
  "Use the completed architecture-review-fast report as the foreground triage result; write the full review report path and digest when the background review finishes."
198
210
  ].filter(Boolean).join(" ");
199
211
  return runCwJson([
@@ -304,7 +316,7 @@ function timed(fn) {
304
316
  return { value, elapsedMs: elapsedMs(started) };
305
317
  }
306
318
 
307
- function buildMetrics(started, contextText, sourceContextElapsedMs, fastReview, fastReviewElapsedMs, fullReviewScheduleElapsedMs) {
319
+ function buildMetrics(started, contextText, sourceContextElapsedMs, fastReview, fastReviewElapsedMs, fullReviewScheduleElapsedMs, changedFrom) {
308
320
  const steps = Array.isArray(fastReview?.steps) ? fastReview.steps : [];
309
321
  const handleKinds = countBy(steps.map((step) => step && step.handleKind).filter(Boolean));
310
322
  const actions = countBy(steps.map((step) => step && step.action).filter(Boolean));
@@ -314,7 +326,8 @@ function buildMetrics(started, contextText, sourceContextElapsedMs, fastReview,
314
326
  sourceContext: {
315
327
  elapsedMs: sourceContextElapsedMs,
316
328
  bytes: Buffer.byteLength(contextText, "utf8"),
317
- digest: `sha256:${crypto.createHash("sha256").update(contextText, "utf8").digest("hex")}`
329
+ digest: `sha256:${crypto.createHash("sha256").update(contextText, "utf8").digest("hex")}`,
330
+ ...(changedFrom ? { changedFrom } : {})
318
331
  },
319
332
  fastReview: {
320
333
  elapsedMs: fastReviewElapsedMs,
@@ -388,6 +401,7 @@ function usage(code) {
388
401
  "",
389
402
  "options:",
390
403
  " --profile core --ref HEAD --profile-file PATH --cache-dir DIR --context-out PATH",
404
+ " --changed-from REF (incremental overlay: scope context to files changed since REF)",
391
405
  " --fast-model MODEL --strong-model MODEL",
392
406
  " --invariant TEXT --focus TEXT --preview --once",
393
407
  " --schedule-full [--full-delay-minutes N]",
@@ -143,6 +143,22 @@ function main() {
143
143
  note(rel);
144
144
  }
145
145
 
146
+ // 5c. Homebrew formula (repo root, not under pluginRoot). Structured surface:
147
+ // a git-tag formula with no sha256. Homebrew reads the version from the
148
+ // tag, so the ONLY literal that moves is `tag: "v<version>"` (an explicit
149
+ // `version` line would be redundant and brew audit rejects it). A targeted
150
+ // exact-string swap keeps the file byte-formatting intact;
151
+ // version-sync-check.js asserts the tag at HEAD, so it can never drift.
152
+ const formula = path.join(repoRoot, "Formula", "cool-workflow.rb");
153
+ if (fs.existsSync(formula)) {
154
+ const text = fs.readFileSync(formula, "utf8");
155
+ const updated = text.split(`tag: "v${current}"`).join(`tag: "v${next}"`);
156
+ if (updated !== text) {
157
+ fs.writeFileSync(formula, updated);
158
+ note("Formula/cool-workflow.rb");
159
+ }
160
+ }
161
+
146
162
  process.stdout.write(`bump:version ${current} -> ${next}\n`);
147
163
  for (const rel of touched) process.stdout.write(` updated ${rel}\n`);
148
164
 
@@ -83,7 +83,7 @@ const canonicalApps = [
83
83
  "--source",
84
84
  "plugins/cool-workflow/docs/workflow-app-framework.7.md",
85
85
  "--scope",
86
- "Cool Workflow v0.1.92",
86
+ "Cool Workflow v0.1.93",
87
87
  "--freshness",
88
88
  "as of release preparation"
89
89
  ]
@@ -117,14 +117,14 @@ function main() {
117
117
  assert.ok(summary, `${app.id} must appear in app list`);
118
118
  assert.equal(summary.sourceKind, "app-directory");
119
119
  assert.equal(summary.legacy, false);
120
- assert.equal(summary.version, "0.1.92");
120
+ assert.equal(summary.version, "0.1.93");
121
121
 
122
122
  const validation = runJson(["app", "validate", manifestPath]);
123
123
  assert.equal(validation.valid, true, `${app.id} manifest must validate`);
124
124
 
125
125
  const shown = runJson(["app", "show", app.id]);
126
126
  assert.equal(shown.app.id, app.id);
127
- assert.equal(shown.app.version, "0.1.92");
127
+ assert.equal(shown.app.version, "0.1.93");
128
128
  assert.ok(shown.app.metadata.canonical, `${app.id} must be marked canonical`);
129
129
  assert.ok(shown.app.sandboxProfiles.length > 0, `${app.id} must declare sandbox profiles`);
130
130
  assertTaskIdsUnique(shown);
@@ -135,7 +135,7 @@ function main() {
135
135
  const plan = runJson(["plan", app.id, ...app.args(workspace)]);
136
136
  const state = JSON.parse(fs.readFileSync(plan.statePath, "utf8"));
137
137
  assert.equal(state.workflow.app.id, app.id);
138
- assert.equal(state.workflow.app.version, "0.1.92");
138
+ assert.equal(state.workflow.app.version, "0.1.93");
139
139
  assert.equal(state.workflow.app.metadata.canonical, true);
140
140
  assert.ok(state.tasks.some((task) => task.requiresEvidence), `${app.id} plan must include evidence gates`);
141
141
  assert.ok(state.tasks.every((task) => task.sandboxProfileId), `${app.id} plan must include sandbox hints`);
@@ -6,7 +6,7 @@ const fs = require("node:fs");
6
6
  const path = require("node:path");
7
7
  const { CoolWorkflowRunner } = require("../dist/orchestrator.js");
8
8
 
9
- const TARGET_VERSION = "0.1.92";
9
+ const TARGET_VERSION = "0.1.93";
10
10
  const PREVIOUS_VERSION = "0.1.31";
11
11
  const pluginRoot = path.resolve(__dirname, "..");
12
12
  const repoRoot = path.resolve(pluginRoot, "..", "..");
@@ -33,7 +33,7 @@ function main() {
33
33
  const appValidation = runJson(["app", "validate", "end-to-end-golden-path"], pluginRoot);
34
34
  assert.equal(appValidation.valid, true);
35
35
  assert.equal(appValidation.summary.id, "end-to-end-golden-path");
36
- assert.equal(appValidation.summary.version, "0.1.92");
36
+ assert.equal(appValidation.summary.version, "0.1.93");
37
37
 
38
38
  const plan = runJson(
39
39
  [
@@ -42,7 +42,7 @@ function main() {
42
42
  "--repo",
43
43
  tmp,
44
44
  "--question",
45
- "Prove the deterministic v0.1.92 end-to-end golden path."
45
+ "Prove the deterministic v0.1.93 end-to-end golden path."
46
46
  ],
47
47
  pluginRoot
48
48
  );
@@ -52,7 +52,7 @@ function main() {
52
52
 
53
53
  let state = readJson(plan.statePath);
54
54
  assert.equal(state.workflow.app.id, "end-to-end-golden-path");
55
- assert.equal(state.workflow.app.version, "0.1.92");
55
+ assert.equal(state.workflow.app.version, "0.1.93");
56
56
  assert.equal(state.loopStage, "interpret");
57
57
 
58
58
  const dispatch = runJson(["dispatch", plan.runId, "--limit", "1", "--sandbox", "readonly"], tmp);
@@ -195,7 +195,7 @@ function main() {
195
195
  assert.equal(reportPath, plan.reportPath);
196
196
  assert.ok(fs.existsSync(reportPath));
197
197
  const report = fs.readFileSync(reportPath, "utf8");
198
- assert.match(report, /Workflow App: end-to-end-golden-path@0\.1\.92/);
198
+ assert.match(report, /Workflow App: end-to-end-golden-path@0\.1\.93/);
199
199
  assert.match(report, /## Candidates/);
200
200
  assert.match(report, /## Trust Audit/);
201
201
  assert.match(report, /## Acceptance Rationale/);
@@ -69,7 +69,15 @@ function cliDispatchTokens() {
69
69
  }
70
70
 
71
71
  function cliDispatchSources() {
72
- return [cli, path.join(pluginRoot, "dist", "cli", "command-surface.js")].filter((file) => fs.existsSync(file));
72
+ // The dispatcher + every per-command handler module carved out of it (the
73
+ // command-surface god-object decomposition). A verb's subcommand `case`s may
74
+ // live in dist/cli/handlers/<group>.js, so scan those too or their tokens read
75
+ // as "missing from dist/cli.js".
76
+ const handlersDir = path.join(pluginRoot, "dist", "cli", "handlers");
77
+ const handlerFiles = fs.existsSync(handlersDir)
78
+ ? fs.readdirSync(handlersDir).filter((name) => name.endsWith(".js")).map((name) => path.join(handlersDir, name))
79
+ : [];
80
+ return [cli, path.join(pluginRoot, "dist", "cli", "command-surface.js"), ...handlerFiles].filter((file) => fs.existsSync(file));
73
81
  }
74
82
 
75
83
  function cliHelpTokens() {
@@ -196,6 +196,11 @@ function main() {
196
196
  checkIncludes("plugins/cool-workflow/docs/release-and-migration.7.md", VERSION, checks);
197
197
  checkIncludes("CHANGELOG.md", `## ${VERSION}`, checks);
198
198
  checkIncludes("RELEASE.md", VERSION, checks);
199
+ // Homebrew formula (repo root): git-tag formula. Homebrew scans the version
200
+ // from the tag, so the tag is the single version surface to gate (an explicit
201
+ // `version` line would be redundant and brew audit rejects it). bump-version.js
202
+ // moves this tag.
203
+ checkIncludes("Formula/cool-workflow.rb", `tag: "v${VERSION}"`, checks);
199
204
  checkIncludes("plugins/cool-workflow/skills/cool-workflow/SKILL.md", "release:check", checks);
200
205
 
201
206
  process.stdout.write(