cool-workflow 0.1.79 → 0.1.81
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.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +51 -3
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +64 -0
- package/apps/architecture-review-fast/workflow.js +153 -0
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/agent-config.js +21 -7
- package/dist/candidate-scoring.js +42 -22
- package/dist/capability-core.js +132 -17
- package/dist/capability-registry.js +138 -168
- package/dist/cli.js +97 -98
- package/dist/collaboration.js +5 -6
- package/dist/commit.js +20 -6
- package/dist/compare.js +18 -0
- package/dist/coordinator/classify.js +45 -0
- package/dist/coordinator/paths.js +42 -0
- package/dist/coordinator/util.js +129 -0
- package/dist/coordinator.js +127 -300
- package/dist/dispatch.js +35 -0
- package/dist/drive.js +79 -6
- package/dist/error-feedback.js +8 -4
- package/dist/evidence-reasoning.js +3 -3
- package/dist/execution-backend/agent.js +331 -0
- package/dist/execution-backend/probes.js +96 -0
- package/dist/execution-backend/util.js +47 -0
- package/dist/execution-backend.js +73 -421
- package/dist/mcp-server.js +79 -183
- package/dist/multi-agent/graph.js +84 -0
- package/dist/multi-agent/helpers.js +145 -0
- package/dist/multi-agent/paths.js +22 -0
- package/dist/multi-agent-eval/format.js +194 -0
- package/dist/multi-agent-eval/normalize.js +51 -0
- package/dist/multi-agent-eval.js +39 -244
- package/dist/multi-agent-host.js +0 -19
- package/dist/multi-agent.js +125 -314
- package/dist/node-snapshot.js +3 -3
- package/dist/observability/format.js +61 -0
- package/dist/observability/intake.js +98 -0
- package/dist/observability.js +14 -160
- package/dist/operator-ux/format.js +364 -0
- package/dist/operator-ux.js +22 -363
- package/dist/orchestrator/lifecycle-operations.js +2 -1
- package/dist/orchestrator/report.js +8 -0
- package/dist/orchestrator.js +26 -9
- package/dist/reclamation.js +26 -21
- package/dist/run-export.js +494 -25
- package/dist/run-registry/derive.js +172 -0
- package/dist/run-registry/format.js +124 -0
- package/dist/run-registry/gc.js +251 -0
- package/dist/run-registry/policy.js +16 -0
- package/dist/run-registry/queue.js +116 -0
- package/dist/run-registry.js +89 -597
- package/dist/run-state-schema.js +1 -0
- package/dist/sandbox-profile.js +43 -2
- package/dist/state-explosion/format.js +159 -0
- package/dist/state-explosion/helpers.js +82 -0
- package/dist/state-explosion.js +165 -304
- package/dist/state-node.js +19 -4
- package/dist/telemetry-attestation.js +55 -0
- package/dist/telemetry-demo.js +15 -3
- package/dist/telemetry-ledger.js +60 -15
- package/dist/topology.js +25 -8
- package/dist/triggers.js +33 -14
- package/dist/trust-audit.js +145 -33
- package/dist/version.js +1 -1
- package/dist/worker-isolation/helpers.js +51 -0
- package/dist/worker-isolation/paths.js +46 -0
- package/dist/worker-isolation.js +39 -115
- package/docs/agent-delegation-drive.7.md +71 -0
- package/docs/canonical-workflow-apps.7.md +37 -0
- package/docs/cli-mcp-parity.7.md +16 -0
- package/docs/contract-migration-tooling.7.md +6 -0
- package/docs/control-plane-scheduling.7.md +6 -0
- package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
- package/docs/durable-state-and-locking.7.md +8 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
- package/docs/execution-backends.7.md +6 -0
- package/docs/index.md +2 -0
- package/docs/launch/demo.tape +28 -0
- package/docs/launch/launch-kit.md +96 -17
- package/docs/launch/pre-launch-checklist.md +53 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +8 -0
- package/docs/multi-agent-eval-replay-harness.7.md +6 -0
- package/docs/multi-agent-operator-ux.7.md +6 -0
- package/docs/multi-agent-trust-policy-audit.7.md +27 -0
- package/docs/node-snapshot-diff-replay.7.md +6 -0
- package/docs/observability-cost-accounting.7.md +6 -0
- package/docs/project-index.md +27 -6
- package/docs/real-execution-backends.7.md +6 -0
- package/docs/release-and-migration.7.md +8 -0
- package/docs/release-tooling.7.md +6 -0
- package/docs/routines.md +23 -0
- package/docs/run-registry-control-plane.7.md +89 -2
- package/docs/run-retention-reclamation.7.md +8 -0
- package/docs/source-context-profiles.7.md +119 -0
- package/docs/state-explosion-management.7.md +13 -0
- package/docs/team-collaboration.7.md +6 -0
- package/docs/trust-model.md +267 -0
- package/docs/unix-principles.md +49 -1
- package/docs/vendor-manifest-loadability.7.md +43 -0
- package/docs/web-desktop-workbench.7.md +6 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +142 -0
- package/package.json +4 -1
- package/scripts/agents/builtin-templates.json +7 -0
- package/scripts/agents/claude-p-agent.js +129 -43
- package/scripts/architecture-review-fast.js +362 -0
- package/scripts/bump-version.js +5 -10
- package/scripts/canonical-apps-list.js +64 -0
- package/scripts/canonical-apps.js +36 -4
- package/scripts/coverage-gate.js +211 -0
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
- package/scripts/parity-check.js +5 -0
- package/scripts/release-check.js +5 -1
- package/scripts/source-context.js +291 -0
- package/scripts/version-sync-check.js +5 -7
- package/skills/ci-triage/SKILL.md +50 -0
- package/skills/ci-triage/agents/openai.yaml +4 -0
- package/skills/cool-workflow/SKILL.md +4 -1
- package/skills/deploy-check/SKILL.md +55 -0
- package/skills/deploy-check/agents/openai.yaml +4 -0
- package/skills/design-qa/SKILL.md +49 -0
- package/skills/design-qa/agents/openai.yaml +4 -0
- package/skills/pr-review/SKILL.md +45 -0
- package/skills/pr-review/agents/openai.yaml +4 -0
- package/dist/capability-dispatcher.js +0 -86
package/dist/node-snapshot.js
CHANGED
|
@@ -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/
|
|
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.
|
|
@@ -176,7 +176,7 @@ function diffNodeSnapshots(baseline, candidate) {
|
|
|
176
176
|
const sections = SNAPSHOT_SECTIONS.map((section) => {
|
|
177
177
|
const baselineValue = sectionValue(baseline.body, section);
|
|
178
178
|
const candidateValue = sectionValue(candidate.body, section);
|
|
179
|
-
const sameBytes = (0, multi_agent_eval_1.
|
|
179
|
+
const sameBytes = (0, multi_agent_eval_1.replayStableStringify)(baselineValue) === (0, multi_agent_eval_1.replayStableStringify)(candidateValue);
|
|
180
180
|
let change;
|
|
181
181
|
if (sameBytes)
|
|
182
182
|
change = "same";
|
|
@@ -213,7 +213,7 @@ function replayNodeSnapshot(run, snapshot, options = {}) {
|
|
|
213
213
|
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
214
|
}
|
|
215
215
|
const body = (0, multi_agent_eval_1.normalizeValue)(snapshot.body);
|
|
216
|
-
const outputFingerprint = (0, state_explosion_1.fingerprintStrings)([(0, multi_agent_eval_1.
|
|
216
|
+
const outputFingerprint = (0, state_explosion_1.fingerprintStrings)([(0, multi_agent_eval_1.replayStableStringify)(body)]);
|
|
217
217
|
const replay = {
|
|
218
218
|
schemaVersion: 1,
|
|
219
219
|
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
|
+
}
|
package/dist/observability.js
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
|
|
781
|
-
|
|
782
|
-
|
|
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
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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; } });
|