cool-workflow 0.1.98 → 0.2.1

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 (315) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +18 -7
  4. package/apps/architecture-review/app.json +2 -2
  5. package/apps/architecture-review/workflow.js +12 -12
  6. package/apps/architecture-review-fast/app.json +1 -1
  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/cli/dispatch.js +236 -0
  12. package/dist/cli/entry.js +120 -0
  13. package/dist/cli/io.js +21 -4
  14. package/dist/cli/parseargv.js +157 -0
  15. package/dist/cli.js +6 -33
  16. package/dist/core/capability-table.js +3518 -0
  17. package/dist/core/format/help.js +314 -0
  18. package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
  19. package/dist/core/hash.js +137 -0
  20. package/dist/core/multi-agent/candidate-scoring.js +219 -0
  21. package/dist/core/multi-agent/collaboration.js +481 -0
  22. package/dist/core/multi-agent/coordinator.js +515 -0
  23. package/dist/core/multi-agent/eval-replay.js +306 -0
  24. package/dist/core/multi-agent/runtime.js +929 -0
  25. package/dist/core/multi-agent/topology.js +298 -0
  26. package/dist/core/multi-agent/trust-policy.js +197 -0
  27. package/dist/core/pipeline/commit-gate.js +320 -0
  28. package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
  29. package/dist/core/pipeline/dispatch.js +103 -0
  30. package/dist/core/pipeline/drive-decide.js +227 -0
  31. package/dist/core/pipeline/error-feedback.js +161 -0
  32. package/dist/core/pipeline/loop-expansion.js +124 -0
  33. package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
  34. package/dist/core/pipeline/runner.js +230 -0
  35. package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
  36. package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
  37. package/dist/core/state/node-projection.js +95 -0
  38. package/dist/core/state/node-snapshot.js +230 -0
  39. package/dist/core/state/run-paths.js +93 -0
  40. package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
  41. package/dist/core/state/schema.js +50 -0
  42. package/dist/core/state/state-explosion/digest.js +243 -0
  43. package/dist/core/state/state-explosion/graph.js +527 -0
  44. package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
  45. package/dist/core/state/state-explosion/report.js +187 -0
  46. package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
  47. package/dist/{state-node.js → core/state/state-node.js} +90 -113
  48. package/dist/core/state/types.js +19 -0
  49. package/dist/{validation.js → core/state/validation.js} +64 -131
  50. package/dist/core/trust/evidence-grounding.js +134 -0
  51. package/dist/core/trust/ledger.js +199 -0
  52. package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
  53. package/dist/core/trust/telemetry-ledger.js +127 -0
  54. package/dist/core/types.js +20 -0
  55. package/dist/core/version.js +16 -0
  56. package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
  57. package/dist/mcp/dispatch.js +104 -0
  58. package/dist/mcp/server.js +144 -0
  59. package/dist/mcp-server.js +6 -84
  60. package/dist/{agent-config.js → shell/agent-config.js} +118 -71
  61. package/dist/shell/app-run-cli.js +88 -0
  62. package/dist/shell/audit-cli.js +259 -0
  63. package/dist/shell/audit-provenance.js +83 -0
  64. package/dist/shell/candidate-scoring-io.js +459 -0
  65. package/dist/shell/collaboration-io.js +264 -0
  66. package/dist/shell/commit-summary.js +104 -0
  67. package/dist/shell/commit.js +290 -0
  68. package/dist/shell/coordinator-io.js +476 -0
  69. package/dist/shell/demo-cli.js +19 -0
  70. package/dist/shell/dispatch.js +162 -0
  71. package/dist/shell/doctor.js +292 -0
  72. package/dist/shell/drive.js +885 -0
  73. package/dist/shell/error-feedback-io.js +305 -0
  74. package/dist/shell/eval-io.js +473 -0
  75. package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
  76. package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
  77. package/dist/shell/exec-backend-cli.js +88 -0
  78. package/dist/shell/execution-backend/agent.js +507 -0
  79. package/dist/shell/execution-backend/ci.js +15 -0
  80. package/dist/shell/execution-backend/container.js +69 -0
  81. package/dist/shell/execution-backend/envelopes.js +55 -0
  82. package/dist/shell/execution-backend/local.js +113 -0
  83. package/dist/shell/execution-backend/probes.js +175 -0
  84. package/dist/shell/execution-backend/registry.js +402 -0
  85. package/dist/shell/execution-backend/remote.js +128 -0
  86. package/dist/shell/execution-backend/types.js +11 -0
  87. package/dist/shell/feedback-cli.js +81 -0
  88. package/dist/shell/feedback-operations.js +48 -0
  89. package/dist/shell/fs-atomic.js +276 -0
  90. package/dist/shell/harness.js +98 -0
  91. package/dist/shell/ledger-cli.js +212 -0
  92. package/dist/shell/ledger-io.js +169 -0
  93. package/dist/shell/man-cli.js +89 -0
  94. package/dist/shell/metrics-cli.js +100 -0
  95. package/dist/shell/multi-agent-cli.js +1002 -0
  96. package/dist/shell/multi-agent-host.js +563 -0
  97. package/dist/shell/multi-agent-io.js +387 -0
  98. package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
  99. package/dist/shell/node-store.js +124 -0
  100. package/dist/{observability/format.js → shell/observability-format.js} +7 -1
  101. package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
  102. package/dist/{observability.js → shell/observability.js} +159 -332
  103. package/dist/{onramp.js → shell/onramp.js} +11 -0
  104. package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
  105. package/dist/shell/operator-ux.js +431 -0
  106. package/dist/shell/orchestrator.js +231 -0
  107. package/dist/shell/pipeline-cli.js +667 -0
  108. package/dist/shell/pipeline.js +217 -0
  109. package/dist/shell/reclamation-io.js +1366 -0
  110. package/dist/shell/registry-cli.js +344 -0
  111. package/dist/{remote-source.js → shell/remote-source.js} +2 -2
  112. package/dist/shell/report-cli.js +101 -0
  113. package/dist/shell/report-view-cli.js +117 -0
  114. package/dist/{orchestrator → shell}/report.js +289 -282
  115. package/dist/shell/reporter.js +62 -0
  116. package/dist/shell/run-export-cli.js +106 -0
  117. package/dist/shell/run-export.js +680 -0
  118. package/dist/shell/run-registry-io.js +1014 -0
  119. package/dist/shell/run-store.js +164 -0
  120. package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
  121. package/dist/{scheduler.js → shell/scheduler-io.js} +257 -48
  122. package/dist/shell/scheduling-io.js +321 -0
  123. package/dist/shell/state-cli.js +181 -0
  124. package/dist/shell/state-explosion-cli.js +197 -0
  125. package/dist/shell/telemetry-cli.js +85 -0
  126. package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
  127. package/dist/shell/telemetry-ledger-io.js +132 -0
  128. package/dist/{term.js → shell/term.js} +36 -46
  129. package/dist/shell/topology-io.js +361 -0
  130. package/dist/shell/trust-audit.js +472 -0
  131. package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
  132. package/dist/shell/verifier.js +48 -0
  133. package/dist/shell/workbench-host.js +258 -0
  134. package/dist/shell/workbench-text.js +18 -0
  135. package/dist/shell/workbench.js +170 -0
  136. package/dist/shell/worker-cli.js +124 -0
  137. package/dist/shell/worker-isolation.js +852 -0
  138. package/dist/shell/workflow-app-loader.js +650 -0
  139. package/docs/agent-delegation-drive.7.md +4 -0
  140. package/docs/cli-mcp-parity.7.md +282 -219
  141. package/docs/contract-migration-tooling.7.md +4 -0
  142. package/docs/control-plane-scheduling.7.md +4 -0
  143. package/docs/durable-state-and-locking.7.md +4 -0
  144. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  145. package/docs/execution-backends.7.md +4 -0
  146. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  147. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  148. package/docs/multi-agent-operator-ux.7.md +4 -0
  149. package/docs/node-snapshot-diff-replay.7.md +4 -0
  150. package/docs/observability-cost-accounting.7.md +6 -1
  151. package/docs/project-index.md +137 -71
  152. package/docs/real-execution-backends.7.md +4 -0
  153. package/docs/release-and-migration.7.md +4 -0
  154. package/docs/release-tooling.7.md +4 -0
  155. package/docs/remote-source-review.7.md +4 -4
  156. package/docs/report-verifiable-bundle.7.md +1 -1
  157. package/docs/run-registry-control-plane.7.md +4 -0
  158. package/docs/run-retention-reclamation.7.md +25 -0
  159. package/docs/security-trust-hardening.7.md +3 -1
  160. package/docs/state-explosion-management.7.md +4 -0
  161. package/docs/team-collaboration.7.md +4 -0
  162. package/docs/web-desktop-workbench.7.md +15 -1
  163. package/manifest/plugin.manifest.json +1 -1
  164. package/manifest/source-context-profiles.json +9 -13
  165. package/package.json +1 -1
  166. package/scripts/agents/agent-adapter-core.js +22 -2
  167. package/scripts/agents/claude-p-agent.js +8 -3
  168. package/scripts/agents/cw-attest-wrap.js +2 -2
  169. package/scripts/agents/gemini-agent.js +5 -1
  170. package/scripts/agents/opencode-agent.js +5 -1
  171. package/scripts/bump-version.js +4 -3
  172. package/scripts/canonical-apps.js +4 -4
  173. package/scripts/dogfood-architecture-review.js +2 -3
  174. package/scripts/dogfood-release.js +3 -3
  175. package/scripts/gen-parity-doc.js +15 -2
  176. package/scripts/golden-path.js +4 -4
  177. package/scripts/onramp-check.js +1 -1
  178. package/scripts/parity-check.js +38 -21
  179. package/scripts/release-flow.js +2 -2
  180. package/scripts/sync-project-index.js +51 -27
  181. package/scripts/validate-run-state-schema.js +2 -2
  182. package/scripts/version-sync-check.js +30 -30
  183. package/dist/candidate-scoring.js +0 -729
  184. package/dist/capability-core.js +0 -1189
  185. package/dist/capability-registry.js +0 -885
  186. package/dist/cli/command-surface.js +0 -494
  187. package/dist/cli/format.js +0 -56
  188. package/dist/cli/handlers/audit.js +0 -82
  189. package/dist/cli/handlers/blackboard.js +0 -81
  190. package/dist/cli/handlers/candidate.js +0 -40
  191. package/dist/cli/handlers/clones.js +0 -34
  192. package/dist/cli/handlers/collaboration.js +0 -61
  193. package/dist/cli/handlers/eval.js +0 -40
  194. package/dist/cli/handlers/ledger.js +0 -169
  195. package/dist/cli/handlers/maintenance.js +0 -107
  196. package/dist/cli/handlers/multi-agent.js +0 -165
  197. package/dist/cli/handlers/node.js +0 -41
  198. package/dist/cli/handlers/operational.js +0 -155
  199. package/dist/cli/handlers/operator.js +0 -146
  200. package/dist/cli/handlers/registry.js +0 -68
  201. package/dist/cli/handlers/run.js +0 -153
  202. package/dist/cli/handlers/scheduling.js +0 -132
  203. package/dist/cli/handlers/workbench.js +0 -41
  204. package/dist/cli/handlers/worker.js +0 -45
  205. package/dist/cli/run-summary.js +0 -45
  206. package/dist/clones.js +0 -162
  207. package/dist/collaboration.js +0 -726
  208. package/dist/commit.js +0 -592
  209. package/dist/compare.js +0 -18
  210. package/dist/coordinator/classify.js +0 -45
  211. package/dist/coordinator/paths.js +0 -42
  212. package/dist/coordinator/util.js +0 -126
  213. package/dist/coordinator.js +0 -990
  214. package/dist/daemon.js +0 -44
  215. package/dist/dispatch.js +0 -250
  216. package/dist/doctor.js +0 -212
  217. package/dist/drive.js +0 -864
  218. package/dist/error-feedback.js +0 -419
  219. package/dist/evidence-grounding.js +0 -184
  220. package/dist/execution-backend/agent.js +0 -354
  221. package/dist/execution-backend/probes.js +0 -112
  222. package/dist/execution-backend/util.js +0 -47
  223. package/dist/execution-backend.js +0 -961
  224. package/dist/gates.js +0 -48
  225. package/dist/harness.js +0 -61
  226. package/dist/ledger.js +0 -313
  227. package/dist/loop-expansion.js +0 -60
  228. package/dist/mcp/tool-call.js +0 -470
  229. package/dist/mcp/tool-definitions.js +0 -1066
  230. package/dist/mcp-surface.js +0 -30
  231. package/dist/multi-agent/graph.js +0 -84
  232. package/dist/multi-agent/helpers.js +0 -141
  233. package/dist/multi-agent/ids.js +0 -20
  234. package/dist/multi-agent/paths.js +0 -22
  235. package/dist/multi-agent-eval/normalize.js +0 -51
  236. package/dist/multi-agent-eval.js +0 -678
  237. package/dist/multi-agent-host.js +0 -777
  238. package/dist/multi-agent.js +0 -984
  239. package/dist/node-projection.js +0 -59
  240. package/dist/node-snapshot.js +0 -260
  241. package/dist/operator-ux.js +0 -631
  242. package/dist/orchestrator/app-operations.js +0 -211
  243. package/dist/orchestrator/audit-operations.js +0 -182
  244. package/dist/orchestrator/candidate-operations.js +0 -117
  245. package/dist/orchestrator/cli-options.js +0 -294
  246. package/dist/orchestrator/collaboration-operations.js +0 -86
  247. package/dist/orchestrator/feedback-operations.js +0 -81
  248. package/dist/orchestrator/host-operations.js +0 -78
  249. package/dist/orchestrator/lifecycle-operations.js +0 -650
  250. package/dist/orchestrator/migration-operations.js +0 -44
  251. package/dist/orchestrator/multi-agent-operations.js +0 -362
  252. package/dist/orchestrator/topology-operations.js +0 -84
  253. package/dist/orchestrator.js +0 -925
  254. package/dist/pipeline-runner.js +0 -285
  255. package/dist/reclamation/hash.js +0 -72
  256. package/dist/reclamation.js +0 -812
  257. package/dist/reporter.js +0 -67
  258. package/dist/run-export.js +0 -815
  259. package/dist/run-registry/derive.js +0 -175
  260. package/dist/run-registry/format.js +0 -124
  261. package/dist/run-registry/gc.js +0 -251
  262. package/dist/run-registry/policy.js +0 -16
  263. package/dist/run-registry/queue.js +0 -115
  264. package/dist/run-registry.js +0 -850
  265. package/dist/run-state-schema.js +0 -68
  266. package/dist/scheduling.js +0 -184
  267. package/dist/state-explosion.js +0 -1014
  268. package/dist/state.js +0 -367
  269. package/dist/telemetry-ledger.js +0 -196
  270. package/dist/topology.js +0 -565
  271. package/dist/triggers.js +0 -184
  272. package/dist/trust-audit.js +0 -644
  273. package/dist/types/blackboard.js +0 -2
  274. package/dist/types/candidate.js +0 -2
  275. package/dist/types/collaboration.js +0 -2
  276. package/dist/types/core.js +0 -2
  277. package/dist/types/drive.js +0 -10
  278. package/dist/types/error-feedback.js +0 -2
  279. package/dist/types/evidence-reasoning.js +0 -2
  280. package/dist/types/execution-backend.js +0 -2
  281. package/dist/types/multi-agent.js +0 -2
  282. package/dist/types/observability.js +0 -2
  283. package/dist/types/pipeline.js +0 -2
  284. package/dist/types/reclamation.js +0 -8
  285. package/dist/types/report-bundle.js +0 -6
  286. package/dist/types/result.js +0 -2
  287. package/dist/types/run-registry.js +0 -2
  288. package/dist/types/run.js +0 -2
  289. package/dist/types/sandbox.js +0 -2
  290. package/dist/types/schedule.js +0 -2
  291. package/dist/types/state-node.js +0 -2
  292. package/dist/types/topology.js +0 -2
  293. package/dist/types/trust.js +0 -2
  294. package/dist/types/workbench.js +0 -2
  295. package/dist/types/worker.js +0 -2
  296. package/dist/types/workflow-app.js +0 -2
  297. package/dist/types.js +0 -44
  298. package/dist/util/fingerprint.js +0 -19
  299. package/dist/util/fingerprint.test.js +0 -27
  300. package/dist/verifier.js +0 -78
  301. package/dist/version.js +0 -8
  302. package/dist/workbench-host.js +0 -192
  303. package/dist/workbench.js +0 -192
  304. package/dist/worker-accept/acceptance.js +0 -114
  305. package/dist/worker-accept/blackboard-fanout.js +0 -80
  306. package/dist/worker-accept/blackboard-linkage.js +0 -19
  307. package/dist/worker-accept/context.js +0 -2
  308. package/dist/worker-accept/telemetry-ledger.js +0 -126
  309. package/dist/worker-accept/validation.js +0 -77
  310. package/dist/worker-accept/verifier-completion.js +0 -73
  311. package/dist/worker-isolation/helpers.js +0 -51
  312. package/dist/worker-isolation/paths.js +0 -46
  313. package/dist/worker-isolation.js +0 -656
  314. package/dist/workflow-api.js +0 -131
  315. /package/dist/{types → core/types}/boundary.js +0 -0
