cool-workflow 0.2.3 → 0.2.5

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 (143) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.gemini-plugin/mcp.json +10 -0
  4. package/.gemini-plugin/plugin.json +40 -0
  5. package/.opencode-plugin/mcp.json +10 -0
  6. package/.opencode-plugin/plugin.json +40 -0
  7. package/README.md +202 -48
  8. package/apps/architecture-review/app.json +1 -1
  9. package/apps/architecture-review-fast/app.json +1 -1
  10. package/apps/end-to-end-golden-path/app.json +1 -1
  11. package/apps/pr-review-fix-ci/app.json +1 -1
  12. package/apps/release-cut/app.json +1 -1
  13. package/apps/research-synthesis/app.json +1 -1
  14. package/dist/cli/dispatch.js +33 -4
  15. package/dist/cli/entry.js +11 -19
  16. package/dist/cli/global-flags.js +113 -0
  17. package/dist/cli/io.js +6 -20
  18. package/dist/cli/parseargv.js +7 -1
  19. package/dist/core/capability-data.js +339 -10
  20. package/dist/core/format/help.js +80 -4
  21. package/dist/core/format/recovery-hint.js +32 -0
  22. package/dist/core/multi-agent/collaboration.js +35 -6
  23. package/dist/core/multi-agent/runtime.js +7 -0
  24. package/dist/core/multi-agent/trust-policy.js +7 -1
  25. package/dist/core/pipeline/contract.js +7 -0
  26. package/dist/core/pipeline/error-feedback.js +2 -2
  27. package/dist/core/trust/evidence-grounding.js +13 -1
  28. package/dist/core/util/cli-args.js +55 -0
  29. package/dist/core/version.js +1 -1
  30. package/dist/mcp/dispatch.js +22 -2
  31. package/dist/mcp/server.js +124 -13
  32. package/dist/mcp-server.js +20 -0
  33. package/dist/shell/commit.js +8 -2
  34. package/dist/shell/coordinator-io.js +73 -1
  35. package/dist/shell/drive.js +129 -64
  36. package/dist/shell/error-feedback-io.js +6 -0
  37. package/dist/shell/execution-backend/agent.js +205 -24
  38. package/dist/shell/execution-backend/container.js +44 -10
  39. package/dist/shell/execution-backend/local.js +47 -10
  40. package/dist/shell/fs-atomic.js +93 -12
  41. package/dist/shell/ledger-cli.js +9 -2
  42. package/dist/shell/multi-agent-cli.js +5 -1
  43. package/dist/shell/onramp.js +48 -5
  44. package/dist/shell/pipeline-cli.js +20 -2
  45. package/dist/shell/pipeline.js +2 -1
  46. package/dist/shell/reclamation-io.js +76 -7
  47. package/dist/shell/registry-cli.js +4 -0
  48. package/dist/shell/run-export.js +52 -4
  49. package/dist/shell/run-registry-io.js +1 -0
  50. package/dist/shell/run-store.js +156 -0
  51. package/dist/shell/scheduler-io.js +101 -10
  52. package/dist/shell/telemetry-ledger-io.js +36 -24
  53. package/dist/shell/trust-audit.js +104 -10
  54. package/dist/shell/workbench-host.js +121 -10
  55. package/dist/shell/workbench.js +79 -5
  56. package/dist/shell/worker-isolation.js +1 -1
  57. package/dist/shell/workflow-app-loader.js +67 -1
  58. package/dist/wiring/capability-table/basics.js +7 -2
  59. package/dist/wiring/capability-table/exec-backend.js +42 -24
  60. package/dist/wiring/capability-table/multi-agent.js +69 -69
  61. package/dist/wiring/capability-table/pipeline.js +60 -28
  62. package/dist/wiring/capability-table/registry-core.js +29 -6
  63. package/dist/wiring/capability-table/reporting.js +45 -39
  64. package/dist/wiring/capability-table/scheduling-registry.js +66 -60
  65. package/dist/wiring/capability-table/state.js +34 -34
  66. package/dist/wiring/capability-table/trust-ledger.js +66 -24
  67. package/dist/wiring/capability-table/workflow-apps.js +15 -15
  68. package/docs/agent-delegation-drive.7.md +17 -0
  69. package/docs/cli-mcp-parity.7.md +43 -13
  70. package/docs/contract-migration-tooling.7.md +4 -0
  71. package/docs/control-plane-scheduling.7.md +38 -0
  72. package/docs/cross-agent-ledger.7.md +20 -8
  73. package/docs/durable-state-and-locking.7.md +4 -0
  74. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  75. package/docs/execution-backends.7.md +4 -0
  76. package/docs/fix.7.md +4 -4
  77. package/docs/getting-started.md +40 -32
  78. package/docs/index.md +17 -0
  79. package/docs/launch/demo.tape +4 -3
  80. package/docs/mcp-app-surface.7.md +6 -0
  81. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  82. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  83. package/docs/multi-agent-operator-ux.7.md +4 -0
  84. package/docs/node-snapshot-diff-replay.7.md +4 -0
  85. package/docs/observability-cost-accounting.7.md +4 -0
  86. package/docs/project-index.md +43 -9
  87. package/docs/real-execution-backends.7.md +4 -0
  88. package/docs/release-and-migration.7.md +4 -0
  89. package/docs/release-tooling.7.md +22 -0
  90. package/docs/routine.7.md +22 -0
  91. package/docs/run-registry-control-plane.7.md +4 -0
  92. package/docs/run-retention-reclamation.7.md +28 -3
  93. package/docs/state-explosion-management.7.md +4 -0
  94. package/docs/team-collaboration.7.md +4 -0
  95. package/docs/trust-audit-anchor.7.md +4 -0
  96. package/docs/web-desktop-workbench.7.md +26 -2
  97. package/docs/workflow-app-framework.7.md +31 -0
  98. package/manifest/plugin.manifest.json +1 -1
  99. package/manifest/source-context-profiles.json +4 -3
  100. package/package.json +5 -2
  101. package/scripts/agents/agent-adapter-core.js +26 -0
  102. package/scripts/agents/claude-p-agent.js +4 -1
  103. package/scripts/agents/codex-agent.js +4 -0
  104. package/scripts/agents/cw-attest-wrap.js +1 -1
  105. package/scripts/agents/gemini-agent.js +4 -0
  106. package/scripts/agents/opencode-agent.js +5 -0
  107. package/scripts/block-unapproved-tag.js +160 -0
  108. package/scripts/bump-version.js +27 -10
  109. package/scripts/canonical-apps.js +4 -4
  110. package/scripts/children/batch-delegate-child.js +72 -4
  111. package/scripts/children/http-batch-delegate-child.js +132 -0
  112. package/scripts/children/http-delegate-child.js +8 -0
  113. package/scripts/dogfood-release.js +2 -2
  114. package/scripts/fake-date-for-reproduction.js +1 -1
  115. package/scripts/golden-path.js +4 -4
  116. package/scripts/lang-policy-check.js +82 -0
  117. package/scripts/purity-baseline.json +0 -30
  118. package/scripts/purity-gate.js +16 -3
  119. package/scripts/release-check.js +2 -1
  120. package/scripts/release-flow.js +264 -41
  121. package/scripts/release-gate.js +184 -0
  122. package/scripts/release-oneclick.js +438 -0
  123. package/scripts/release-tags.js +47 -0
  124. package/scripts/verdict-keygen.js +2 -2
  125. package/scripts/verify-bump-reproduction.js +193 -0
  126. package/scripts/verify-verdict-signature.js +1 -1
  127. package/scripts/version-sync-check.js +39 -22
  128. package/ui/workbench/app.css +41 -9
  129. package/ui/workbench/app.js +160 -27
  130. package/ui/workbench/index.html +2 -2
  131. package/docs/agent-framework.md +0 -177
  132. package/docs/designs/handoff-ledger.md +0 -145
  133. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +0 -40
  134. package/docs/launch/launch-kit.md +0 -195
  135. package/docs/launch/pre-launch-checklist.md +0 -53
  136. package/docs/readme-v0.1.87-full.md +0 -301
  137. package/docs/routines.md +0 -101
  138. package/docs/scheduled-tasks.md +0 -80
  139. package/scripts/agents/claude-p-agent.sh +0 -9
  140. package/scripts/block-unapproved-tag.sh +0 -60
  141. package/scripts/release-gate.sh +0 -94
  142. package/scripts/verify-bump-reproduction.sh +0 -148
  143. package/scripts/verify-container-selfref.js +0 -64
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // verify-bump-reproduction.js — closes the HEAD~1 verdict-replay bypass.
4
+ //
5
+ // release-gate.yml / npm-publish.yml tolerate a verdict written for the tag
6
+ // commit's PARENT (release-flow.js's cut() reviews content, then adds a
7
+ // mechanical version-bump + the verdict as a NEW child commit that actually
8
+ // gets tagged). A validly-signed verdict at the parent proves someone once
9
+ // approved THAT commit — it does NOT prove the child (the thing actually being
10
+ // tagged) is the deterministic bump cut() would have produced, rather than an
11
+ // attacker's own commit smuggling in arbitrary changes on top of an old,
12
+ // genuinely-approved parent (a real signature on a REPLAYED verdict).
13
+ //
14
+ // This script independently reproduces the bump: checks out the approved
15
+ // parent into a scratch worktree, runs the SAME bump:version/sync:project-index
16
+ // steps cut() runs, stages the SAME way cut() stages (git add -u + the
17
+ // explicit verdict/.sig paths, never -A), and requires the resulting tree to
18
+ // match the ACTUAL tagged commit's tree byte-for-byte. Any difference —
19
+ // anywhere, including a single added file — fails closed.
20
+ //
21
+ // (Node port of the former verify-bump-reproduction.sh; behavior kept line
22
+ // for line — same steps, same messages, same exit map.)
23
+ //
24
+ // Usage: verify-bump-reproduction.js <approved-parent-sha> <tagged-sha> <verdict-repo-relative-path> [sig-repo-relative-path]
25
+ //
26
+ // Exit 0: the tagged commit's tree matches the reproduced bump exactly.
27
+ // Exit 1: mismatch, or any step failed (install, bump, sync, worktree, etc).
28
+
29
+ const fs = require("node:fs");
30
+ const os = require("node:os");
31
+ const path = require("node:path");
32
+ const { spawnSync } = require("node:child_process");
33
+
34
+ // Where THIS SCRIPT ITSELF lives — distinct from REPO_ROOT (the git repo being
35
+ // operated ON, resolved below from the invocation cwd). These coincide in
36
+ // ordinary production use (the script runs from within the same checkout it
37
+ // verifies), but conflating them is wrong: REPO_ROOT could be an ARBITRARY git
38
+ // context (e.g. a test harness's throwaway clone of old history, which never
39
+ // has this script's own sibling files, since they postdate whatever was
40
+ // cloned). Sibling files this script depends on must be found relative to
41
+ // where it is installed, never relative to the repo it happens to be pointed at.
42
+ const SCRIPT_DIR = __dirname;
43
+
44
+ function err(msg) {
45
+ process.stderr.write(`${msg}\n`);
46
+ }
47
+
48
+ const [, , PARENT, TAGGED, VERDICT_REL, SIG_REL = ""] = process.argv;
49
+ if (!PARENT || !TAGGED || !VERDICT_REL) {
50
+ err("usage: verify-bump-reproduction.js <parent-sha> <tagged-sha> <verdict-rel-path> [sig-rel-path]");
51
+ process.exit(1);
52
+ }
53
+
54
+ function run(cmd, args, opts = {}) {
55
+ return spawnSync(cmd, args, { encoding: "utf8", ...opts });
56
+ }
57
+ function gitIn(dir, args, opts = {}) {
58
+ return run("git", ["-C", dir, ...args], opts);
59
+ }
60
+
61
+ const top = run("git", ["rev-parse", "--show-toplevel"]);
62
+ if (top.status !== 0) process.exit(1);
63
+ const REPO_ROOT = top.stdout.trim();
64
+
65
+ const SCRATCH_PARENT = fs.mkdtempSync(path.join(os.tmpdir(), "cw-bump-repro-"));
66
+ const SCRATCH = path.join(SCRATCH_PARENT, "wt");
67
+ function cleanup() {
68
+ gitIn(REPO_ROOT, ["worktree", "remove", "--force", SCRATCH], { stdio: "ignore" });
69
+ fs.rmSync(SCRATCH_PARENT, { recursive: true, force: true });
70
+ }
71
+
72
+ function main() {
73
+ const wt = gitIn(REPO_ROOT, ["worktree", "add", "--quiet", "--detach", SCRATCH, PARENT], { stdio: "ignore" });
74
+ if (wt.status !== 0) {
75
+ err(`verify-bump-reproduction: could not create a scratch worktree at ${PARENT}`);
76
+ return 1;
77
+ }
78
+
79
+ // The target version comes from the TAGGED commit (not the parent, which may
80
+ // still be pre-bump) — read via git plumbing, no separate checkout needed.
81
+ const pkgShow = gitIn(REPO_ROOT, ["show", `${TAGGED}:plugins/cool-workflow/package.json`]);
82
+ let VERSION = "";
83
+ if (pkgShow.status === 0) {
84
+ try {
85
+ VERSION = JSON.parse(pkgShow.stdout).version || "";
86
+ } catch {
87
+ VERSION = "";
88
+ }
89
+ }
90
+ if (!VERSION) {
91
+ err(`verify-bump-reproduction: could not read package.json version from tagged commit ${TAGGED}`);
92
+ return 1;
93
+ }
94
+
95
+ // sync-project-index.js embeds a wall-clock "Generated on <date>" line. Pin it
96
+ // to the TAGGED commit's own committer date (UTC) via a Node --require preload
97
+ // that overrides the global Date constructor (fake-date-for-reproduction.js),
98
+ // NOT an application-level env var: the scratch worktree runs the APPROVED
99
+ // PARENT's OWN checked-out copy of sync-project-index.js, which for every
100
+ // release cut before this mechanism existed has no idea any such env var is
101
+ // meant to be read — an app-level opt-in is a no-op against code that doesn't
102
+ // know to opt in, so it can only ever "work" for releases cut after the
103
+ // mechanism landed (confirmed empirically: re-running an already-shipped
104
+ // release's real approved-parent/tagged pair on a later calendar day produced
105
+ // a tree mismatch whose ONLY diff was that one date line). A global override
106
+ // of the Date constructor, injected before any application code runs, is
107
+ // transparent to the code being executed regardless of which version it is.
108
+ const dateShow = gitIn(REPO_ROOT, ["show", "-s", "--format=%cd", "--date=format-local:%Y-%m-%d", TAGGED], {
109
+ env: { ...process.env, TZ: "UTC" },
110
+ });
111
+ const CUT_DATE = dateShow.status === 0 ? dateShow.stdout.trim() : "";
112
+ if (!CUT_DATE) {
113
+ err("verify-bump-reproduction: could not read the tagged commit's committer date");
114
+ return 1;
115
+ }
116
+ const FAKE_DATE_PRELOAD = path.join(SCRIPT_DIR, "fake-date-for-reproduction.js");
117
+
118
+ // Each step's exit code is checked EXPLICITLY and immediately (not via one
119
+ // combined chain) — a chain's overall success can silently survive an earlier
120
+ // step's failure if a future edit ever loosens it, which would flip this
121
+ // fail-closed gate to fail-open without changing its outward shape.
122
+ // stdout/stderr from each step are captured (not discarded) so a real
123
+ // failure — a transient npm registry hiccup vs. an actual reproduction
124
+ // mismatch — is distinguishable in the workflow log instead of both
125
+ // collapsing into the same generic message.
126
+ const stepCwd = path.join(SCRATCH, "plugins", "cool-workflow");
127
+ const stepEnv = {
128
+ ...process.env,
129
+ NODE_OPTIONS: `--require ${FAKE_DATE_PRELOAD}`,
130
+ CW_FAKE_DATE: CUT_DATE,
131
+ };
132
+ function runStep(label, cmd, args) {
133
+ const r = run(cmd, args, { cwd: stepCwd, env: stepEnv });
134
+ const out = (r.stdout || "") + (r.stderr || "");
135
+ const code = r.error ? 1 : r.status;
136
+ if (code !== 0) {
137
+ err(`verify-bump-reproduction: ${label} failed (exit ${code}):`);
138
+ err(out);
139
+ return false;
140
+ }
141
+ return true;
142
+ }
143
+
144
+ const bumpOk =
145
+ runStep("npm install", "npm", ["install", "--no-package-lock", "--ignore-scripts"]) &&
146
+ runStep("bump:version", "npm", ["run", "bump:version", "--", VERSION]) &&
147
+ runStep("sync:project-index", "npm", ["run", "sync:project-index", "--", "--repo-only"]);
148
+ if (!bumpOk) {
149
+ err(`verify-bump-reproduction: reproducing the bump for ${PARENT} -> v${VERSION} failed`);
150
+ return 1;
151
+ }
152
+
153
+ fs.mkdirSync(path.join(SCRATCH, ".cw-release"), { recursive: true });
154
+ try {
155
+ fs.copyFileSync(path.join(REPO_ROOT, VERDICT_REL), path.join(SCRATCH, VERDICT_REL));
156
+ } catch {
157
+ return 1;
158
+ }
159
+ if (SIG_REL && fs.existsSync(path.join(REPO_ROOT, SIG_REL))) {
160
+ try {
161
+ fs.copyFileSync(path.join(REPO_ROOT, SIG_REL), path.join(SCRATCH, SIG_REL));
162
+ } catch {
163
+ return 1;
164
+ }
165
+ }
166
+
167
+ // Mirror cut()'s OWN staging exactly (git-add -u + the explicit verdict/.sig
168
+ // paths) — never -A, so an untracked stray left by npm/tooling in the scratch
169
+ // worktree can never silently ride into what we compare.
170
+ gitIn(SCRATCH, ["add", "-u"]);
171
+ gitIn(SCRATCH, ["add", "--", VERDICT_REL]);
172
+ if (SIG_REL && fs.existsSync(path.join(SCRATCH, SIG_REL))) {
173
+ gitIn(SCRATCH, ["add", "--", SIG_REL]);
174
+ }
175
+
176
+ const EXPECTED_TREE = gitIn(SCRATCH, ["write-tree"]).stdout.trim();
177
+ const ACTUAL_TREE = gitIn(REPO_ROOT, ["rev-parse", `${TAGGED}^{tree}`]).stdout.trim();
178
+
179
+ if (EXPECTED_TREE !== ACTUAL_TREE) {
180
+ err(`verify-bump-reproduction: ${TAGGED}'s tree (${ACTUAL_TREE}) does not match the deterministic bump reproduced from approved parent ${PARENT} (${EXPECTED_TREE}) — refusing`);
181
+ return 1;
182
+ }
183
+
184
+ return 0;
185
+ }
186
+
187
+ let code = 1;
188
+ try {
189
+ code = main();
190
+ } finally {
191
+ cleanup();
192
+ }
193
+ process.exit(code);
@@ -4,7 +4,7 @@
4
4
  // verify-verdict-signature.js — verify an ed25519 signature over a committed
