cool-workflow 0.1.78 → 0.1.80
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 +29 -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/capability-core.js +71 -0
- package/dist/capability-registry.js +13 -8
- package/dist/cli.js +49 -1
- package/dist/drive.js +74 -1
- package/dist/evidence-reasoning.js +2 -2
- package/dist/execution-backend.js +6 -1
- package/dist/mcp-server.js +56 -13
- package/dist/orchestrator/lifecycle-operations.js +2 -1
- package/dist/orchestrator.js +1 -1
- package/dist/run-export.js +370 -25
- package/dist/run-registry.js +11 -4
- package/dist/state-explosion.js +100 -21
- package/dist/telemetry-demo.js +154 -0
- package/dist/version.js +1 -1
- package/docs/agent-delegation-drive.7.md +60 -0
- package/docs/canonical-workflow-apps.7.md +37 -0
- package/docs/cli-mcp-parity.7.md +14 -0
- package/docs/contract-migration-tooling.7.md +6 -0
- package/docs/control-plane-scheduling.7.md +6 -0
- package/docs/durable-state-and-locking.7.md +6 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
- package/docs/execution-backends.7.md +6 -0
- package/docs/index.md +1 -0
- package/docs/launch/demo.tape +28 -0
- package/docs/launch/launch-kit.md +172 -0
- package/docs/launch/pre-launch-checklist.md +53 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +6 -0
- package/docs/multi-agent-eval-replay-harness.7.md +6 -0
- package/docs/multi-agent-operator-ux.7.md +6 -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 +16 -6
- package/docs/real-execution-backends.7.md +6 -0
- package/docs/release-and-migration.7.md +6 -0
- package/docs/release-tooling.7.md +6 -0
- package/docs/routines.md +23 -0
- package/docs/run-registry-control-plane.7.md +44 -1
- package/docs/run-retention-reclamation.7.md +6 -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/unix-principles.md +49 -1
- 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 +2 -1
- package/scripts/agents/claude-p-agent.js +129 -43
- package/scripts/architecture-review-fast.js +362 -0
- package/scripts/bump-version.js +1 -0
- package/scripts/canonical-apps.js +21 -4
- package/scripts/coverage-gate.js +211 -0
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
- package/scripts/source-context.js +291 -0
- package/scripts/version-sync-check.js +1 -0
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cool-workflow",
|
|
3
3
|
"description": "Auditable workflow control-plane and orchestration runtime: TypeScript dispatch, evidence-gated verification, state commits, scheduling, routines, multi-agent coordination, and MCP. Delegates execution to external agents — never runs models.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.80",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "COOLWHITE LLC"
|
|
7
7
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cool-workflow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.80",
|
|
4
4
|
"description": "Auditable workflow control-plane and orchestration runtime: TypeScript dispatch, evidence-gated verification, state commits, scheduling, routines, multi-agent coordination, and MCP. Delegates execution to external agents — never runs models.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "COOLWHITE LLC"
|
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
[](https://github.com/coo1white/cool-workflow/actions/workflows/ci.yml)
|
|
11
|
+
[](https://www.npmjs.com/package/cool-workflow)
|
|
12
|
+
[](https://www.npmjs.com/package/cool-workflow)
|
|
11
13
|
[](https://github.com/coo1white/cool-workflow/tags)
|
|
12
14
|
[](../../LICENSE)
|
|
13
15
|

|
|
@@ -631,8 +633,32 @@ CHANGELOG.md and RELEASE.md are content surfaces checked by the dogfood-release
|
|
|
631
633
|
|
|
632
634
|
Auto-compaction hook moved from `saveCheckpoint()` to explicit `maybeCompactRun()` calls after major lifecycle mutations. Fixes test fixture fingerprint instability. Also fixes the dogfood-release version-sync pipeline: always use `npm run bump:version`, never hand-edit version.ts alone.
|
|
633
635
|
|
|
634
|
-
v0.1.76
|
|
636
|
+
## Control-plane naming (v0.1.76)
|
|
635
637
|
|
|
636
|
-
|
|
638
|
+
Positioning consistency: every self-describing surface names CW an auditable workflow control-plane / Workflow App framework, not an "SDK" (which survives only in the red-line disclaimer "embeds no model SDK").
|
|
637
639
|
|
|
638
|
-
v0.1.
|
|
640
|
+
## Workflow orchestration: Tracks 1–3 (v0.1.77)
|
|
641
|
+
|
|
642
|
+
The orchestration vision landed in one release, all reviewer-gated:
|
|
643
|
+
|
|
644
|
+
- **Track 1 — telemetry attestation**: each agent's reported token usage is verified against an operator ed25519 trust key (`attested`/`unattested`/`absent`, surfaced loudly), recorded in a tamper-evident hash-chained ledger; opt-in `require-attested-telemetry` fails closed on unverifiable usage.
|
|
645
|
+
- **Track 2 — concurrent failure semantics**: a `parallel()` phase runs its agents concurrently with declared collapse rules — **collect-all** (a failing hop never aborts siblings) and **kill-on-timeout** (a hung agent is killed at its deadline and counted as one failure). 16 agents with a forced hang + crash + dirty-return complete with no deadlock and a replay-complete record.
|
|
646
|
+
- **Track 3 — boundary contract**: per-task output `schema` validation (dependency-free, parks on mismatch), `limits.tokenBudget` enforced against recorded usage, and the one-way executor boundary welded into the type layer (a callable crossing it fails `npm run build`).
|
|
647
|
+
|
|
648
|
+
## Working onboarding + npm distribution (v0.1.78)
|
|
649
|
+
|
|
650
|
+
`--agent-command builtin:claude` resolves to a bundled read-only claude wrapper that completes workers with a real agent; the cross-directory quickstart crash is fixed; missing optional inputs no longer leak `{{name}}` into prompts. Published to npm (`cool-workflow`, bins `cw`/`cool-workflow`) with LICENSE and metadata. Live dogfood proof committed under `docs/dogfood/`.
|
|
651
|
+
|
|
652
|
+
## Tamper-evidence demo (v0.1.79)
|
|
653
|
+
|
|
654
|
+
`cw demo tamper` — a hermetic, one-command proof that a recorded telemetry verdict cannot be forged undetected: it builds a real ed25519-signed ledger, forges it at the ledger layer (verdict flip + recomputed local hash → the chain still breaks) and the signature layer (inflated tokens, reused signature → ed25519 rejects), all verified offline with only the public key. `cw telemetry verify <run>` is the operator-facing half (`cw_telemetry_verify` on MCP).
|
|
655
|
+
|
|
656
|
+
## Opt-in live agent output during a drive (on main, ships next)
|
|
657
|
+
|
|
658
|
+
Set `CW_AGENT_STREAM=1` to see each worker's live agent trace. The bundled claude wrapper (`builtin:claude` / `scripts/agents/claude-p-agent.js`) keeps the legacy `--output-format json` path by default; only the opt-in path runs claude in `--output-format stream-json` and renders a concise human trace (tool uses, assistant text, per-turn summaries) to **stderr**. CW core forwards that stderr to the operator's terminal only when `CW_AGENT_STREAM=1`, CW's own stderr is a TTY, and `CW_NO_STREAM` is not set; piped/CI runs stay silent (Rule of Silence). Core only forwards the stream, never parses it — vendor-specific rendering is the wrapper's concern (policy), not the kernel's (mechanism).
|
|
659
|
+
|
|
660
|
+
v0.1.79
|
|
661
|
+
|
|
662
|
+
## Fast Architecture Review (v0.1.80)
|
|
663
|
+
|
|
664
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"id": "architecture-review",
|
|
4
4
|
"title": "Architecture Review",
|
|
5
5
|
"summary": "Map a repository architecture, assess risks, verify important findings, and synthesize an evidence-backed verdict.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.80",
|
|
7
7
|
"author": "COOLWHITE LLC",
|
|
8
8
|
"inputs": [
|
|
9
9
|
{
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "architecture-review-fast",
|
|
4
|
+
"title": "Architecture Review Fast",
|
|
5
|
+
"summary": "Run a shorter architecture review with parallel map and assess phases for faster first results.",
|
|
6
|
+
"version": "0.1.80",
|
|
7
|
+
"author": "COOLWHITE LLC",
|
|
8
|
+
"inputs": [
|
|
9
|
+
{
|
|
10
|
+
"name": "repo",
|
|
11
|
+
"type": "path",
|
|
12
|
+
"required": true,
|
|
13
|
+
"description": "Repository path to inspect."
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "question",
|
|
17
|
+
"type": "string",
|
|
18
|
+
"required": true,
|
|
19
|
+
"description": "Architecture question or decision to review."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "invariant",
|
|
23
|
+
"type": "string",
|
|
24
|
+
"repeated": true,
|
|
25
|
+
"description": "Invariant that must remain true."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "focus",
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Optional subsystem, risk area, or file path to emphasize.",
|
|
31
|
+
"default": "the highest-risk runtime and operator paths"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "sourceContext",
|
|
35
|
+
"type": "path",
|
|
36
|
+
"description": "Optional JSONL source context file generated by scripts/source-context.js export.",
|
|
37
|
+
"default": ""
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "sourceContextDigest",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Optional digest or cache key for the supplied source context.",
|
|
43
|
+
"default": ""
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"sandboxProfiles": [
|
|
47
|
+
"readonly"
|
|
48
|
+
],
|
|
49
|
+
"compatibility": {
|
|
50
|
+
"minVersion": "0.1.79",
|
|
51
|
+
"workflowSchemaVersion": 1,
|
|
52
|
+
"notes": "Opt-in fast architecture review app; the full architecture-review app remains unchanged."
|
|
53
|
+
},
|
|
54
|
+
"metadata": {
|
|
55
|
+
"canonical": true,
|
|
56
|
+
"domain": "software-architecture",
|
|
57
|
+
"mode": "fast",
|
|
58
|
+
"fullReviewApp": "architecture-review",
|
|
59
|
+
"maintainedAs": "official-userland"
|
|
60
|
+
},
|
|
61
|
+
"workflow": {
|
|
62
|
+
"entrypoint": "workflow.js"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
const FAST_MODEL = modelHint("CW_ARCHITECTURE_REVIEW_FAST_MODEL");
|
|
2
|
+
const STRONG_MODEL = modelHint("CW_ARCHITECTURE_REVIEW_STRONG_MODEL");
|
|
3
|
+
|
|
4
|
+
module.exports = ({ workflow, phase, parallel, agent, artifact, input }) => {
|
|
5
|
+
const inputs = [
|
|
6
|
+
input("repo", {
|
|
7
|
+
type: "path",
|
|
8
|
+
required: true,
|
|
9
|
+
description: "Repository path to inspect."
|
|
10
|
+
}),
|
|
11
|
+
input("question", {
|
|
12
|
+
type: "string",
|
|
13
|
+
required: true,
|
|
14
|
+
description: "Architecture question or decision to review."
|
|
15
|
+
}),
|
|
16
|
+
input("invariant", {
|
|
17
|
+
type: "string",
|
|
18
|
+
repeated: true,
|
|
19
|
+
description: "Invariant that must remain true."
|
|
20
|
+
}),
|
|
21
|
+
input("focus", {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Optional subsystem, risk area, or file path to emphasize.",
|
|
24
|
+
default: "the highest-risk runtime and operator paths"
|
|
25
|
+
}),
|
|
26
|
+
input("sourceContext", {
|
|
27
|
+
type: "path",
|
|
28
|
+
description: "Optional JSONL source context file generated by scripts/source-context.js export.",
|
|
29
|
+
default: ""
|
|
30
|
+
}),
|
|
31
|
+
input("sourceContextDigest", {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Optional digest or cache key for the supplied source context.",
|
|
34
|
+
default: ""
|
|
35
|
+
})
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
return workflow({
|
|
39
|
+
id: "architecture-review-fast",
|
|
40
|
+
title: "Architecture Review Fast",
|
|
41
|
+
summary: "Run a shorter architecture review with parallel map and assess phases for faster first results.",
|
|
42
|
+
limits: {
|
|
43
|
+
maxAgents: 12,
|
|
44
|
+
maxConcurrentAgents: 4
|
|
45
|
+
},
|
|
46
|
+
inputs,
|
|
47
|
+
sandboxProfiles: ["readonly"],
|
|
48
|
+
metadata: {
|
|
49
|
+
mode: "fast",
|
|
50
|
+
fullReviewApp: "architecture-review"
|
|
51
|
+
},
|
|
52
|
+
phases: [
|
|
53
|
+
parallel("Map", [
|
|
54
|
+
agent(
|
|
55
|
+
"map:runtime-surface",
|
|
56
|
+
[
|
|
57
|
+
"Fast-map the runtime architecture in {{repo}} for {{question}}.",
|
|
58
|
+
contextInstruction(),
|
|
59
|
+
"Focus: {{focus}}. Invariants: {{invariant}}.",
|
|
60
|
+
"Return the primary entrypoints, state stores, execution paths, and the exact files or commands inspected."
|
|
61
|
+
].join(" "),
|
|
62
|
+
fastOptions("Runtime surface mapper", { resultCache: sourceContextResultCache() })
|
|
63
|
+
),
|
|
64
|
+
agent(
|
|
65
|
+
"map:operator-surface",
|
|
66
|
+
[
|
|
67
|
+
"Fast-map operator, CI, deployment, test, release, and background-job surfaces in {{repo}} for {{question}}.",
|
|
68
|
+
contextInstruction(),
|
|
69
|
+
"Focus: {{focus}}. Return concrete files, scripts, configs, missing areas, and candidate runtime bottlenecks."
|
|
70
|
+
].join(" "),
|
|
71
|
+
fastOptions("Operator surface mapper", { resultCache: sourceContextResultCache() })
|
|
72
|
+
)
|
|
73
|
+
]),
|
|
74
|
+
parallel("Assess", [
|
|
75
|
+
agent(
|
|
76
|
+
"assess:risks",
|
|
77
|
+
[
|
|
78
|
+
"Assess the fast map for real P0/P1/P2 architecture and correctness risks.",
|
|
79
|
+
"Separate confirmed risks, conditional risks, non-issues, and unknowns.",
|
|
80
|
+
"Tie every important claim to inspected evidence and the invariants {{invariant}}."
|
|
81
|
+
].join(" "),
|
|
82
|
+
fastOptions("Risk assessor", { resultCache: sourceContextResultCache({ includeCompletedResults: "previous-phases" }) })
|
|
83
|
+
),
|
|
84
|
+
agent(
|
|
85
|
+
"assess:runtime-speed",
|
|
86
|
+
[
|
|
87
|
+
"Assess runtime speed and user-wait risk for {{question}}.",
|
|
88
|
+
"Look for serial agent work, repeated repository scanning, missing cache keys, oversized prompts, and long foreground jobs.",
|
|
89
|
+
"Recommend mechanisms that preserve POLA, stdout/stderr discipline, and zero runtime dependencies."
|
|
90
|
+
].join(" "),
|
|
91
|
+
fastOptions("Runtime speed assessor", { resultCache: sourceContextResultCache({ includeCompletedResults: "previous-phases" }) })
|
|
92
|
+
)
|
|
93
|
+
]),
|
|
94
|
+
phase("Verify", [
|
|
95
|
+
agent(
|
|
96
|
+
"verify:p0-p2-risks",
|
|
97
|
+
[
|
|
98
|
+
"Re-open evidence for every candidate P0/P1/P2 risk from the fast assessment.",
|
|
99
|
+
"Confirm real risks, downgrade unsupported claims, and list exact file paths, commands, logs, or unknowns.",
|
|
100
|
+
"The cw:result evidence array must cite durable locators."
|
|
101
|
+
].join(" "),
|
|
102
|
+
strongOptions("Evidence verifier", { requiresEvidence: true })
|
|
103
|
+
)
|
|
104
|
+
]),
|
|
105
|
+
phase("Verdict", [
|
|
106
|
+
artifact(
|
|
107
|
+
"verdict:fast-synthesis",
|
|
108
|
+
[
|
|
109
|
+
"Synthesize a fast architecture verdict for {{question}}.",
|
|
110
|
+
"Include a short answer, compact architecture map, ranked risks, speed recommendations, non-issues, and evidence links.",
|
|
111
|
+
"State when the full architecture-review app should be scheduled as a background routine.",
|
|
112
|
+
"The cw:result evidence array must support the final verdict."
|
|
113
|
+
].join(" "),
|
|
114
|
+
strongOptions("Fast verdict synthesizer", { requiresEvidence: true })
|
|
115
|
+
)
|
|
116
|
+
])
|
|
117
|
+
]
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
function fastOptions(label, extra) {
|
|
122
|
+
return taskOptions(label, FAST_MODEL, extra);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function strongOptions(label, extra) {
|
|
126
|
+
return taskOptions(label, STRONG_MODEL, extra);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function taskOptions(label, model, extra) {
|
|
130
|
+
return {
|
|
131
|
+
label,
|
|
132
|
+
sandboxProfileId: "readonly",
|
|
133
|
+
...(model ? { model } : {}),
|
|
134
|
+
...(extra || {})
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function modelHint(name) {
|
|
139
|
+
const value = String(process.env[name] || "").trim();
|
|
140
|
+
return value || undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function contextInstruction() {
|
|
144
|
+
return [
|
|
145
|
+
"If {{sourceContext}} is non-empty, read that JSONL source context first and treat {{sourceContextDigest}} as its cache/digest hint.",
|
|
146
|
+
"If the supplied context is missing, unreadable, or obviously stale, say so explicitly instead of guessing.",
|
|
147
|
+
"If no source context is supplied, inspect {{repo}} directly."
|
|
148
|
+
].join(" ");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function sourceContextResultCache(extra) {
|
|
152
|
+
return { mode: "read-write", keyInput: "sourceContextDigest", ...(extra || {}) };
|
|
153
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"id": "pr-review-fix-ci",
|
|
4
4
|
"title": "PR Review Fix CI",
|
|
5
5
|
"summary": "Review a pull request or branch, inspect CI failures, diagnose actionable issues, optionally patch, verify, and summarize with evidence.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.80",
|
|
7
7
|
"author": "COOLWHITE LLC",
|
|
8
8
|
"inputs": [
|
|
9
9
|
{
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"id": "release-cut",
|
|
4
4
|
"title": "Release Cut",
|
|
5
5
|
"summary": "Prepare a release with checklist discipline: version checks, changelog, tests, packaging, release notes, and final verification.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.80",
|
|
7
7
|
"author": "COOLWHITE LLC",
|
|
8
8
|
"inputs": [
|
|
9
9
|
{
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"id": "research-synthesis",
|
|
4
4
|
"title": "Research Synthesis",
|
|
5
5
|
"summary": "Split a research question into claims, investigate sources, cross-check evidence, verify claims, and synthesize a concise answer.",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.80",
|
|
7
7
|
"author": "COOLWHITE LLC",
|
|
8
8
|
"inputs": [
|
|
9
9
|
{
|
package/dist/capability-core.js
CHANGED
|
@@ -35,6 +35,9 @@ exports.runShow = runShow;
|
|
|
35
35
|
exports.runResume = runResume;
|
|
36
36
|
exports.runArchive = runArchive;
|
|
37
37
|
exports.runRerun = runRerun;
|
|
38
|
+
exports.runExportArchive = runExportArchive;
|
|
39
|
+
exports.runImportArchive = runImportArchive;
|
|
40
|
+
exports.runVerifyImport = runVerifyImport;
|
|
38
41
|
exports.queueAdd = queueAdd;
|
|
39
42
|
exports.queueList = queueList;
|
|
40
43
|
exports.queueDrain = queueDrain;
|
|
@@ -61,12 +64,17 @@ exports.sandboxProfileIdFrom = sandboxProfileIdFrom;
|
|
|
61
64
|
exports.withoutRuntimeKeys = withoutRuntimeKeys;
|
|
62
65
|
exports.optionalString = optionalString;
|
|
63
66
|
exports.isRecord = isRecord;
|
|
67
|
+
exports.telemetryVerify = telemetryVerify;
|
|
68
|
+
exports.demoTamper = demoTamper;
|
|
64
69
|
const capability_registry_1 = require("./capability-registry");
|
|
65
70
|
const drive_1 = require("./drive");
|
|
66
71
|
const agent_config_1 = require("./agent-config");
|
|
67
72
|
const run_registry_1 = require("./run-registry");
|
|
68
73
|
const observability_1 = require("./observability");
|
|
74
|
+
const telemetry_ledger_1 = require("./telemetry-ledger");
|
|
75
|
+
const telemetry_demo_1 = require("./telemetry-demo");
|
|
69
76
|
const state_1 = require("./state");
|
|
77
|
+
const run_export_1 = require("./run-export");
|
|
70
78
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
71
79
|
const node_path_1 = __importDefault(require("node:path"));
|
|
72
80
|
const scheduling_1 = require("./scheduling");
|
|
@@ -190,6 +198,19 @@ function flag(value) {
|
|
|
190
198
|
return false;
|
|
191
199
|
return Boolean(value);
|
|
192
200
|
}
|
|
201
|
+
function withInvocationCwd(args, fn) {
|
|
202
|
+
const cwd = optionalString(args.cwd);
|
|
203
|
+
if (!cwd)
|
|
204
|
+
return fn();
|
|
205
|
+
const previous = process.cwd();
|
|
206
|
+
process.chdir(cwd);
|
|
207
|
+
try {
|
|
208
|
+
return fn();
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
process.chdir(previous);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
193
214
|
function runRegistryRefresh(reg, args) {
|
|
194
215
|
return reg.refresh({ scope: scopeOf(args, "repo") });
|
|
195
216
|
}
|
|
@@ -247,6 +268,27 @@ function runArchive(reg, runId, args) {
|
|
|
247
268
|
function runRerun(reg, runId, args) {
|
|
248
269
|
return reg.rerun(runId, { scope: scopeOf(args, "home"), reason: optionalString(args.reason) });
|
|
249
270
|
}
|
|
271
|
+
function runExportArchive(runner, runId, args) {
|
|
272
|
+
return withInvocationCwd(args, () => {
|
|
273
|
+
const output = optionalString(args.output || args.path || args.archive) || `${runId}.cwrun.json`;
|
|
274
|
+
return (0, run_export_1.exportRun)(runner.loadRun(runId), node_path_1.default.resolve(output));
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function runImportArchive(runner, args) {
|
|
278
|
+
return withInvocationCwd(args, () => {
|
|
279
|
+
const archive = optionalString(args.archive || args.path || args.file);
|
|
280
|
+
if (!archive)
|
|
281
|
+
throw new Error("run import requires an archive path (positional, --archive, --path, or --file)");
|
|
282
|
+
const target = optionalString(args.target || args.repo || args.cwd) || process.cwd();
|
|
283
|
+
const imported = (0, run_export_1.importRun)(node_path_1.default.resolve(archive), node_path_1.default.resolve(target));
|
|
284
|
+
const registry = new run_registry_1.RunRegistry(node_path_1.default.resolve(target), runner);
|
|
285
|
+
const registryReport = registry.refresh({ scope: "repo" });
|
|
286
|
+
return { ...imported, registry: registryReport };
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function runVerifyImport(runner, runId, args) {
|
|
290
|
+
return withInvocationCwd(args, () => (0, run_export_1.verifyImportedRun)(runner.loadRun(runId)));
|
|
291
|
+
}
|
|
250
292
|
function queueAdd(reg, args) {
|
|
251
293
|
return reg.queueAdd({
|
|
252
294
|
runId: optionalString(args.runId),
|
|
@@ -628,3 +670,32 @@ function optionalString(value) {
|
|
|
628
670
|
function isRecord(value) {
|
|
629
671
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
630
672
|
}
|
|
673
|
+
// ---- telemetry attestation: read-only ledger verification (Track 1) --------
|
|
674
|
+
// Re-prove a run's telemetry chain offline: prevHash linkage + independent per-
|
|
675
|
+
// record hash recompute (never trusts the stored hash). The auditable claim made
|
|
676
|
+
// inspectable on demand — anyone can run this; a forged/edited record fails it.
|
|
677
|
+
function telemetryVerify(runner, args) {
|
|
678
|
+
const runId = optionalString(args.runId || args.run);
|
|
679
|
+
if (!runId)
|
|
680
|
+
throw new Error("telemetry verify requires a run id (cw telemetry verify <run-id>)");
|
|
681
|
+
const run = runner.loadRun(runId);
|
|
682
|
+
const v = (0, telemetry_ledger_1.verifyTelemetryLedger)(run);
|
|
683
|
+
return {
|
|
684
|
+
schemaVersion: 1,
|
|
685
|
+
runId: run.id,
|
|
686
|
+
present: v.present,
|
|
687
|
+
verified: v.verified,
|
|
688
|
+
records: v.records.length,
|
|
689
|
+
attested: v.attested,
|
|
690
|
+
unattested: v.unattested,
|
|
691
|
+
absent: v.absent,
|
|
692
|
+
failedChecks: v.checks.filter((c) => !c.pass).map((c) => ({ name: c.name, code: c.code }))
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
// ---- demo: tamper-evidence (the one-command proof) -------------------------
|
|
696
|
+
// Hermetic, deterministic-shape: builds a real ed25519-signed telemetry ledger,
|
|
697
|
+
// then forges it two ways and shows both tamper-evidence layers catch it. CLI-only
|
|
698
|
+
// (a human-facing demonstration; the underlying verify is the telemetry.verify verb).
|
|
699
|
+
function demoTamper(_runner, _args = {}) {
|
|
700
|
+
return (0, telemetry_demo_1.runTamperDemo)();
|
|
701
|
+
}
|
|
@@ -215,13 +215,13 @@ const BUILTIN_CAPABILITIES = [
|
|
|
215
215
|
{ capability: "multi-agent.blackboard", summary: "Operate on the active multi-agent blackboard.", entry: "hostMultiAgentBlackboard", surface: "both", cli: { path: ["multi-agent", "blackboard"], jsonMode: "default" }, mcp: { tool: "cw_multi_agent_blackboard" } },
|
|
216
216
|
{ capability: "multi-agent.score", summary: "Score a candidate with evidence.", entry: "hostMultiAgentScore", surface: "both", cli: { path: ["multi-agent", "score"], jsonMode: "default" }, mcp: { tool: "cw_multi_agent_score" } },
|
|
217
217
|
{ capability: "multi-agent.select", summary: "Select a candidate with the verifier gate.", entry: "hostMultiAgentSelect", surface: "both", cli: { path: ["multi-agent", "select"], jsonMode: "default" }, mcp: { tool: "cw_multi_agent_select" } },
|
|
218
|
-
{ capability: "multi-agent.summary", summary: "Read the multi-agent runtime summary.", entry: "multiAgentSummary", surface: "both", cli: { path: ["multi-agent", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_summary" } },
|
|
218
|
+
{ capability: "multi-agent.summary", summary: "Read the structured multi-agent runtime summary for a run.", entry: "multiAgentSummary", surface: "both", cli: { path: ["multi-agent", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_summary" } },
|
|
219
219
|
{ capability: "multi-agent.summarize", summary: "Read the combined state-explosion report.", entry: "multiAgentSummarize", surface: "both", cli: { path: ["multi-agent", "summarize"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_summarize" } },
|
|
220
|
-
{ capability: "multi-agent.graph", summary: "Read the multi-agent operator graph.", entry: "multiAgentOperatorGraph", surface: "both", cli: { path: ["multi-agent", "graph"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_graph" } },
|
|
220
|
+
{ capability: "multi-agent.graph", summary: "Read the structured multi-agent operator graph for a run.", entry: "multiAgentOperatorGraph", surface: "both", cli: { path: ["multi-agent", "graph"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_graph" } },
|
|
221
221
|
{ capability: "multi-agent.graph.compact", summary: "Read a compact/focused multi-agent graph view.", entry: "multiAgentGraphView", surface: "both", cli: { path: ["multi-agent", "graph"], caseTokens: ["multi-agent", "graph"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_graph_compact" } },
|
|
222
|
-
{ capability: "multi-agent.dependencies", summary: "Read derived multi-agent dependency edges.", entry: "multiAgentDependencies", surface: "both", cli: { path: ["multi-agent", "dependencies"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_dependencies" } },
|
|
223
|
-
{ capability: "multi-agent.failures", summary: "Read failed
|
|
224
|
-
{ capability: "multi-agent.evidence", summary: "Read evidence adoption status
|
|
222
|
+
{ capability: "multi-agent.dependencies", summary: "Read derived multi-agent dependency edges for operator inspection.", entry: "multiAgentDependencies", surface: "both", cli: { path: ["multi-agent", "dependencies"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_dependencies" } },
|
|
223
|
+
{ capability: "multi-agent.failures", summary: "Read failed, blocked, rejected, and ambiguous multi-agent records.", entry: "multiAgentFailures", surface: "both", cli: { path: ["multi-agent", "failures"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_failures" } },
|
|
224
|
+
{ capability: "multi-agent.evidence", summary: "Read evidence adoption status from worker output through selection and commit. Each row carries a derived rationaleStatus (explained|unexplained|not-applicable).", entry: "multiAgentEvidence", surface: "both", cli: { path: ["multi-agent", "evidence"], jsonMode: "flag" }, mcp: { tool: "cw_multi_agent_evidence" } },
|
|
225
225
|
{ capability: "multi-agent.reasoning", summary: "Explain why each evidence item was adopted/rejected.", entry: "multiAgentReasoning", surface: "both", cli: { path: ["multi-agent", "reasoning"], jsonMode: "flag" }, mcp: { tool: "cw_evidence_reasoning" } },
|
|
226
226
|
{ capability: "multi-agent.reasoning.refresh", summary: "Refresh the durable evidence-reasoning index.", entry: "multiAgentReasoningRefresh", surface: "both", cli: { path: ["multi-agent", "reasoning"], caseTokens: ["multi-agent", "reasoning"], jsonMode: "default" }, mcp: { tool: "cw_evidence_reasoning_refresh" } },
|
|
227
227
|
// ---- multi-agent lifecycle records --------------------------------------
|
|
@@ -285,7 +285,7 @@ const BUILTIN_CAPABILITIES = [
|
|
|
285
285
|
{ capability: "backend.agent.config.set", summary: "Set the durable agent delegation config (command-template/endpoint/model; API keys never written).", entry: "backendAgentConfigSet", surface: "both", cli: { path: ["backend", "agent", "config"], caseTokens: ["backend", "agent"], jsonMode: "default" }, mcp: { tool: "cw_backend_agent_config_set" }, payloadIdentical: false, reason: "Mutating: persists $CW_HOME/agent-config.json (secret-stripped) before returning the effective config; both surfaces perform the same write — it is a surface-mutating verb, not a read probe." },
|
|
286
286
|
// ---- worker isolation ---------------------------------------------------
|
|
287
287
|
{ capability: "worker.list", summary: "List worker isolation scopes.", entry: "listWorkers", surface: "both", cli: { path: ["worker", "list"], jsonMode: "default" }, mcp: { tool: "cw_worker_list" } },
|
|
288
|
-
{ capability: "worker.summary", summary: "Read the structured worker summary.", entry: "summarizeWorkerRecords", surface: "both", cli: { path: ["worker", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_worker_summary" } },
|
|
288
|
+
{ capability: "worker.summary", summary: "Read the structured worker summary for a run.", entry: "summarizeWorkerRecords", surface: "both", cli: { path: ["worker", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_worker_summary" } },
|
|
289
289
|
{ capability: "worker.show", summary: "Show one worker isolation scope.", entry: "showWorker", surface: "both", cli: { path: ["worker", "show"], jsonMode: "default" }, mcp: { tool: "cw_worker_show" } },
|
|
290
290
|
{ capability: "worker.manifest", summary: "Write and return a worker manifest.", entry: "showWorkerManifest", surface: "both", cli: { path: ["worker", "manifest"], jsonMode: "default" }, mcp: { tool: "cw_worker_manifest" } },
|
|
291
291
|
{ capability: "worker.output", summary: "Record worker output.", entry: "recordWorkerOutput", surface: "both", cli: { path: ["worker", "output"], jsonMode: "default" }, mcp: { tool: "cw_worker_output" } },
|
|
@@ -299,12 +299,12 @@ const BUILTIN_CAPABILITIES = [
|
|
|
299
299
|
{ capability: "candidate.rank", summary: "Rank candidates with gates.", entry: "rankCandidates", surface: "both", cli: { path: ["candidate", "rank"], jsonMode: "default" }, mcp: { tool: "cw_candidate_rank" } },
|
|
300
300
|
{ capability: "candidate.select", summary: "Select a candidate with the verifier gate.", entry: "selectCandidate", surface: "both", cli: { path: ["candidate", "select"], jsonMode: "default" }, mcp: { tool: "cw_candidate_select" } },
|
|
301
301
|
{ capability: "candidate.reject", summary: "Reject a candidate with a reason.", entry: "rejectCandidate", surface: "both", cli: { path: ["candidate", "reject"], jsonMode: "default" }, mcp: { tool: "cw_candidate_reject" } },
|
|
302
|
-
{ capability: "candidate.summary", summary: "Read the structured candidate summary.", entry: "summarizeCandidateOperatorRecords", surface: "both", cli: { path: ["candidate", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_candidate_summary" } },
|
|
302
|
+
{ capability: "candidate.summary", summary: "Read the structured candidate summary for a run.", entry: "summarizeCandidateOperatorRecords", surface: "both", cli: { path: ["candidate", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_candidate_summary" } },
|
|
303
303
|
// ---- feedback -----------------------------------------------------------
|
|
304
304
|
{ capability: "feedback.list", summary: "List run feedback records.", entry: "listFeedback", surface: "both", cli: { path: ["feedback", "list"], jsonMode: "default" }, mcp: { tool: "cw_feedback_list" } },
|
|
305
305
|
{ capability: "feedback.show", summary: "Show a run feedback record.", entry: "showFeedback", surface: "both", cli: { path: ["feedback", "show"], jsonMode: "default" }, mcp: { tool: "cw_feedback_show" } },
|
|
306
306
|
{ capability: "feedback.collect", summary: "Collect feedback from failed nodes.", entry: "collectFeedback", surface: "both", cli: { path: ["feedback", "collect"], jsonMode: "default" }, mcp: { tool: "cw_feedback_collect" } },
|
|
307
|
-
{ capability: "feedback.summary", summary: "Read the structured feedback summary.", entry: "summarizeFeedbackRecords", surface: "both", cli: { path: ["feedback", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_feedback_summary" } },
|
|
307
|
+
{ capability: "feedback.summary", summary: "Read the structured feedback summary for a run.", entry: "summarizeFeedbackRecords", surface: "both", cli: { path: ["feedback", "summary"], jsonMode: "flag" }, mcp: { tool: "cw_feedback_summary" } },
|
|
308
308
|
{ capability: "feedback.task", summary: "Create a correction task for feedback.", entry: "createFeedbackTask", surface: "both", cli: { path: ["feedback", "task"], jsonMode: "default" }, mcp: { tool: "cw_feedback_task" } },
|
|
309
309
|
{ capability: "feedback.resolve", summary: "Resolve or reject feedback.", entry: "resolveFeedback", surface: "both", cli: { path: ["feedback", "resolve"], jsonMode: "default" }, mcp: { tool: "cw_feedback_resolve" } },
|
|
310
310
|
// ---- scheduling ---------------------------------------------------------
|
|
@@ -344,6 +344,9 @@ const BUILTIN_CAPABILITIES = [
|
|
|
344
344
|
{ capability: "run.resume", summary: "Resolve a run by id and continue it from durable state.", entry: "runRegistry.resume", surface: "both", cli: { path: ["run", "resume"], jsonMode: "flag" }, mcp: { tool: "cw_run_resume" } },
|
|
345
345
|
{ capability: "run.archive", summary: "Archive/unarchive a run (overlay mark; never deletes source).", entry: "runRegistry.archive", surface: "both", cli: { path: ["run", "archive"], jsonMode: "default" }, mcp: { tool: "cw_run_archive" } },
|
|
346
346
|
{ capability: "run.rerun", summary: "Re-run a failed run as a NEW run linked to the original by provenance.", entry: "runRegistry.rerun", surface: "both", cli: { path: ["run", "rerun"], jsonMode: "default" }, mcp: { tool: "cw_run_rerun" } },
|
|
347
|
+
{ capability: "run.export", summary: "Export a run to a portable archive with run-local files and digest integrity.", entry: "runExportArchive", surface: "both", cli: { path: ["run", "export"], jsonMode: "default" }, mcp: { tool: "cw_run_export" } },
|
|
348
|
+
{ capability: "run.import", summary: "Restore a portable run archive into a target repo and verify restored file digests.", entry: "runImportArchive", surface: "both", cli: { path: ["run", "import"], jsonMode: "default" }, mcp: { tool: "cw_run_import" } },
|
|
349
|
+
{ capability: "run.verify-import", summary: "Verify an imported run against its restore manifest and telemetry chain.", entry: "runVerifyImport", surface: "both", cli: { path: ["run", "verify-import"], jsonMode: "default" }, mcp: { tool: "cw_run_verify_import" } },
|
|
347
350
|
{ capability: "run.drive", summary: "Preview the next agent-delegation drive step for a run (read-only, deterministic).", entry: "runDrivePreview", surface: "both", cli: { path: ["run", "drive"], caseTokens: ["run", "drive"], jsonMode: "default" }, mcp: { tool: "cw_run_drive" } },
|
|
348
351
|
{ capability: "run.drive.step", summary: "Drive a run by delegating each worker to the agent backend (plan->dispatch->fulfill->accept->commit; --once for one step).", entry: "runDrive", surface: "both", cli: { path: ["run", "drive"], caseTokens: ["run", "drive"], jsonMode: "default" }, mcp: { tool: "cw_run_drive_step" }, payloadIdentical: false, reason: "Mutating: advances the run by spawning the external agent per worker and recording attested output — not a read probe. CLI (--drive/--step) and MCP route through the same drive() core." },
|
|
349
352
|
{
|
|
@@ -374,6 +377,8 @@ const BUILTIN_CAPABILITIES = [
|
|
|
374
377
|
{ capability: "gc.plan", summary: "Dry-run plan of run reclamation (per-kind bytes + capability downgrade); frees nothing.", entry: "gcPlan", surface: "both", cli: { path: ["gc", "plan"], caseTokens: ["gc", "plan"], jsonMode: "flag" }, mcp: { tool: "cw_gc_plan" } },
|
|
375
378
|
{ capability: "gc.run", summary: "Execute the write-ahead reclamation transaction (skeleton -> tombstone -> fsync -> free).", entry: "gcRun", surface: "both", cli: { path: ["gc", "run"], caseTokens: ["gc", "run"], jsonMode: "flag" }, mcp: { tool: "cw_gc_run" }, payloadIdentical: false, reason: "Mutating: frees disk and appends a tombstone; both surfaces perform the identical transaction but the payload reports now-derived bytesFreed/tombstone." },
|
|
376
379
|
{ capability: "gc.verify", summary: "Re-prove a reclaimed run: skeleton-complete, tombstone chain untampered, artifacts reconstructable.", entry: "gcVerify", surface: "both", cli: { path: ["gc", "verify"], caseTokens: ["gc", "verify"], jsonMode: "flag" }, mcp: { tool: "cw_gc_verify" } },
|
|
380
|
+
{ capability: "telemetry.verify", summary: "Re-prove a run's telemetry attestation ledger offline (chain linkage + independent hash recompute).", entry: "telemetryVerify", surface: "both", cli: { path: ["telemetry", "verify"], caseTokens: ["telemetry"], jsonMode: "flag" }, mcp: { tool: "cw_telemetry_verify" } },
|
|
381
|
+
{ capability: "demo.tamper", summary: "Prove tamper-evidence: build a signed telemetry ledger, forge it, watch verification fail offline.", entry: "demoTamper", surface: "cli-only", cli: { path: ["demo", "tamper"], caseTokens: ["demo", "tamper"], jsonMode: "flag" }, reason: "Human-facing demonstration (operator/newcomer onboarding); the underlying integrity check is exposed programmatically as the both-surface telemetry.verify. No agent or MCP client needs to invoke a demo." },
|
|
377
382
|
{ capability: "history", summary: "Read a cross-repo unified run timeline (newest first).", entry: "runRegistry.history", surface: "both", cli: { path: ["history"], jsonMode: "flag" }, mcp: { tool: "cw_history" } },
|
|
378
383
|
// ---- web / desktop workbench (v0.1.30) ----------------------------------
|
|
379
384
|
// A THIRD FRONT DOOR — a read-only renderer, not a new brain. Both verbs route
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const orchestrator_1 = require("./orchestrator");
|
|
|
10
10
|
const capability_registry_1 = require("./capability-registry");
|
|
11
11
|
const capability_core_1 = require("./capability-core");
|
|
12
12
|
const observability_1 = require("./observability");
|
|
13
|
+
const telemetry_demo_1 = require("./telemetry-demo");
|
|
13
14
|
const run_registry_1 = require("./run-registry");
|
|
14
15
|
const daemon_1 = require("./daemon");
|
|
15
16
|
const scheduler_1 = require("./scheduler");
|
|
@@ -1063,10 +1064,19 @@ async function main() {
|
|
|
1063
1064
|
case "rerun":
|
|
1064
1065
|
printJson((0, capability_core_1.runRerun)(registry, required(id, "run id"), args.options));
|
|
1065
1066
|
return;
|
|
1067
|
+
case "export":
|
|
1068
|
+
printJson((0, capability_core_1.runExportArchive)(runner, required(id || optionalArg(args.options.runId || args.options.run), "run id"), args.options));
|
|
1069
|
+
return;
|
|
1070
|
+
case "import":
|
|
1071
|
+
printJson((0, capability_core_1.runImportArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path }));
|
|
1072
|
+
return;
|
|
1073
|
+
case "verify-import":
|
|
1074
|
+
printJson((0, capability_core_1.runVerifyImport)(runner, required(id || optionalArg(args.options.runId || args.options.run), "run id"), args.options));
|
|
1075
|
+
return;
|
|
1066
1076
|
default:
|
|
1067
1077
|
if (await tryDispatchCli(args, runner))
|
|
1068
1078
|
return;
|
|
1069
|
-
throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive [run-id] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--repo R --question Q]");
|
|
1079
|
+
throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--repo R --question Q]");
|
|
1070
1080
|
}
|
|
1071
1081
|
}
|
|
1072
1082
|
case "queue": {
|
|
@@ -1179,6 +1189,44 @@ async function main() {
|
|
|
1179
1189
|
process.stdout.write(`${(0, run_registry_1.formatHistory)(result)}\n`);
|
|
1180
1190
|
return;
|
|
1181
1191
|
}
|
|
1192
|
+
case "telemetry": {
|
|
1193
|
+
const [subcommand, id] = args.positionals;
|
|
1194
|
+
switch (subcommand) {
|
|
1195
|
+
case "verify": {
|
|
1196
|
+
const result = (0, capability_core_1.telemetryVerify)(runner, { ...args.options, runId: id || args.options.runId || args.options.run });
|
|
1197
|
+
if (wantsJson(args.options))
|
|
1198
|
+
printJson(result);
|
|
1199
|
+
else
|
|
1200
|
+
process.stdout.write(`${(0, telemetry_demo_1.formatTelemetryVerify)(result)}\n`);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
default:
|
|
1204
|
+
if (await tryDispatchCli(args, runner))
|
|
1205
|
+
return;
|
|
1206
|
+
throw new Error("Usage: cw.js telemetry verify <run-id> [--json]");
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
case "demo": {
|
|
1210
|
+
const [subcommand] = args.positionals;
|
|
1211
|
+
switch (subcommand) {
|
|
1212
|
+
case "tamper": {
|
|
1213
|
+
const result = (0, capability_core_1.demoTamper)(runner, args.options);
|
|
1214
|
+
if (wantsJson(args.options))
|
|
1215
|
+
printJson(result);
|
|
1216
|
+
else
|
|
1217
|
+
process.stdout.write(`${(0, telemetry_demo_1.formatTamperDemo)(result)}\n`);
|
|
1218
|
+
// Fail closed: if the proof did not hold (a tamper went undetected),
|
|
1219
|
+
// exit nonzero so the demo can never green a broken guarantee.
|
|
1220
|
+
if (!result.proven)
|
|
1221
|
+
process.exitCode = 1;
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
default:
|
|
1225
|
+
if (await tryDispatchCli(args, runner))
|
|
1226
|
+
return;
|
|
1227
|
+
throw new Error("Usage: cw.js demo tamper [--json]");
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1182
1230
|
case "workbench": {
|
|
1183
1231
|
const [subcommand, runId] = args.positionals;
|
|
1184
1232
|
switch (subcommand) {
|