cool-workflow 0.2.5 → 0.2.6

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 (80) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.gemini-plugin/plugin.json +1 -1
  4. package/.opencode-plugin/plugin.json +1 -1
  5. package/README.md +5 -3
  6. package/apps/architecture-review/app.json +1 -1
  7. package/apps/architecture-review-fast/app.json +1 -1
  8. package/apps/end-to-end-golden-path/app.json +1 -1
  9. package/apps/pr-review-fix-ci/app.json +1 -1
  10. package/apps/release-cut/app.json +1 -1
  11. package/apps/research-synthesis/app.json +1 -1
  12. package/dist/core/state/run-paths.js +3 -30
  13. package/dist/core/version.js +1 -1
  14. package/dist/mcp/server.js +95 -27
  15. package/dist/mcp/tool-process.js +181 -0
  16. package/dist/mcp-server.js +8 -1
  17. package/dist/shell/agent-config.js +11 -2
  18. package/dist/shell/audit-cli.js +1 -1
  19. package/dist/shell/drive.js +99 -89
  20. package/dist/shell/execution-backend/agent.js +18 -15
  21. package/dist/shell/execution-backend/local.js +1 -0
  22. package/dist/shell/fs-atomic.js +3 -0
  23. package/dist/shell/metrics-cli.js +1 -1
  24. package/dist/shell/multi-agent-cli.js +4 -1
  25. package/dist/shell/multi-agent-operator-ux.js +1 -1
  26. package/dist/shell/observability.js +7 -4
  27. package/dist/shell/operator-ux.js +1 -1
  28. package/dist/shell/perf-trace.js +136 -0
  29. package/dist/shell/pipeline.js +1 -1
  30. package/dist/shell/report-view-cli.js +2 -0
  31. package/dist/shell/run-export-cli.js +5 -2
  32. package/dist/shell/run-export.js +241 -27
  33. package/dist/shell/run-registry-io.js +8 -0
  34. package/dist/shell/run-store.js +27 -3
  35. package/dist/shell/state-explosion-cli.js +4 -1
  36. package/dist/shell/telemetry-demo.js +1 -1
  37. package/dist/shell/trust-audit.js +91 -43
  38. package/dist/shell/workbench.js +4 -1
  39. package/dist/wiring/capability-table/parity.js +10 -5
  40. package/docs/agent-delegation-drive.7.md +2 -0
  41. package/docs/cli-mcp-parity.7.md +21 -5
  42. package/docs/contract-migration-tooling.7.md +2 -0
  43. package/docs/control-plane-scheduling.7.md +2 -0
  44. package/docs/durable-state-and-locking.7.md +2 -0
  45. package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
  46. package/docs/execution-backends.7.md +2 -0
  47. package/docs/mcp-app-surface.7.md +21 -0
  48. package/docs/multi-agent-cli-mcp-surface.7.md +2 -0
  49. package/docs/multi-agent-eval-replay-harness.7.md +2 -0
  50. package/docs/multi-agent-operator-ux.7.md +2 -0
  51. package/docs/node-snapshot-diff-replay.7.md +2 -0
  52. package/docs/observability-cost-accounting.7.md +2 -0
  53. package/docs/project-index.md +18 -4
  54. package/docs/real-execution-backends.7.md +2 -0
  55. package/docs/release-and-migration.7.md +2 -0
  56. package/docs/release-tooling.7.md +10 -0
  57. package/docs/run-registry-control-plane.7.md +35 -9
  58. package/docs/run-retention-reclamation.7.md +2 -0
  59. package/docs/state-explosion-management.7.md +2 -0
  60. package/docs/team-collaboration.7.md +2 -0
  61. package/docs/trust-audit-anchor.7.md +2 -0
  62. package/docs/web-desktop-workbench.7.md +48 -0
  63. package/manifest/plugin.manifest.json +1 -1
  64. package/package.json +3 -2
  65. package/scripts/canonical-apps.js +4 -4
  66. package/scripts/dogfood-release.js +1 -1
  67. package/scripts/gen-manifests.js +32 -61
  68. package/scripts/golden-path.js +4 -4
  69. package/scripts/parity-check.js +42 -23
  70. package/scripts/purity-baseline.json +0 -3
  71. package/scripts/release-flow.js +43 -13
  72. package/scripts/release-gate.js +30 -6
  73. package/scripts/schema-version-inventory.json +31 -0
  74. package/scripts/validate-run-state-schema.js +95 -4
  75. package/scripts/verify-release-verdict.js +139 -0
  76. package/ui/workbench/app.css +15 -7
  77. package/ui/workbench/app.js +118 -16
  78. package/ui/workbench/index.html +2 -0
  79. package/ui/workbench/inspection.js +51 -0
  80. package/ui/workbench/navigation.js +44 -0