5
5
  // release verdict file, against the committed public key
6
6
  // (.cw-release/verdict-signing.pub). Portable (node + node:crypto only) so
7
- // CI (release-gate.yml, npm-publish.yml) and the local block-unapproved-tag.sh
7
+ // CI (release-gate.yml, npm-publish.yml) and the local block-unapproved-tag.js
8
8
  // hook can all shell out to the SAME check instead of three drifting copies.
9
9
  //
10
10
  // Exit 0: signature verifies. Exit 1: missing file, unreadable key, or a
@@ -106,68 +106,68 @@ function main() {
106
106
  // above (version.ts/dist/package.json/manifests/docs) still pin the release.
107
107
  checkIncludes("plugins/cool-workflow/docs/index.md", "release and migration", checks);
108
108
  checkIncludes("plugins/cool-workflow/docs/multi-agent-topologies.7.md", "Multi-Agent Topologies", checks);
109
- checkIncludes("plugins/cool-workflow/docs/multi-agent-cli-mcp-surface.7.md", VERSION, checks);
110
- checkIncludes("plugins/cool-workflow/docs/multi-agent-operator-ux.7.md", VERSION, checks);
111
- checkIncludes("plugins/cool-workflow/docs/multi-agent-eval-replay-harness.7.md", VERSION, checks);
109
+ checkIncludesOwnLine("plugins/cool-workflow/docs/multi-agent-cli-mcp-surface.7.md", VERSION, checks);
110
+ checkIncludesOwnLine("plugins/cool-workflow/docs/multi-agent-operator-ux.7.md", VERSION, checks);
111
+ checkIncludesOwnLine("plugins/cool-workflow/docs/multi-agent-eval-replay-harness.7.md", VERSION, checks);
112
112
  checkIncludes("plugins/cool-workflow/docs/state-explosion-management.7.md", "State Explosion Management", checks);
113
- checkIncludes("plugins/cool-workflow/docs/state-explosion-management.7.md", VERSION, checks);
113
+ checkIncludesOwnLine("plugins/cool-workflow/docs/state-explosion-management.7.md", VERSION, checks);
114
114
  checkIncludes("plugins/cool-workflow/docs/evidence-adoption-reasoning-chain.7.md", "Evidence Adoption Reasoning Chain", checks);
115
- checkIncludes("plugins/cool-workflow/docs/evidence-adoption-reasoning-chain.7.md", VERSION, checks);
115
+ checkIncludesOwnLine("plugins/cool-workflow/docs/evidence-adoption-reasoning-chain.7.md", VERSION, checks);
116
116
  checkIncludes("plugins/cool-workflow/docs/coordinator-blackboard.7.md", "Coordinator / Blackboard", checks);
117
117
  checkIncludes("plugins/cool-workflow/docs/cli-mcp-parity.7.md", "CLI", checks);
118
- checkIncludes("plugins/cool-workflow/docs/cli-mcp-parity.7.md", VERSION, checks);
118
+ checkIncludesOwnLine("plugins/cool-workflow/docs/cli-mcp-parity.7.md", VERSION, checks);
119
119
  checkIncludes("plugins/cool-workflow/docs/index.md", "cli-mcp-parity.7.md", checks);
120
120
  checkIncludes("plugins/cool-workflow/docs/run-registry-control-plane.7.md", "Run Registry / Control Plane", checks);
121
- checkIncludes("plugins/cool-workflow/docs/run-registry-control-plane.7.md", VERSION, checks);
121
+ checkIncludesOwnLine("plugins/cool-workflow/docs/run-registry-control-plane.7.md", VERSION, checks);
122
122
  checkIncludes("plugins/cool-workflow/docs/index.md", "run-registry-control-plane.7.md", checks);
123
123
  checkIncludes("plugins/cool-workflow/test/run-registry-control-plane-smoke.js", "run-registry-control-plane-smoke", checks);
124
124
  checkIncludes("plugins/cool-workflow/docs/execution-backends.7.md", "Execution Backends", checks);
125
- checkIncludes("plugins/cool-workflow/docs/execution-backends.7.md", VERSION, checks);
125
+ checkIncludesOwnLine("plugins/cool-workflow/docs/execution-backends.7.md", VERSION, checks);
126
126
  checkIncludes("plugins/cool-workflow/docs/index.md", "execution-backends.7.md", checks);
127
127
  checkIncludes("plugins/cool-workflow/test/execution-backends-smoke.js", "execution-backends-smoke", checks);
128
128
  checkIncludes("plugins/cool-workflow/docs/web-desktop-workbench.7.md", "Web / Desktop Workbench", checks);
129
- checkIncludes("plugins/cool-workflow/docs/web-desktop-workbench.7.md", VERSION, checks);
129
+ checkIncludesOwnLine("plugins/cool-workflow/docs/web-desktop-workbench.7.md", VERSION, checks);
130
130
  checkIncludes("plugins/cool-workflow/docs/index.md", "web-desktop-workbench.7.md", checks);
131
131
  checkIncludes("plugins/cool-workflow/test/web-desktop-workbench-smoke.js", "web-desktop-workbench-smoke", checks);
132
132
  checkIncludes("plugins/cool-workflow/docs/observability-cost-accounting.7.md", "Observability + Cost Accounting", checks);
133
- checkIncludes("plugins/cool-workflow/docs/observability-cost-accounting.7.md", VERSION, checks);
133
+ checkIncludesOwnLine("plugins/cool-workflow/docs/observability-cost-accounting.7.md", VERSION, checks);
134
134
  checkIncludes("plugins/cool-workflow/docs/index.md", "observability-cost-accounting.7.md", checks);
135
135
  checkIncludes("plugins/cool-workflow/test/observability-cost-accounting-smoke.js", "observability-cost-accounting-smoke", checks);
136
136
  checkIncludes("plugins/cool-workflow/docs/team-collaboration.7.md", "Team Collaboration", checks);
137
- checkIncludes("plugins/cool-workflow/docs/team-collaboration.7.md", VERSION, checks);
137
+ checkIncludesOwnLine("plugins/cool-workflow/docs/team-collaboration.7.md", VERSION, checks);
138
138
  checkIncludes("plugins/cool-workflow/docs/index.md", "team-collaboration.7.md", checks);
139
139
  checkIncludes("plugins/cool-workflow/test/team-collaboration-smoke.js", "team-collaboration-smoke", checks);
140
140
  checkIncludes("plugins/cool-workflow/docs/release-tooling.7.md", "Release Tooling", checks);
141
- checkIncludes("plugins/cool-workflow/docs/release-tooling.7.md", VERSION, checks);
141
+ checkIncludesOwnLine("plugins/cool-workflow/docs/release-tooling.7.md", VERSION, checks);
142
142
  checkIncludes("plugins/cool-workflow/docs/index.md", "release-tooling.7.md", checks);
143
143
  checkIncludes("plugins/cool-workflow/test/release-tooling-smoke.js", "release-tooling-smoke", checks);
144
144
  checkIncludes("plugins/cool-workflow/docs/real-execution-backends.7.md", "Real Execution Backend Integrations", checks);
145
- checkIncludes("plugins/cool-workflow/docs/real-execution-backends.7.md", VERSION, checks);
145
+ checkIncludesOwnLine("plugins/cool-workflow/docs/real-execution-backends.7.md", VERSION, checks);
146
146
  checkIncludes("plugins/cool-workflow/docs/index.md", "real-execution-backends.7.md", checks);
147
147
  checkIncludes("plugins/cool-workflow/test/real-execution-backends-smoke.js", "real-execution-backends-smoke", checks);
148
148
  checkIncludes("plugins/cool-workflow/docs/node-snapshot-diff-replay.7.md", "Node Snapshot / Diff / Replay", checks);
149
- checkIncludes("plugins/cool-workflow/docs/node-snapshot-diff-replay.7.md", VERSION, checks);
149
+ checkIncludesOwnLine("plugins/cool-workflow/docs/node-snapshot-diff-replay.7.md", VERSION, checks);
150
150
  checkIncludes("plugins/cool-workflow/docs/index.md", "node-snapshot-diff-replay.7.md", checks);
151
151
  checkIncludes("plugins/cool-workflow/test/node-snapshot-diff-replay-smoke.js", "node-snapshot-diff-replay-smoke", checks);
152
152
  checkIncludes("plugins/cool-workflow/docs/contract-migration-tooling.7.md", "Contract Migration Tooling", checks);
153
- checkIncludes("plugins/cool-workflow/docs/contract-migration-tooling.7.md", VERSION, checks);
153
+ checkIncludesOwnLine("plugins/cool-workflow/docs/contract-migration-tooling.7.md", VERSION, checks);
154
154
  checkIncludes("plugins/cool-workflow/docs/index.md", "contract-migration-tooling.7.md", checks);
155
155
  checkIncludes("plugins/cool-workflow/test/contract-migration-tooling-smoke.js", "contract-migration-tooling-smoke", checks);
156
156
  checkIncludes("plugins/cool-workflow/docs/control-plane-scheduling.7.md", "Control-Plane Scheduling", checks);
157
- checkIncludes("plugins/cool-workflow/docs/control-plane-scheduling.7.md", VERSION, checks);
157
+ checkIncludesOwnLine("plugins/cool-workflow/docs/control-plane-scheduling.7.md", VERSION, checks);
158
158
  checkIncludes("plugins/cool-workflow/docs/index.md", "control-plane-scheduling.7.md", checks);
159
159
  checkIncludes("plugins/cool-workflow/test/control-plane-scheduling-smoke.js", "control-plane-scheduling-smoke", checks);
160
160
  checkIncludes("plugins/cool-workflow/docs/agent-delegation-drive.7.md", "Agent Delegation Drive", checks);
161
- checkIncludes("plugins/cool-workflow/docs/agent-delegation-drive.7.md", VERSION, checks);
161
+ checkIncludesOwnLine("plugins/cool-workflow/docs/agent-delegation-drive.7.md", VERSION, checks);
162
162
  checkIncludes("plugins/cool-workflow/docs/index.md", "agent-delegation-drive.7.md", checks);
163
163
  checkIncludes("plugins/cool-workflow/test/agent-delegation-drive-smoke.js", "agent-delegation-drive-smoke", checks);
164
164
  checkIncludes("plugins/cool-workflow/docs/run-retention-reclamation.7.md", "Run Retention & Provable Reclamation", checks);
165
- checkIncludes("plugins/cool-workflow/docs/run-retention-reclamation.7.md", VERSION, checks);
165
+ checkIncludesOwnLine("plugins/cool-workflow/docs/run-retention-reclamation.7.md", VERSION, checks);
166
166
  checkIncludes("plugins/cool-workflow/docs/index.md", "run-retention-reclamation.7.md", checks);
167
167
  checkIncludes("plugins/cool-workflow/test/run-retention-reclamation-smoke.js", "run-retention-reclamation-smoke", checks);
168
168
  checkIncludes("plugins/cool-workflow/src/wiring/capability-table/scheduling-registry.ts", "gc.plan", checks);
169
169
  checkIncludes("plugins/cool-workflow/docs/durable-state-and-locking.7.md", "Durable State & Locking", checks);
170
- checkIncludes("plugins/cool-workflow/docs/durable-state-and-locking.7.md", VERSION, checks);
170
+ checkIncludesOwnLine("plugins/cool-workflow/docs/durable-state-and-locking.7.md", VERSION, checks);
171
171
  checkIncludes("plugins/cool-workflow/docs/index.md", "durable-state-and-locking.7.md", checks);
172
172
  checkIncludes("plugins/cool-workflow/test/durable-atomic-write-smoke.js", "durable-atomic-write-smoke", checks);
173
173
  checkIncludes("plugins/cool-workflow/src/shell/fs-atomic.ts", "withFileLock", checks);
@@ -201,12 +201,12 @@ function main() {
201
201
  checkIncludes("plugins/cool-workflow/docs/getting-started.md", "npm run release:check", checks);
202
202
  checkIncludes("plugins/cool-workflow/package.json", "eval:replay", checks);
203
203
  checkIncludes("plugins/cool-workflow/docs/trust-audit-anchor.7.md", "Trust Audit Anchor", checks);
204
- checkIncludes("plugins/cool-workflow/docs/trust-audit-anchor.7.md", VERSION, checks);
204
+ checkIncludesOwnLine("plugins/cool-workflow/docs/trust-audit-anchor.7.md", VERSION, checks);
205
205
  checkIncludes("plugins/cool-workflow/docs/index.md", "trust-audit-anchor.7.md", checks);
206
206
  checkIncludes("plugins/cool-workflow/test/trust-audit-anchor-smoke.js", "trust-audit-anchor-smoke", checks);
207
- checkIncludes("plugins/cool-workflow/docs/release-and-migration.7.md", VERSION, checks);
207
+ checkIncludesOwnLine("plugins/cool-workflow/docs/release-and-migration.7.md", VERSION, checks);
208
208
  checkIncludes("CHANGELOG.md", `## ${VERSION}`, checks);
209
- checkIncludes("RELEASE.md", VERSION, checks);
209
+ checkIncludesOwnLine("RELEASE.md", VERSION, checks);
210
210
  // Homebrew formula (repo root): git-tag formula. Homebrew scans the version
211
211
  // from the tag, so the tag is the single version surface to gate (an explicit
212
212
  // `version` line would be redundant and brew audit rejects it). bump-version.js
@@ -266,4 +266,21 @@ function checkIncludes(relativePath, needle, checks) {
266
266
  checks.push({ path: relativePath, includes: needle });
267
267
  }
268
268
 
269
+ // A bare version number (e.g. "0.2.4") can appear anywhere in a doc's
270
+ // prose — an example command, a cross-reference — without the doc's own
271
+ // version-history footer (a blank-line-separated list, one release per
272
+ // line, appended by bump-version.js's --content step) actually having
273
+ // been updated. A plain substring check would silently pass on the
274
+ // coincidental prose match and never notice the real footer line is
275
+ // missing (found live: v0.2.4's bump left release-tooling.7.md's footer
276
+ // stuck at 0.2.3, masked by an unrelated "npm run release -- 0.2.4"
277
+ // example a few lines up). Require the needle on its own line instead.
278
+ function checkIncludesOwnLine(relativePath, needle, checks) {
279
+ const src = readReleaseSource(relativePath);
280
+ assert.ok(src.exists, `${relativePath} must exist`);
281
+ const hasOwnLine = src.text.split("\n").some((line) => line.trim() === needle);
282
+ assert.ok(hasOwnLine, `${relativePath} must include ${needle} as its own line (not just as a substring)`);
283
+ checks.push({ path: relativePath, includesOwnLine: needle });
284
+ }
285
+
269
286
  main();
@@ -27,21 +27,31 @@
27
27
  }
28
28
  }
