cool-workflow 0.1.97 → 0.2.0

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 (309) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +11 -2
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/cli/dispatch.js +236 -0
  11. package/dist/cli/entry.js +120 -0
  12. package/dist/cli/io.js +21 -4
  13. package/dist/cli/parseargv.js +157 -0
  14. package/dist/cli.js +6 -33
  15. package/dist/core/capability-table.js +3534 -0
  16. package/dist/core/format/help.js +314 -0
  17. package/dist/{state-explosion/format.js → core/format/state-explosion-text.js} +10 -1
  18. package/dist/core/hash.js +137 -0
  19. package/dist/core/multi-agent/candidate-scoring.js +219 -0
  20. package/dist/core/multi-agent/collaboration.js +481 -0
  21. package/dist/core/multi-agent/coordinator.js +515 -0
  22. package/dist/core/multi-agent/eval-replay.js +306 -0
  23. package/dist/core/multi-agent/runtime.js +929 -0
  24. package/dist/core/multi-agent/topology.js +298 -0
  25. package/dist/core/multi-agent/trust-policy.js +197 -0
  26. package/dist/core/pipeline/commit-gate.js +320 -0
  27. package/dist/{pipeline-contract.js → core/pipeline/contract.js} +24 -37
  28. package/dist/core/pipeline/dispatch.js +103 -0
  29. package/dist/core/pipeline/drive-decide.js +227 -0
  30. package/dist/core/pipeline/error-feedback.js +161 -0
  31. package/dist/core/pipeline/loop-expansion.js +124 -0
  32. package/dist/{result-normalize.js → core/pipeline/result-normalize.js} +14 -37
  33. package/dist/core/pipeline/runner.js +230 -0
  34. package/dist/{contract-migration.js → core/state/contract-migration.js} +68 -92
  35. package/dist/{state-migrations.js → core/state/migrations.js} +103 -96
  36. package/dist/core/state/node-projection.js +95 -0
  37. package/dist/core/state/node-snapshot.js +230 -0
  38. package/dist/core/state/run-paths.js +93 -0
  39. package/dist/{schema-validate.js → core/state/schema-validate.js} +35 -28
  40. package/dist/core/state/schema.js +50 -0
  41. package/dist/core/state/state-explosion/digest.js +243 -0
  42. package/dist/core/state/state-explosion/graph.js +527 -0
  43. package/dist/{state-explosion → core/state/state-explosion}/helpers.js +34 -3
  44. package/dist/core/state/state-explosion/report.js +187 -0
  45. package/dist/{state-explosion → core/state/state-explosion}/size.js +25 -7
  46. package/dist/{state-node.js → core/state/state-node.js} +90 -113
  47. package/dist/core/state/types.js +19 -0
  48. package/dist/{validation.js → core/state/validation.js} +64 -131
  49. package/dist/core/trust/evidence-grounding.js +134 -0
  50. package/dist/core/trust/ledger.js +199 -0
  51. package/dist/{telemetry-attestation.js → core/trust/telemetry-attestation.js} +94 -68
  52. package/dist/core/trust/telemetry-ledger.js +127 -0
  53. package/dist/core/types.js +20 -0
  54. package/dist/core/version.js +16 -0
  55. package/dist/{workflow-app-framework.js → core/workflow-apps/app-schema.js} +337 -426
  56. package/dist/mcp/dispatch.js +104 -0
  57. package/dist/mcp/server.js +144 -0
  58. package/dist/mcp-server.js +6 -84
  59. package/dist/{agent-config.js → shell/agent-config.js} +118 -71
  60. package/dist/shell/app-run-cli.js +88 -0
  61. package/dist/shell/audit-cli.js +259 -0
  62. package/dist/shell/audit-provenance.js +83 -0
  63. package/dist/shell/candidate-scoring-io.js +459 -0
  64. package/dist/shell/collaboration-io.js +264 -0
  65. package/dist/shell/commit-summary.js +104 -0
  66. package/dist/shell/commit.js +290 -0
  67. package/dist/shell/coordinator-io.js +476 -0
  68. package/dist/shell/demo-cli.js +19 -0
  69. package/dist/shell/dispatch.js +162 -0
  70. package/dist/{doctor.js → shell/doctor.js} +123 -56
  71. package/dist/shell/drive.js +873 -0
  72. package/dist/shell/error-feedback-io.js +305 -0
  73. package/dist/shell/eval-io.js +473 -0
  74. package/dist/{multi-agent-eval/format.js → shell/eval-text.js} +78 -49
  75. package/dist/{evidence-reasoning.js → shell/evidence-reasoning.js} +124 -255
  76. package/dist/shell/exec-backend-cli.js +88 -0
  77. package/dist/shell/execution-backend/agent.js +475 -0
  78. package/dist/shell/execution-backend/ci.js +15 -0
  79. package/dist/shell/execution-backend/container.js +69 -0
  80. package/dist/shell/execution-backend/envelopes.js +55 -0
  81. package/dist/shell/execution-backend/local.js +113 -0
  82. package/dist/shell/execution-backend/probes.js +175 -0
  83. package/dist/shell/execution-backend/registry.js +402 -0
  84. package/dist/shell/execution-backend/remote.js +128 -0
  85. package/dist/shell/execution-backend/types.js +11 -0
  86. package/dist/shell/feedback-cli.js +81 -0
  87. package/dist/shell/feedback-operations.js +48 -0
  88. package/dist/shell/fs-atomic.js +276 -0
  89. package/dist/shell/harness.js +98 -0
  90. package/dist/shell/ledger-cli.js +212 -0
  91. package/dist/shell/ledger-io.js +169 -0
  92. package/dist/shell/man-cli.js +89 -0
  93. package/dist/shell/metrics-cli.js +98 -0
  94. package/dist/shell/multi-agent-cli.js +1002 -0
  95. package/dist/shell/multi-agent-host.js +563 -0
  96. package/dist/shell/multi-agent-io.js +387 -0
  97. package/dist/{multi-agent-operator-ux.js → shell/multi-agent-operator-ux.js} +234 -191
  98. package/dist/shell/node-store.js +124 -0
  99. package/dist/{observability/format.js → shell/observability-format.js} +7 -1
  100. package/dist/{observability/intake.js → shell/observability-intake.js} +79 -56
  101. package/dist/{observability.js → shell/observability.js} +159 -332
  102. package/dist/{onramp.js → shell/onramp.js} +11 -0
  103. package/dist/{operator-ux/format.js → shell/operator-ux-text.js} +250 -239
  104. package/dist/shell/operator-ux.js +431 -0
  105. package/dist/shell/orchestrator.js +231 -0
  106. package/dist/shell/pipeline-cli.js +667 -0
  107. package/dist/shell/pipeline.js +217 -0
  108. package/dist/shell/reclamation-io.js +1366 -0
  109. package/dist/shell/registry-cli.js +329 -0
  110. package/dist/{remote-source.js → shell/remote-source.js} +12 -5
  111. package/dist/shell/report-cli.js +101 -0
  112. package/dist/shell/report-view-cli.js +117 -0
  113. package/dist/{orchestrator → shell}/report.js +289 -282
  114. package/dist/shell/reporter.js +62 -0
  115. package/dist/shell/run-export-cli.js +106 -0
  116. package/dist/shell/run-export.js +680 -0
  117. package/dist/shell/run-registry-io.js +1014 -0
  118. package/dist/shell/run-store.js +164 -0
  119. package/dist/{sandbox-profile.js → shell/sandbox-profile.js} +134 -95
  120. package/dist/{scheduler.js → shell/scheduler-io.js} +248 -48
  121. package/dist/shell/scheduling-io.js +311 -0
  122. package/dist/shell/state-cli.js +181 -0
  123. package/dist/shell/state-explosion-cli.js +197 -0
  124. package/dist/shell/telemetry-cli.js +85 -0
  125. package/dist/{telemetry-demo.js → shell/telemetry-demo.js} +149 -119
  126. package/dist/shell/telemetry-ledger-io.js +132 -0
  127. package/dist/{term.js → shell/term.js} +36 -46
  128. package/dist/shell/topology-io.js +361 -0
  129. package/dist/shell/trust-audit.js +471 -0
  130. package/dist/{multi-agent-trust.js → shell/trust-policy-io.js} +67 -205
  131. package/dist/shell/verifier.js +48 -0
  132. package/dist/shell/workbench-host.js +250 -0
  133. package/dist/shell/workbench-text.js +18 -0
  134. package/dist/shell/workbench.js +175 -0
  135. package/dist/shell/worker-cli.js +124 -0
  136. package/dist/shell/worker-isolation.js +852 -0
  137. package/dist/shell/workflow-app-loader.js +650 -0
  138. package/docs/agent-delegation-drive.7.md +4 -0
  139. package/docs/cli-mcp-parity.7.md +284 -211
  140. package/docs/contract-migration-tooling.7.md +4 -0
  141. package/docs/control-plane-scheduling.7.md +4 -0
  142. package/docs/cross-agent-ledger.7.md +217 -0
  143. package/docs/designs/handoff-ledger.md +145 -0
  144. package/docs/durable-state-and-locking.7.md +4 -0
  145. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  146. package/docs/execution-backends.7.md +4 -0
  147. package/docs/handoff-setup.md +120 -0
  148. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  149. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  150. package/docs/multi-agent-operator-ux.7.md +4 -0
  151. package/docs/node-snapshot-diff-replay.7.md +4 -0
  152. package/docs/observability-cost-accounting.7.md +4 -0
  153. package/docs/project-index.md +143 -71
  154. package/docs/real-execution-backends.7.md +4 -0
  155. package/docs/release-and-migration.7.md +4 -0
  156. package/docs/release-tooling.7.md +4 -0
  157. package/docs/run-registry-control-plane.7.md +4 -0
  158. package/docs/run-retention-reclamation.7.md +25 -0
  159. package/docs/state-explosion-management.7.md +4 -0
  160. package/docs/team-collaboration.7.md +4 -0
  161. package/docs/web-desktop-workbench.7.md +4 -0
  162. package/manifest/plugin.manifest.json +1 -1
  163. package/manifest/source-context-profiles.json +9 -13
  164. package/package.json +1 -1
  165. package/scripts/agents/codex-agent.js +34 -4
  166. package/scripts/agents/cw-attest-wrap.js +2 -2
  167. package/scripts/bump-version.js +4 -3
  168. package/scripts/canonical-apps.js +4 -4
  169. package/scripts/children/batch-delegate-child.js +30 -10
  170. package/scripts/dogfood-architecture-review.js +2 -3
  171. package/scripts/dogfood-release.js +3 -3
  172. package/scripts/gen-parity-doc.js +15 -2
  173. package/scripts/golden-path.js +4 -4
  174. package/scripts/onramp-check.js +1 -1
  175. package/scripts/parity-check.js +38 -21
  176. package/scripts/release-flow.js +9 -3
  177. package/scripts/sync-project-index.js +51 -27
  178. package/scripts/validate-run-state-schema.js +2 -2
  179. package/scripts/version-sync-check.js +30 -30
  180. package/dist/candidate-scoring.js +0 -729
  181. package/dist/capability-core.js +0 -1186
  182. package/dist/capability-registry.js +0 -879
  183. package/dist/cli/command-surface.js +0 -490
  184. package/dist/cli/format.js +0 -56
  185. package/dist/cli/handlers/audit.js +0 -82
  186. package/dist/cli/handlers/blackboard.js +0 -81
  187. package/dist/cli/handlers/candidate.js +0 -40
  188. package/dist/cli/handlers/clones.js +0 -34
  189. package/dist/cli/handlers/collaboration.js +0 -61
  190. package/dist/cli/handlers/eval.js +0 -40
  191. package/dist/cli/handlers/maintenance.js +0 -107
  192. package/dist/cli/handlers/multi-agent.js +0 -165
  193. package/dist/cli/handlers/node.js +0 -41
  194. package/dist/cli/handlers/operational.js +0 -155
  195. package/dist/cli/handlers/operator.js +0 -146
  196. package/dist/cli/handlers/registry.js +0 -68
  197. package/dist/cli/handlers/run.js +0 -153
  198. package/dist/cli/handlers/scheduling.js +0 -132
  199. package/dist/cli/handlers/workbench.js +0 -41
  200. package/dist/cli/handlers/worker.js +0 -45
  201. package/dist/cli/run-summary.js +0 -45
  202. package/dist/clones.js +0 -162
  203. package/dist/collaboration.js +0 -726
  204. package/dist/commit.js +0 -592
  205. package/dist/compare.js +0 -18
  206. package/dist/coordinator/classify.js +0 -45
  207. package/dist/coordinator/paths.js +0 -42
  208. package/dist/coordinator/util.js +0 -126
  209. package/dist/coordinator.js +0 -990
  210. package/dist/daemon.js +0 -44
  211. package/dist/dispatch.js +0 -250
  212. package/dist/drive.js +0 -827
  213. package/dist/error-feedback.js +0 -419
  214. package/dist/evidence-grounding.js +0 -184
  215. package/dist/execution-backend/agent.js +0 -294
  216. package/dist/execution-backend/probes.js +0 -112
  217. package/dist/execution-backend/util.js +0 -47
  218. package/dist/execution-backend.js +0 -961
  219. package/dist/gates.js +0 -48
  220. package/dist/harness.js +0 -61
  221. package/dist/loop-expansion.js +0 -60
  222. package/dist/mcp/tool-call.js +0 -434
  223. package/dist/mcp/tool-definitions.js +0 -1040
  224. package/dist/mcp-surface.js +0 -30
  225. package/dist/multi-agent/graph.js +0 -84
  226. package/dist/multi-agent/helpers.js +0 -141
  227. package/dist/multi-agent/ids.js +0 -20
  228. package/dist/multi-agent/paths.js +0 -22
  229. package/dist/multi-agent-eval/normalize.js +0 -51
  230. package/dist/multi-agent-eval.js +0 -678
  231. package/dist/multi-agent-host.js +0 -777
  232. package/dist/multi-agent.js +0 -984
  233. package/dist/node-projection.js +0 -59
  234. package/dist/node-snapshot.js +0 -260
  235. package/dist/operator-ux.js +0 -631
  236. package/dist/orchestrator/app-operations.js +0 -211
  237. package/dist/orchestrator/audit-operations.js +0 -182
  238. package/dist/orchestrator/candidate-operations.js +0 -117
  239. package/dist/orchestrator/cli-options.js +0 -294
  240. package/dist/orchestrator/collaboration-operations.js +0 -86
  241. package/dist/orchestrator/feedback-operations.js +0 -81
  242. package/dist/orchestrator/host-operations.js +0 -78
  243. package/dist/orchestrator/lifecycle-operations.js +0 -626
  244. package/dist/orchestrator/migration-operations.js +0 -44
  245. package/dist/orchestrator/multi-agent-operations.js +0 -362
  246. package/dist/orchestrator/topology-operations.js +0 -84
  247. package/dist/orchestrator.js +0 -917
  248. package/dist/pipeline-runner.js +0 -285
  249. package/dist/reclamation/hash.js +0 -72
  250. package/dist/reclamation.js +0 -812
  251. package/dist/reporter.js +0 -67
  252. package/dist/run-export.js +0 -784
  253. package/dist/run-registry/derive.js +0 -175
  254. package/dist/run-registry/format.js +0 -124
  255. package/dist/run-registry/gc.js +0 -251
  256. package/dist/run-registry/policy.js +0 -16
  257. package/dist/run-registry/queue.js +0 -115
  258. package/dist/run-registry.js +0 -850
  259. package/dist/run-state-schema.js +0 -68
  260. package/dist/scheduling.js +0 -184
  261. package/dist/state-explosion.js +0 -1014
  262. package/dist/state.js +0 -367
  263. package/dist/telemetry-ledger.js +0 -196
  264. package/dist/topology.js +0 -565
  265. package/dist/triggers.js +0 -184
  266. package/dist/trust-audit.js +0 -644
  267. package/dist/types/blackboard.js +0 -2
  268. package/dist/types/candidate.js +0 -2
  269. package/dist/types/collaboration.js +0 -2
  270. package/dist/types/core.js +0 -2
  271. package/dist/types/drive.js +0 -10
  272. package/dist/types/error-feedback.js +0 -2
  273. package/dist/types/evidence-reasoning.js +0 -2
  274. package/dist/types/execution-backend.js +0 -2
  275. package/dist/types/multi-agent.js +0 -2
  276. package/dist/types/observability.js +0 -2
  277. package/dist/types/pipeline.js +0 -2
  278. package/dist/types/reclamation.js +0 -8
  279. package/dist/types/report-bundle.js +0 -6
  280. package/dist/types/result.js +0 -2
  281. package/dist/types/run-registry.js +0 -2
  282. package/dist/types/run.js +0 -2
  283. package/dist/types/sandbox.js +0 -2
  284. package/dist/types/schedule.js +0 -2
  285. package/dist/types/state-node.js +0 -2
  286. package/dist/types/topology.js +0 -2
  287. package/dist/types/trust.js +0 -2
  288. package/dist/types/workbench.js +0 -2
  289. package/dist/types/worker.js +0 -2
  290. package/dist/types/workflow-app.js +0 -2
  291. package/dist/types.js +0 -44
  292. package/dist/util/fingerprint.js +0 -19
  293. package/dist/util/fingerprint.test.js +0 -27
  294. package/dist/verifier.js +0 -78
  295. package/dist/version.js +0 -8
  296. package/dist/workbench-host.js +0 -182
  297. package/dist/workbench.js +0 -192
  298. package/dist/worker-accept/acceptance.js +0 -114
  299. package/dist/worker-accept/blackboard-fanout.js +0 -80
  300. package/dist/worker-accept/blackboard-linkage.js +0 -19
  301. package/dist/worker-accept/context.js +0 -2
  302. package/dist/worker-accept/telemetry-ledger.js +0 -126
  303. package/dist/worker-accept/validation.js +0 -77
  304. package/dist/worker-accept/verifier-completion.js +0 -73
  305. package/dist/worker-isolation/helpers.js +0 -51
  306. package/dist/worker-isolation/paths.js +0 -46
  307. package/dist/worker-isolation.js +0 -656
  308. package/dist/workflow-api.js +0 -131
  309. /package/dist/{types → core/types}/boundary.js +0 -0
