cool-workflow 0.1.92 → 0.1.94
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 +104 -129
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/architecture-review-fast/workflow.js +15 -2
- 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 +47 -0
- package/dist/capability-registry.js +2 -0
- package/dist/cli/command-surface.js +165 -1352
- package/dist/cli/format.js +56 -0
- package/dist/cli/handlers/audit.js +82 -0
- package/dist/cli/handlers/blackboard.js +81 -0
- package/dist/cli/handlers/candidate.js +40 -0
- package/dist/cli/handlers/clones.js +34 -0
- package/dist/cli/handlers/collaboration.js +61 -0
- package/dist/cli/handlers/eval.js +40 -0
- package/dist/cli/handlers/maintenance.js +107 -0
- package/dist/cli/handlers/multi-agent.js +165 -0
- package/dist/cli/handlers/node.js +41 -0
- package/dist/cli/handlers/operational.js +155 -0
- package/dist/cli/handlers/operator.js +146 -0
- package/dist/cli/handlers/registry.js +68 -0
- package/dist/cli/handlers/run.js +153 -0
- package/dist/cli/handlers/scheduling.js +126 -0
- package/dist/cli/handlers/workbench.js +41 -0
- package/dist/cli/handlers/worker.js +45 -0
- package/dist/cli/io.js +27 -0
- package/dist/cli/run-summary.js +45 -0
- package/dist/commit.js +0 -5
- package/dist/execution-backend.js +0 -11
- package/dist/mcp/tool-call.js +2 -0
- package/dist/mcp/tool-definitions.js +8 -0
- package/dist/orchestrator/app-operations.js +205 -0
- package/dist/orchestrator.js +41 -153
- package/dist/state-explosion.js +0 -7
- package/dist/term.js +0 -18
- package/dist/validation.js +0 -21
- package/dist/version.js +1 -1
- package/docs/agent-delegation-drive.7.md +13 -7
- package/docs/cli-mcp-parity.7.md +19 -2
- package/docs/contract-migration-tooling.7.md +3 -1
- package/docs/control-plane-scheduling.7.md +3 -1
- package/docs/durable-state-and-locking.7.md +3 -1
- package/docs/evidence-adoption-reasoning-chain.7.md +3 -1
- package/docs/execution-backends.7.md +3 -1
- package/docs/mcp-app-surface.7.md +12 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +3 -1
- package/docs/multi-agent-eval-replay-harness.7.md +3 -1
- package/docs/multi-agent-operator-ux.7.md +3 -1
- package/docs/node-snapshot-diff-replay.7.md +3 -1
- package/docs/observability-cost-accounting.7.md +3 -1
- package/docs/project-index.md +16 -3
- package/docs/real-execution-backends.7.md +3 -1
- package/docs/release-and-migration.7.md +3 -1
- package/docs/release-tooling.7.md +3 -1
- package/docs/run-registry-control-plane.7.md +27 -3
- package/docs/run-retention-reclamation.7.md +3 -1
- package/docs/state-explosion-management.7.md +3 -1
- package/docs/team-collaboration.7.md +3 -1
- package/docs/web-desktop-workbench.7.md +3 -1
- package/manifest/plugin.manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/agents/builtin-templates.json +3 -2
- package/scripts/agents/claude-p-agent.js +6 -6
- package/scripts/agents/codex-agent.js +17 -3
- package/scripts/agents/deepseek-agent.js +23 -0
- package/scripts/agents/gemini-opencode-agent.js +25 -0
- package/scripts/agents/opencode-agent.js +57 -8
- package/scripts/architecture-review-fast.js +19 -5
- package/scripts/bump-version.js +16 -0
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
- package/scripts/parity-check.js +9 -1
- package/scripts/release-flow.js +35 -0
- package/scripts/vendor-preflight.js +127 -0
- package/scripts/version-sync-check.js +5 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleRun = handleRun;
|
|
4
|
+
const capability_core_1 = require("../../capability-core");
|
|
5
|
+
const run_registry_1 = require("../../run-registry");
|
|
6
|
+
const run_summary_1 = require("../run-summary");
|
|
7
|
+
const io_1 = require("../io");
|
|
8
|
+
/** `cw run <app> --drive [--once]` (Agent Delegation Drive) + the run-registry verbs
|
|
9
|
+
* (drive/search/list/show/resume/archive/rerun/export/import/verify-import/inspect-archive/restore). */
|
|
10
|
+
function handleRun(args, runner) {
|
|
11
|
+
// Agent Delegation Drive (v0.1.38): `cw run <app> --drive [--once]` drives a
|
|
12
|
+
// run end-to-end by delegating each worker to the agent backend. Distinct from
|
|
13
|
+
// the run-REGISTRY verbs below. `--preview` (or the `run drive <run-id>` form)
|
|
14
|
+
// is the read-only, deterministic next-step preview.
|
|
15
|
+
//
|
|
16
|
+
// A run-REGISTRY subcommand keyword (resume/show/...) must NOT be intercepted
|
|
17
|
+
// here just because it carries a --drive flag of its own — e.g.
|
|
18
|
+
// `run resume <id> --drive` is the resume verb's opt-in continuation, not
|
|
19
|
+
// `run <app=resume> --drive`. Fall through to the switch for those keywords.
|
|
20
|
+
const runRegistrySubcommand = new Set([
|
|
21
|
+
"drive", "search", "list", "show", "resume", "archive", "rerun", "export", "import", "verify-import", "inspect-archive", "restore"
|
|
22
|
+
]);
|
|
23
|
+
if (args.options.drive && !runRegistrySubcommand.has(String(args.positionals[0] || ""))) {
|
|
24
|
+
const target = args.positionals[0];
|
|
25
|
+
const runId = (0, io_1.optionalArg)(args.options.run) || (0, io_1.optionalArg)(args.options.runId);
|
|
26
|
+
if (args.options.preview) {
|
|
27
|
+
(0, io_1.printJson)((0, capability_core_1.runDrivePreview)(runner, { ...args.options, runId: runId || target }));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const driveArgs = { ...args.options };
|
|
31
|
+
if (runId)
|
|
32
|
+
driveArgs.runId = runId;
|
|
33
|
+
else
|
|
34
|
+
driveArgs.appId = target;
|
|
35
|
+
const dr = (0, capability_core_1.runDrive)(runner, driveArgs);
|
|
36
|
+
(0, io_1.printJson)(dr);
|
|
37
|
+
if (!(0, io_1.wantsJson)(args.options)) {
|
|
38
|
+
(0, run_summary_1.emitRunSummary)(runner, args.options, {
|
|
39
|
+
runId: dr.runId,
|
|
40
|
+
reportPath: dr.reportPath,
|
|
41
|
+
status: dr.status,
|
|
42
|
+
statePath: dr.statePath,
|
|
43
|
+
completedWorkers: dr.completedWorkers,
|
|
44
|
+
plannedWorkers: dr.plannedWorkers,
|
|
45
|
+
agentConfigured: dr.agentConfigured
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
|
|
51
|
+
const [subcommand, id] = args.positionals;
|
|
52
|
+
switch (subcommand) {
|
|
53
|
+
case "drive": {
|
|
54
|
+
// `run drive <run-id>` = read-only preview; `--step [--once]` = mutating drive.
|
|
55
|
+
if (args.options.step) {
|
|
56
|
+
const driveArgs = { ...args.options };
|
|
57
|
+
if (id)
|
|
58
|
+
driveArgs.runId = id;
|
|
59
|
+
const dr = (0, capability_core_1.runDrive)(runner, driveArgs);
|
|
60
|
+
(0, io_1.printJson)(dr);
|
|
61
|
+
if (!(0, io_1.wantsJson)(args.options)) {
|
|
62
|
+
(0, run_summary_1.emitRunSummary)(runner, args.options, {
|
|
63
|
+
runId: dr.runId,
|
|
64
|
+
reportPath: dr.reportPath,
|
|
65
|
+
status: dr.status,
|
|
66
|
+
statePath: dr.statePath,
|
|
67
|
+
completedWorkers: dr.completedWorkers,
|
|
68
|
+
plannedWorkers: dr.plannedWorkers,
|
|
69
|
+
agentConfigured: dr.agentConfigured
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
(0, io_1.printJson)((0, capability_core_1.runDrivePreview)(runner, { ...args.options, runId: (0, io_1.required)(id, "run id") }));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
case "search": {
|
|
78
|
+
const result = (0, capability_core_1.runSearch)(registry, args.options);
|
|
79
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
80
|
+
(0, io_1.printJson)(result);
|
|
81
|
+
else
|
|
82
|
+
process.stdout.write(`${(0, run_registry_1.formatRunSearch)(result)}\n`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
case "list": {
|
|
86
|
+
const result = (0, capability_core_1.runList)(registry, args.options);
|
|
87
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
88
|
+
(0, io_1.printJson)(result);
|
|
89
|
+
else
|
|
90
|
+
process.stdout.write(`${(0, run_registry_1.formatRunSearch)(result)}\n`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
case "show": {
|
|
94
|
+
const result = (0, capability_core_1.runShow)(registry, (0, io_1.required)(id, "run id"), args.options);
|
|
95
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
96
|
+
(0, io_1.printJson)(result);
|
|
97
|
+
else
|
|
98
|
+
process.stdout.write(`${(0, run_registry_1.formatRunShow)(result)}\n`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
case "resume": {
|
|
102
|
+
const result = (0, capability_core_1.runResume)(registry, runner, (0, io_1.required)(id, "run id"), args.options);
|
|
103
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
104
|
+
(0, io_1.printJson)(result);
|
|
105
|
+
else
|
|
106
|
+
process.stdout.write(`${(0, run_registry_1.formatResume)(result)}\n`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
case "archive":
|
|
110
|
+
(0, io_1.printJson)((0, capability_core_1.runArchive)(registry, id, args.options));
|
|
111
|
+
return;
|
|
112
|
+
case "rerun":
|
|
113
|
+
(0, io_1.printJson)((0, capability_core_1.runRerun)(registry, (0, io_1.required)(id, "run id"), args.options));
|
|
114
|
+
return;
|
|
115
|
+
case "export":
|
|
116
|
+
(0, io_1.printJson)((0, capability_core_1.runExportArchive)(runner, (0, io_1.required)(id || (0, io_1.optionalArg)(args.options.runId || args.options.run), "run id"), args.options));
|
|
117
|
+
return;
|
|
118
|
+
case "import":
|
|
119
|
+
(0, io_1.printJson)((0, capability_core_1.runImportArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path }));
|
|
120
|
+
return;
|
|
121
|
+
case "verify-import": {
|
|
122
|
+
const result = (0, capability_core_1.runVerifyImport)(runner, (0, io_1.required)(id || (0, io_1.optionalArg)(args.options.runId || args.options.run), "run id"), args.options);
|
|
123
|
+
(0, io_1.printJson)(result);
|
|
124
|
+
// Fail-closed ONLY behind --strict, so the default exit stays 0
|
|
125
|
+
// (byte-identical). With --strict, any failed restore check — including
|
|
126
|
+
// the new trust-audit row — exits 1 for `verify-import && restore`.
|
|
127
|
+
if (Boolean(args.options.strict) && !result.ok)
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
case "inspect-archive": {
|
|
132
|
+
const result = (0, capability_core_1.runInspectArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path });
|
|
133
|
+
(0, io_1.printJson)(result);
|
|
134
|
+
// Read-only diagnostic: exit 1 when the archive fails any integrity check,
|
|
135
|
+
// so `cw run inspect-archive <path> && restore` stops on a bad archive.
|
|
136
|
+
if (!result.ok)
|
|
137
|
+
process.exitCode = 1;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
case "restore": {
|
|
141
|
+
const result = (0, capability_core_1.runRestoreArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path });
|
|
142
|
+
(0, io_1.printJson)(result);
|
|
143
|
+
// Fail-closed: exit 1 when inspect OR verify failed, so a tampered or
|
|
144
|
+
// unverifiable archive never reports a made-up success (mirrors the
|
|
145
|
+
// inspect-archive exit-1 pattern).
|
|
146
|
+
if (!result.ok)
|
|
147
|
+
process.exitCode = 1;
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
default:
|
|
151
|
+
throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import|inspect-archive|restore [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--incremental] [--repo R --question Q]");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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.handleSchedule = handleSchedule;
|
|
7
|
+
exports.handleRoutine = handleRoutine;
|
|
8
|
+
exports.handleSched = handleSched;
|
|
9
|
+
// `cw schedule` / `cw routine` / `cw sched` handlers — the scheduling command
|
|
10
|
+
// family, carved out of the command-surface god-dispatch. Three sibling verbs:
|
|
11
|
+
// schedule — desktop scheduler (create/list/.../daemon) over the Scheduler
|
|
12
|
+
// routine — routine triggers (create/list/delete/fire/events) over the bridge
|
|
13
|
+
// sched — durable run-queue scheduling (plan/lease/release/.../policy)
|
|
14
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
15
|
+
const daemon_1 = require("../../daemon");
|
|
16
|
+
const capability_core_1 = require("../../capability-core");
|
|
17
|
+
const io_1 = require("../io");
|
|
18
|
+
/** `cw schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon`. */
|
|
19
|
+
async function handleSchedule(args, scheduler) {
|
|
20
|
+
const [subcommand, id] = args.positionals;
|
|
21
|
+
switch (subcommand) {
|
|
22
|
+
case "create":
|
|
23
|
+
(0, io_1.printJson)(scheduler.create(args.options));
|
|
24
|
+
return;
|
|
25
|
+
case "list":
|
|
26
|
+
(0, io_1.printJson)(scheduler.list(args.options.status ? String(args.options.status) : undefined));
|
|
27
|
+
return;
|
|
28
|
+
case "delete":
|
|
29
|
+
(0, io_1.printJson)(scheduler.delete((0, io_1.required)(id, "schedule id")));
|
|
30
|
+
return;
|
|
31
|
+
case "due":
|
|
32
|
+
(0, io_1.printJson)(scheduler.due());
|
|
33
|
+
return;
|
|
34
|
+
case "complete":
|
|
35
|
+
(0, io_1.printJson)(scheduler.complete((0, io_1.required)(id, "schedule id"), args.options));
|
|
36
|
+
return;
|
|
37
|
+
case "pause":
|
|
38
|
+
(0, io_1.printJson)(scheduler.pause((0, io_1.required)(id, "schedule id")));
|
|
39
|
+
return;
|
|
40
|
+
case "resume":
|
|
41
|
+
(0, io_1.printJson)(scheduler.resume((0, io_1.required)(id, "schedule id")));
|
|
42
|
+
return;
|
|
43
|
+
case "run-now":
|
|
44
|
+
(0, io_1.printJson)(scheduler.runNow((0, io_1.required)(id, "schedule id")));
|
|
45
|
+
return;
|
|
46
|
+
case "history":
|
|
47
|
+
(0, io_1.printJson)(scheduler.history(id));
|
|
48
|
+
return;
|
|
49
|
+
case "daemon": {
|
|
50
|
+
const daemon = new daemon_1.DesktopSchedulerDaemon({
|
|
51
|
+
cwd: String(args.options.cwd || process.cwd()),
|
|
52
|
+
intervalSeconds: Number(args.options.intervalSeconds || args.options.interval || 60)
|
|
53
|
+
});
|
|
54
|
+
if (args.options.once) {
|
|
55
|
+
(0, io_1.printJson)(daemon.tick());
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
await daemon.run();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
throw new Error("Usage: cw.js schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** `cw routine create|list|delete|fire|events`. */
|
|
66
|
+
function handleRoutine(args, triggers) {
|
|
67
|
+
const [subcommand, idOrKind, payloadPath] = args.positionals;
|
|
68
|
+
switch (subcommand) {
|
|
69
|
+
case "create":
|
|
70
|
+
(0, io_1.printJson)(triggers.create(args.options));
|
|
71
|
+
return;
|
|
72
|
+
case "list":
|
|
73
|
+
(0, io_1.printJson)(triggers.list(args.options.kind ? String(args.options.kind) : undefined));
|
|
74
|
+
return;
|
|
75
|
+
case "delete":
|
|
76
|
+
(0, io_1.printJson)(triggers.delete((0, io_1.required)(idOrKind, "trigger id")));
|
|
77
|
+
return;
|
|
78
|
+
case "fire": {
|
|
79
|
+
const kind = (0, io_1.required)(idOrKind, "trigger kind");
|
|
80
|
+
const payload = payloadPath ? JSON.parse(node_fs_1.default.readFileSync(payloadPath, "utf8")) : args.options;
|
|
81
|
+
(0, io_1.printJson)(triggers.fire(kind, payload));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
case "events":
|
|
85
|
+
(0, io_1.printJson)(triggers.events(idOrKind));
|
|
86
|
+
return;
|
|
87
|
+
default:
|
|
88
|
+
throw new Error("Usage: cw.js routine create|list|delete|fire|events");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** `cw sched plan|lease|release|complete|reclaim|reset|policy [show|set]` — durable run-queue. */
|
|
92
|
+
function handleSched(args, runner) {
|
|
93
|
+
const registry = (0, capability_core_1.runRegistryFor)(args.options, runner);
|
|
94
|
+
const [subcommand, idArg] = args.positionals;
|
|
95
|
+
switch (subcommand) {
|
|
96
|
+
case "plan":
|
|
97
|
+
(0, io_1.printJson)((0, capability_core_1.schedPlan)(registry, args.options));
|
|
98
|
+
return;
|
|
99
|
+
case "lease":
|
|
100
|
+
(0, io_1.printJson)((0, capability_core_1.schedLease)(registry, args.options));
|
|
101
|
+
return;
|
|
102
|
+
case "release":
|
|
103
|
+
(0, io_1.printJson)((0, capability_core_1.schedRelease)(registry, { ...args.options, leaseId: args.options.leaseId || idArg }));
|
|
104
|
+
return;
|
|
105
|
+
case "complete":
|
|
106
|
+
(0, io_1.printJson)((0, capability_core_1.schedComplete)(registry, { ...args.options, leaseId: args.options.leaseId || idArg }));
|
|
107
|
+
return;
|
|
108
|
+
case "reclaim":
|
|
109
|
+
(0, io_1.printJson)((0, capability_core_1.schedReclaim)(registry, args.options));
|
|
110
|
+
return;
|
|
111
|
+
case "reset":
|
|
112
|
+
(0, io_1.printJson)((0, capability_core_1.schedReset)(registry, { ...args.options, id: args.options.id || idArg }));
|
|
113
|
+
return;
|
|
114
|
+
case "policy": {
|
|
115
|
+
const [, action] = args.positionals;
|
|
116
|
+
if (action === "set") {
|
|
117
|
+
(0, io_1.printJson)((0, capability_core_1.schedPolicySet)(registry, args.options));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
(0, io_1.printJson)((0, capability_core_1.schedPolicyShow)(registry));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
default:
|
|
124
|
+
throw new Error("Usage: cw.js sched plan|lease|release|complete|reclaim|reset|policy [show|set] [id] [--maxConcurrent N --maxAttempts N ...]");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleWorkbench = handleWorkbench;
|
|
4
|
+
const workbench_1 = require("../../workbench");
|
|
5
|
+
const workbench_host_1 = require("../../workbench-host");
|
|
6
|
+
const format_1 = require("../format");
|
|
7
|
+
const io_1 = require("../io");
|
|
8
|
+
/** `cw workbench serve [--port N] [--once] | view <run-id> [--json]` — the optional
|
|
9
|
+
* read-only, localhost-only workbench. Behaviour-identical to the former inline case. */
|
|
10
|
+
async function handleWorkbench(args, runner) {
|
|
11
|
+
const [subcommand, runId] = args.positionals;
|
|
12
|
+
switch (subcommand) {
|
|
13
|
+
case "view": {
|
|
14
|
+
// Read-only five-panel view of one run. Same core entry as cw_workbench_view.
|
|
15
|
+
const view = (0, workbench_1.buildWorkbenchRunView)(runner, (0, io_1.required)(runId, "run id"));
|
|
16
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
17
|
+
(0, io_1.printJson)(view);
|
|
18
|
+
else
|
|
19
|
+
process.stdout.write(`${(0, format_1.formatWorkbenchView)(view)}\n`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
case "serve": {
|
|
23
|
+
// The OPTIONAL localhost host. `--once`/`--json` emit the descriptor only
|
|
24
|
+
// (no server); the default starts the read-only, localhost-only host.
|
|
25
|
+
if (args.options.once || (0, io_1.wantsJson)(args.options)) {
|
|
26
|
+
(0, io_1.printJson)((0, workbench_1.buildWorkbenchServeDescriptor)(runner, { ...args.options, once: true }));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const host = new workbench_host_1.WorkbenchHost({
|
|
30
|
+
runner,
|
|
31
|
+
cwd: String(args.options.cwd || process.cwd()),
|
|
32
|
+
port: Number(args.options.port) || undefined,
|
|
33
|
+
scope: args.options.scope === "repo" ? "repo" : "home"
|
|
34
|
+
});
|
|
35
|
+
await host.run();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
default:
|
|
39
|
+
throw new Error("Usage: cw.js workbench serve [--port N] [--once] | view <run-id> [--json]");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleWorker = handleWorker;
|
|
4
|
+
const operator_ux_1 = require("../../operator-ux");
|
|
5
|
+
const io_1 = require("../io");
|
|
6
|
+
/** `cw worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]`. */
|
|
7
|
+
function handleWorker(args, runner) {
|
|
8
|
+
const [subcommand, runId, workerId, resultPath] = args.positionals;
|
|
9
|
+
switch (subcommand) {
|
|
10
|
+
case "list":
|
|
11
|
+
(0, io_1.printJson)(runner.listWorkers((0, io_1.required)(runId, "run id"), args.options));
|
|
12
|
+
return;
|
|
13
|
+
case "summary": {
|
|
14
|
+
const summary = runner.summarizeWorkerRecords((0, io_1.required)(runId, "run id"));
|
|
15
|
+
if ((0, io_1.wantsJson)(args.options))
|
|
16
|
+
(0, io_1.printJson)(summary);
|
|
17
|
+
else
|
|
18
|
+
process.stdout.write(`${(0, operator_ux_1.formatWorkerSummary)(summary)}\n`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
case "show":
|
|
22
|
+
(0, io_1.printJson)(runner.showWorker((0, io_1.required)(runId, "run id"), (0, io_1.required)(workerId, "worker id")));
|
|
23
|
+
return;
|
|
24
|
+
case "manifest":
|
|
25
|
+
(0, io_1.printJson)(runner.showWorkerManifest((0, io_1.required)(runId, "run id"), (0, io_1.required)(workerId, "worker id")));
|
|
26
|
+
return;
|
|
27
|
+
case "output":
|
|
28
|
+
(0, io_1.printJson)(runner.recordWorkerOutput((0, io_1.required)(runId, "run id"), (0, io_1.required)(workerId, "worker id"), (0, io_1.required)(resultPath, "result file"), args.options));
|
|
29
|
+
return;
|
|
30
|
+
case "fail":
|
|
31
|
+
(0, io_1.printJson)(runner.recordWorkerFailure((0, io_1.required)(runId, "run id"), (0, io_1.required)(workerId, "worker id"), String(args.options.message || (0, io_1.required)(resultPath, "failure message")), args.options));
|
|
32
|
+
return;
|
|
33
|
+
case "validate": {
|
|
34
|
+
// Non-null = a boundary violation: a validate verb must report an invalid
|
|
35
|
+
// verdict through its exit code, not just print it and exit 0.
|
|
36
|
+
const violation = runner.validateWorker((0, io_1.required)(runId, "run id"), (0, io_1.required)(workerId, "worker id"), resultPath);
|
|
37
|
+
(0, io_1.printJson)(violation);
|
|
38
|
+
if (violation)
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
throw new Error("Usage: cw.js worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]");
|
|
44
|
+
}
|
|
45
|
+
}
|
package/dist/cli/io.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared CLI input/output helpers, extracted from command-surface.ts so the
|
|
3
|
+
// dispatcher and per-command handler modules import ONE copy instead of carrying
|
|
4
|
+
// these in the god-object. Pure + zero-dep: arg coercion + JSON stdout.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.required = required;
|
|
7
|
+
exports.optionalArg = optionalArg;
|
|
8
|
+
exports.printJson = printJson;
|
|
9
|
+
exports.wantsJson = wantsJson;
|
|
10
|
+
/** Require a positional/option value or fail with a copy-pasteable recovery tip. */
|
|
11
|
+
function required(value, label) {
|
|
12
|
+
if (!value)
|
|
13
|
+
throw new Error(`Missing ${label}.\n Tip: find run ids with "cw run list" or create one with "cw quickstart"`);
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
/** Normalize an optional CLI arg to a trimmed non-empty string, else undefined. */
|
|
17
|
+
function optionalArg(value) {
|
|
18
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
19
|
+
}
|
|
20
|
+
/** Machine payload to stdout (stdout = data; never colored, never chrome). */
|
|
21
|
+
function printJson(value) {
|
|
22
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
23
|
+
}
|
|
24
|
+
/** True when the caller asked for JSON output (`--json` or `--format json`). */
|
|
25
|
+
function wantsJson(options) {
|
|
26
|
+
return Boolean(options.json || options.format === "json");
|
|
27
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
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.emitRunSummary = emitRunSummary;
|
|
7
|
+
// Shared calm end-of-run summary helper, lifted out of command-surface.ts so the
|
|
8
|
+
// `audit-run`/`quickstart` path (still in the dispatcher) AND the carved `run`
|
|
9
|
+
// drive paths (src/cli/handlers/run.ts) emit ONE identical summary — no copy.
|
|
10
|
+
// Stderr/human-side ONLY: stdout (the `--json` payload) stays byte-exact.
|
|
11
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const capability_core_1 = require("../capability-core");
|
|
14
|
+
const reporter_1 = require("../reporter");
|
|
15
|
+
/** Emit the calm end-of-run summary (stderr, TTY-gated inside the reporter): the COMPACT findings
|
|
16
|
+
* table re-parsed from each completed worker's `cw:result`, the report path, where the per-worker
|
|
17
|
+
* transcripts live, and — under `--full` — the report inline. Stderr/human-side ONLY: stdout (the
|
|
18
|
+
* `--json` payload printed just before this) stays byte-exact. Shared by the quickstart and the
|
|
19
|
+
* two `run --drive` paths so all three render an identical summary. */
|
|
20
|
+
function emitRunSummary(runner, options, fields) {
|
|
21
|
+
// Anchor run reads to the run's OWN repo (a drive/quickstart may run cross-directory): the run
|
|
22
|
+
// dir is <repo>/.cw/runs/<id>/, holding each worker's transcript.md next to its result.md.
|
|
23
|
+
const runDir = typeof fields.statePath === "string" ? node_path_1.default.dirname(fields.statePath) : undefined;
|
|
24
|
+
const baseDir = runDir ? node_path_1.default.resolve(runDir, "..", "..", "..") : undefined;
|
|
25
|
+
const findings = (0, capability_core_1.collectRunFindings)(runner, fields.runId, baseDir);
|
|
26
|
+
// --full ALSO prints the report inline at run end (the compact table stays the default summary).
|
|
27
|
+
let fullReport;
|
|
28
|
+
if (options.full && fields.reportPath && node_fs_1.default.existsSync(fields.reportPath)) {
|
|
29
|
+
try {
|
|
30
|
+
fullReport = node_fs_1.default.readFileSync(fields.reportPath, "utf8");
|
|
31
|
+
}
|
|
32
|
+
catch { /* best-effort inline */ }
|
|
33
|
+
}
|
|
34
|
+
reporter_1.reporter.runSummary({
|
|
35
|
+
runId: fields.runId,
|
|
36
|
+
reportPath: fields.reportPath,
|
|
37
|
+
status: fields.status,
|
|
38
|
+
completedWorkers: fields.completedWorkers,
|
|
39
|
+
plannedWorkers: fields.plannedWorkers,
|
|
40
|
+
agentConfigured: fields.agentConfigured,
|
|
41
|
+
findings,
|
|
42
|
+
runDir,
|
|
43
|
+
fullReport
|
|
44
|
+
});
|
|
45
|
+
}
|
package/dist/commit.js
CHANGED
|
@@ -80,11 +80,6 @@ function commitState(run, input) {
|
|
|
80
80
|
candidateId: gate.candidateId,
|
|
81
81
|
selectionId: gate.selectionId,
|
|
82
82
|
evidence,
|
|
83
|
-
// Partial commit (v0.1.59): operator commits only specified tasks.
|
|
84
|
-
// Failed/pending tasks remain active for later retry. The verifier gate
|
|
85
|
-
// still applies per-task; partial is about scope, not about skipping gates.
|
|
86
|
-
partial: Array.isArray(options.partialTaskIds) && options.partialTaskIds.length > 0 || undefined,
|
|
87
|
-
partialTaskIds: options.partialTaskIds?.length ? options.partialTaskIds : undefined,
|
|
88
83
|
acceptanceRationale: gate.rationale
|
|
89
84
|
? {
|
|
90
85
|
...gate.rationale,
|
|
@@ -34,18 +34,15 @@ exports.backendIds = backendIds;
|
|
|
34
34
|
exports.isBackendId = isBackendId;
|
|
35
35
|
exports.getBackendDescriptor = getBackendDescriptor;
|
|
36
36
|
exports.resolveBackendSelection = resolveBackendSelection;
|
|
37
|
-
exports.backendSelectionFrom = backendSelectionFrom;
|
|
38
37
|
exports.requiredSandboxDimensions = requiredSandboxDimensions;
|
|
39
38
|
exports.attestSandbox = attestSandbox;
|
|
40
39
|
exports.probeBackend = probeBackend;
|
|
41
40
|
exports.runBackend = runBackend;
|
|
42
41
|
exports.createExecutionBackend = createExecutionBackend;
|
|
43
|
-
exports.listExecutionBackends = listExecutionBackends;
|
|
44
42
|
exports.backendListPayload = backendListPayload;
|
|
45
43
|
exports.backendShowPayload = backendShowPayload;
|
|
46
44
|
exports.backendProbePayload = backendProbePayload;
|
|
47
45
|
exports.buildChildEnv = buildChildEnv;
|
|
48
|
-
exports.clearProbeCache = clearProbeCache;
|
|
49
46
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
50
47
|
const node_path_1 = __importDefault(require("node:path"));
|
|
51
48
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -265,10 +262,6 @@ function resolveBackendSelection(requested, env = process.env) {
|
|
|
265
262
|
}
|
|
266
263
|
return { backendId: exports.DEFAULT_BACKEND_ID, source: "default" };
|
|
267
264
|
}
|
|
268
|
-
function backendSelectionFrom(args, env = process.env) {
|
|
269
|
-
const requested = (0, util_1.firstString)(args.backend, args.backendId, args.executionBackend);
|
|
270
|
-
return resolveBackendSelection(requested, env);
|
|
271
|
-
}
|
|
272
265
|
// ---------------------------------------------------------------------------
|
|
273
266
|
// Sandbox dimension mapping + attestation. The sandbox profile is the contract.
|
|
274
267
|
// ---------------------------------------------------------------------------
|
|
@@ -852,9 +845,6 @@ function createExecutionBackend(id) {
|
|
|
852
845
|
run: (request) => runBackend({ ...request, backendId: id })
|
|
853
846
|
};
|
|
854
847
|
}
|
|
855
|
-
function listExecutionBackends() {
|
|
856
|
-
return backendIds().map(createExecutionBackend);
|
|
857
|
-
}
|
|
858
848
|
// ---- inspection payloads (shared by CLI + MCP via the orchestrator) --------
|
|
859
849
|
function backendListPayload() {
|
|
860
850
|
return { schemaVersion: 1, default: exports.DEFAULT_BACKEND_ID, backends: listBackendDescriptors() };
|
|
@@ -916,4 +906,3 @@ function cachedProbeBackend(id, context) {
|
|
|
916
906
|
_probeCache.set(key, { result, at: Date.now() });
|
|
917
907
|
return result;
|
|
918
908
|
}
|
|
919
|
-
function clearProbeCache() { _probeCache.clear(); }
|
package/dist/mcp/tool-call.js
CHANGED
|
@@ -364,6 +364,8 @@ function callTool(name, args) {
|
|
|
364
364
|
return (0, capability_core_1.runVerifyImport)(runner, String(args.runId || ""), args);
|
|
365
365
|
case "cw_run_inspect_archive":
|
|
366
366
|
return (0, capability_core_1.runInspectArchive)(runner, args);
|
|
367
|
+
case "cw_run_restore":
|
|
368
|
+
return (0, capability_core_1.runRestoreArchive)(runner, args);
|
|
367
369
|
case "cw_report_verify_bundle":
|
|
368
370
|
return (0, capability_core_1.runVerifyReportBundle)(runner, args);
|
|
369
371
|
case "cw_report_bundle":
|
|
@@ -837,6 +837,14 @@ function toolDefinitions() {
|
|
|
837
837
|
file: stringSchema("Alias for archive"),
|
|
838
838
|
cwd: stringSchema("Invocation workspace")
|
|
839
839
|
}),
|
|
840
|
+
capabilityTool("run.restore", "Fail-closed restore of a portable run archive in one step: integrity-inspect the bundle first (writes nothing), import it, then verify the imported run. Reports ok:true only when both inspect and verify pass; refuses (ok:false, exit 1) a tampered or unverifiable bundle, importing nothing. Peer of `cw run restore`.", {
|
|
841
|
+
archive: stringSchema("Archive path"),
|
|
842
|
+
path: stringSchema("Alias for archive"),
|
|
843
|
+
file: stringSchema("Alias for archive"),
|
|
844
|
+
target: stringSchema("Restore target repo directory"),
|
|
845
|
+
repo: stringSchema("Alias for target"),
|
|
846
|
+
cwd: stringSchema("Invocation workspace")
|
|
847
|
+
}),
|
|
840
848
|
capabilityTool("report.verify-bundle", "Offline, self-contained verify of a portable run bundle: proves the archive bytes, the telemetry hash chain, the trust-audit chain, and (with the bundle's embedded public key) the ed25519 signatures — no source repo, no pre-existing .cw tree, no out-of-band key. Restores into a throwaway tmpdir and writes nothing. A forged or edited bundle fails it. Peer of `cw report verify-bundle`.", {
|
|
841
849
|
archive: stringSchema("Bundle (.cwrun.json) path"),
|
|
842
850
|
path: stringSchema("Alias for archive"),
|