@@ -413,20 +413,25 @@ function lintRegistry() {
413
413
  }
414
414
  /**
415
415
  * Compare the declared registry against the ACTUAL surfaces and report every
416
- * fail-closed gap. `mcpTools` is the live `tools/list` result; `cliTokens` is the
417
- * set of `case "<token>"` strings parsed from the CLI source.
416
+ * fail-closed gap. `mcpTools` is the live `tools/list` result. `cliTokens` is
417
+ * optional test input for an independent token source; the table-driven live
418
+ * gate leaves it out and probes dispatcher reachability instead.
418
419
  */
419
420
  function buildParityReport(input) {
420
421
  const declaredTools = new Set((0, registry_core_1.declaredMcpTools)());
421
422
  const actualTools = new Set(input.mcpTools);
422
423
  const declaredTokens = new Set(declaredCliTokens());
423
- const actualTokens = new Set(input.cliTokens);
424
+ const actualTokens = new Set(input.cliTokens || []);
424
425
  const declaredHelpTokens = new Set(declaredCliHelpTokens());
425
426
  const actualHelpTokens = new Set(input.helpTokens || []);
426
427
  const missingMcpTools = [...declaredTools].filter((tool) => !actualTools.has(tool)).sort();
427
428
  const undeclaredMcpTools = [...actualTools].filter((tool) => !declaredTools.has(tool)).sort();
428
- const missingCliTokens = [...declaredTokens].filter((token) => !actualTokens.has(token)).sort();
429
- const undeclaredCliTokens = [...actualTokens].filter((token) => !declaredTokens.has(token)).sort();
429
+ const missingCliTokens = input.cliTokens
430
+ ? [...declaredTokens].filter((token) => !actualTokens.has(token)).sort()
431
+ : [];
432
+ const undeclaredCliTokens = input.cliTokens
433
+ ? [...actualTokens].filter((token) => !declaredTokens.has(token)).sort()
434
+ : [];
430
435
  const helpMissingCliTokens = input.helpTokens
431
436
  ? [...declaredHelpTokens].filter((token) => !actualHelpTokens.has(token)).sort()
432
437
  : [];
@@ -438,3 +438,5 @@ The one-command `cw -q` headline now routes the question and defaults the repo t
438
438
  0.2.4
439
439
 
440
440
  0.2.5
441
+
442
+ 0.2.6
@@ -97,6 +97,20 @@ and any other request falls back to the newest supported entry (see
97
97
  `SUPPORTED_PROTOCOL_VERSIONS` in `src/mcp/server.ts`). With today's
98
98
  one-entry list the reply bytes are unchanged.
99
99
 
100
+ ## MCP Tool Authority
101
+
102
+ `CW_MCP_ENABLED_TOOLS` and `CW_MCP_DISABLED_TOOLS` are optional comma lists of
103
+ exact MCP tool names. Space at either end of a name is taken out, and a second
104
+ name has no effect. The enabled list is an allowlist. The disabled list is then
105
+ applied, so deny has the last word. With both values unset, the server keeps its
106
+ full `tools/list` output and present tool access.
107
+
108
+ An empty name or a name not in the live registry stops server start with a
109
+ stderr diagnostic and a non-zero exit. Under a good policy, `tools/list` keeps
110
+ the registry order and shows only allowed tools. A call to a filtered tool gives
111
+ the normal MCP `isError: true` result and does not start its handler. This is a
112
+ server control, not an OS sandbox or an approval system.
113
+
100
114
  ## The Parity Matrix
101
115
 
102
116
  The matrix below is made from the live registry — one row per capability,
@@ -463,11 +477,11 @@ The shared arg helpers (`required`, `optionalArg`, `wantsJson`) live in
463
477
  `src/core/util/cli-args.ts`, a pure module used by the CLI and MCP sides of
464
478
  every wiring slice; they were moved out of `cli/io.ts` because the purity
465
479
  gate's layer rule says `wiring/` may not take imports from `cli/`. The parity
466
- scanner works the same way: `cliDispatchTokens()` gets the live token list
467
- straight from the registry's CLI capabilities (`cli.caseTokens` when a row
468
- names more than one first token, else `cli.path`), then makes sure each
469
- declared path resolves through the live dispatcher there is no grep over
470
- built dispatch source.
480
+ gate does not use a token list made from the registry as proof of that same
481
+ registry. It runs real `cw help`, checks every declared CLI path through the
482
+ dispatcher lookup used by `dispatch(args)`, reads MCP `tools/list` from a live
483
+ server, and runs CLI-process to MCP payload probes. There is no grep over built
484
+ dispatch source.
471
485
 