@@ -1,31 +1,54 @@
1
1
  "use strict";
2
- // Telemetry attestation (Track 1) make "auditable" a FACT, not a claim.
2
+ // core/trust/telemetry-attestation.tsed25519 usage/result attestation.
3
3
  //
4
- // The agent self-reports its token usage on stdout (parseAgentReport). A control
5
- // plane that records that number verbatim is recording a CLAIM: a tampered or
6
- // fabricated usage survives untouched. This module is the verify gate that turns
7
- // the claim into an attestation:
4
+ // MILESTONE 8. The AGENT (executor) signs; CW only VERIFIES with an
5
+ // operator-given PUBLIC key CW holds no private key, ever. Uses
6
+ // node:crypto's built-in ed25519 sign/verify (no npm dependency).
8
7
  //
9
- // - The EXECUTOR signs a canonical payload binding {usage, runId, taskId,
10
- // promptDigest} with its private key (ed25519). The binding context is what
11
- // stops one task's signature being replayed onto another.
12
- // - CW VERIFIES that signature against an operator-provisioned PUBLIC key.
13
- // CW holds ONLY the public key — it can verify, but can neither forge a
14
- // signature nor (the red line) call a model to measure usage itself. A
15
- // third-party auditor with the same public key can re-verify independently.
8
+ // `crypto.verify`/`crypto.createPublicKey` are allowed here per
9
+ // v2/PLAN.md's lint carve-out for this exact file (Target shape,
10
+ // core/trust/telemetry-attestation.ts comment) this remains otherwise
11
+ // pure (no fs, no process.env, no clock; `resolveTrustPublicKey`'s lazy
12
+ // `require("node:fs")` is the one exception, ported byte-identically
13
+ // from the old build's own lazy-require pattern so a bundle that never
14
+ // resolves a key path pays no fs cost).
16
15
  //
