cool-workflow 0.1.80 → 0.1.82

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 (122) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +42 -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/agent-config.js +21 -7
  11. package/dist/candidate-scoring.js +62 -48
  12. package/dist/capability-core.js +152 -96
  13. package/dist/capability-registry.js +160 -174
  14. package/dist/cli.js +90 -100
  15. package/dist/collaboration.js +5 -6
  16. package/dist/commit.js +232 -209
  17. package/dist/compare.js +18 -0
  18. package/dist/coordinator/classify.js +45 -0
  19. package/dist/coordinator/paths.js +42 -0
  20. package/dist/coordinator/util.js +126 -0
  21. package/dist/coordinator.js +127 -300
  22. package/dist/dispatch.js +46 -3
  23. package/dist/drive.js +7 -7
  24. package/dist/error-feedback.js +8 -4
  25. package/dist/evidence-reasoning.js +5 -2
  26. package/dist/execution-backend/agent.js +294 -0
  27. package/dist/execution-backend/probes.js +96 -0
  28. package/dist/execution-backend/util.js +47 -0
  29. package/dist/execution-backend.js +77 -450
  30. package/dist/gates.js +48 -0
  31. package/dist/mcp-server.js +34 -173
  32. package/dist/multi-agent/graph.js +84 -0
  33. package/dist/multi-agent/helpers.js +141 -0
  34. package/dist/multi-agent/ids.js +20 -0
  35. package/dist/multi-agent/paths.js +22 -0
  36. package/dist/multi-agent-eval/format.js +194 -0
  37. package/dist/multi-agent-eval/normalize.js +51 -0
  38. package/dist/multi-agent-eval.js +63 -242
  39. package/dist/multi-agent-host.js +53 -40
  40. package/dist/multi-agent-operator-ux.js +2 -1
  41. package/dist/multi-agent-trust.js +5 -5
  42. package/dist/multi-agent.js +125 -314
  43. package/dist/node-projection.js +59 -0
  44. package/dist/node-snapshot.js +11 -21
  45. package/dist/observability/format.js +61 -0
  46. package/dist/observability/intake.js +98 -0
  47. package/dist/observability.js +14 -160
  48. package/dist/operator-ux/format.js +364 -0
  49. package/dist/operator-ux.js +22 -363
  50. package/dist/orchestrator/lifecycle-operations.js +22 -1
  51. package/dist/orchestrator/report.js +8 -0
  52. package/dist/orchestrator.js +41 -10
  53. package/dist/reclamation.js +32 -55
  54. package/dist/run-export.js +138 -14
  55. package/dist/run-registry/derive.js +172 -0
  56. package/dist/run-registry/format.js +124 -0
  57. package/dist/run-registry/gc.js +251 -0
  58. package/dist/run-registry/policy.js +16 -0
  59. package/dist/run-registry/queue.js +116 -0
  60. package/dist/run-registry.js +78 -593
  61. package/dist/run-state-schema.js +1 -0
  62. package/dist/sandbox-profile.js +43 -2
  63. package/dist/scheduler.js +34 -4
  64. package/dist/state-explosion/format.js +159 -0
  65. package/dist/state-explosion/helpers.js +82 -0
  66. package/dist/state-explosion.js +65 -283
  67. package/dist/state-node.js +19 -4
  68. package/dist/telemetry-attestation.js +55 -0
  69. package/dist/telemetry-demo.js +15 -3
  70. package/dist/telemetry-ledger.js +60 -15
  71. package/dist/topology.js +50 -12
  72. package/dist/triggers.js +33 -14
  73. package/dist/trust-audit.js +215 -71
  74. package/dist/validation.js +328 -0
  75. package/dist/version.js +1 -1
  76. package/dist/worker-isolation/helpers.js +51 -0
  77. package/dist/worker-isolation/paths.js +46 -0
  78. package/dist/worker-isolation.js +182 -173
  79. package/docs/agent-delegation-drive.7.md +14 -0
  80. package/docs/cli-mcp-parity.7.md +5 -0
  81. package/docs/contract-migration-tooling.7.md +3 -0
  82. package/docs/control-plane-scheduling.7.md +3 -0
  83. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  84. package/docs/durable-state-and-locking.7.md +5 -0
  85. package/docs/evidence-adoption-reasoning-chain.7.md +3 -0
  86. package/docs/execution-backends.7.md +3 -0
  87. package/docs/index.md +1 -0
  88. package/docs/launch/launch-kit.md +46 -23
  89. package/docs/launch/pre-launch-checklist.md +14 -14
  90. package/docs/multi-agent-cli-mcp-surface.7.md +5 -0
  91. package/docs/multi-agent-eval-replay-harness.7.md +3 -0
  92. package/docs/multi-agent-operator-ux.7.md +3 -0
  93. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  94. package/docs/node-snapshot-diff-replay.7.md +3 -0
  95. package/docs/observability-cost-accounting.7.md +3 -0
  96. package/docs/project-index.md +23 -6
  97. package/docs/real-execution-backends.7.md +3 -0
  98. package/docs/release-and-migration.7.md +5 -0
  99. package/docs/release-tooling.7.md +35 -2
  100. package/docs/run-registry-control-plane.7.md +55 -8
  101. package/docs/run-retention-reclamation.7.md +5 -0
  102. package/docs/state-explosion-management.7.md +3 -0
  103. package/docs/team-collaboration.7.md +3 -0
  104. package/docs/trust-model.md +267 -0
  105. package/docs/vendor-manifest-loadability.7.md +43 -0
  106. package/docs/web-desktop-workbench.7.md +3 -0
  107. package/manifest/plugin.manifest.json +1 -1
  108. package/manifest/source-context-profiles.json +1 -1
  109. package/package.json +4 -2
  110. package/scripts/agents/builtin-templates.json +7 -0
  111. package/scripts/bump-version.js +5 -11
  112. package/scripts/canonical-apps-list.js +64 -0
  113. package/scripts/canonical-apps.js +19 -4
  114. package/scripts/children/batch-delegate-child.js +58 -0
  115. package/scripts/children/http-delegate-child.js +39 -0
  116. package/scripts/dogfood-release.js +1 -1
  117. package/scripts/golden-path.js +4 -4
  118. package/scripts/parity-check.js +5 -0
  119. package/scripts/release-check.js +5 -1
  120. package/scripts/release-flow.js +181 -5
  121. package/scripts/version-sync-check.js +5 -8
  122. package/dist/capability-dispatcher.js +0 -86
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ // Canonical StateNode projection (F9 de-triplication) — the SINGLE source of
3
+ // truth for which StateNode fields make up the derived, fingerprinted body.
4
+ //
5
+ // Previously this 13-field set was hand-copied in three places: node-snapshot.ts's
6
+ // snapshotBody, reclamation.ts's snapshotProjectionDigest, and reclamation.ts's
7
+ // rawNodeBody/nodeBodyDigest (whose comment literally said "Mirror
8
+ // node-snapshot.ts"). Any field added in one place but not the others would drift
9
+ // the projection — and because reclamation hashes are tombstone-chained, a drift
10
+ // would silently break the chain. This module collapses the list to ONE export so
11
+ // the field set can only change in one place.
12
+ //
13
+ // BYTE-IDENTITY [load-bearing]: the projection / digest OUTPUT here is identical to
14
+ // the prior in-line implementations. `normalizeValue` sorts object keys, so the
15
+ // literal field ORDER never affected the bytes — only the field SET ever mattered.
16
+ // `replayStableStringify(value) === JSON.stringify(normalizeValue(value))` and
17
+ // `normalizeValue` is idempotent, so the projected-body digest and the raw-body
18
+ // digest funnel through the same canonical bytes (node-snapshot-diff-replay +
19
+ // reclamation smokes verify this).
20
+ //
21
+ // Pure: no I/O, no wall-clock, no random — safe in core/state/replay logic.
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.rawNodeProjection = rawNodeProjection;
24
+ exports.projectNodeBody = projectNodeBody;
25
+ exports.nodeProjectionDigestInput = nodeProjectionDigestInput;
26
+ const multi_agent_eval_1 = require("./multi-agent-eval");
27
+ /** The raw (un-normalized) projection input: the canonical field set, copied off
28
+ * the StateNode with no scrubbing. `normalizeValue`/`replayStableStringify` apply
29
+ * the timestamp/path scrubbing downstream. This is the ONE place the field list
30
+ * lives — add or drop a projected field here and every consumer follows. */
31
+ function rawNodeProjection(node) {
32
+ return {
33
+ id: node.id,
34
+ kind: node.kind,
35
+ status: node.status,
36
+ loopStage: node.loopStage,
37
+ inputs: node.inputs,
38
+ outputs: node.outputs,
39
+ artifacts: node.artifacts,
40
+ evidence: node.evidence,
41
+ errors: node.errors,
42
+ parents: node.parents,
43
+ children: node.children,
44
+ contractId: node.contractId,
45
+ metadata: node.metadata
46
+ };
47
+ }
48
+ /** The normalized, derived projected body of one StateNode — timestamps/paths
49
+ * stripped via the eval normalizer, so it is byte-stable across captures of the
50
+ * same logical state. This is exactly node-snapshot.ts's historical snapshotBody. */
51
+ function projectNodeBody(node) {
52
+ return (0, multi_agent_eval_1.normalizeValue)(rawNodeProjection(node));
53
+ }
54
+ /** Stable digest input for the projected body: the canonical bytes that the
55
+ * snapshot/reconstruction digests bind. `replayStableStringify` re-normalizes, so
56
+ * feeding the raw projection or the already-normalized body yields identical bytes. */
57
+ function nodeProjectionDigestInput(node) {
58
+ return (0, multi_agent_eval_1.replayStableStringify)(rawNodeProjection(node));
59
+ }
@@ -13,7 +13,7 @@
13
13
  // divergence (`stale`) or a missing node/artifact (`absent`) diff/replay REFUSE