472
486
  `test/cli-mcp-parity-smoke.js` proves the contract from end to end. It checks
473
487
  registry ⇄ CLI ⇄ MCP coverage (every declared capability is found on its declared
@@ -668,3 +682,5 @@ CLI golden-path fixes: `cw -q "…"` routes the question (was read as an app id
668
682
  0.2.4
669
683
 
670
684
  0.2.5
685
+
686
+ 0.2.6
@@ -185,3 +185,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
185
185
  0.2.4
186
186
 
187
187
  0.2.5
188
+
189
+ 0.2.6
@@ -203,3 +203,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
203
203
  0.2.4
204
204
 
205
205
  0.2.5
206
+
207
+ 0.2.6
@@ -188,3 +188,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
188
188
  0.2.4
189
189
 
190
190
  0.2.5
191
+
192
+ 0.2.6
@@ -329,3 +329,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
329
329
  0.2.4
330
330
 
331
331
  0.2.5
332
+
333
+ 0.2.6
@@ -359,3 +359,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
359
359
  0.2.4
360
360
 
361
361
  0.2.5
362
+
363
+ 0.2.6
@@ -21,6 +21,27 @@ The bridge keeps to CW's base-system rules:
21
21
  protocol errors to the model still lets it read the message and try
22
22
  again
23
23
 
24
+ ## Control and Tool Processes
25
+
26
+ The MCP parent process reads JSON-RPC, writes JSON-RPC, and answers `ping`.
27
+ One child process runs `tools/call` work in order. A file lock wait or a long
28
+ agent call in that child does not stop the parent from answering `ping`.
29
+
30
+ The child sends back the same JSON text that the old in-process tool call gave
31
+ back. Tool names, input names, output shapes, run files, and CLI parity stay
32
+ the same.
33
+
34
+ If the child stops during a tool call, CW gives an `isError: true` result for
35
+ that call. CW does not run the call again, because it may have written part of
36
+ a run. Read the saved run state before you try the call again. The next tool
37
+ call starts a new child process.
38
+
39
+ When stdin ends, CW keeps the ordered tool queue to its end and then stops the
40
+ child. This lets a client send a last batch and close stdin without losing its
41
+ replies. On `SIGINT` or `SIGTERM`, CW stops the child at once and then ends by
42
+ the same signal. A tool waiting on a file lock cannot wake later and write
43
+ state after its parent has ended.
44
+
24
45
  ## App Run Flow
25
46
 
26
47
  Use `cw_app_list`, `cw_app_show`, and `cw_app_validate` to look at app
@@ -335,3 +335,5 @@ The host-facing surface tracks the CLI golden-path fixes (`cw -q` routing + repo
335
335
  0.2.4
336
336
 
337
337
  0.2.5
338
+
339
+ 0.2.6
@@ -361,3 +361,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
361
361
  0.2.4
362
362
 
363
363
  0.2.5
364
+
365
+ 0.2.6
@@ -373,3 +373,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
373
373
  0.2.4
374
374
 
375
375
  0.2.5
376
+
377
+ 0.2.6
@@ -194,3 +194,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
194
194
  0.2.4
195
195
 
196
196
  0.2.5
197
+
198
+ 0.2.6
@@ -254,3 +254,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
254
254
  0.2.4
255
255
 
256
256
  0.2.5
257
+
258
+ 0.2.6
@@ -1,15 +1,15 @@
1
1
  # Cool Workflow Project Index
2
2
 
3
- Generated from the current repository code on 2026-07-13 by `npm run sync:project-index`.
3
+ Generated from the current repository code on 2026-07-14 by `npm run sync:project-index`.
4
4
 
5
5
  ## Snapshot
6
6
 
7
7
  - Package: `cool-workflow`
8
- - Version: `0.2.5`
9
- - Source modules: `151`
8
+ - Version: `0.2.6`
9
+ - Source modules: `153`
10
10
  - Workflow apps: `8`
11
11
  - Docs: `58`
12
- - Smoke tests: `236`
12
+ - Smoke tests: `248`
13
13
  - Repository: https://github.com/coo1white/cool-workflow
14
14
 
15
15
  ## Architecture
@@ -125,6 +125,7 @@ multi-agent host -> topology -> blackboard/coordinator
125
125
  - [core/util/numeric-flag.ts](../src/core/util/numeric-flag.ts)
126
126
  - [mcp/dispatch.ts](../src/mcp/dispatch.ts)
127
127
  - [mcp/server.ts](../src/mcp/server.ts)
128
+ - [mcp/tool-process.ts](../src/mcp/tool-process.ts)
128
129
  - [shell/agent-config.ts](../src/shell/agent-config.ts)
129
130
  - [shell/app-run-cli.ts](../src/shell/app-run-cli.ts)
130
131
  - [shell/audit-cli.ts](../src/shell/audit-cli.ts)
@@ -166,6 +167,7 @@ multi-agent host -> topology -> blackboard/coordinator
166
167
  - [shell/observability.ts](../src/shell/observability.ts)
167
168
  - [shell/onramp.ts](../src/shell/onramp.ts)
168
169
  - [shell/operator-ux-text.ts](../src/shell/operator-ux-text.ts)
170
+ - [shell/perf-trace.ts](../src/shell/perf-trace.ts)
169
171
  - [shell/pipeline-cli.ts](../src/shell/pipeline-cli.ts)
170
172
  - [shell/pipeline.ts](../src/shell/pipeline.ts)
171
173
  - [shell/reclamation-io.ts](../src/shell/reclamation-io.ts)
@@ -282,6 +284,7 @@ multi-agent host -> topology -> blackboard/coordinator
282
284
 
283
285
  Smoke tests mirror the public contracts. The high-signal suites are:
284
286
 
287
+ - [agent-auto-detect-gemini-native-smoke.js](../test/agent-auto-detect-gemini-native-smoke.js)
285
288
  - [agent-backend-concurrent-user-env-smoke.js](../test/agent-backend-concurrent-user-env-smoke.js)
286
289
  - [agent-backend-sandbox-deny-smoke.js](../test/agent-backend-sandbox-deny-smoke.js)
287
290
  - [agent-backend-user-env-smoke.js](../test/agent-backend-user-env-smoke.js)
@@ -382,13 +385,18 @@ Smoke tests mirror the public contracts. The high-signal suites are:
382
385
  - [ledger-verify-smoke.js](../test/ledger-verify-smoke.js)
383
386
  - [loop-bounded-expansion-smoke.js](../test/loop-bounded-expansion-smoke.js)
384
387
  - [man-run-registry-traversal-smoke.js](../test/man-run-registry-traversal-smoke.js)
388
+ - [manifest-vendor-registry-failclosed-smoke.js](../test/manifest-vendor-registry-failclosed-smoke.js)
385
389
  - [mcp-app-surface-smoke.js](../test/mcp-app-surface-smoke.js)
390
+ - [mcp-control-process-responsiveness-smoke.js](../test/mcp-control-process-responsiveness-smoke.js)
386
391
  - [mcp-ping-and-arg-coercion-smoke.js](../test/mcp-ping-and-arg-coercion-smoke.js)
387
392
  - [mcp-protocol-version-smoke.js](../test/mcp-protocol-version-smoke.js)
388
393
  - [mcp-queue-epipe-smoke.js](../test/mcp-queue-epipe-smoke.js)
389
394
  - [mcp-surface-registry-smoke.js](../test/mcp-surface-registry-smoke.js)
395
+ - [mcp-tool-authority-policy-smoke.js](../test/mcp-tool-authority-policy-smoke.js)
390
396
  - [mcp-tool-call-coverage-smoke.js](../test/mcp-tool-call-coverage-smoke.js)
391
397
  - [mcp-tool-call-error-isresult-smoke.js](../test/mcp-tool-call-error-isresult-smoke.js)
398
+ - [mcp-tool-process-lifecycle-smoke.js](../test/mcp-tool-process-lifecycle-smoke.js)
399
+ - [mcp-tool-shutdown-containment-smoke.js](../test/mcp-tool-shutdown-containment-smoke.js)
392
400
  - [mcp-untrusted-content-advisory-smoke.js](../test/mcp-untrusted-content-advisory-smoke.js)
393
401
  - [metrics-summary-limit-smoke.js](../test/metrics-summary-limit-smoke.js)
394
402
  - [missing-artifact-gate-live-smoke.js](../test/missing-artifact-gate-live-smoke.js)
@@ -416,6 +424,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
416
424
  - [operator-ux-smoke.js](../test/operator-ux-smoke.js)
417
425
  - [orphan-runs-gc-smoke.js](../test/orphan-runs-gc-smoke.js)
418
426
  - [parallel-onramp-smoke.js](../test/parallel-onramp-smoke.js)
427
+ - [parity-cli-reachability-smoke.js](../test/parity-cli-reachability-smoke.js)
419
428
  - [parity-doc-sync-smoke.js](../test/parity-doc-sync-smoke.js)
420
429
  - [parse-guard-smoke.js](../test/parse-guard-smoke.js)
421
430
  - [parse-hardening-round2-smoke.js](../test/parse-hardening-round2-smoke.js)
@@ -456,14 +465,17 @@ Smoke tests mirror the public contracts. The high-signal suites are:
456
465
  - [robustness-hardening-smoke.js](../test/robustness-hardening-smoke.js)
457
466
  - [run-all-agent-env-hermetic-smoke.js](../test/run-all-agent-env-hermetic-smoke.js)
458
467
  - [run-all-json-summary-smoke.js](../test/run-all-json-summary-smoke.js)
468
+ - [run-archive-intake-limits-smoke.js](../test/run-archive-intake-limits-smoke.js)
459
469
  - [run-export-cross-machine-smoke.js](../test/run-export-cross-machine-smoke.js)
460
470
  - [run-export-import-smoke.js](../test/run-export-import-smoke.js)
461
471
  - [run-export-restore-rerun-smoke.js](../test/run-export-restore-rerun-smoke.js)
462
472
  - [run-export-restore-resume-smoke.js](../test/run-export-restore-resume-smoke.js)
463
473
  - [run-fixture-compat-smoke.js](../test/run-fixture-compat-smoke.js)
474
+ - [run-import-canonical-table-smoke.js](../test/run-import-canonical-table-smoke.js)
464
475
  - [run-import-path-traversal-smoke.js](../test/run-import-path-traversal-smoke.js)
465
476
  - [run-import-tamper-failclosed-smoke.js](../test/run-import-tamper-failclosed-smoke.js)
466
477
  - [run-inspect-archive-smoke.js](../test/run-inspect-archive-smoke.js)
478
+ - [run-paths-shell-boundary-smoke.js](../test/run-paths-shell-boundary-smoke.js)
467
479
  - [run-registry-control-plane-smoke.js](../test/run-registry-control-plane-smoke.js)
468
480
  - [run-restore-failclosed-smoke.js](../test/run-restore-failclosed-smoke.js)
469
481
  - [run-resume-drive-smoke.js](../test/run-resume-drive-smoke.js)
@@ -477,6 +489,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
477
489
  - [schedule-routine-daemon-smoke.js](../test/schedule-routine-daemon-smoke.js)
478
490
  - [scheduling-routine-lock-concurrency-smoke.js](../test/scheduling-routine-lock-concurrency-smoke.js)
479
491
  - [schema-validation-smoke.js](../test/schema-validation-smoke.js)
492
+ - [schema-version-definition-guard-smoke.js](../test/schema-version-definition-guard-smoke.js)
480
493
  - [security-trust-hardening-smoke.js](../test/security-trust-hardening-smoke.js)
481
494
  - [self-audit-hardening-smoke.js](../test/self-audit-hardening-smoke.js)
482
495
  - [sigint-sigterm-drive-loop-smoke.js](../test/sigint-sigterm-drive-loop-smoke.js)
@@ -513,6 +526,7 @@ Smoke tests mirror the public contracts. The high-signal suites are:
513
526
  - [verify-import-audit-chain-smoke.js](../test/verify-import-audit-chain-smoke.js)
514
527
  - [web-desktop-workbench-smoke.js](../test/web-desktop-workbench-smoke.js)
515
528
  - [wiring-lazy-shell-imports-smoke.js](../test/wiring-lazy-shell-imports-smoke.js)
529
+ - [workbench-load-smoke.js](../test/workbench-load-smoke.js)
516
530
  - [workbench-port-range-smoke.js](../test/workbench-port-range-smoke.js)
517
531
  - [worker-accept-path-architecture-smoke.js](../test/worker-accept-path-architecture-smoke.js)
518
532
  - [worker-isolation-smoke.js](../test/worker-isolation-smoke.js)
@@ -201,3 +201,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
201
201
  0.2.4
202
202
 
203
203
  0.2.5
204
+
205
+ 0.2.6
@@ -341,3 +341,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
341
341
  0.2.4
342
342
 
343
343
  0.2.5
344
+
345
+ 0.2.6
@@ -169,6 +169,14 @@ LLM step (the reviewer) is **delegated** through CW's agent backend, so whicheve
169
169
  model you set up does the review. CW starts the agent argv-style (`shell:false`),
170
170
  takes on the agent's own credentials, and pulls in no model SDK — the red line.
171
171
 
172
+ The control plane runs the deterministic gate once. It keeps a failed child
173
+ command's short tail on stderr for the operator, but never puts that tail in a
174
+ saved verdict. The reviewer does not run that gate again. It checks judgment
175
+ questions the gate cannot check. A reviewer rejection has exact `REJECTED`,
176
+ `kind: semantic-review`, and numbered facts with repo-relative `file:line`
177
+ places. Other rejection text is invalid reviewer output: the cut stops, no tag
178
+ is made, and it is not a verified code rejection.
179
+
172
180
  ```bash
173
181
  # the operator's one-command release (scripts/release-oneclick.js — preflight,
174
182
  # gated cut, tag-only push, CI wait, npm confirmation, verdict-record PR):
@@ -322,3 +330,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
322
330
  0.2.4
323
331
 
324
332
  0.2.5
333
+
334
+ 0.2.6
@@ -123,6 +123,11 @@ adds the drive outcome to the result under a `drive` field. The default (no
123
123
  gives `drive.status="blocked"` (fail-closed, never a made-up completion); CW
124
124
  hands worker execution to your agent and never runs a model itself.
125
125
 
126
+ Human output with `--drive` or `--once` prints the drive status, worker counts,
127
+ each drive step, and the terminal commit id when there is one. This makes a
128
+ blocked or failed drive clear without `--json`. Bare `run resume` keeps its old
129
+ text as it is.
130
+
126
131
  ## Queue
127
132
 
128
133
  `queue add` adds a durable entry to the end of `$CW_HOME/registry/queue.json` with an
@@ -177,6 +182,15 @@ whose top-level integrity block is *absent* — closing the legacy fail-open sea
177
182
  where a stripped-integrity archive imported unverified. Unset (the default) keeps
178
183
  legacy integrity-less archives byte-identical; the flag is mechanism, not policy.
179
184
 
185
+ An operator can also set `CW_MAX_RUN_ARCHIVE_BYTES`,
186
+ `CW_MAX_RUN_ARCHIVE_FILES`, or `CW_MAX_RUN_ARCHIVE_CONTENT_BYTES`. Each value
187
+ has to be a positive safe integer. The first sets a raw file byte limit before
188
+ the archive is read. The second sets a normalized file row limit. The last sets
189
+ the total decoded content byte limit, checked from declared sizes before decode
190
+ and again while content is decoded. A bad setting or over-limit archive stops
191
+ before a run directory is made. With all three unset, import, inspect, restore,
192
+ and offline bundle check keep their present behavior.
193
+
180
194
  The archive's run id becomes a directory name under `DIR/.cw/runs/`, so import
181
195
  also refuses any run id that is not a single safe path segment (`[A-Za-z0-9._-]`,
182
196
  with no separator and not the `.` or `..` component) and asserts the resolved run
@@ -216,11 +230,20 @@ before importing a bad archive. It is a true preview of import: under
216
230
  turn away) also inspects as `ok:false`; with the env unset (default) an absent integrity
217
231
  block is only reported, not failed.
218
232
 
233
+ The file table is checked before any write. Every row needs a known role, a
234
+ safe size, a sha256 value, and a relative path. Paths are made portable and
235
+ then have to be unique. `state.json`, `import-manifest.json`, and lock files
236
+ are made by the restore work and are not accepted from an archive. A bad row
237
+ or two rows with the same path make inspect, import, and restore fail closed.
238
+ No run directory is made for that input.
239
+
219
240
  **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
241
+ does the whole move-a-run-to-another-machine flow as one atomic, fail-closed
242
+ step. It integrity-**inspects** the bundle first, imports it into a same-disk
243
+ staging tree, and checks the file, telemetry, trust-audit, and run-state records there.
244
+ Only then does it put final paths into state and publish the run with one
245
+ directory rename. It reports `ok:true` only after a check of the published
246
+ tree. This closes a real gap: `run import` runs a
224
247
  verification (it re-proves restored file digests, the **telemetry ledger**, and
225
248
  the **trust-audit hash chain**) and reports it, but does NOT fail on it — it
226
249
  exits `0` even when that chain does not verify. So a run whose telemetry or
@@ -229,13 +252,14 @@ made-up success. `run restore` refuses exactly that: it fails closed on the same
229
252
  verification `import` only reports. A bundle that fails the up-front integrity
230
253
  inspect is refused **before any import**, so nothing is written and the run is
231
254
  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
255
+ A bundle that imports in staging but fails a chain check is reported with
256
+ `ok:false`, `imported:null`, and no final run. A final run with the same id is
257
+ never merged or replaced. A staging write fault is cleaned up. It exits `1`
258
+ whenever `ok:false`, so `cw run restore <path>` is a
234
259
  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
260
+ exit — never a made-up success or a half-written final run. The result is structured
236
261
  (`{ 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).
262
+ scriptable. `run import` and `run inspect-archive` are unchanged.
239
263
 
240
264
  MCP gives the same mechanisms as `cw_run_export`, `cw_run_import`,
241
265
  `cw_run_verify_import`, `cw_run_inspect_archive`, and `cw_run_restore`; the CLI
@@ -484,3 +508,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
484
508
  0.2.4
485
509
 
486
510
  0.2.5
511
+
512
+ 0.2.6
@@ -294,3 +294,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
294
294
  0.2.4
295
295
 
296
296
  0.2.5
297
+
298
+ 0.2.6
@@ -330,3 +330,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
330
330
  0.2.4
331
331
 
332
332
  0.2.5
333
+
334
+ 0.2.6
@@ -266,3 +266,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
266
266
  0.2.4
267
267
 
268
268
  0.2.5
269
+
270
+ 0.2.6
@@ -73,3 +73,5 @@ security-trust-hardening(7), cli-mcp-parity(7), report-verifiable-bundle(7)
73
73
  0.2.4
74
74
 
75
75
  0.2.5
76
+
77
+ 0.2.6
@@ -10,6 +10,28 @@ speed and the MCP server (JSON-RPC over stdio) showed things for machine context
10
10
  Workbench lets a person look at a run quickly — and adds NOTHING else. It works out,
11
11
  decides, and keeps nothing that the CLI/MCP cannot already make.
12
12
 
13
+ ## Simple UI rules
14
+
15
+ The Workbench follows three public sets of rules:
16
+
17
+ - FreeBSD [style(9)](https://man.freebsd.org/cgi/man.cgi?query=style&sektion=9)
18
+ says that usage text has to agree with the man page and that error text has
19
+ to be easy to find. CW keeps command words and error words clear and fixed.
20
+ - FreeBSD [hier(7)](https://man.freebsd.org/cgi/man.cgi?query=hier&sektion=7)
21
+ gives each sort of file one place. The Workbench keeps no state; `.cw/`
22
+ stays the one state source.
23
+ - Homebrew [brew(1)](https://docs.brew.sh/Manpage) puts its essential commands
24
+ before its full command list, and gives `help`, `doctor`, `info`, and
25
+ `search`. CW gives one clear next command in place of a hidden recovery
26
+ action. Homebrew [External Commands](https://docs.brew.sh/External-Commands)
27
+ also shows how a front door may be added without a change to the tool's
28
+ inside parts. The Workbench stays a view over present CW capabilities.
29
+ - Codex [Best practices](https://learn.chatgpt.com/guides/best-practices.md)
30
+ puts context, checks, and review in the work path. Its
31
+ [app commands](https://learn.chatgpt.com/docs/reference/commands.md) keep
32
+ search, key movement, and Back/Forward movement close at hand. The
33
+ Workbench keeps the run and panel in the page address for the same reason.
34
+
13
35
  ## The third front door (mechanism vs policy)
14
36
 
15
37
  The kernel and the durable `.cw/` state are the MECHANISM. The CLI, the MCP
@@ -85,6 +107,7 @@ The host has least privilege and is local by default:
85
107
 
86
108
  - it binds the loopback interface `127.0.0.1` ONLY — never a public address
87
109
  - it is READ-ONLY: every route is `GET`; any write verb is turned away with `405`
110
+ - a read view makes no audit, metrics, or other derived file under `.cw/`
88
111
  - it turns away non-localhost `Host` headers (a DNS-rebinding defense) with `403`
89
112
  - it turns away path traversal out of `ui/workbench/` with `403`
90
113
  - it serves nothing past the current user's `.cw/` scope and the Run Registry's
@@ -120,6 +143,29 @@ cw workbench view <run-id> [--json] # five-panel WorkbenchRunView for on
120
143
  cw workbench serve [--port N] [--scope repo|home] [--once|--json] [--require-token]
121
144
  ```
122
145
 
146
+ The page address may name one run and one panel:
147
+
148
+ ```text
149
+ #run=<encoded-run-id>&tab=<graph|blackboard|worker|candidate|audit|metrics|collaboration>
150
+ ```
151
+
152
+ The `run` value is needed for a run view. With no `tab`, the page uses
153
+ `graph`. A bad tab name is changed to `graph`. Back, Forward, and page reload
154
+ keep the named view. The Workbench token stays in the page query and is never
155
+ put in this fragment.
156
+
157
+ The run list and panels work with a keyboard. Left and Right move through the
158
+ panel tabs; Home and End go to the first and last tab. The active tab and its
159
+ panel are joined with the standard ARIA tab and tabpanel links.
160
+
161
+ When a present panel payload has an `integrity`, `problems`,
162
+ `missingEvidence`, `nextAction`, or `nextActions` fact, the page puts a small
163
+ `What matters` block before the full panel record. It copies only source
164
+ values. It does not make a new state, rank, or action. An empty problem or
165
+ missing-evidence list is shown as `none`. A field with a shape the page does
166
+ not know is left out of the block. The full structured view or JSON stays
167
+ under the block.
168
+
123
169
  `cw workbench serve` with `--once`/`--json` prints the serve descriptor (bind
124
170
  host/port, scope, routes) and stops without starting a server; the default starts
125
171
  the localhost host (like `schedule daemon`). The MCP tools `cw_workbench_view` and
@@ -304,3 +350,5 @@ _No behavioral change in v0.1.89 (CLI-surface golden-path + help-output fixes on
304
350
  next-step line when a run is blocked or failed.
305
351
 
306
352
  0.2.5
353
+
354
+ 0.2.6
@@ -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.2.5",
5
+ "version": "0.2.6",
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.2.5",
3
+ "version": "0.2.6",
4
4
  "bin": {
5
5
  "cool-workflow": "scripts/cw.js",
6
6
  "cw": "scripts/cw.js"
@@ -75,7 +75,8 @@
75
75
  "test:unit": "node dist/cli.js version > /dev/null && node test/run-unit.js",
76
76
  "eval:replay": "tsc -p tsconfig.json && node test/multi-agent-eval-replay-harness-smoke.js",
77
77
  "ci": "npm run build && npm run check && npm run test && npm run release:check",
78
- "validate:schema": "node scripts/validate-run-state-schema.js"
78
+ "validate:schema": "node scripts/validate-run-state-schema.js",
79
+ "bench:workbench:deep": "node ../../scripts/bench/workbench-load.js"
79
80
  },
80
81
  "devDependencies": {
81
82
  "@types/node": "^26.1.1",
@@ -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.2.5",
86
+ "Cool Workflow v0.2.6",
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.2.5");
120
+ assert.equal(summary.version, "0.2.6");
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.2.5");
127
+ assert.equal(shown.app.version, "0.2.6");
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.2.5");
138
+ assert.equal(state.workflow.app.version, "0.2.6");
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/shell/orchestrator.js");
8
8
 
9
- const TARGET_VERSION = "0.2.5";
9
+ const TARGET_VERSION = "0.2.6";
10
10
  const PREVIOUS_VERSION = "0.1.31";
11
11
  const pluginRoot = path.resolve(__dirname, "..");
12
12
  const repoRoot = path.resolve(pluginRoot, "..", "..");