17
- // HONEST CEILING [load-bearing]: a signature proves the usage came from the
18
- // keyholder and was not tampered in transit — NON-REPUDIABLE ATTRIBUTION, not
19
- // ground-truth measurement. A dishonest keyholder can still sign a lie, but the
20
- // lie is now cryptographically bound to its signer. That is strictly stronger
21
- // than self-signed sha256 (which any party can recompute) and is the most a
22
- // delegating control-plane can claim without measuring (which it must not).
23
- //
24
- // Default is honest: no signature `unattested`, no usage `absent`. Usage is
25
- // NEVER silently recorded as trusted.
26
- var __importDefault = (this && this.__importDefault) || function (mod) {
27
- return (mod && mod.__esModule) ? mod : { "default": mod };
28
- };
16
+ // Evidence: SPEC/ledger-trust.md "The signing model", "Attestation
17
+ // verify", byte-compat items 2 and 11;
18
+ // plugins/cool-workflow/src/telemetry-attestation.ts:1-319.
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
29
52
  Object.defineProperty(exports, "__esModule", { value: true });
30
53
  exports.stableStringify = stableStringify;
31
54
  exports.canonicalTelemetryPayload = canonicalTelemetryPayload;
@@ -34,9 +57,17 @@ exports.verifyTelemetryAttestation = verifyTelemetryAttestation;
34
57
  exports.resolveTrustPublicKey = resolveTrustPublicKey;