29
29
  * { box-sizing: border-box; }
30
+ /* The body is a flex column and main takes the leftover height (flex: 1 +
31
+ min-height: 0 so the inner panes can scroll) — no hardcoded header
32
+ height, so a header that wraps to two lines no longer pushes the panes
33
+ past the bottom of the window. */
30
34
  body {
31
35
  margin: 0;
32
36
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
33
37
  background: var(--bg);
34
38
  color: var(--ink);
35
39
  font-size: 14px;
40
+ display: flex;
41
+ flex-direction: column;
42
+ height: 100vh;
36
43
  }
37
44
  header { padding: 14px 20px; border-bottom: 1px solid var(--line); }
38
45
  header h1 { margin: 0; font-size: 18px; font-weight: 600; }
39
46
  header .muted, .muted { color: var(--muted); font-weight: 400; }
40
47
  header .trust { margin: 4px 0 0; font-size: 12px; color: var(--muted); }
41
48
  code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
42
- main { display: grid; grid-template-columns: 320px 1fr; height: calc(100vh - 64px); }
49
+ main { display: grid; grid-template-columns: 320px 1fr; flex: 1; min-height: 0; }
43
50
  .sidebar { border-right: 1px solid var(--line); overflow-y: auto; padding: 12px; }
44
51
  .bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
