cool-workflow 0.1.79 → 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 +9 -1
- 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 +38 -0
- package/dist/capability-registry.js +11 -8
- package/dist/cli.js +10 -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 +48 -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/version.js +1 -1
- package/docs/agent-delegation-drive.7.md +58 -0
- package/docs/canonical-workflow-apps.7.md +37 -0
- package/docs/cli-mcp-parity.7.md +12 -0
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- package/docs/durable-state-and-locking.7.md +4 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
- package/docs/execution-backends.7.md +4 -0
- package/docs/index.md +1 -0
- package/docs/launch/demo.tape +28 -0
- package/docs/launch/launch-kit.md +59 -3
- package/docs/launch/pre-launch-checklist.md +53 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
- package/docs/multi-agent-eval-replay-harness.7.md +4 -0
- package/docs/multi-agent-operator-ux.7.md +4 -0
- package/docs/node-snapshot-diff-replay.7.md +4 -0
- package/docs/observability-cost-accounting.7.md +4 -0
- package/docs/project-index.md +13 -5
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +4 -0
- package/docs/routines.md +23 -0
- package/docs/run-registry-control-plane.7.md +42 -1
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/source-context-profiles.7.md +119 -0
- package/docs/state-explosion-management.7.md +11 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/unix-principles.md +49 -1
- package/docs/web-desktop-workbench.7.md +4 -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
|
@@ -649,8 +649,16 @@ The orchestration vision landed in one release, all reviewer-gated:
|
|
|
649
649
|
|
|
650
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
651
|
|
|
652
|
-
## Tamper-evidence demo (
|
|
652
|
+
## Tamper-evidence demo (v0.1.79)
|
|
653
653
|
|
|
654
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
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
|
+
|
|
656
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;
|
|
@@ -71,6 +74,7 @@ const observability_1 = require("./observability");
|
|
|
71
74
|
const telemetry_ledger_1 = require("./telemetry-ledger");
|
|
72
75
|
const telemetry_demo_1 = require("./telemetry-demo");
|
|
73
76
|
const state_1 = require("./state");
|
|
77
|
+
const run_export_1 = require("./run-export");
|
|
74
78
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
75
79
|
const node_path_1 = __importDefault(require("node:path"));
|
|
76
80
|
const scheduling_1 = require("./scheduling");
|
|
@@ -194,6 +198,19 @@ function flag(value) {
|
|
|
194
198
|
return false;
|
|
195
199
|
return Boolean(value);
|
|
196
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
|
+
}
|
|
197
214
|
function runRegistryRefresh(reg, args) {
|
|
198
215
|
return reg.refresh({ scope: scopeOf(args, "repo") });
|
|
199
216
|
}
|
|
@@ -251,6 +268,27 @@ function runArchive(reg, runId, args) {
|
|
|
251
268
|
function runRerun(reg, runId, args) {
|
|
252
269
|
return reg.rerun(runId, { scope: scopeOf(args, "home"), reason: optionalString(args.reason) });
|
|
253
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
|
+
}
|
|
254
292
|
function queueAdd(reg, args) {
|
|
255
293
|
return reg.queueAdd({
|
|
256
294
|
runId: optionalString(args.runId),
|
|
@@ -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
|
{
|
package/dist/cli.js
CHANGED
|
@@ -1064,10 +1064,19 @@ async function main() {
|
|
|
1064
1064
|
case "rerun":
|
|
1065
1065
|
printJson((0, capability_core_1.runRerun)(registry, required(id, "run id"), args.options));
|
|
1066
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;
|
|
1067
1076
|
default:
|
|
1068
1077
|
if (await tryDispatchCli(args, runner))
|
|
1069
1078
|
return;
|
|
1070
|
-
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]");
|
|
1071
1080
|
}
|
|
1072
1081
|
}
|
|
1073
1082
|
case "queue": {
|
package/dist/drive.js
CHANGED
|
@@ -31,12 +31,14 @@ exports.driveConcurrentRound = driveConcurrentRound;
|
|
|
31
31
|
exports.drive = drive;
|
|
32
32
|
exports.drivePreview = drivePreview;
|
|
33
33
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
34
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
34
35
|
const dispatch_1 = require("./dispatch");
|
|
35
36
|
const execution_backend_1 = require("./execution-backend");
|
|
36
37
|
const worker_isolation_1 = require("./worker-isolation");
|
|
37
38
|
const agent_config_1 = require("./agent-config");
|
|
38
39
|
const scheduling_1 = require("./scheduling");
|
|
39
40
|
const observability_1 = require("./observability");
|
|
41
|
+
const state_1 = require("./state");
|
|
40
42
|
exports.DRIVE_SCHEMA_VERSION = 1;
|
|
41
43
|
/** The task the next drive step would advance: a RUNNING (already-dispatched,
|
|
42
44
|
* awaiting fulfillment / retry) task first, else the next PENDING task in the
|
|
@@ -198,8 +200,26 @@ function processSelectedTask(ctx, selected, preparedOutcome) {
|
|
|
198
200
|
// Progress BEFORE the (possibly multi-minute) agent spawn, so a live drive shows
|
|
199
201
|
// immediate activity instead of a long silence on the first worker. task.label
|
|
200
202
|
// is the human-facing display name; the id stays the stable reference.
|
|
201
|
-
emitProgress(`→ ${selected.label || selected.id} (${selected.phase}) — ${dispatched ? "dispatched, " : ""}spawning agent, may take minutes…`);
|
|
202
203
|
const promptDigest = node_fs_1.default.existsSync(manifest.inputPath) ? (0, execution_backend_1.sha256)(node_fs_1.default.readFileSync(manifest.inputPath, "utf8")) : (0, execution_backend_1.sha256)(manifest.prompt || "");
|
|
204
|
+
const cachePath = resultCachePath(run, selected, (0, execution_backend_1.sha256)(selected.prompt));
|
|
205
|
+
if (cachePath && node_fs_1.default.existsSync(cachePath)) {
|
|
206
|
+
emitProgress(`↺ ${selected.label || selected.id} (${selected.phase}) — accepting cached result`);
|
|
207
|
+
try {
|
|
208
|
+
node_fs_1.default.writeFileSync(manifest.resultPath, node_fs_1.default.readFileSync(cachePath, "utf8"), "utf8");
|
|
209
|
+
runner.recordWorkerOutput(runId, workerId, manifest.resultPath, {});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
return handleHop(ctx, selected, workerId, `result cache rejected: ${error instanceof Error ? error.message : String(error)}`, dispatched);
|
|
213
|
+
}
|
|
214
|
+
return step("accept", "ok", {
|
|
215
|
+
runId,
|
|
216
|
+
taskId: selected.id,
|
|
217
|
+
phase: selected.phase,
|
|
218
|
+
handleKind: "result-cache",
|
|
219
|
+
reason: "result cache hit"
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
emitProgress(`→ ${selected.label || selected.id} (${selected.phase}) — ${dispatched ? "dispatched, " : ""}spawning agent, may take minutes…`);
|
|
203
223
|
const envelope = (0, execution_backend_1.runBackend)(buildAgentRequest(ctx, run, selected, manifest, preparedOutcome));
|
|
204
224
|
const handle = envelope.provenance.handle;
|
|
205
225
|
const reportedModel = handle?.metadata?.reportedModel || "unreported";
|
|
@@ -236,6 +256,9 @@ function processSelectedTask(ctx, selected, preparedOutcome) {
|
|
|
236
256
|
catch (error) {
|
|
237
257
|
return handleHop(ctx, selected, workerId, `result.md rejected: ${error instanceof Error ? error.message : String(error)}`, dispatched);
|
|
238
258
|
}
|
|
259
|
+
if (cachePath && manifest.resultPath && node_fs_1.default.existsSync(manifest.resultPath)) {
|
|
260
|
+
writeResultCache(cachePath, node_fs_1.default.readFileSync(manifest.resultPath, "utf8"));
|
|
261
|
+
}
|
|
239
262
|
return step("accept", "ok", {
|
|
240
263
|
runId,
|
|
241
264
|
taskId: selected.id,
|
|
@@ -245,6 +268,53 @@ function processSelectedTask(ctx, selected, preparedOutcome) {
|
|
|
245
268
|
reportedModel
|
|
246
269
|
});
|
|
247
270
|
}
|
|
271
|
+
function resultCachePath(run, task, promptDigest) {
|
|
272
|
+
const policy = task.resultCache;
|
|
273
|
+
if (!policy || policy.mode !== "read-write")
|
|
274
|
+
return undefined;
|
|
275
|
+
const keyInput = policy.keyInput;
|
|
276
|
+
const keyValue = keyInput ? String(run.inputs[keyInput] || "").trim() : "";
|
|
277
|
+
if (!keyInput || !keyValue)
|
|
278
|
+
return undefined;
|
|
279
|
+
const completedResultsDigest = completedResultsCacheDigest(run, task);
|
|
280
|
+
if (completedResultsDigest === undefined)
|
|
281
|
+
return undefined;
|
|
282
|
+
const digest = (0, execution_backend_1.sha256)(JSON.stringify({
|
|
283
|
+
schemaVersion: 1,
|
|
284
|
+
workflowId: run.workflow.id,
|
|
285
|
+
taskId: task.id,
|
|
286
|
+
keyInput,
|
|
287
|
+
keyValue,
|
|
288
|
+
promptDigest,
|
|
289
|
+
completedResultsDigest
|
|
290
|
+
})).replace(/^sha256:/, "");
|
|
291
|
+
return node_path_1.default.join(run.cwd, ".cw", "cache", "worker-results", (0, state_1.safeFileName)(run.workflow.id), `${(0, state_1.safeFileName)(task.id)}-${digest.slice(0, 32)}.md`);
|
|
292
|
+
}
|
|
293
|
+
function completedResultsCacheDigest(run, task) {
|
|
294
|
+
if (task.resultCache?.includeCompletedResults !== "previous-phases")
|
|
295
|
+
return "";
|
|
296
|
+
const phaseIndex = run.phases.findIndex((phase) => phase.name === task.phase || phase.id === task.phase);
|
|
297
|
+
if (phaseIndex < 0)
|
|
298
|
+
return undefined;
|
|
299
|
+
const previousTaskIds = new Set(run.phases.slice(0, phaseIndex).flatMap((phase) => phase.taskIds));
|
|
300
|
+
const records = run.tasks
|
|
301
|
+
.filter((candidate) => previousTaskIds.has(candidate.id))
|
|
302
|
+
.sort((a, b) => a.id.localeCompare(b.id))
|
|
303
|
+
.map((candidate) => {
|
|
304
|
+
if (candidate.status !== "completed" || !candidate.resultPath || !node_fs_1.default.existsSync(candidate.resultPath))
|
|
305
|
+
return undefined;
|
|
306
|
+
return [candidate.id, (0, execution_backend_1.sha256)(node_fs_1.default.readFileSync(candidate.resultPath, "utf8"))];
|
|
307
|
+
});
|
|
308
|
+
if (records.some((record) => record === undefined))
|
|
309
|
+
return undefined;
|
|
310
|
+
return (0, execution_backend_1.sha256)(JSON.stringify(records));
|
|
311
|
+
}
|
|
312
|
+
function writeResultCache(file, content) {
|
|
313
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(file), { recursive: true });
|
|
314
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
315
|
+
node_fs_1.default.writeFileSync(tmp, content, "utf8");
|
|
316
|
+
node_fs_1.default.renameSync(tmp, file);
|
|
317
|
+
}
|
|
248
318
|
/** Advance ONE concurrent ROUND: fulfill up to `limit` ready tasks in the first
|
|
249
319
|
* runnable phase as a single batch, recording results in DETERMINISTIC task
|
|
250
320
|
* order (the existing phase/dispatch order) regardless of completion order — so
|
|
@@ -322,6 +392,9 @@ function prepareConcurrentOutcomes(ctx, batch) {
|
|
|
322
392
|
continue;
|
|
323
393
|
}
|
|
324
394
|
const manifest = runner.showWorkerManifest(runId, workerId);
|
|
395
|
+
const cachePath = resultCachePath(run, task, (0, execution_backend_1.sha256)(task.prompt));
|
|
396
|
+
if (cachePath && node_fs_1.default.existsSync(cachePath))
|
|
397
|
+
continue;
|
|
325
398
|
const job = (0, execution_backend_1.prepareAgentSpawn)(buildAgentRequest(ctx, run, task, manifest));
|
|
326
399
|
if (job) {
|
|
327
400
|
jobs.push(job);
|
|
@@ -389,11 +389,11 @@ function deriveCounterfactuals(run, scores) {
|
|
|
389
389
|
// node. This returns the operator-graph node ids backing every decision-bearing
|
|
390
390
|
// reasoning step of an adopted chain, so state-explosion can protect them.
|
|
391
391
|
// ---------------------------------------------------------------------------
|
|
392
|
-
function reasoningCriticalNodeIds(run) {
|
|
392
|
+
function reasoningCriticalNodeIds(run, operator = (0, multi_agent_operator_ux_1.summarizeMultiAgentOperator)(run)) {
|
|
393
393
|
const ids = new Set();
|
|
394
394
|
const faninIds = new Set((run.multiAgent?.fanins || []).map((entry) => entry.id));
|
|
395
395
|
const commitById = new Map((run.commits || []).map((commit) => [commit.id, commit]));
|
|
396
|
-
for (const evidence of
|
|
396
|
+
for (const evidence of operator.evidence) {
|
|
397
397
|
if (evidence.status !== "adopted")
|
|
398
398
|
continue;
|
|
399
399
|
for (const id of evidence.candidateIds)
|
|
@@ -887,13 +887,18 @@ function runAgentProcess(descriptor, policy, request, label, handle, attestation
|
|
|
887
887
|
outcome = request.preparedAgentOutcome;
|
|
888
888
|
}
|
|
889
889
|
else {
|
|
890
|
+
// Live output is opt-in (POLA): stdout is always captured as data, while
|
|
891
|
+
// stderr is forwarded only when the operator explicitly asks for a stream
|
|
892
|
+
// and this process is attached to a terminal. CI/pipes stay silent.
|
|
893
|
+
const streamStderr = process.env.CW_AGENT_STREAM === "1" && Boolean(process.stderr.isTTY) && process.env.CW_NO_STREAM !== "1";
|
|
890
894
|
const child = (0, node_child_process_1.spawnSync)(resolved.binary, realArgs, {
|
|
891
895
|
cwd: request.cwd,
|
|
892
896
|
env: { ...process.env },
|
|
893
897
|
encoding: "utf8",
|
|
894
898
|
timeout: resolved.timeoutMs || 600000,
|
|
895
899
|
maxBuffer: 32 * 1024 * 1024,
|
|
896
|
-
shell: false
|
|
900
|
+
shell: false,
|
|
901
|
+
stdio: ["ignore", "pipe", streamStderr ? "inherit" : "pipe"]
|
|
897
902
|
});
|
|
898
903
|
outcome = {
|
|
899
904
|
...(child.error ? { spawnError: messageOf(child.error) } : {}),
|