35
58
  exports.signTelemetry = signTelemetry;
36
59
  exports.verifyTelemetrySignatures = verifyTelemetrySignatures;
37
- const node_crypto_1 = __importDefault(require("node:crypto"));
38
- /** Deterministic, key-sorted JSON so signer and verifier hash byte-identical
39
- * input regardless of object key order. */
60
+ const crypto = __importStar(require("node:crypto"));
61
+ /** `src/telemetry-attestation.ts`'s `stableStringify` sorts keys
62
+ * recursively, AND maps a top-level `undefined` input to the literal
63
+ * string `"null"`. Divergent from `core/hash.ts`'s
64
+ * `ledgerStableStringify` exactly at the top-level-undefined edge (see
65
+ * v2/PLAN.md byte-compat item 2). Re-exported under this file's own
66
+ * name (rather than importing `telemetryStableStringify` from
67
+ * core/hash.ts) because SPEC/ledger-trust.md's "Exported functions"
68
+ * list names `stableStringify` as a real export of THIS module — the
69
+ * two are byte-identical behavior, kept as separate named exports per
70
+ * their separate call sites. */
40
71
  function stableStringify(value) {
41
72
  if (value === null || typeof value !== "object")
42
73
  return JSON.stringify(value) ?? "null";
@@ -54,10 +85,10 @@ function canonicalTelemetryPayload(usage, ctx) {
54
85
  runId: ctx.runId,
55
86
  taskId: ctx.taskId,
56
87
  promptDigest: ctx.promptDigest,
57
- // Present ONLY when the signer covered the result. Omitting the key keeps the
58
- // canonical bytes byte-identical to the original 4-field payload, so every
59
- // pre-result-coverage signature still verifies (POLA / back-compat).
60
- ...(ctx.resultDigest !== undefined ? { resultDigest: ctx.resultDigest } : {})
88
+ // Present ONLY when the signer covered the result omitting the key
89
+ // keeps the canonical bytes byte-identical to the original 4-field
90
+ // payload, so every pre-result-coverage signature still verifies.
91
+ ...(ctx.resultDigest !== undefined ? { resultDigest: ctx.resultDigest } : {}),
61
92
  });