52
+ /* The sidebar heading is a real <h2> (document outline / screen-reader
53
+ navigation) styled to the size the old <strong> label had. */
54
+ .bar h2 { margin: 0; font-size: 14px; font-weight: 600; }
45
55
  button {
46
56
  background: var(--panel-2); color: var(--ink); border: 1px solid var(--line);
47
57
  border-radius: 6px; padding: 4px 10px; cursor: pointer; font-size: 12px;
@@ -51,16 +61,28 @@ input[type="search"] {
51
61
  width: 100%; background: var(--panel); color: var(--ink);
52
62
  border: 1px solid var(--line); border-radius: 6px; padding: 6px 8px; margin-bottom: 8px;
53
63
  }
54
- .freshness { font-size: 11px; color: var(--muted); margin-bottom: 8px; }
64
+ .freshness { font-size: 12px; color: var(--muted); margin-bottom: 8px; }
55
65
  .run-list { list-style: none; margin: 0; padding: 0; }
56
- .run-list li {
66
+ .run-list li,
67
+ .run-list button {
57
68
  padding: 8px; border: 1px solid var(--line); border-radius: 6px;
58
69
  margin-bottom: 6px; cursor: pointer; background: var(--panel);
59
70
  }
60
- .run-list li:hover { border-color: var(--accent); }
61
- .run-list li.active { border-color: var(--accent); background: var(--panel-2); }
71
+ /* Only the run-row <button> needs a plain-element reset: a <button> has
72
+ its own default display/width/font/color, a plain <li> (used only for
73
+ the error and empty-state rows) does not and must keep its own color
74
+ (.err red, .muted gray) — see app.js. */
75
+ .run-list button {
76
+ display: block; width: 100%; text-align: left; font: inherit; color: inherit;
77
+ }
78
+ .run-list li:hover, .run-list button:hover { border-color: var(--accent); }
79
+ .run-list li.active, .run-list button.active { border-color: var(--accent); background: var(--panel-2); }
80
+ /* Run rows are now real <button> elements (for Tab/Enter/Space); make the
81
+ keyboard focus ring visible — there is no :focus-visible rule for this
82
+ element otherwise. */
83
+ .run-list button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
62
84
  .run-list .rid { font-family: ui-monospace, monospace; font-size: 12px; display: flex; align-items: center; gap: 6px; }
63
- .run-list .meta { color: var(--muted); font-size: 11px; margin-top: 2px; }
85
+ .run-list .meta { color: var(--muted); font-size: 12px; margin-top: 2px; }
64
86
  .status-dot {
65
87
  display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: none;
66
88
  background: var(--muted);
@@ -81,13 +103,23 @@ input[type="search"] {
81
103
  padding: 8px 12px; border-bottom: 1px solid var(--line);
82
104
  }
83
105
  .panel-card > .head .title { font-weight: 600; }
84
- .panel-card > .head .src { font-size: 11px; color: var(--muted); font-family: ui-monospace, monospace; }
85
- .badge { font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line); }
106
+ .panel-card > .head .src { font-size: 12px; color: var(--muted); font-family: ui-monospace, monospace; }
107
+ .badge { font-size: 12px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line); }
86
108
  .badge.present { color: var(--present); border-color: var(--present); }
87
109
  .badge.absent { color: var(--absent); border-color: var(--absent); }
88
110
  .badge.stale { color: var(--absent); border-color: var(--absent); }
89
111
  .badge.valid { color: var(--present); border-color: var(--present); }
90
112
  .badge.missing, .badge.bad { color: var(--bad); border-color: var(--bad); }
113
+ /* Lifecycle states shown as a badge in the run detail header (the other
114
+ lifecycle values reuse the neutral/present/absent colors above). */
115
+ .badge.blocked { color: var(--absent); border-color: var(--absent); }
116
+ .badge.failed { color: var(--bad); border-color: var(--bad); }
117
+ .badge.completed { color: var(--present); border-color: var(--present); }
118
+ .badge.running { color: var(--accent); border-color: var(--accent); }
119
+ /* One plain next-step line under the header when a run is blocked/failed. */
120
+ .recovery-hint { margin: 0 0 12px; font-size: 12px; color: var(--absent); }
121
+ /* Second line of the empty-list state: the suggested next command. */
122
+ .run-list li .hint { margin-top: 4px; font-size: 12px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
91
123
  pre.json {
92
124
  margin: 0; padding: 12px; overflow-x: auto; font-size: 12px;
93
125
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; line-height: 1.5;
@@ -99,7 +131,7 @@ pre.json {
99
131
  .err { color: var(--bad); }
100
132
  .struct-block { padding: 10px 12px; border-top: 1px solid var(--line); }
101
133
  .struct-block:first-child { border-top: none; }
102
- .struct-block .struct-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 6px; }
134
+ .struct-block .struct-title { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 6px; }
103
135
  .struct-table { width: 100%; border-collapse: collapse; font-size: 12px; }
104
136
  .struct-table th, .struct-table td {
105
137
  text-align: left; padding: 4px 8px; border-bottom: 1px solid var(--line);