14
14
  // with a structured error — never a silent stale replay.
15
15
  // - REUSE, don't fork: operates on the real StateNode (getRunNode) and reuses the
16
- // eval harness's normalizeValue/stableStringify and state-explosion's
16
+ // eval harness's normalizeValue/replayStableStringify and state-explosion's
17
17
  // fingerprintStrings. No parallel node type, normalizer, or replay engine.
18
18
  // - DETERMINISTIC: `now` is injected; the deterministic payload (normalized body
19
19
  // + outputFingerprint) carries zero wall-clock, so two replays are byte-identical.
@@ -37,7 +37,9 @@ const node_path_1 = __importDefault(require("node:path"));
37
37
  const pipeline_runner_1 = require("./pipeline-runner");
38
38
  const state_1 = require("./state");
39
39
  const multi_agent_eval_1 = require("./multi-agent-eval");
40
+ const node_projection_1 = require("./node-projection");
40
41
  const state_explosion_1 = require("./state-explosion");
42
+ const validation_1 = require("./validation");
41
43
  exports.NODE_SNAPSHOT_SCHEMA_VERSION = 1;
42
44
  /** Structured fail-closed error (mirrors the PipelineContractError shape). */
43
45
  class NodeSnapshotError extends Error {
@@ -64,23 +66,11 @@ const SNAPSHOT_SECTIONS = [
64
66
  "metadata"
65
67
  ];
66
68
  /** The normalized projection of a node — timestamps/paths stripped by the eval
67
- * normalizer, so it is byte-stable across captures of the same logical state. */
69
+ * normalizer, so it is byte-stable across captures of the same logical state. The
70
+ * canonical field set lives in node-projection.ts (shared with reclamation.ts so
71
+ * the projection can never drift across the two). */
68
72
  function snapshotBody(node) {
69
- return (0, multi_agent_eval_1.normalizeValue)({
70
- id: node.id,
71
- kind: node.kind,
72
- status: node.status,
73
- loopStage: node.loopStage,
74
- inputs: node.inputs,
75
- outputs: node.outputs,
76
- artifacts: node.artifacts,
77
- evidence: node.evidence,
78
- errors: node.errors,
79
- parents: node.parents,
80
- children: node.children,
81
- contractId: node.contractId,
82
- metadata: node.metadata
83
- });
73
+ return (0, node_projection_1.projectNodeBody)(node);
84
74
  }
85
75
  /** RAW fingerprint (NOT normalized): any transition (updatedAt/status) or
86
76
  * artifact/evidence change flips it, which is how drift is detected. */
@@ -113,7 +103,7 @@ function readNodeSnapshot(run, snapshotId) {
113
103
  for (const nodeDir of node_fs_1.default.readdirSync(root)) {
114
104
  const file = node_path_1.default.join(root, nodeDir, `${snapshotId}.json`);
115
105
  if (node_fs_1.default.existsSync(file))
116
- return JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
106
+ return (0, validation_1.validateNodeSnapshot)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
117
107
  }
118
108
  }
119
109
  throw new NodeSnapshotError("snapshot-not-found", `Node snapshot ${snapshotId} not found in run ${run.id}`, { freshness: "absent" });
@@ -125,7 +115,7 @@ function readNodeReplay(run, replayId) {
125
115
  for (const nodeDir of node_fs_1.default.readdirSync(root)) {
126
116
  const file = node_path_1.default.join(root, nodeDir, "replays", `${replayId}.json`);
127
117
  if (node_fs_1.default.existsSync(file))
128
- return JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
118
+ return (0, validation_1.validateNodeReplayRun)(JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
129
119
  }
130
120
  }
131
121
  throw new NodeSnapshotError("replay-not-found", `Node replay ${replayId} not found in run ${run.id}`, { freshness: "absent" });
@@ -176,7 +166,7 @@ function diffNodeSnapshots(baseline, candidate) {
176
166
  const sections = SNAPSHOT_SECTIONS.map((section) => {
177
167
  const baselineValue = sectionValue(baseline.body, section);
178
168
  const candidateValue = sectionValue(candidate.body, section);
179
- const sameBytes = (0, multi_agent_eval_1.stableStringify)(baselineValue) === (0, multi_agent_eval_1.stableStringify)(candidateValue);
169
+ const sameBytes = (0, multi_agent_eval_1.replayStableStringify)(baselineValue) === (0, multi_agent_eval_1.replayStableStringify)(candidateValue);
180
170
  let change;
181
171
  if (sameBytes)
182
172
  change = "same";
@@ -213,7 +203,7 @@ function replayNodeSnapshot(run, snapshot, options = {}) {
213
203
  throw new NodeSnapshotError(freshness === "stale" ? "snapshot-stale" : "snapshot-absent", reason || `cannot replay a ${freshness} snapshot of node ${snapshot.nodeId}`, { freshness, details: { runId: run.id, nodeId: snapshot.nodeId } });
214
204
  }
215
205
  const body = (0, multi_agent_eval_1.normalizeValue)(snapshot.body);
216
- const outputFingerprint = (0, state_explosion_1.fingerprintStrings)([(0, multi_agent_eval_1.stableStringify)(body)]);
206
+ const outputFingerprint = (0, state_explosion_1.fingerprintStrings)([(0, multi_agent_eval_1.replayStableStringify)(body)]);
217
207
  const replay = {
218
208
  schemaVersion: 1,
219
209
  replayId: `replay-${snapshot.snapshotId}-${outputFingerprint.replace("sha256:", "").slice(0, 8)}`,
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatMetricsReport = formatMetricsReport;
4
+ exports.formatMetricsSummary = formatMetricsSummary;
5
+ function formatRate(r) {
6
+ if (r.state === "n/a")
7
+ return `n/a (0 samples)`;
8
+ return `${((r.rate * 100)).toFixed(1)}% (${r.count}/${r.total})`;
9
+ }
10
+ function formatMs(ms) {
11
+ if (ms === null)
12
+ return "—";
13
+ if (ms < 1000)
14
+ return `${ms}ms`;
15
+ return `${(ms / 1000).toFixed(1)}s`;
16
+ }
17
+ function formatCost(c) {
18
+ const parts = [`state=${c.state}`];
19
+ if (c.attestedUsd !== null)
20
+ parts.push(`attested=${c.currency} ${c.attestedUsd}`);
21
+ if (c.estimatedUsd !== null)
22
+ parts.push(`estimated=${c.currency} ${c.estimatedUsd}`);
23
+ if (c.unpricedModels.length)
24
+ parts.push(`unpriced-models=${c.unpricedModels.join(",")}`);
25
+ return parts.join(" ");
26
+ }
27
+ function formatMetricsReport(report) {
28
+ const lines = [];
29
+ lines.push(`metrics ${report.runId} [${report.freshness.status}] app=${report.scope.app || "-"}`);
30
+ lines.push(` time: run=${formatMs(report.time.run.wallClockMs)}${report.time.run.inFlight ? " (in-flight)" : ""} active-task=${formatMs(report.time.activeTaskMs)} in-flight-items=${report.time.inFlight}`);
31
+ lines.push(` failure-rate: ${formatRate(report.rates.failure)}`);
32
+ lines.push(` verifier-pass: ${formatRate(report.rates.verifierPass)}`);
33
+ lines.push(` cand-acceptance: ${formatRate(report.rates.candidateAcceptance)}`);
34
+ const collab = report.collaboration;
35
+ lines.push(` collaboration: approvals=${collab.approvals} rejections=${collab.rejections} comments=${collab.comments} handoffs=${collab.handoffs} reviewers=${collab.reviewers} approval-rate=${formatRate(collab.approvalRate)} time-to-approval=${collab.timeToApproval.meanMs === null ? "n/a" : `${Math.round(collab.timeToApproval.meanMs / 1000)}s`} (${collab.timeToApproval.samples} samples)`);
36
+ const cov = report.usage.coverage === null ? "n/a" : `${(report.usage.coverage * 100).toFixed(0)}%`;
37
+ lines.push(` usage: attested=${report.usage.attestedUnits}/${report.usage.units} units (coverage ${cov}), unreported=${report.usage.unreportedUnits}; tokens in=${report.usage.inputTokens} out=${report.usage.outputTokens} total=${report.usage.totalTokens}`);
38
+ lines.push(` cost: ${formatCost(report.cost)}`);
39
+ if (report.usage.models.length)
40
+ lines.push(` models: ${report.usage.models.join(", ")}`);
41
+ lines.push(` next: ${report.nextAction}`);
42
+ return lines.join("\n");
43
+ }
44
+ function formatMetricsSummary(summary) {
45
+ const lines = [];
46
+ lines.push(`metrics summary scope=${summary.scope} runs=${summary.runCount}${summary.unreadableRuns ? ` (+${summary.unreadableRuns} unreadable)` : ""}`);
47
+ lines.push(` failure-rate: ${formatRate(summary.rates.failure)}`);
48
+ lines.push(` verifier-pass: ${formatRate(summary.rates.verifierPass)}`);
49
+ lines.push(` cand-acceptance: ${formatRate(summary.rates.candidateAcceptance)}`);
50
+ const cov = summary.usage.coverage === null ? "n/a" : `${(summary.usage.coverage * 100).toFixed(0)}%`;
51
+ lines.push(` usage: attested=${summary.usage.attestedUnits}/${summary.usage.units} units (coverage ${cov}); tokens total=${summary.usage.totalTokens}`);
52
+ lines.push(` cost: ${formatCost(summary.cost)}`);
53
+ for (const app of summary.byApp) {
54
+ lines.push(` app ${app.key}: runs=${app.runCount} verifier=${formatRate(app.rates.verifierPass)} cost=${formatCost(app.cost)}`);
55
+ }
56
+ for (const backend of summary.byBackend) {
57
+ lines.push(` backend ${backend.key}: runs=${backend.runCount} failure=${formatRate(backend.rates.failure)}`);
58
+ }
59
+ lines.push(` next: ${summary.nextAction}`);
60
+ return lines.join("\n");
61
+ }
@@ -0,0 +1,98 @@
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.loadCostPolicy = loadCostPolicy;
7
+ exports.parseUsageFromArgs = parseUsageFromArgs;
8
+ // Intake helpers for observability — POLICY as DATA and host-attested usage
9
+ // parsing, kept out of the kernel. Pure/IO-edge functions carved out of
10
+ // observability.ts (god-module carve) so the metrics module no longer bundles
11
+ // the CLI/MCP argument-intake layer. Re-exported from observability.ts to keep
12
+ // the public surface byte-unchanged.
13
+ const node_fs_1 = __importDefault(require("node:fs"));
14
+ const node_path_1 = __importDefault(require("node:path"));
15
+ const state_1 = require("../state");
16
+ /** Resolve a CostPolicy from CLI/MCP args. `--pricing <path>` loads a policy
17
+ * file; `--pricing default|bundled` loads the bundled example under
18
+ * manifest/pricing.policy.json. Absent ⇒ undefined ⇒ cost is `unpriced`/
19
+ * `unreported`, never guessed. */
20
+ function loadCostPolicy(args, pluginRoot) {
21
+ const raw = args.pricing ?? args.pricingPolicy ?? args.policy;
22
+ if (raw === undefined || raw === null || raw === "")
23
+ return undefined;
24
+ const value = String(raw);
25
+ const file = value === "default" || value === "bundled"
26
+ ? node_path_1.default.join(pluginRoot, "manifest", "pricing.policy.json")
27
+ : node_path_1.default.resolve(value);
28
+ if (!node_fs_1.default.existsSync(file))
29
+ throw new Error(`Pricing policy file not found: ${file}`);
30
+ const parsed = (0, state_1.readJson)(file);
31
+ if (!parsed || parsed.schemaVersion !== 1 || !Array.isArray(parsed.models)) {
32
+ throw new Error(`Invalid pricing policy (expected schemaVersion 1 + models[]): ${file}`);
33
+ }
34
+ return parsed;
35
+ }
36
+ /** Parse a host-attested UsageRecord from CLI/MCP intake args. Returns undefined
37
+ * when NO usage was provided (⇒ `unreported`). CW never fabricates usage, so a
38
+ * caller that passes nothing gets nothing. */
39
+ function parseUsageFromArgs(args, now) {
40
+ const inline = args.usage;
41
+ if (inline && typeof inline === "object" && !Array.isArray(inline)) {
42
+ return normalizeUsage(inline, now);
43
+ }
44
+ const input = numeric(args.usageInputTokens ?? args["usage-input-tokens"]);
45
+ const output = numeric(args.usageOutputTokens ?? args["usage-output-tokens"]);
46
+ const model = args.usageModel ?? args["usage-model"];
47
+ const total = numeric(args.usageTotalTokens ?? args["usage-total-tokens"]);
48
+ const cacheRead = numeric(args.usageCacheReadTokens ?? args["usage-cache-read-tokens"]);
49
+ const cacheWrite = numeric(args.usageCacheWriteTokens ?? args["usage-cache-write-tokens"]);
50
+ if (input === undefined && output === undefined && total === undefined && model === undefined) {
51
+ return undefined;
52
+ }
53
+ return normalizeUsage({
54
+ source: args.usageSource ?? args["usage-source"],
55
+ model,
56
+ inputTokens: input,
57
+ outputTokens: output,
58
+ totalTokens: total,
59
+ cacheReadTokens: cacheRead,
60
+ cacheWriteTokens: cacheWrite,
61
+ attestedAt: args.usageAttestedAt ?? args["usage-attested-at"],
62
+ note: args.usageNote ?? args["usage-note"]
63
+ }, now);
64
+ }
65
+ function normalizeUsage(raw, now) {
66
+ const source = raw.source === "operator-recorded" ? "operator-recorded" : "host-attested";
67
+ const usage = {
68
+ schemaVersion: 1,
69
+ source,
70
+ attestedAt: typeof raw.attestedAt === "string" && raw.attestedAt ? raw.attestedAt : now
71
+ };
72
+ if (raw.model !== undefined && raw.model !== null && raw.model !== "")
73
+ usage.model = String(raw.model);
74
+ const input = numeric(raw.inputTokens);
75
+ const output = numeric(raw.outputTokens);
76
+ const total = numeric(raw.totalTokens);
77
+ const cacheRead = numeric(raw.cacheReadTokens);
78
+ const cacheWrite = numeric(raw.cacheWriteTokens);
79
+ if (input !== undefined)
80
+ usage.inputTokens = input;
81
+ if (output !== undefined)
82
+ usage.outputTokens = output;
83
+ if (total !== undefined)
84
+ usage.totalTokens = total;
85
+ if (cacheRead !== undefined)
86
+ usage.cacheReadTokens = cacheRead;
87
+ if (cacheWrite !== undefined)
88
+ usage.cacheWriteTokens = cacheWrite;
89
+ if (raw.note !== undefined && raw.note !== null && raw.note !== "")
90
+ usage.note = String(raw.note);
91
+ return usage;
92
+ }
93
+ function numeric(value) {
94
+ if (value === undefined || value === null || value === "")
95
+ return undefined;
96
+ const n = Number(value);
97
+ return Number.isFinite(n) ? n : undefined;
98
+ }
@@ -34,7 +34,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
34
34
  return (mod && mod.__esModule) ? mod : { "default": mod };
35
35
  };
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.METRICS_SCHEMA_VERSION = void 0;
37
+ exports.formatMetricsSummary = exports.formatMetricsReport = exports.parseUsageFromArgs = exports.loadCostPolicy = exports.METRICS_SCHEMA_VERSION = void 0;
38
38
  exports.fingerprintMetricsSource = fingerprintMetricsSource;
39
39
  exports.deriveUsageTotals = deriveUsageTotals;
40
40
  exports.deriveAttestationCoverage = deriveAttestationCoverage;
@@ -46,13 +46,8 @@ exports.deriveMetricsReport = deriveMetricsReport;
46
46
  exports.deriveCollaborationMetrics = deriveCollaborationMetrics;
47
47
  exports.metricsDir = metricsDir;
48
48
  exports.loadPersistedMetricsFingerprint = loadPersistedMetricsFingerprint;
49
- exports.loadPersistedMetricsReport = loadPersistedMetricsReport;
50
49
  exports.showMetricsReport = showMetricsReport;
51
50
  exports.deriveMetricsSummary = deriveMetricsSummary;
52
- exports.loadCostPolicy = loadCostPolicy;
53
- exports.parseUsageFromArgs = parseUsageFromArgs;
54
- exports.formatMetricsReport = formatMetricsReport;
55
- exports.formatMetricsSummary = formatMetricsSummary;
56
51
  const node_crypto_1 = __importDefault(require("node:crypto"));
57
52
  const node_fs_1 = __importDefault(require("node:fs"));
58
53
  const node_path_1 = __importDefault(require("node:path"));
@@ -558,18 +553,6 @@ function loadPersistedMetricsFingerprint(run) {
558
553
  return undefined;
559
554
  }
560
555
  }
561
- /** Read the full persisted per-run report, if any (never throws). */
562
- function loadPersistedMetricsReport(run) {
563
- const file = metricsReportPath(run);
564
- if (!node_fs_1.default.existsSync(file))
565
- return undefined;
566
- try {
567
- return (0, state_1.readJson)(file);
568
- }
569
- catch {
570
- return undefined;
571
- }
572
- }
573
556
  /** Derive + persist the per-run report. The RETURNED payload is order- and
574
557
  * cache-independent (freshness === "valid", persistedFingerprint === itself),
575
558
  * so `cw metrics show --json` and `cw_metrics_show` are byte-identical. The
@@ -775,148 +758,19 @@ function deriveMetricsSummary(inputs, options) {
775
758
  };
776
759
  }
777
760
  // ---------------------------------------------------------------------------
778
- // Pricing policy loader (POLICY as DATA kept out of the kernel).
761
+ // Intake (POLICY as DATA + host-attested usage parsing) now lives in
762
+ // ./observability/intake.ts (god-module carve). Re-exported so importers of
763
+ // "./observability" keep the unchanged surface.
779
764
  // ---------------------------------------------------------------------------
780
- /** Resolve a CostPolicy from CLI/MCP args. `--pricing <path>` loads a policy
781
- * file; `--pricing default|bundled` loads the bundled example under
782
- * manifest/pricing.policy.json. Absent undefined cost is `unpriced`/
783
- * `unreported`, never guessed. */
784
- function loadCostPolicy(args, pluginRoot) {
785
- const raw = args.pricing ?? args.pricingPolicy ?? args.policy;
786
- if (raw === undefined || raw === null || raw === "")
787
- return undefined;
788
- const value = String(raw);
789
- const file = value === "default" || value === "bundled"
790
- ? node_path_1.default.join(pluginRoot, "manifest", "pricing.policy.json")
791
- : node_path_1.default.resolve(value);
792
- if (!node_fs_1.default.existsSync(file))
793
- throw new Error(`Pricing policy file not found: ${file}`);
794
- const parsed = (0, state_1.readJson)(file);
795
- if (!parsed || parsed.schemaVersion !== 1 || !Array.isArray(parsed.models)) {
796
- throw new Error(`Invalid pricing policy (expected schemaVersion 1 + models[]): ${file}`);
797
- }
798
- return parsed;
799
- }
800
- /** Parse a host-attested UsageRecord from CLI/MCP intake args. Returns undefined
801
- * when NO usage was provided (⇒ `unreported`). CW never fabricates usage, so a
802
- * caller that passes nothing gets nothing. */
803
- function parseUsageFromArgs(args, now) {
804
- const inline = args.usage;
805
- if (inline && typeof inline === "object" && !Array.isArray(inline)) {
806
- return normalizeUsage(inline, now);
807
- }
808
- const input = numeric(args.usageInputTokens ?? args["usage-input-tokens"]);
809
- const output = numeric(args.usageOutputTokens ?? args["usage-output-tokens"]);
810
- const model = args.usageModel ?? args["usage-model"];
811
- const total = numeric(args.usageTotalTokens ?? args["usage-total-tokens"]);
812
- const cacheRead = numeric(args.usageCacheReadTokens ?? args["usage-cache-read-tokens"]);
813
- const cacheWrite = numeric(args.usageCacheWriteTokens ?? args["usage-cache-write-tokens"]);
814
- if (input === undefined && output === undefined && total === undefined && model === undefined) {
815
- return undefined;
816
- }
817
- return normalizeUsage({
818
- source: args.usageSource ?? args["usage-source"],
819
- model,
820
- inputTokens: input,
821
- outputTokens: output,
822
- totalTokens: total,
823
- cacheReadTokens: cacheRead,
824
- cacheWriteTokens: cacheWrite,
825
- attestedAt: args.usageAttestedAt ?? args["usage-attested-at"],
826
- note: args.usageNote ?? args["usage-note"]
827
- }, now);
828
- }
829
- function normalizeUsage(raw, now) {
830
- const source = raw.source === "operator-recorded" ? "operator-recorded" : "host-attested";
831
- const usage = {
832
- schemaVersion: 1,
833
- source,
834
- attestedAt: typeof raw.attestedAt === "string" && raw.attestedAt ? raw.attestedAt : now
835
- };
836
- if (raw.model !== undefined && raw.model !== null && raw.model !== "")
837
- usage.model = String(raw.model);
838
- const input = numeric(raw.inputTokens);
839
- const output = numeric(raw.outputTokens);
840
- const total = numeric(raw.totalTokens);
841
- const cacheRead = numeric(raw.cacheReadTokens);
842
- const cacheWrite = numeric(raw.cacheWriteTokens);
843
- if (input !== undefined)
844
- usage.inputTokens = input;
845
- if (output !== undefined)
846
- usage.outputTokens = output;
847
- if (total !== undefined)
848
- usage.totalTokens = total;
849
- if (cacheRead !== undefined)
850
- usage.cacheReadTokens = cacheRead;
851
- if (cacheWrite !== undefined)
852
- usage.cacheWriteTokens = cacheWrite;
853
- if (raw.note !== undefined && raw.note !== null && raw.note !== "")
854
- usage.note = String(raw.note);
855
- return usage;
856
- }
857
- function numeric(value) {
858
- if (value === undefined || value === null || value === "")
859
- return undefined;
860
- const n = Number(value);
861
- return Number.isFinite(n) ? n : undefined;
862
- }
765
+ var intake_1 = require("./observability/intake");
766
+ Object.defineProperty(exports, "loadCostPolicy", { enumerable: true, get: function () { return intake_1.loadCostPolicy; } });
767
+ Object.defineProperty(exports, "parseUsageFromArgs", { enumerable: true, get: function () { return intake_1.parseUsageFromArgs; } });
863
768
  // ---------------------------------------------------------------------------
864
- // Human formatters (CLI default text; --json emits the canonical payload).
769
+ // Human formatters (CLI default text; --json emits the canonical payload) now
770
+ // live in ./observability/format.ts (god-module carve, mirrors
771
+ // run-registry/format.ts). Re-exported so importers of "./observability" keep
772
+ // the unchanged surface.
865
773
  // ---------------------------------------------------------------------------
866
- function formatRate(r) {
867
- if (r.state === "n/a")
868
- return `n/a (0 samples)`;
869
- return `${((r.rate * 100)).toFixed(1)}% (${r.count}/${r.total})`;
870
- }
871
- function formatMs(ms) {
872
- if (ms === null)
873
- return "—";
874
- if (ms < 1000)
875
- return `${ms}ms`;
876
- return `${(ms / 1000).toFixed(1)}s`;
877
- }
878
- function formatCost(c) {
879
- const parts = [`state=${c.state}`];
880
- if (c.attestedUsd !== null)
881
- parts.push(`attested=${c.currency} ${c.attestedUsd}`);
882
- if (c.estimatedUsd !== null)
883
- parts.push(`estimated=${c.currency} ${c.estimatedUsd}`);
884
- if (c.unpricedModels.length)
885
- parts.push(`unpriced-models=${c.unpricedModels.join(",")}`);
886
- return parts.join(" ");
887
- }
888
- function formatMetricsReport(report) {
889
- const lines = [];
890
- lines.push(`metrics ${report.runId} [${report.freshness.status}] app=${report.scope.app || "-"}`);
891
- lines.push(` time: run=${formatMs(report.time.run.wallClockMs)}${report.time.run.inFlight ? " (in-flight)" : ""} active-task=${formatMs(report.time.activeTaskMs)} in-flight-items=${report.time.inFlight}`);
892
- lines.push(` failure-rate: ${formatRate(report.rates.failure)}`);
893
- lines.push(` verifier-pass: ${formatRate(report.rates.verifierPass)}`);
894
- lines.push(` cand-acceptance: ${formatRate(report.rates.candidateAcceptance)}`);
895
- const collab = report.collaboration;
896
- lines.push(` collaboration: approvals=${collab.approvals} rejections=${collab.rejections} comments=${collab.comments} handoffs=${collab.handoffs} reviewers=${collab.reviewers} approval-rate=${formatRate(collab.approvalRate)} time-to-approval=${collab.timeToApproval.meanMs === null ? "n/a" : `${Math.round(collab.timeToApproval.meanMs / 1000)}s`} (${collab.timeToApproval.samples} samples)`);
897
- const cov = report.usage.coverage === null ? "n/a" : `${(report.usage.coverage * 100).toFixed(0)}%`;
898
- lines.push(` usage: attested=${report.usage.attestedUnits}/${report.usage.units} units (coverage ${cov}), unreported=${report.usage.unreportedUnits}; tokens in=${report.usage.inputTokens} out=${report.usage.outputTokens} total=${report.usage.totalTokens}`);
899
- lines.push(` cost: ${formatCost(report.cost)}`);
900
- if (report.usage.models.length)
901
- lines.push(` models: ${report.usage.models.join(", ")}`);
902
- lines.push(` next: ${report.nextAction}`);
903
- return lines.join("\n");
904
- }
905
- function formatMetricsSummary(summary) {
906
- const lines = [];
907
- lines.push(`metrics summary scope=${summary.scope} runs=${summary.runCount}${summary.unreadableRuns ? ` (+${summary.unreadableRuns} unreadable)` : ""}`);
908
- lines.push(` failure-rate: ${formatRate(summary.rates.failure)}`);
909
- lines.push(` verifier-pass: ${formatRate(summary.rates.verifierPass)}`);
910
- lines.push(` cand-acceptance: ${formatRate(summary.rates.candidateAcceptance)}`);
911
- const cov = summary.usage.coverage === null ? "n/a" : `${(summary.usage.coverage * 100).toFixed(0)}%`;
912
- lines.push(` usage: attested=${summary.usage.attestedUnits}/${summary.usage.units} units (coverage ${cov}); tokens total=${summary.usage.totalTokens}`);
913
- lines.push(` cost: ${formatCost(summary.cost)}`);
914
- for (const app of summary.byApp) {
915
- lines.push(` app ${app.key}: runs=${app.runCount} verifier=${formatRate(app.rates.verifierPass)} cost=${formatCost(app.cost)}`);
916
- }
917
- for (const backend of summary.byBackend) {
918
- lines.push(` backend ${backend.key}: runs=${backend.runCount} failure=${formatRate(backend.rates.failure)}`);
919
- }
920
- lines.push(` next: ${summary.nextAction}`);
921
- return lines.join("\n");
922
- }
774
+ var format_1 = require("./observability/format");
775
+ Object.defineProperty(exports, "formatMetricsReport", { enumerable: true, get: function () { return format_1.formatMetricsReport; } });
776
+ Object.defineProperty(exports, "formatMetricsSummary", { enumerable: true, get: function () { return format_1.formatMetricsSummary; } });