62
93
  }
63
94
  function messageOf(error) {
@@ -72,9 +103,9 @@ function numberAt(usage, ...keys) {
72
103
  }
73
104
  return undefined;
74
105
  }
75
- /** Map the agent's free-form usage report onto UsageRecord token buckets, tolerating
76
- * snake_case / camelCase variants (input_tokens vs inputTokens, etc.). CW never
77
- * invents a number — an unreported bucket stays undefined, never zero. */
106
+ /** Map the agent's free-form usage report onto token buckets, tolerating
107
+ * snake_case / camelCase variants. CW never invents a number — an
108
+ * unreported bucket stays `undefined`, never 0. */
78
109
  function normalizeReportedUsage(usage) {
79
110
  if (!usage)
80
111
  return {};
@@ -83,11 +114,15 @@ function normalizeReportedUsage(usage) {
83
114
  outputTokens: numberAt(usage, "outputTokens", "output_tokens", "completionTokens", "completion_tokens"),
84
115
  cacheReadTokens: numberAt(usage, "cacheReadTokens", "cache_read_tokens", "cacheReadInputTokens", "cache_read_input_tokens"),
85
116
  cacheWriteTokens: numberAt(usage, "cacheWriteTokens", "cache_write_tokens", "cacheCreationInputTokens", "cache_creation_input_tokens"),
86
- totalTokens: numberAt(usage, "totalTokens", "total_tokens")
117
+ totalTokens: numberAt(usage, "totalTokens", "total_tokens"),
87
118
  };
88
119
  }