package/dist/gates.js DELETED
@@ -1,48 +0,0 @@
1
- "use strict";
2
- // Shared, drift-proof gate primitives (F4). These two helpers were previously
3
- // duplicated "in sync by comment" in commit.ts and candidate-scoring.ts — the
4
- // no-false-green gate and the sandbox-profile lookup. A by-comment sync is a
5
- // structural drift hazard: nothing prevents one copy from changing without the
6
- // other, and the two gates MUST agree (selection + commit must reach the same
7
- // empty-capture verdict). Extracting ONE implementation each, imported by both
8
- // call sites, makes that drift impossible.
9
- //
10
- // Pure functions over PERSISTED state only — no clock, no randomness, no fs —
11
- // so both selection and commit replays reach the same gate decision. Keep them
12
- // fail-closed: when in doubt the caller must BLOCK, never silently pass.
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.emptyCaptureWarning = emptyCaptureWarning;
15
- exports.sandboxProfileForCandidate = sandboxProfileForCandidate;
16
- /** The HARD no-false-green gate (DIRECTION.md "ambiguity is a visible state").
17
- * A verifier node is built FROM a result node; when that result captured no
18
- * structured signal at all the result node carries a `metadata.captureWarning`
19
- * marker (set in worker-isolation / lifecycle ingest via isEmptyCapture). The
20
- * worker output is still ACCEPTED (a recorded warning, never a silent pass), but
21
- * a verifier-GATED commit — and candidate SELECTION — must NOT be able to
22
- * present that zero-evidence result as clean/green. We detect it here, reading
23
- * ONLY persisted state (the source result node's metadata) — purely functional,
24
- * no clock/ordering — so snapshot replay reaches the same gate decision.
25
- * Returns the marker string, or undefined.
26
- *
27
- * Resolution trail: verifier node -> its input/parent result node. We look at
28
- * `inputs.inputNodeId` (set by runPipelineStage) first, then fall back to the
29
- * first parent, so it works regardless of which ingest path produced the node. */
30
- function emptyCaptureWarning(run, verifierNode) {
31
- const resultNodeId = (typeof verifierNode.inputs?.inputNodeId === "string" ? verifierNode.inputs.inputNodeId : undefined) ||
32
- verifierNode.parents[0];
33
- const resultNode = resultNodeId ? (run.nodes || []).find((node) => node.id === resultNodeId) : undefined;
34
- const warning = resultNode?.metadata?.captureWarning;
35
- return typeof warning === "string" && warning ? warning : undefined;
36
- }
37
- /** Resolve the sandbox profile that backed a candidate's acceptance: the
38
- * worker's profile if the candidate has a worker, else the originating task's.
39
- * Read by both the commit gate's acceptance rationale and selection. Accepts an
40
- * optional candidate so the commit-side caller (which may not have resolved a
41
- * candidate) can share the same lookup. Pure over persisted run state. */
42
- function sandboxProfileForCandidate(run, candidate) {
43
- const worker = candidate?.workerId ? (run.workers || []).find((entry) => entry.id === candidate.workerId) : undefined;
44
- if (worker?.sandboxProfileId)
45
- return worker.sandboxProfileId;
46
- const task = candidate?.taskId ? (run.tasks || []).find((entry) => entry.id === candidate.taskId) : undefined;
47
- return task?.sandboxProfileId;
48
- }
package/dist/harness.js DELETED
@@ -1,61 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeTaskFiles = writeTaskFiles;
7
- exports.renderTask = renderTask;
8
- const node_fs_1 = __importDefault(require("node:fs"));
9
- const node_path_1 = __importDefault(require("node:path"));
10
- const state_1 = require("./state");
11
- function writeTaskFiles(run) {
12
- for (const task of run.tasks) {
13
- const taskPath = node_path_1.default.join(run.paths.tasksDir, `${(0, state_1.safeFileName)(task.id)}.md`);
14
- task.taskPath = taskPath;
15
- node_fs_1.default.writeFileSync(taskPath, renderTask(run, task), "utf8");
16
- }
17
- }
18
- function renderTask(run, task) {
19
- return [
20
- `# ${task.id}`,
21
- "",
22
- `- Workflow: ${run.workflow.title}`,
23
- `- Run: ${run.id}`,
24
- `- Phase: ${task.phase}`,
25
- `- Kind: ${task.kind}`,
26
- "",
27
- "## Inputs",
28
- "",
29
- `- Repository: ${String(run.inputs.repo || run.cwd)}`,
30
- `- Question: ${String(run.inputs.question || "")}`,
31
- `- Invariants: ${formatInputList(run.inputs.invariant)}`,
32
- "",
33
- "## Task",
34
- "",
35
- task.prompt,
36
- "",
37
- "## Output Contract",
38
- "",
39
- "- Return a concise Markdown summary.",
40
- "- Include concrete evidence paths and line numbers when applicable.",
41
- "- Separate real, conditional, non-issue, and unknown findings when reviewing risk.",
42
- "- For verification or verdict tasks, include a `cw:result` JSON fence with `findings` and `evidence`.",
43
- "- Do not edit files unless the parent agent session explicitly assigned implementation work.",
44
- "",
45
- "```cw:result",
46
- "{",
47
- ' "summary": "one sentence",',
48
- ' "findings": [',
49
- ' { "id": "finding-id", "classification": "real|conditional|non-issue|unknown", "severity": "P0|P1|P2|P3|none", "evidence": ["file-or-url:line"] }',
50
- " ],",
51
- ' "evidence": ["file-or-url:line"]',
52
- "}",
53
- "```",
54
- ""
55
- ].join("\n");
56
- }
57
- function formatInputList(value) {
58
- if (Array.isArray(value))
59
- return value.join("; ");
60
- return value ? String(value) : "";
61
- }
package/dist/ledger.js DELETED
@@ -1,313 +0,0 @@
1
- "use strict";
2
- // Cross-agent handoff ledger — the core mechanism for two agents scoped to two
3
- // separate repos to hand each other a CHANGE PROPOSAL or a REVIEW VERDICT as
4
- // verifiable data, not chat. Design: docs/designs/handoff-ledger.md.
5
- //
6
- // Stage 1 (human-relay transport): a ledger entry is a self-contained JSON
7
- // object carrying its own sha256 content digest. The producing side prints one;
8
- // the operator carries it to the other session; the consuming side VERIFIES it
9
- // fail-closed (a tampered or malformed entry is refused, never acted on) before
10
- // turning a proposal into a real PR or recording a verdict.
11
- //
12
- // Zero-dependency (only node stdlib). `build*`/`verify*` are pure; the stage-2
13
- // git transport adds `listLedgerEntries`, a READ-ONLY scan of a shared ledger
14
- // directory (the working tree of a handoff repo) that verifies every entry
15
- // fail-closed. No run state, no writes, no network.
16
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- var desc = Object.getOwnPropertyDescriptor(m, k);
19
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
- desc = { enumerable: true, get: function() { return m[k]; } };
21
- }
22
- Object.defineProperty(o, k2, desc);
23
- }) : (function(o, m, k, k2) {
24
- if (k2 === undefined) k2 = k;
25
- o[k2] = m[k];
26
- }));
27
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
- Object.defineProperty(o, "default", { enumerable: true, value: v });
29
- }) : function(o, v) {
30
- o["default"] = v;
31
- });
32
- var __importStar = (this && this.__importStar) || (function () {
33
- var ownKeys = function(o) {
34
- ownKeys = Object.getOwnPropertyNames || function (o) {
35
- var ar = [];
36
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
- return ar;
38
- };
39
- return ownKeys(o);
40
- };
41
- return function (mod) {
42
- if (mod && mod.__esModule) return mod;
43
- var result = {};
44
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
- __setModuleDefault(result, mod);
46
- return result;
47
- };
48
- })();
49
- Object.defineProperty(exports, "__esModule", { value: true });
50
- exports.computeLedgerDigest = computeLedgerDigest;
51
- exports.buildLedgerProposal = buildLedgerProposal;
52
- exports.buildLedgerReview = buildLedgerReview;
53
- exports.verifyLedgerEntry = verifyLedgerEntry;
54
- exports.applyLedgerProposal = applyLedgerProposal;
55
- exports.listLedgerEntries = listLedgerEntries;
56
- exports.unionLedgerEntries = unionLedgerEntries;
57
- exports.resolveLedgerInbox = resolveLedgerInbox;
58
- const crypto = __importStar(require("crypto"));
59
- const fs = __importStar(require("fs"));
60
- const path = __importStar(require("path"));
61
- /** Deterministic JSON with recursively sorted object keys, so the digest is a
62
- * function of content only — never key insertion order. */
63
- function stableStringify(value) {
64
- if (value === null || typeof value !== "object")
65
- return JSON.stringify(value);
66
- if (Array.isArray(value))
67
- return `[${value.map(stableStringify).join(",")}]`;
68
- const keys = Object.keys(value).sort();
69
- const body = keys
70
- .map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`)
71
- .join(",");
72
- return `{${body}}`;
73
- }
74
- /** sha256 over the canonical content (every field except `id` and `digest`,
75
- * which are derived FROM it). Returns the full `sha256:<hex>` form. */
76
- function computeLedgerDigest(entry) {
77
- const hash = crypto.createHash("sha256");
78
- hash.update(stableStringify(entry));
79
- return `sha256:${hash.digest("hex")}`;
80
- }
81
- /** Content-addressed id: `ldg-` + the first 16 hex chars of the digest. Two
82
- * entries with the same content (and createdAt) get the same id. */
83
- function deriveId(digest) {
84
- return `ldg-${digest.replace(/^sha256:/, "").slice(0, 16)}`;
85
- }
86
- function seal(content) {
87
- const digest = computeLedgerDigest(content);
88
- return { ...content, id: deriveId(digest), digest };
89
- }
90
- function buildLedgerProposal(input) {
91
- const content = {
92
- kind: "proposal",
93
- schemaVersion: 1,
94
- from: input.from,
95
- to: input.to,
96
- title: input.title,
97
- rationale: input.rationale,
98
- targetFiles: [...input.targetFiles],
99
- suggestedDiff: input.suggestedDiff || "",
100
- createdAt: input.createdAt
101
- };
102
- return seal(content);
103
- }
104
- function buildLedgerReview(input) {
105
- const content = {
106
- kind: "review",
107
- schemaVersion: 1,
108
- from: input.from,
109
- to: input.to,
110
- target: input.target,
111
- verdict: input.verdict,
112
- findings: [...input.findings],
113
- createdAt: input.createdAt
114
- };
115
- return seal(content);
116
- }
117
- function isRecord(value) {
118
- return typeof value === "object" && value !== null && !Array.isArray(value);
119
- }
120
- const PROPOSAL_FIELDS = ["from", "to", "title", "rationale", "targetFiles", "suggestedDiff", "createdAt"];
121
- const REVIEW_FIELDS = ["from", "to", "target", "verdict", "findings", "createdAt"];
122
- /** Fail-closed verification. Any structural defect, unknown kind, or digest
123
- * mismatch yields `ok:false` — the caller refuses to act on it. */
124
- function verifyLedgerEntry(raw) {
125
- const checks = [];
126
- const fail = (name, code, detail) => {
127
- checks.push({ name, pass: false, code, detail });
128
- return {
129
- ok: false,
130
- id: isRecord(raw) && typeof raw.id === "string" ? raw.id : null,
131
- kind: isRecord(raw) && typeof raw.kind === "string" ? raw.kind : null,
132
- checks,
133
- failedChecks: checks.filter((c) => !c.pass).map((c) => ({ name: c.name, code: c.code, detail: c.detail }))
134
- };
135
- };
136
- if (!isRecord(raw))
137
- return fail("structure", "ledger-not-object", "entry is not a JSON object");
138
- checks.push({ name: "structure", pass: true });
139
- const kind = raw.kind;
140
- if (kind !== "proposal" && kind !== "review")
141
- return fail("kind", "ledger-unknown-kind", `kind must be proposal|review, got ${JSON.stringify(kind)}`);
142
- checks.push({ name: "kind", pass: true });
143
- if (raw.schemaVersion !== 1)
144
- return fail("schema", "ledger-bad-schema", `schemaVersion must be 1, got ${JSON.stringify(raw.schemaVersion)}`);
145
- checks.push({ name: "schema", pass: true });
146
- if (typeof raw.digest !== "string" || !raw.digest)
147
- return fail("digest-present", "ledger-missing-digest", "digest is absent or not a string");
148
- checks.push({ name: "digest-present", pass: true });
149
- const fields = kind === "proposal" ? PROPOSAL_FIELDS : REVIEW_FIELDS;
150
- const content = { kind, schemaVersion: 1 };
151
- for (const field of fields) {
152
- if (!(field in raw))
153
- return fail("fields", "ledger-missing-field", `required field ${field} is absent`);
154
- content[field] = raw[field];
155
- }
156
- if (kind === "review" && raw.verdict !== "APPROVED" && raw.verdict !== "REJECTED") {
157
- return fail("verdict", "ledger-bad-verdict", `verdict must be APPROVED|REJECTED, got ${JSON.stringify(raw.verdict)}`);
158
- }
159
- checks.push({ name: "fields", pass: true });
160
- const recomputed = computeLedgerDigest(content);
161
- if (recomputed !== raw.digest) {
162
- return fail("digest", "ledger-digest-mismatch", `stored digest does not match content (recomputed ${recomputed})`);
163
- }
164
- checks.push({ name: "digest", pass: true });
165
- // Bind the id to the content: it MUST be the content-addressed id derived from
166
- // the digest. Without this, `id` is a free, unverified field (it is excluded
167
- // from the digest) — a forged entry could set `id` to collide with a legit
168
- // one, and any id-keyed de-duplication (`cw ledger list` union) would silently
169
- // drop one of them. Fail closed so a spoofed or absent id is refused, not
170
- // trusted.
171
- const expectedId = deriveId(raw.digest);
172
- if (raw.id !== expectedId) {
173
- return fail("id", "ledger-id-mismatch", `id ${JSON.stringify(raw.id)} is not the content-addressed id for this digest (expected ${expectedId})`);
174
- }
175
- checks.push({ name: "id", pass: true });
176
- return { ok: true, id: expectedId, kind, checks, failedChecks: [] };
177
- }
178
- /** Fail-closed extraction of a proposal's `suggestedDiff` for `git apply`. The
179
- * diff can ONLY escape after the entry verifies: a tampered entry, a review
180
- * (not a proposal), or a proposal with no diff all yield `ok:false` and
181
- * `diff:null`, so `cw ledger apply <file> | git apply` can never feed an
182
- * unverified patch to git. The kernel never shells out to git — turning the
183
- * diff into a patch stays the operator's step (mechanism, not policy). */
184
- function applyLedgerProposal(raw) {
185
- const verified = verifyLedgerEntry(raw);
186
- if (!verified.ok) {
187
- return { ok: false, id: verified.id, kind: verified.kind, diff: null, failedChecks: verified.failedChecks };
188
- }
189
- if (verified.kind !== "proposal") {
190
- return { ok: false, id: verified.id, kind: verified.kind, diff: null, failedChecks: [{ name: "kind", code: "ledger-not-a-proposal", detail: "apply expects a proposal entry, not a review" }] };
191
- }
192
- const rec = isRecord(raw) ? raw : {};
193
- const diff = typeof rec.suggestedDiff === "string" ? rec.suggestedDiff : "";
194
- if (!diff) {
195
- return { ok: false, id: verified.id, kind: verified.kind, diff: null, failedChecks: [{ name: "diff", code: "ledger-empty-diff", detail: "proposal carries no suggestedDiff to apply" }] };
196
- }
197
- return { ok: true, id: verified.id, kind: verified.kind, diff, failedChecks: [] };
198
- }
199
- /** Read every `*.json` in `dir`, verify each entry fail-closed, and report.
200
- * `allOk` is false if any entry is tampered, malformed, or unreadable — so the
201
- * receiving side refuses the whole inbox rather than acting on a mixed batch. */
202
- function listLedgerEntries(dir) {
203
- let names;
204
- try {
205
- names = fs.readdirSync(dir).filter((n) => n.endsWith(".json")).sort();
206
- }
207
- catch (error) {
208
- const entry = { file: dir, id: null, kind: null, from: null, to: null, title: null, target: null, verdict: null, ok: false, failedChecks: [{ name: "dir", code: "ledger-dir-unreadable", detail: error.message }] };
209
- return { dir, count: 0, allOk: false, entries: [entry], resolution: resolveLedgerInbox([entry]) };
210
- }
211
- const entries = names.map((name) => {
212
- const file = path.join(dir, name);
213
- let raw;
214
- try {
215
- const stat = fs.lstatSync(file);
216
- if (!stat.isFile()) {
217
- return { file: name, id: null, kind: null, from: null, to: null, title: null, target: null, verdict: null, ok: false, failedChecks: [{ name: "file", code: "ledger-entry-not-regular" }] };
218
- }
219
- raw = JSON.parse(fs.readFileSync(file, "utf8"));
220
- }
221
- catch {
222
- return { file: name, id: null, kind: null, from: null, to: null, title: null, target: null, verdict: null, ok: false, failedChecks: [{ name: "parse", code: "ledger-bad-json" }] };
223
- }
224
- const result = verifyLedgerEntry(raw);
225
- const rec = isRecord(raw) ? raw : {};
226
- return {
227
- file: name,
228
- id: result.id,
229
- kind: result.kind,
230
- from: typeof rec.from === "string" ? rec.from : null,
231
- to: typeof rec.to === "string" ? rec.to : null,
232
- title: typeof rec.title === "string" ? rec.title : null,
233
- target: typeof rec.target === "string" ? rec.target : null,
234
- verdict: typeof rec.verdict === "string" ? rec.verdict : null,
235
- ok: result.ok,
236
- failedChecks: result.failedChecks
237
- };
238
- });
239
- return { dir, count: entries.length, allOk: entries.every((e) => e.ok), entries, resolution: resolveLedgerInbox(entries) };
240
- }
241
- /** Union-verify several mirror directories into ONE fail-closed inbox. Verified
242
- * entries are de-duplicated by their content-addressed id (the same entry
243
- * mirrored to N hosts collapses to one, recording every mirror it came from);
244
- * failing entries are kept per-occurrence so every problem in every mirror is
245
- * visible. `allOk` is false if ANY entry in ANY mirror does not verify — a
246
- * tampered mirror fails the whole batch. Safe because entries are immutable and
247
- * content-addressed, so a union is a conflict-free set-union, not a merge. */
248
- function unionLedgerEntries(dirs) {
249
- const byId = new Map();
250
- const failures = [];
251
- let allOk = true;
252
- for (const dir of dirs) {
253
- const listed = listLedgerEntries(dir);
254
- if (!listed.allOk)
255
- allOk = false;
256
- for (const entry of listed.entries) {
257
- if (entry.ok && entry.id) {
258
- const existing = byId.get(entry.id);
259
- if (existing) {
260
- if (!existing.dirs.includes(dir))
261
- existing.dirs.push(dir);
262
- }
263
- else {
264
- byId.set(entry.id, { ...entry, dirs: [dir] });
265
- }
266
- }
267
- else {
268
- failures.push({ ...entry, dirs: [dir] });
269
- }
270
- }
271
- }
272
- const entries = [...byId.values(), ...failures];
273
- return { dirs, count: entries.length, allOk, entries, resolution: resolveLedgerInbox(entries) };
274
- }
275
- /** Derive a machine-actionable inbox summary: pair each proposal with the
276
- * review(s) that target it and report whether it is pending, approved,
277
- * rejected, or contested. Only VERIFIED entries take part — a tampered review
278
- * must never resolve a proposal, so a proposal with only a failing review
279
- * stays `pending` (fail-closed). Pure derivation over content-addressed
280
- * entries: no git, no network, no policy (it reports the decision, it does not
281
- * enforce one). */
282
- function resolveLedgerInbox(entries) {
283
- const verified = entries.filter((e) => e.ok);
284
- const reviews = verified.filter((e) => e.kind === "review" && e.target);
285
- const proposals = verified
286
- .filter((e) => e.kind === "proposal" && e.id)
287
- .map((p) => {
288
- const answering = reviews.filter((r) => r.target === p.id);
289
- const verdicts = new Set(answering.map((r) => r.verdict));
290
- let resolution;
291
- if (answering.length === 0)
292
- resolution = "pending";
293
- else if (verdicts.size > 1)
294
- resolution = "contested";
295
- else
296
- resolution = verdicts.has("APPROVED") ? "approved" : "rejected";
297
- return {
298
- id: p.id,
299
- title: p.title,
300
- resolution,
301
- reviews: answering.map((r) => r.id).sort()
302
- };
303
- })
304
- .sort((a, b) => a.id.localeCompare(b.id));
305
- const tally = (s) => proposals.filter((p) => p.resolution === s).length;
306
- return {
307
- proposals,
308
- pending: tally("pending"),
309
- approved: tally("approved"),
310
- rejected: tally("rejected"),
311
- contested: tally("contested")
312
- };
313
- }
@@ -1,60 +0,0 @@
1
- "use strict";
2
- // Bounded dynamic control flow (#2) — a declarative LOOP phase whose tasks are a
3
- // per-round TEMPLATE: after each round completes, a registered PURE predicate decides
4
- // whether to run another round (a fresh phase appended after this one, with the same
5
- // tasks under round-suffixed ids) or stop. Hard-capped at `maxRounds`.
6
- //
7
- // REPLAY-DETERMINISM: the predicate is a pure function of RECORDED round results +
8
- // recorded usage — no IO/clock/random in its context by construction. The engine
9
- // RECORDS each decision as a `loop-control` state node, so a replay walks the recorded
10
- // round sequence; re-running the predicate is a verification cross-check, not the
11
- // source of truth. Predicates are NAMED (registry refs), never inline closures —
12
- // closures cannot be serialized into state or re-evaluated byte-identically on replay.
13
- //
14
- // The materialization (cloning tasks, appending phases, recording the loop-control
15
- // node) lives in the orchestrator (maybeExpandLoop), which owns writeTaskFiles + the
16
- // plan pipeline; THIS module is just the pure registry + the STATIC expansion bound.
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.registerLoopPredicate = registerLoopPredicate;
19
- exports.getLoopPredicate = getLoopPredicate;
20
- exports.hasLoopPredicate = hasLoopPredicate;
21
- exports.maxLoopExpansion = maxLoopExpansion;
22
- const REGISTRY = new Map();
23
- /** Register a named pure loop predicate (apps register theirs at load; CW ships a few
24
- * built-ins below). Re-registering a name overwrites it. */
25
- function registerLoopPredicate(name, fn) {
26
- REGISTRY.set(name, fn);
27
- }
28
- function getLoopPredicate(name) {
29
- return REGISTRY.get(name);
30
- }
31
- function hasLoopPredicate(name) {
32
- return REGISTRY.has(name);
33
- }
34
- // ---- Built-in predicates ---------------------------------------------------------
35
- /** Stop once a round produced no findings (a convergence loop: keep going while the
36
- * agent still reports findings; stop when a round comes back empty). */
37
- registerLoopPredicate("no-new-findings", (ctx) => {
38
- const empty = ctx.roundResults.every((r) => !r || !Array.isArray(r.findings) || r.findings.length === 0);
39
- return empty
40
- ? { done: true, reason: "no-new-findings: the latest round produced no findings" }
41
- : { done: false, reason: "no-new-findings: the latest round still has findings" };
42
- });
43
- /** Always stop after the first round (a degenerate loop ≈ a normal phase; useful as a
44
- * default / for tests). */
45
- registerLoopPredicate("single-round", () => ({ done: true, reason: "single-round: stop after one round" }));
46
- /** Static worst-case number of EXTRA tasks a fully-expanded run could mint, derived
47
- * purely from the workflow DECLARATION (every loop origin phase contributes
48
- * (maxRounds-1) × its round-1 task count). Used to keep the drive's iteration bound
49
- * safe as tasks grow, WITHOUT reading any runtime result — so the bound is itself
50
- * replay-stable and the loop is provably bounded. Zero when there are no loop phases. */
51
- function maxLoopExpansion(run) {
52
- let extra = 0;
53
- for (const phase of run.phases) {
54
- if (phase.loop && typeof phase.loop.maxRounds === "number" && phase.loop.maxRounds > 1) {
55
- const templateTaskCount = phase.taskIds.length;
56
- extra += (phase.loop.maxRounds - 1) * templateTaskCount;
57
- }
58
- }
59
- return extra;
60
- }