cool-workflow 0.1.84 → 0.1.86
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 +47 -331
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/architecture-review-fast/workflow.js +2 -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 +220 -5
- package/dist/capability-registry.js +90 -51
- package/dist/cli/command-surface.js +47 -2
- package/dist/doctor.js +37 -1
- package/dist/mcp/tool-call.js +428 -0
- package/dist/mcp/tool-definitions.js +1027 -0
- package/dist/mcp-surface.js +5 -1416
- package/dist/onramp.js +421 -0
- package/dist/orchestrator.js +20 -15
- package/dist/run-export.js +139 -1
- package/dist/telemetry-demo.js +119 -0
- package/dist/types/report-bundle.js +6 -0
- package/dist/types.js +1 -0
- package/dist/version.js +1 -1
- package/dist/workbench-host.js +1 -8
- package/docs/agent-delegation-drive.7.md +23 -2
- package/docs/cli-mcp-parity.7.md +38 -7
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- package/docs/dogfood-one-real-repo.7.md +9 -1
- 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/getting-started.md +40 -2
- package/docs/index.md +51 -37
- 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 +23 -7
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +5 -1
- package/docs/release-history.md +342 -0
- package/docs/release-tooling.7.md +18 -0
- package/docs/report-verifiable-bundle.7.md +123 -0
- package/docs/run-registry-control-plane.7.md +4 -0
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +4 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +1 -1
- package/package.json +2 -1
- package/scripts/architecture-review-fast.js +44 -2
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-release.js +55 -133
- package/scripts/golden-path.js +4 -4
- package/scripts/onramp-check.js +47 -0
- package/scripts/parity-check.js +740 -2
- package/scripts/release-check.js +2 -0
- package/scripts/source-context.js +31 -5
- package/scripts/version-sync-check.js +4 -2
package/dist/onramp.js
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
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.optionEnabled = optionEnabled;
|
|
7
|
+
exports.npmCommand = npmCommand;
|
|
8
|
+
exports.nodeSmokeCommand = nodeSmokeCommand;
|
|
9
|
+
exports.detectSourceCheckout = detectSourceCheckout;
|
|
10
|
+
exports.shellQuote = shellQuote;
|
|
11
|
+
exports.buildDoctorOnramp = buildDoctorOnramp;
|
|
12
|
+
exports.resolveChangedFiles = resolveChangedFiles;
|
|
13
|
+
exports.evaluateOnrampContract = evaluateOnrampContract;
|
|
14
|
+
exports.recommendSmokeTests = recommendSmokeTests;
|
|
15
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
16
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
17
|
+
const node_child_process_1 = require("node:child_process");
|
|
18
|
+
const CURATED_SMOKE_MAP = [
|
|
19
|
+
{
|
|
20
|
+
patterns: ["src/doctor.ts", "src/onramp.ts", "scripts/onramp-check.js"],
|
|
21
|
+
smokes: ["doctor-smoke.js", "onramp-check-smoke.js"]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
patterns: ["README.md", "docs/getting-started.md", "docs/index.md"],
|
|
25
|
+
smokes: ["quickstart-readme-path-smoke.js", "doctor-smoke.js"]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
patterns: ["src/cli.ts", "src/cli/"],
|
|
29
|
+
smokes: ["cli-command-surface-smoke.js", "cli-jsonmode-parity-smoke.js", "cli-mcp-parity-smoke.js"]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
patterns: ["src/orchestrator.ts"],
|
|
33
|
+
smokes: ["cli-mcp-parity-smoke.js"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
patterns: ["src/capability-registry.ts", "scripts/parity-check.js"],
|
|
37
|
+
smokes: ["cli-mcp-parity-smoke.js", "cli-jsonmode-parity-smoke.js", "parity-doc-sync-smoke.js"]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
patterns: ["src/mcp-server.ts", "src/mcp-surface.ts"],
|
|
41
|
+
smokes: ["mcp-surface-registry-smoke.js", "mcp-app-surface-smoke.js", "cli-mcp-parity-smoke.js"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
patterns: ["src/run-export.ts", "src/types/run.ts"],
|
|
45
|
+
smokes: ["run-export-import-smoke.js", "run-export-restore-resume-smoke.js", "run-inspect-archive-smoke.js"]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
patterns: ["src/capability-core.ts", "src/drive.ts", "src/agent-config.ts"],
|
|
49
|
+
smokes: ["quickstart-smoke.js", "quickstart-check-smoke.js", "agent-delegation-drive-smoke.js"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
patterns: ["src/telemetry", "src/worker-accept/telemetry"],
|
|
53
|
+
smokes: ["telemetry-ledger-smoke.js", "telemetry-attestation-smoke.js", "telemetry-verify-signatures-smoke.js"]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
patterns: ["src/workbench", "ui/workbench/"],
|
|
57
|
+
smokes: ["web-desktop-workbench-smoke.js"]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
patterns: ["src/scheduler.ts", "src/scheduling.ts", "src/daemon.ts", "src/triggers.ts"],
|
|
61
|
+
smokes: ["schedule-routine-daemon-smoke.js", "sched-policy-validation-smoke.js"]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
patterns: ["src/multi-agent", "src/topology.ts", "src/coordinator", "src/evidence-reasoning.ts", "src/state-explosion"],
|
|
65
|
+
smokes: [
|
|
66
|
+
"multi-agent-runtime-core-smoke.js",
|
|
67
|
+
"multi-agent-topologies-map-reduce-smoke.js",
|
|
68
|
+
"multi-agent-topologies-debate-smoke.js",
|
|
69
|
+
"multi-agent-topologies-judge-panel-smoke.js",
|
|
70
|
+
"multi-agent-cli-mcp-surface-smoke.js",
|
|
71
|
+
"blackboard-state-explosion-management-smoke.js"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
function optionEnabled(value) {
|
|
76
|
+
if (value === undefined || value === false)
|
|
77
|
+
return false;
|
|
78
|
+
if (typeof value === "string" && ["", "0", "false", "no"].includes(value.toLowerCase()))
|
|
79
|
+
return false;
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function npmCommand(cwd, script) {
|
|
83
|
+
const source = detectSourceCheckout(cwd);
|
|
84
|
+
const base = `npm run ${script}`;
|
|
85
|
+
return source ? `${source.chdir}${base}` : base;
|
|
86
|
+
}
|
|
87
|
+
function nodeSmokeCommand(cwd, smoke) {
|
|
88
|
+
const source = detectSourceCheckout(cwd);
|
|
89
|
+
const base = `node test/${smoke}`;
|
|
90
|
+
return source ? `${source.chdir}${base}` : base;
|
|
91
|
+
}
|
|
92
|
+
function detectSourceCheckout(cwd) {
|
|
93
|
+
const resolved = node_path_1.default.resolve(cwd);
|
|
94
|
+
const candidates = [resolved, node_path_1.default.join(resolved, "plugins", "cool-workflow")];
|
|
95
|
+
for (const candidate of candidates) {
|
|
96
|
+
try {
|
|
97
|
+
const pkg = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(candidate, "package.json"), "utf8"));
|
|
98
|
+
if (pkg.name === "cool-workflow") {
|
|
99
|
+
return {
|
|
100
|
+
packageDir: candidate,
|
|
101
|
+
chdir: candidate === resolved ? "" : `cd ${shellQuote(node_path_1.default.relative(resolved, candidate) || ".")} && `
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* keep looking */
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
function shellQuote(value) {
|
|
112
|
+
if (/^[A-Za-z0-9_./:-]+$/.test(value))
|
|
113
|
+
return value;
|
|
114
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
115
|
+
}
|
|
116
|
+
function buildDoctorOnramp(options = {}) {
|
|
117
|
+
const cwd = node_path_1.default.resolve(options.cwd || process.cwd());
|
|
118
|
+
const agentCommand = "--agent-command builtin:claude";
|
|
119
|
+
const onramp = {
|
|
120
|
+
schemaVersion: 1,
|
|
121
|
+
summary: "start small, run the short gate while changing code, then run the full gate before release",
|
|
122
|
+
sections: [
|
|
123
|
+
{
|
|
124
|
+
id: "first-run",
|
|
125
|
+
title: "First Run",
|
|
126
|
+
summary: "Prove the tool, check the setup, then make one report.",
|
|
127
|
+
actions: [
|
|
128
|
+
{
|
|
129
|
+
id: "demo",
|
|
130
|
+
title: "Prove tamper checks",
|
|
131
|
+
command: "cw demo tamper",
|
|
132
|
+
reason: "Shows the core trust check without an agent or a repo."
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "setup",
|
|
136
|
+
title: "Check setup",
|
|
137
|
+
command: "cw doctor --onramp",
|
|
138
|
+
reason: "Names local setup trouble before a run is made."
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "dry-run",
|
|
142
|
+
title: "Check a real run",
|
|
143
|
+
command: `cw quickstart architecture-review --check --repo /path/to/repo --question "What are the main risks?" ${agentCommand}`,
|
|
144
|
+
reason: "Does no writes and no agent call; it checks inputs first."
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: "report",
|
|
148
|
+
title: "Make the report",
|
|
149
|
+
command: `cw quickstart architecture-review --repo /path/to/repo --question "What are the main risks?" ${agentCommand}`,
|
|
150
|
+
reason: "Runs the short user path: ask, run, verify, report."
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: "bundle",
|
|
154
|
+
title: "Make a bundle",
|
|
155
|
+
command: `cw quickstart architecture-review --repo /path/to/repo --question "What are the main risks?" ${agentCommand} --bundle`,
|
|
156
|
+
reason: "Seals a completed report into a portable file the receiver can check offline."
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "verify-bundle",
|
|
160
|
+
title: "Check the bundle",
|
|
161
|
+
command: "cw report verify-bundle report.cwrun.json",
|
|
162
|
+
reason: "Checks the report bundle without the source repo or a .cw tree."
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "change-loop",
|
|
168
|
+
title: "Change Loop",
|
|
169
|
+
summary: "Use the small checks while changing code; save the slow full gate for the end.",
|
|
170
|
+
actions: [
|
|
171
|
+
{
|
|
172
|
+
id: "build",
|
|
173
|
+
title: "Type check the change",
|
|
174
|
+
command: npmCommand(cwd, "build"),
|
|
175
|
+
reason: "Fast first check for TypeScript errors."
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "target-smoke",
|
|
179
|
+
title: "Run the closest smoke",
|
|
180
|
+
command: nodeSmokeCommand(cwd, "doctor-smoke.js"),
|
|
181
|
+
reason: "Replace this smoke name with the one that covers your changed path."
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "fast-suite",
|
|
185
|
+
title: "Run the parallel suite",
|
|
186
|
+
command: npmCommand(cwd, "test:fast"),
|
|
187
|
+
reason: "Runs all smokes with isolated state and parallel workers."
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: "surface-guard",
|
|
193
|
+
title: "Surface Guard",
|
|
194
|
+
summary: "Keep the wide runner, CLI, and MCP faces tied to one source.",
|
|
195
|
+
actions: [
|
|
196
|
+
{
|
|
197
|
+
id: "registry",
|
|
198
|
+
title: "Declare each new verb once",
|
|
199
|
+
command: npmCommand(cwd, "parity:check"),
|
|
200
|
+
reason: "Fails if CLI and MCP drift from the capability registry."
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
id: "manifest",
|
|
204
|
+
title: "Check generated faces",
|
|
205
|
+
command: npmCommand(cwd, "gen:manifests -- --check"),
|
|
206
|
+
reason: "Fails if plugin manifests drift from source."
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "release-gate",
|
|
212
|
+
title: "Release Gate",
|
|
213
|
+
summary: "Run the full gate only when the batch is ready.",
|
|
214
|
+
actions: [
|
|
215
|
+
{
|
|
216
|
+
id: "release-check",
|
|
217
|
+
title: "Dry-run the release gate",
|
|
218
|
+
command: npmCommand(cwd, "release:check"),
|
|
219
|
+
reason: "Builds, checks docs and generated files, runs the parallel suite, and makes no tag."
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
};
|
|
225
|
+
if (options.changedFrom) {
|
|
226
|
+
const changed = resolveChangedFiles({ cwd, changedFrom: options.changedFrom, env: options.env });
|
|
227
|
+
const contract = evaluateOnrampContract(changed.files, { cwd });
|
|
228
|
+
onramp.changedFiles = changed;
|
|
229
|
+
onramp.contract = contract;
|
|
230
|
+
onramp.recommendedChecks = {
|
|
231
|
+
summary: contract.recommendedSmokeTests.length
|
|
232
|
+
? "run the closest smoke tests first, then the fast suite and release gate"
|
|
233
|
+
: "no changed files were found; use the normal short checks",
|
|
234
|
+
smokeTests: contract.recommendedSmokeTests,
|
|
235
|
+
commands: contract.recommendedCommands
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return onramp;
|
|
239
|
+
}
|
|
240
|
+
function resolveChangedFiles(options = {}) {
|
|
241
|
+
const cwd = node_path_1.default.resolve(options.cwd || process.cwd());
|
|
242
|
+
const root = gitRoot(cwd);
|
|
243
|
+
const baseRef = resolveBaseRef(root, options.changedFrom, options.env || process.env);
|
|
244
|
+
const files = new Set();
|
|
245
|
+
for (const file of gitLines(root, ["diff", "--name-only", baseRef, "--"]))
|
|
246
|
+
files.add(normalizeChangedPath(file));
|
|
247
|
+
for (const file of gitLines(root, ["ls-files", "--others", "--exclude-standard"]))
|
|
248
|
+
files.add(normalizeChangedPath(file));
|
|
249
|
+
return { baseRef, files: [...files].filter(Boolean).sort() };
|
|
250
|
+
}
|
|
251
|
+
function evaluateOnrampContract(files, options = {}) {
|
|
252
|
+
const cwd = node_path_1.default.resolve(options.cwd || process.cwd());
|
|
253
|
+
const normalized = [...new Set(files.map((file) => normalizeChangedPath(file)).filter(Boolean))].sort();
|
|
254
|
+
const issues = [];
|
|
255
|
+
const runtimeFiles = normalized.filter(isRuntimeSource);
|
|
256
|
+
const appFiles = normalized.filter((file) => file.startsWith("plugins/cool-workflow/apps/"));
|
|
257
|
+
const typeFiles = normalized.filter((file) => file.startsWith("plugins/cool-workflow/src/types/") && file.endsWith(".ts"));
|
|
258
|
+
const scriptFiles = normalized.filter((file) => file.startsWith("plugins/cool-workflow/scripts/"));
|
|
259
|
+
const surfaceFiles = normalized.filter(isSurfaceFile);
|
|
260
|
+
const smokeFiles = normalized.filter((file) => /^plugins\/cool-workflow\/test\/.+-smoke\.js$/.test(file));
|
|
261
|
+
const docFiles = normalized.filter(isDocFile);
|
|
262
|
+
const iterationFiles = normalized.filter((file) => file === "ITERATION_LOG.md");
|
|
263
|
+
const sourceAppOrScript = runtimeFiles.length > 0 || typeFiles.length > 0 || appFiles.length > 0 || scriptFiles.length > 0;
|
|
264
|
+
if ((runtimeFiles.length > 0 || appFiles.length > 0) && smokeFiles.length === 0) {
|
|
265
|
+
issues.push({
|
|
266
|
+
code: "runtime-smoke-required",
|
|
267
|
+
detail: "Runtime or app changes must include at least one smoke test change.",
|
|
268
|
+
fix: "Add or update a focused test/*-smoke.js file for the changed behavior.",
|
|
269
|
+
files: [...runtimeFiles, ...appFiles]
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
if (typeFiles.length > 0 && runtimeFiles.length === 0 && appFiles.length === 0) {
|
|
273
|
+
issues.push({
|
|
274
|
+
code: "types-without-runtime",
|
|
275
|
+
detail: "Type-only source changes are not a valid cycle.",
|
|
276
|
+
fix: "Add the runtime behavior that reads the type, or remove the type-only change.",
|
|
277
|
+
files: typeFiles
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
if (surfaceFiles.length > 0 && docFiles.length === 0) {
|
|
281
|
+
issues.push({
|
|
282
|
+
code: "surface-docs-required",
|
|
283
|
+
detail: "CLI, MCP, or capability surface changes must update public docs.",
|
|
284
|
+
fix: "Update README.md or plugins/cool-workflow/docs/*.md with the changed surface.",
|
|
285
|
+
files: surfaceFiles
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
if (sourceAppOrScript && iterationFiles.length === 0) {
|
|
289
|
+
issues.push({
|
|
290
|
+
code: "iteration-log-required",
|
|
291
|
+
detail: "Source, app, or script changes must be recorded in ITERATION_LOG.md.",
|
|
292
|
+
fix: "Append one cycle row with goal, files, tests, gate, and tag decision.",
|
|
293
|
+
files: [...runtimeFiles, ...typeFiles, ...appFiles, ...scriptFiles]
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
const recommendedSmokeTests = recommendSmokeTests(normalized, cwd);
|
|
297
|
+
return {
|
|
298
|
+
ok: issues.length === 0,
|
|
299
|
+
changedFiles: normalized,
|
|
300
|
+
recommendedSmokeTests,
|
|
301
|
+
recommendedCommands: recommendedCommands(normalized, recommendedSmokeTests, cwd),
|
|
302
|
+
issues
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function recommendSmokeTests(files, cwd = process.cwd()) {
|
|
306
|
+
const normalized = files.map((file) => normalizeChangedPath(file));
|
|
307
|
+
const smokes = new Set();
|
|
308
|
+
const curatedFiles = new Set();
|
|
309
|
+
for (const file of normalized) {
|
|
310
|
+
const pluginPath = stripPluginPrefix(file);
|
|
311
|
+
for (const entry of CURATED_SMOKE_MAP) {
|
|
312
|
+
const matched = entry.patterns.some((pattern) => pluginPath === pattern || pluginPath.startsWith(pattern));
|
|
313
|
+
if (matched) {
|
|
314
|
+
curatedFiles.add(file);
|
|
315
|
+
for (const smoke of entry.smokes)
|
|
316
|
+
smokes.add(smoke);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const available = availableSmokeTests(cwd);
|
|
321
|
+
for (const file of normalized) {
|
|
322
|
+
if (curatedFiles.has(file))
|
|
323
|
+
continue;
|
|
324
|
+
const pluginPath = stripPluginPrefix(file);
|
|
325
|
+
if (!pluginPath.startsWith("src/"))
|
|
326
|
+
continue;
|
|
327
|
+
const base = node_path_1.default.basename(pluginPath, ".ts");
|
|
328
|
+
const direct = `${base}-smoke.js`;
|
|
329
|
+
if (available.includes(direct))
|
|
330
|
+
smokes.add(direct);
|
|
331
|
+
const tokens = base.split(/[^a-zA-Z0-9]+/).filter((token) => token.length >= 3);
|
|
332
|
+
for (const smoke of available) {
|
|
333
|
+
if (tokens.some((token) => smoke.includes(token)))
|
|
334
|
+
smokes.add(smoke);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return [...smokes].sort();
|
|
338
|
+
}
|
|
339
|
+
function recommendedCommands(files, smokes, cwd) {
|
|
340
|
+
const commands = new Set();
|
|
341
|
+
commands.add(npmCommand(cwd, "build"));
|
|
342
|
+
for (const smoke of smokes)
|
|
343
|
+
commands.add(nodeSmokeCommand(cwd, smoke));
|
|
344
|
+
commands.add(npmCommand(cwd, "test:fast"));
|
|
345
|
+
if (files.some(isSurfaceFile))
|
|
346
|
+
commands.add(npmCommand(cwd, "parity:check"));
|
|
347
|
+
if (files.some(isSurfaceFile))
|
|
348
|
+
commands.add(npmCommand(cwd, "gen:manifests -- --check"));
|
|
349
|
+
commands.add(npmCommand(cwd, "release:check"));
|
|
350
|
+
return [...commands];
|
|
351
|
+
}
|
|
352
|
+
function resolveBaseRef(root, changedFrom, env) {
|
|
353
|
+
if (changedFrom)
|
|
354
|
+
return verifyRef(root, changedFrom);
|
|
355
|
+
if (env.CW_ONRAMP_BASE)
|
|
356
|
+
return verifyRef(root, env.CW_ONRAMP_BASE);
|
|
357
|
+
const baseBranch = env.GITHUB_BASE_REF ? `origin/${env.GITHUB_BASE_REF}` : "origin/main";
|
|
358
|
+
const mergeBase = gitOne(root, ["merge-base", "HEAD", baseBranch]);
|
|
359
|
+
if (mergeBase)
|
|
360
|
+
return mergeBase;
|
|
361
|
+
return verifyRef(root, "HEAD");
|
|
362
|
+
}
|
|
363
|
+
function verifyRef(root, ref) {
|
|
364
|
+
const resolved = gitOne(root, ["rev-parse", "--verify", `${ref}^{commit}`]);
|
|
365
|
+
if (!resolved)
|
|
366
|
+
throw new Error(`Unknown onramp base ref: ${ref}`);
|
|
367
|
+
return ref;
|
|
368
|
+
}
|
|
369
|
+
function gitRoot(cwd) {
|
|
370
|
+
return gitOne(node_path_1.default.resolve(cwd), ["rev-parse", "--show-toplevel"]) || node_path_1.default.resolve(cwd);
|
|
371
|
+
}
|
|
372
|
+
function gitLines(cwd, args) {
|
|
373
|
+
const result = (0, node_child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
374
|
+
if (result.status !== 0)
|
|
375
|
+
return [];
|
|
376
|
+
return String(result.stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
377
|
+
}
|
|
378
|
+
function gitOne(cwd, args) {
|
|
379
|
+
return gitLines(cwd, args)[0] || "";
|
|
380
|
+
}
|
|
381
|
+
function availableSmokeTests(cwd) {
|
|
382
|
+
const source = detectSourceCheckout(cwd);
|
|
383
|
+
const testDir = source ? node_path_1.default.join(source.packageDir, "test") : node_path_1.default.join(node_path_1.default.resolve(cwd), "test");
|
|
384
|
+
try {
|
|
385
|
+
return node_fs_1.default.readdirSync(testDir).filter((file) => file.endsWith("-smoke.js")).sort();
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function normalizeChangedPath(file) {
|
|
392
|
+
const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
393
|
+
if (/^(src|apps|scripts|test|docs|dist|manifest|ui|workflows)\//.test(normalized)) {
|
|
394
|
+
return `plugins/cool-workflow/${normalized}`;
|
|
395
|
+
}
|
|
396
|
+
return normalized;
|
|
397
|
+
}
|
|
398
|
+
function stripPluginPrefix(file) {
|
|
399
|
+
return file.startsWith("plugins/cool-workflow/") ? file.slice("plugins/cool-workflow/".length) : file;
|
|
400
|
+
}
|
|
401
|
+
function isRuntimeSource(file) {
|
|
402
|
+
return file.startsWith("plugins/cool-workflow/src/") && file.endsWith(".ts") && !file.startsWith("plugins/cool-workflow/src/types/");
|
|
403
|
+
}
|
|
404
|
+
function isSurfaceFile(file) {
|
|
405
|
+
const pluginPath = stripPluginPrefix(file);
|
|
406
|
+
return (pluginPath === "src/cli.ts" ||
|
|
407
|
+
pluginPath.startsWith("src/cli/") ||
|
|
408
|
+
pluginPath === "src/capability-registry.ts" ||
|
|
409
|
+
pluginPath === "src/mcp-server.ts" ||
|
|
410
|
+
pluginPath === "src/mcp-surface.ts" ||
|
|
411
|
+
pluginPath === "src/orchestrator.ts" ||
|
|
412
|
+
pluginPath === "scripts/parity-check.js");
|
|
413
|
+
}
|
|
414
|
+
function isDocFile(file) {
|
|
415
|
+
return (file === "README.md" ||
|
|
416
|
+
file === "CHANGELOG.md" ||
|
|
417
|
+
file === "RELEASE.md" ||
|
|
418
|
+
file.startsWith("docs/") ||
|
|
419
|
+
file === "plugins/cool-workflow/README.md" ||
|
|
420
|
+
file.startsWith("plugins/cool-workflow/docs/"));
|
|
421
|
+
}
|
package/dist/orchestrator.js
CHANGED
|
@@ -178,7 +178,7 @@ class CoolWorkflowRunner {
|
|
|
178
178
|
return {
|
|
179
179
|
valid: false,
|
|
180
180
|
appId: target,
|
|
181
|
-
appPath:
|
|
181
|
+
appPath: this.resolveFromBase(target),
|
|
182
182
|
issues
|
|
183
183
|
};
|
|
184
184
|
}
|
|
@@ -188,7 +188,7 @@ class CoolWorkflowRunner {
|
|
|
188
188
|
if (!id)
|
|
189
189
|
throw new Error("App id must include at least one letter or digit");
|
|
190
190
|
const title = String(options.title || titleize(id));
|
|
191
|
-
const destinationDir =
|
|
191
|
+
const destinationDir = this.resolveFromBase(String(options.directory || options.output || node_path_1.default.join(this.appsDir, id)));
|
|
192
192
|
const manifestPath = node_path_1.default.join(destinationDir, "app.json");
|
|
193
193
|
const entrypointPath = node_path_1.default.join(destinationDir, "workflow.js");
|
|
194
194
|
if (!options.force && (node_fs_1.default.existsSync(manifestPath) || node_fs_1.default.existsSync(entrypointPath))) {
|
|
@@ -205,8 +205,7 @@ class CoolWorkflowRunner {
|
|
|
205
205
|
}
|
|
206
206
|
packageApp(appId, options = {}) {
|
|
207
207
|
const record = this.loadWorkflowAppById(appId);
|
|
208
|
-
const destination =
|
|
209
|
-
node_path_1.default.join(process.cwd(), ".cw", "packages", `${record.app.id}-${record.app.version}.cwapp.json`)));
|
|
208
|
+
const destination = this.resolveFromBase(String(options.output || node_path_1.default.join(".cw", "packages", `${record.app.id}-${record.app.version}.cwapp.json`)));
|
|
210
209
|
node_fs_1.default.mkdirSync(node_path_1.default.dirname(destination), { recursive: true });
|
|
211
210
|
(0, state_1.writeJson)(destination, {
|
|
212
211
|
schemaVersion: 1,
|
|
@@ -221,7 +220,7 @@ class CoolWorkflowRunner {
|
|
|
221
220
|
if (!id)
|
|
222
221
|
throw new Error("Workflow id must include at least one letter or digit");
|
|
223
222
|
const title = String(options.title || titleize(id));
|
|
224
|
-
const destination =
|
|
223
|
+
const destination = this.resolveFromBase(String(options.output || node_path_1.default.join(this.workflowsDir, `${id}.workflow.js`)));
|
|
225
224
|
if (node_fs_1.default.existsSync(destination) && !options.force) {
|
|
226
225
|
throw new Error(`Refusing to overwrite existing workflow: ${destination}`);
|
|
227
226
|
}
|
|
@@ -248,7 +247,7 @@ class CoolWorkflowRunner {
|
|
|
248
247
|
return lifecycleOps.dispatch(this.loadRun(runId), options);
|
|
249
248
|
}
|
|
250
249
|
recordResult(runId, taskId, resultPath, options = {}) {
|
|
251
|
-
return lifecycleOps.recordResult(this.loadRun(runId), taskId, resultPath, options);
|
|
250
|
+
return lifecycleOps.recordResult(this.loadRun(runId), taskId, this.resolveFromBase(resultPath), options);
|
|
252
251
|
}
|
|
253
252
|
listWorkers(runId, options = {}) {
|
|
254
253
|
return (0, worker_isolation_1.listWorkerScopes)(this.loadRun(runId), {
|
|
@@ -272,13 +271,13 @@ class CoolWorkflowRunner {
|
|
|
272
271
|
return (0, worker_isolation_1.writeWorkerManifest)(run, worker);
|
|
273
272
|
}
|
|
274
273
|
recordWorkerOutput(runId, workerId, resultPath, options = {}) {
|
|
275
|
-
return lifecycleOps.recordWorkerOutput(this.loadRun(runId), workerId, resultPath, options);
|
|
274
|
+
return lifecycleOps.recordWorkerOutput(this.loadRun(runId), workerId, this.resolveFromBase(resultPath), options);
|
|
276
275
|
}
|
|
277
276
|
recordWorkerFailure(runId, workerId, message, options = {}) {
|
|
278
277
|
return lifecycleOps.recordWorkerFailure(this.loadRun(runId), workerId, message, options);
|
|
279
278
|
}
|
|
280
279
|
validateWorker(runId, workerId, targetPath) {
|
|
281
|
-
return (0, worker_isolation_1.validateWorkerBoundary)(this.loadRun(runId), workerId, targetPath ? { path: targetPath } : {});
|
|
280
|
+
return (0, worker_isolation_1.validateWorkerBoundary)(this.loadRun(runId), workerId, targetPath ? { path: this.resolveFromBase(targetPath) } : {});
|
|
282
281
|
}
|
|
283
282
|
// Audit domain — delegated to ./orchestrator/audit-operations (v0.1.40 P3
|
|
284
283
|
// router pattern). The runner stays the routing surface; the logic lives in the
|
|
@@ -314,13 +313,13 @@ class CoolWorkflowRunner {
|
|
|
314
313
|
return auditOps.recordAuditDecision(this.loadRun(runId), workerId, options);
|
|
315
314
|
}
|
|
316
315
|
listSandboxProfiles(options = {}) {
|
|
317
|
-
return (0, sandbox_profile_1.listBundledSandboxProfiles)((0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd ||
|
|
316
|
+
return (0, sandbox_profile_1.listBundledSandboxProfiles)((0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd || this.invocationCwd())));
|
|
318
317
|
}
|
|
319
318
|
showSandboxProfile(profileId, options = {}) {
|
|
320
|
-
return (0, sandbox_profile_1.showBundledSandboxProfile)(profileId, (0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd ||
|
|
319
|
+
return (0, sandbox_profile_1.showBundledSandboxProfile)(profileId, (0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd || this.invocationCwd())));
|
|
321
320
|
}
|
|
322
321
|
validateSandboxProfile(profileFile, options = {}) {
|
|
323
|
-
return (0, sandbox_profile_1.validateSandboxProfileFile)(profileFile, (0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd ||
|
|
322
|
+
return (0, sandbox_profile_1.validateSandboxProfileFile)(this.resolveFromBase(profileFile), (0, sandbox_profile_1.sandboxContextForValidation)(String(options.cwd || this.invocationCwd())));
|
|
324
323
|
}
|
|
325
324
|
listBackends(options = {}) {
|
|
326
325
|
void options;
|
|
@@ -331,7 +330,7 @@ class CoolWorkflowRunner {
|
|
|
331
330
|
return (0, execution_backend_1.backendShowPayload)(backendId);
|
|
332
331
|
}
|
|
333
332
|
probeBackend(backendId, options = {}) {
|
|
334
|
-
return (0, execution_backend_1.backendProbePayload)(backendId, { cwd: String(options.cwd ||
|
|
333
|
+
return (0, execution_backend_1.backendProbePayload)(backendId, { cwd: String(options.cwd || this.invocationCwd()) });
|
|
335
334
|
}
|
|
336
335
|
// Candidate domain — delegated to ./orchestrator/candidate-operations.
|
|
337
336
|
listCandidates(runId, options = {}) {
|
|
@@ -716,6 +715,12 @@ class CoolWorkflowRunner {
|
|
|
716
715
|
loadRun(runId) {
|
|
717
716
|
return (0, state_1.loadRunFromCwd)(runId, this.baseDir);
|
|
718
717
|
}
|
|
718
|
+
invocationCwd() {
|
|
719
|
+
return this.baseDir || process.cwd();
|
|
720
|
+
}
|
|
721
|
+
resolveFromBase(target) {
|
|
722
|
+
return node_path_1.default.resolve(this.invocationCwd(), target);
|
|
723
|
+
}
|
|
719
724
|
loadWorkflowAppById(appId) {
|
|
720
725
|
const record = this.loadWorkflowApps().find((candidate) => candidate.app.id === appId);
|
|
721
726
|
if (!record)
|
|
@@ -725,7 +730,7 @@ class CoolWorkflowRunner {
|
|
|
725
730
|
loadWorkflowAppTarget(target) {
|
|
726
731
|
if (!target)
|
|
727
732
|
throw new Error("Missing workflow app path or id");
|
|
728
|
-
const resolved =
|
|
733
|
+
const resolved = this.resolveFromBase(target);
|
|
729
734
|
if (node_fs_1.default.existsSync(resolved)) {
|
|
730
735
|
const stat = node_fs_1.default.statSync(resolved);
|
|
731
736
|
if (stat.isDirectory())
|
|
@@ -821,9 +826,9 @@ function formatHelp() {
|
|
|
821
826
|
"",
|
|
822
827
|
"Commands:",
|
|
823
828
|
" list",
|
|
824
|
-
" doctor [--json] (check
|
|
829
|
+
" doctor [--json] [--onramp] [--changed-from REF] (check setup and show the shortest safe next steps)",
|
|
825
830
|
" init <workflow-id> [--title TEXT] [--output PATH]",
|
|
826
|
-
" quickstart [app-id] [--repo PATH] [--question TEXT] [--agent-command CMD] [--once] [--preview]",
|
|
831
|
+
" quickstart [app-id] [--repo PATH] [--question TEXT] [--agent-command CMD] [--check] [--once] [--preview]",
|
|
827
832
|
" plan <workflow-id> [--repo PATH] [--question TEXT] [--invariant TEXT]",
|
|
828
833
|
" status <run-id> [--json|--format json]",
|
|
829
834
|
" next <run-id> [--limit N]",
|