89
- /** Verify the agent's signed usage against the operator-provisioned public key.
90
- * Pure + deterministic (no clock, no env). Returns a status, never throws. */
120
+ /** Verify the agent's signed usage against the operator-provisioned
121
+ * public key. Two-arm check (v2/PLAN.md byte-compat item 11): try the
122
+ * 5-field payload (with resultDigest) first; on a miss, retry the
123
+ * 4-field payload (old signers still verify). `coversResult` is set
124
+ * ONLY on a first-arm match — a 4-field fallback match never covers the
125
+ * result, even when a resultDigest sits on the record. Never throws. */
91
126
  function verifyTelemetryAttestation(usage, signatureB64, trustPublicKeyPem, ctx) {
92
127
  if (!usage || Object.keys(usage).length === 0) {
93
128
  return { status: "absent", reason: "agent reported no usage" };
@@ -100,7 +135,7 @@ function verifyTelemetryAttestation(usage, signatureB64, trustPublicKeyPem, ctx)
100
135
  }
101
136
  let publicKey;
102
137
  try {
103
- publicKey = node_crypto_1.default.createPublicKey(trustPublicKeyPem);
138
+ publicKey = crypto.createPublicKey(trustPublicKeyPem);
104
139
  }
105
140
  catch (error) {
106
141
  return { status: "unattested", reason: `trust key unreadable: ${messageOf(error)}` };
@@ -114,18 +149,18 @@ function verifyTelemetryAttestation(usage, signatureB64, trustPublicKeyPem, ctx)
114
149
  catch {
115
150
  return { status: "unattested", reason: "signature is not valid base64" };
116
151
  }
117
- const matches = (c) => node_crypto_1.default.verify(null, Buffer.from(canonicalTelemetryPayload(usage, c), "utf8"), publicKey, signature);
152
+ const matches = (c) => crypto.verify(null, Buffer.from(canonicalTelemetryPayload(usage, c), "utf8"), publicKey, signature);
118
153
  let ok = false;
119
154
  let coversResult = false;
120
155
  try {
121
156
  ok = matches(ctx);
122
- // A match on the first arm (which carries resultDigest when CW has one) means
123
- // the signature covered the result — the findings — not just the usage.
157
+ // A match on the first arm (which carries resultDigest when CW has
158
+ // one) means the signature covered the result, not just the usage.
124
159
  coversResult = ok && ctx.resultDigest !== undefined;
125
- // Back-compat: a signer that predates result coverage signed only the 4-field
126
- // payload, so on a miss retry WITHOUT resultDigest. A NEW signer who covered
127
- // the result fails BOTH arms when the result is edited (its resultDigest no
128
- // longer matches), so result tampering is still caught.
160
+ // Back-compat: a signer that predates result coverage signed only
161
+ // the 4-field payload, so on a miss retry WITHOUT resultDigest. A NEW
162
+ // signer who covered the result fails BOTH arms when the result is
163
+ // edited (its resultDigest no longer matches).
129
164
  if (!ok && ctx.resultDigest !== undefined)
130
165
  ok = matches({ ...ctx, resultDigest: undefined });
131
166
  }
@@ -136,9 +171,10 @@ function verifyTelemetryAttestation(usage, signatureB64, trustPublicKeyPem, ctx)
136
171
  ? { status: "attested", algorithm: "ed25519", ...(coversResult ? { coversResult: true } : {}) }
137
172
  : { status: "unattested", reason: "signature does not match reported usage (tampered, replayed, or wrong key)" };
138
173
  }
139
- /** Resolve a trust key from a config value that is EITHER an inline PEM or a path
140
- * to a `.pem` file. Returns undefined when absent/unreadable (⇒ `unattested`,
141
- * never a hard throw). CW only ever loads a PUBLIC key here. */
174
+ /** Resolve a trust key from a config value that is EITHER an inline PEM
175
+ * or a path to a `.pem` file. Returns undefined when absent/unreadable
176
+ * (⇒ `unattested`, never a hard throw). CW only ever loads a PUBLIC key
177
+ * here. */
142
178
  function resolveTrustPublicKey(value) {
143
179
  if (!value)
144
180
  return undefined;
@@ -148,7 +184,9 @@ function resolveTrustPublicKey(value) {
148
184
  if (trimmed.includes("BEGIN") && trimmed.includes("KEY"))
149
185
  return trimmed;
150
186
  try {
151
- // Lazy require so a bundle that never resolves a key path pays no fs cost.
187
+ // Lazy require so a bundle that never resolves a key path pays no
188
+ // fs cost — byte-identical pattern to the old build's own lazy
189
+ // require here.
152
190
  const fs = require("node:fs");
153
191
  if (fs.existsSync(trimmed))
154
192
  return fs.readFileSync(trimmed, "utf8");
@@ -159,18 +197,16 @@ function resolveTrustPublicKey(value) {
159
197
  return undefined;
160
198
  }
161
199
  // ---------------------------------------------------------------------------
162
- // EXECUTOR-SIDE HELPER — the CW RUNTIME NEVER CALLS THIS.
163
- // Provided for signing wrappers around `claude -p`/endpoints and for tests. It
164
- // touches a private key, never a model, so it does not cross the red line; it is
165
- // kept here only so signer and verifier share one canonicalization.
200
+ // EXECUTOR-SIDE HELPER — the CW RUNTIME NEVER CALLS THIS. Provided for
201
+ // signing wrappers and tests; touches a private key, never a model.
166
202
  // ---------------------------------------------------------------------------
167
203
  function signTelemetry(usage, privateKeyPem, ctx) {
168
204
  const payload = Buffer.from(canonicalTelemetryPayload(usage, ctx), "utf8");
169
- const key = node_crypto_1.default.createPrivateKey(privateKeyPem);
170
- return node_crypto_1.default.sign(null, payload, key).toString("base64");
205
+ const key = crypto.createPrivateKey(privateKeyPem);
206
+ return crypto.sign(null, payload, key).toString("base64");
171
207
  }
172
208
  function stableDigest(value) {
173
- return `sha256:${node_crypto_1.default.createHash("sha256").update(stableStringify(value), "utf8").digest("hex")}`;
209
+ return `sha256:${crypto.createHash("sha256").update(stableStringify(value), "utf8").digest("hex")}`;
174
210
  }
175
211
  function verifyTelemetrySignatures(records, trustPublicKeyPem) {
176
212
  const checks = [];
@@ -188,16 +224,11 @@ function verifyTelemetrySignatures(records, trustPublicKeyPem) {
188
224
  continue;
189
225
  }
190
226
  if (!record.reportedUsage) {
191
- // A claimed-`attested` record with no re-verifiable raw usage cannot be
192
- // independently checked — fail closed rather than trust the stored verdict.
193
227
  failed += 1;
194
228
  checks.push({ name: `signature[${i}]`, pass: false, code: "telemetry-usage-unavailable" });
195
229
  continue;
196
230
  }
197
231
  if (record.reportedUsageDigest !== stableDigest(record.reportedUsage)) {
198
- // The raw usage is stored so a public-key verifier can re-run ed25519.
199
- // The hash-chained record binds its digest; verify the two still match
200
- // before trusting the raw payload for signature re-verification.
201
232
  failed += 1;
202
233
  checks.push({ name: `signature[${i}]`, pass: false, code: "telemetry-usage-digest-mismatch" });
203
234
  continue;
@@ -206,16 +237,11 @@ function verifyTelemetrySignatures(records, trustPublicKeyPem) {
206
237
  runId: record.runId,
207
238
  taskId: record.taskId,
208
239
  promptDigest: record.promptDigest,
209
- // Result-bound records carry the signed digest; verifyTelemetryAttestation
210
- // reconstructs the 5-field payload (and falls back to 4-field for old records).
211
- resultDigest: record.resultDigest
240
+ resultDigest: record.resultDigest,
212
241
  });
213
242
  if (result.status === "attested") {
214
243
  reverified += 1;
215
244
  checks.push({ name: `signature[${i}]`, pass: true });
216
- // Only a signature that actually COVERED the result digest anchors it — a
217
- // 4-field fallback (coversResult false) must not let an injected resultDigest
218
- // be trusted downstream.
219
245
  if (result.coversResult && record.resultDigest) {
220
246
  resultBound.push({ taskId: record.taskId, resultDigest: record.resultDigest });
221
247
  }
@@ -227,7 +253,7 @@ function verifyTelemetrySignatures(records, trustPublicKeyPem) {
227
253
  pass: false,
228
254
  code: result.reason && result.reason.startsWith("trust key unreadable")
229
255
  ? "telemetry-pubkey-unreadable"
230
- : "telemetry-signature-mismatch"
256
+ : "telemetry-signature-mismatch",
231
257
  });
232
258
  }
233
259
  }
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ // core/trust/telemetry-ledger.ts — the hash-chained telemetry
3
+ // attestation ledger's PURE half: genesisPrevHash, computeRecordHash,
4
+ // reportedUsageDigest, verifyTelemetryLedger. Directory/file IO
5
+ // (telemetryLedgerPath, loadTelemetryLedger, appendTelemetryAttestation)
6
+ // lives in shell/telemetry-ledger-io.ts.
7
+ //
8
+ // MILESTONE 8. Byte-exact port of the old build's src/telemetry-ledger.ts
9
+ // verify-side logic. Uses core/hash.ts's `sha256`/`telemetryStableStringify`
10
+ // (see v2/PLAN.md byte-compat item 2's key-omission-vs-null rule).
11
+ //
12
+ // Evidence: SPEC/ledger-trust.md "Telemetry ledger record", byte-compat
13
+ // items 2 and 12; plugins/cool-workflow/src/telemetry-ledger.ts:1-224.
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.TelemetryLedgerCorruptError = exports.TELEMETRY_LEDGER_SCHEMA_VERSION = void 0;
16
+ exports.genesisPrevHash = genesisPrevHash;
17
+ exports.computeRecordHash = computeRecordHash;
18
+ exports.reportedUsageDigest = reportedUsageDigest;
19
+ exports.recordId = recordId;
20
+ exports.verifyTelemetryLedgerRecords = verifyTelemetryLedgerRecords;
21
+ exports.corruptTelemetryLedgerVerification = corruptTelemetryLedgerVerification;
22
+ const hash_1 = require("../hash");
23
+ exports.TELEMETRY_LEDGER_SCHEMA_VERSION = 1;
24
+ /** A telemetry ledger that EXISTS on disk but cannot be parsed (or whose
25
+ * shape is not a record array). This is exactly the corruption/
26
+ * truncation case the hash chain exists to catch — it must fail closed,
27
+ * never be silently treated as the "empty/absent" chain (which verifies
28
+ * as clean). */
29
+ class TelemetryLedgerCorruptError extends Error {
30
+ file;
31
+ constructor(file) {
32
+ super(`Telemetry ledger exists but is corrupt (unparseable): ${file}`);
33
+ this.name = "TelemetryLedgerCorruptError";
34
+ this.file = file;
35
+ }
36
+ }
37
+ exports.TelemetryLedgerCorruptError = TelemetryLedgerCorruptError;
38
+ /** genesis prevHash for a run's chain (no prior record). */
39
+ function genesisPrevHash(runId) {
40
+ return (0, hash_1.sha256)(`cw-telemetry-ledger:${runId}`);
41
+ }
42
+ /** The canonical bytes a recordHash binds — every field except
43
+ * recordHash itself. `reportedUsage`/`resultDigest` are OMITTED (not
44
+ * `null`) when absent, so a usage-only record's hash is byte-identical
45
+ * to a pre-result-coverage one (back-compat with old ledgers) — see
46
+ * v2/PLAN.md byte-compat item 2. */
47
+ function recordHashInput(record) {
48
+ return (0, hash_1.telemetryStableStringify)({
49
+ schemaVersion: record.schemaVersion,
50
+ runId: record.runId,
51
+ recordId: record.recordId,
52
+ recordedAt: record.recordedAt,
53
+ workerId: record.workerId,
54
+ taskId: record.taskId,
55
+ promptDigest: record.promptDigest,
56
+ reportedUsageDigest: record.reportedUsageDigest,
57
+ ...(record.reportedUsage !== undefined ? { reportedUsage: record.reportedUsage } : {}),
58
+ usageSignature: record.usageSignature || null,
59
+ ...(record.resultDigest !== undefined ? { resultDigest: record.resultDigest } : {}),
60
+ attestation: record.attestation,
61
+ attestationReason: record.attestationReason || null,
62
+ prevHash: record.prevHash,
63
+ });
64
+ }
65
+ function computeRecordHash(record) {
66
+ return (0, hash_1.sha256)(recordHashInput(record));
67
+ }
68
+ /** sha256 of the canonical reported usage (compact, chainable). Absent
69
+ * usage gets the digest of `null`, so "the agent reported nothing" is
70
+ * itself bound. */
71
+ function reportedUsageDigest(usage) {
72
+ return (0, hash_1.sha256)((0, hash_1.telemetryStableStringify)(usage ?? null));
73
+ }
74
+ /** Deterministic (chain POSITION, not a process-global counter or
75
+ * wall-clock stamp): `tel-` + chain position, zero-padded to 3. */
76
+ function recordId(seq) {
77
+ return `tel-${String(seq).padStart(3, "0")}`;
78
+ }
79
+ /** Re-prove the whole telemetry chain for a run: prevHash linkage +
80
+ * per-record hash recompute. Recomputes every hash independently —
81
+ * never trusts the stored value. An empty ledger verifies as
82
+ * present:false (nothing to prove), NOT a failure. Pure: takes the
83
+ * already-loaded record array plus the run id, never touches disk. */
84
+ function verifyTelemetryLedgerRecords(runId, records) {
85
+ const checks = [];
86
+ const tally = { attested: 0, unattested: 0, absent: 0 };
87
+ for (const record of records)
88
+ tally[record.attestation] += 1;
89
+ if (!records.length) {
90
+ return { present: false, verified: true, records, checks, ...tally };
91
+ }
92
+ // (a) chain linkage.
93
+ let chainOk = true;
94
+ for (let i = 0; i < records.length; i++) {
95
+ const expectedPrev = i === 0 ? genesisPrevHash(runId) : records[i - 1].recordHash;
96
+ const pass = records[i].prevHash === expectedPrev;
97
+ if (!pass)
98
+ chainOk = false;
99
+ checks.push({ name: `chain-link[${i}]`, pass, code: pass ? undefined : "telemetry-chain-broken" });
100
+ }
101
+ // (b) per-record independent hash recompute (digest integrity).
102
+ let digestsOk = true;
103
+ for (let i = 0; i < records.length; i++) {
104
+ const { recordHash, ...rest } = records[i];
105
+ const recomputed = computeRecordHash(rest);
106
+ const pass = recomputed === recordHash;
107
+ if (!pass)
108
+ digestsOk = false;
109
+ checks.push({ name: `record-hash[${i}]`, pass, code: pass ? undefined : "telemetry-digest-mismatch" });
110
+ }
111
+ return { present: true, verified: chainOk && digestsOk, records, checks, ...tally };
112
+ }
113
+ /** The corrupt-ledger verification shape (present:true, verified:false,
114
+ * one `ledger-load`/`telemetry-ledger-corrupt` failed check). Shared
115
+ * constant so both the CLI-facing shell reader and any pure caller
116
+ * report the exact same shape for a corrupt file. */
117
+ function corruptTelemetryLedgerVerification() {
118
+ return {
119
+ present: true,
120
+ verified: false,
121
+ records: [],
122
+ checks: [{ name: "ledger-load", pass: false, code: "telemetry-ledger-corrupt" }],
123
+ attested: 0,
124
+ unattested: 0,
125
+ absent: 0,
126
+ };
127
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ // src/core/types.ts — barrel for cross-cutting pure type modules under
3
+ // src/core/types/. Mirrors the src/cli.ts + src/cli/ convention: a thin
4
+ // top-level file next to the directory it fronts.
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ __exportStar(require("./types/boundary"), exports);
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION = exports.LEGACY_RUN_STATE_SCHEMA_VERSION = exports.CURRENT_RUN_STATE_SCHEMA_VERSION = exports.WORKFLOW_APP_SCHEMA_VERSION = exports.CURRENT_COOL_WORKFLOW_VERSION = void 0;
4
+ // core/version.ts — the one version string `cw version` prints.
5
+ //
6
+ // Pure. POLA: keep the exact same version marker the old build reports, so
7
+ // `cw version` output does not change bytes just because the code under it
8
+ // was rebuilt. See SPEC/cli-surface.md "Exact outputs > Version" and
9
+ // conformance/cases/version-basic.case.js (regex `/^\d+\.\d+\.\d+\n$/`).
10
+ exports.CURRENT_COOL_WORKFLOW_VERSION = "0.2.0";
11
+ // State-kernel schema version constants (SPEC/state-core.md "Version
12
+ // constants"). Pinned to the old build's src/version.ts byte-for-byte.
13
+ exports.WORKFLOW_APP_SCHEMA_VERSION = 1;
14
+ exports.CURRENT_RUN_STATE_SCHEMA_VERSION = 1;
15
+ exports.LEGACY_RUN_STATE_SCHEMA_VERSION = 0;
16
+ exports.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION = 0;