cool-workflow 0.2.1 → 0.2.3
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/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- 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/cli/dispatch.js +29 -91
- package/dist/cli/entry.js +41 -1
- package/dist/cli/io.js +6 -2
- package/dist/cli/parseargv.js +6 -2
- package/dist/core/capability-data.js +271 -0
- package/dist/core/capability-table.js +16 -3504
- package/dist/core/format/completion.js +68 -0
- package/dist/core/format/help.js +50 -8
- package/dist/core/format/safe-json.js +73 -0
- package/dist/core/format/state-explosion-text.js +1 -1
- package/dist/core/multi-agent/candidate-scoring.js +5 -1
- package/dist/core/multi-agent/collaboration.js +6 -5
- package/dist/core/multi-agent/coordinator.js +9 -8
- package/dist/core/multi-agent/runtime.js +4 -4
- package/dist/core/multi-agent/topology.js +3 -3
- package/dist/core/pipeline/commit-gate.js +2 -1
- package/dist/core/pipeline/dispatch.js +18 -4
- package/dist/core/pipeline/drive-decide.js +2 -1
- package/dist/core/state/migrations.js +16 -1
- package/dist/core/state/state-explosion/digest.js +16 -15
- package/dist/core/state/state-explosion/graph.js +26 -19
- package/dist/core/state/state-explosion/helpers.js +2 -1
- package/dist/core/state/state-explosion/report.js +6 -6
- package/dist/core/trust/ledger.js +2 -1
- package/dist/core/types/execution-backend.js +18 -0
- package/dist/core/types/observability.js +7 -0
- package/dist/core/util/collate.js +23 -0
- package/dist/core/util/numeric-flag.js +40 -0
- package/dist/core/version.js +1 -1
- package/dist/mcp/server.js +99 -11
- package/dist/shell/audit-cli.js +99 -23
- package/dist/shell/commit-summary.js +2 -1
- package/dist/shell/coordinator-io.js +73 -13
- package/dist/shell/dispatch.js +1 -1
- package/dist/shell/doctor.js +80 -1
- package/dist/shell/drive.js +269 -59
- package/dist/shell/eval-text.js +2 -2
- package/dist/shell/evidence-reasoning.js +8 -7
- package/dist/shell/execution-backend/agent.js +20 -1
- package/dist/shell/execution-backend/container.js +4 -1
- package/dist/shell/execution-backend/local.js +4 -1
- package/dist/shell/execution-backend/registry.js +2 -1
- package/dist/shell/execution-backend/types.js +0 -9
- package/dist/shell/feedback-cli.js +6 -6
- package/dist/shell/fs-atomic.js +232 -30
- package/dist/shell/man-cli.js +6 -0
- package/dist/shell/metrics-cli.js +2 -1
- package/dist/shell/multi-agent-cli.js +367 -323
- package/dist/shell/multi-agent-host.js +9 -9
- package/dist/shell/multi-agent-operator-ux.js +82 -39
- package/dist/shell/node-store.js +10 -4
- package/dist/shell/observability.js +13 -12
- package/dist/shell/onramp.js +17 -1
- package/dist/shell/operator-ux-text.js +24 -23
- package/dist/shell/operator-ux.js +22 -20
- package/dist/shell/orchestrator.js +49 -38
- package/dist/shell/pipeline-cli.js +168 -111
- package/dist/shell/reclamation-io.js +16 -5
- package/dist/shell/registry-cli.js +19 -17
- package/dist/shell/remote-source.js +13 -8
- package/dist/shell/report-cli.js +45 -0
- package/dist/shell/report.js +4 -2
- package/dist/shell/run-registry-io.js +77 -19
- package/dist/shell/run-store.js +91 -2
- package/dist/shell/scheduling-io.js +12 -13
- package/dist/shell/state-cli.js +2 -7
- package/dist/shell/state-explosion-cli.js +19 -10
- package/dist/shell/topology-io.js +38 -6
- package/dist/shell/trust-audit.js +264 -23
- package/dist/shell/trust-policy-io.js +1 -1
- package/dist/shell/worker-cli.js +41 -29
- package/dist/shell/worker-isolation.js +34 -9
- package/dist/shell/workflow-app-loader.js +3 -2
- package/dist/wiring/capability-table/basics.js +91 -0
- package/dist/wiring/capability-table/exec-backend.js +171 -0
- package/dist/wiring/capability-table/index.js +42 -0
- package/dist/wiring/capability-table/multi-agent.js +630 -0
- package/dist/wiring/capability-table/parity.js +467 -0
- package/dist/wiring/capability-table/pipeline.js +292 -0
- package/dist/wiring/capability-table/registry-core.js +208 -0
- package/dist/wiring/capability-table/reporting.js +435 -0
- package/dist/wiring/capability-table/scheduling-registry.js +592 -0
- package/dist/wiring/capability-table/state.js +181 -0
- package/dist/wiring/capability-table/trust-ledger.js +158 -0
- package/dist/wiring/capability-table/workflow-apps.js +381 -0
- package/docs/agent-delegation-drive.7.md +4 -0
- package/docs/candidate-scoring.7.md +1 -1
- package/docs/canonical-workflow-apps.7.md +7 -7
- package/docs/cli-mcp-parity.7.md +13 -3
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- package/docs/coordinator-blackboard.7.md +17 -17
- package/docs/dogfood-one-real-repo.7.md +11 -11
- package/docs/durable-state-and-locking.7.md +24 -0
- package/docs/end-to-end-golden-path.7.md +14 -14
- package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
- package/docs/execution-backends.7.md +4 -0
- package/docs/getting-started.md +37 -37
- package/docs/index.md +1 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +21 -17
- package/docs/multi-agent-eval-replay-harness.7.md +17 -13
- package/docs/multi-agent-operator-ux.7.md +23 -19
- package/docs/multi-agent-runtime-core.7.md +22 -22
- package/docs/multi-agent-topologies.7.md +6 -6
- package/docs/multi-agent-trust-policy-audit.7.md +11 -11
- package/docs/node-snapshot-diff-replay.7.md +4 -0
- package/docs/observability-cost-accounting.7.md +4 -0
- package/docs/operator-ux.7.md +34 -34
- package/docs/pipeline-runner.7.md +4 -4
- package/docs/project-index.md +48 -5
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +5 -1
- package/docs/release-tooling.7.md +4 -0
- package/docs/routines.md +4 -4
- package/docs/run-registry-control-plane.7.md +23 -19
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/scheduled-tasks.md +14 -14
- package/docs/security-trust-hardening.7.md +43 -13
- package/docs/state-explosion-management.7.md +14 -10
- package/docs/team-collaboration.7.md +4 -0
- package/docs/trust-audit-anchor.7.md +71 -0
- package/docs/unix-principles.md +3 -1
- package/docs/verifier-gated-commit.7.md +1 -1
- package/docs/web-desktop-workbench.7.md +4 -0
- package/docs/workflow-app-framework.7.md +13 -13
- package/manifest/plugin.manifest.json +1 -1
- package/package.json +4 -2
- package/scripts/agents/claude-p-agent.js +2 -2
- package/scripts/block-unapproved-tag.sh +23 -2
- package/scripts/bump-version.js +24 -2
- package/scripts/canonical-apps.js +4 -4
- package/scripts/children/batch-delegate-child.js +52 -2
- package/scripts/dogfood-release.js +1 -1
- package/scripts/fake-date-for-reproduction.js +44 -0
- package/scripts/golden-path.js +4 -4
- package/scripts/purity-baseline.json +71 -0
- package/scripts/purity-gate.js +239 -0
- package/scripts/release-check.js +8 -1
- package/scripts/release-flow.js +57 -1
- package/scripts/verdict-keygen.js +83 -0
- package/scripts/verify-bump-reproduction.sh +148 -0
- package/scripts/verify-verdict-signature.js +61 -0
- package/scripts/version-sync-check.js +33 -12
- package/skills/cool-workflow/SKILL.md +9 -9
- package/skills/cool-workflow/references/commands.md +89 -88
- package/ui/workbench/app.css +37 -1
- package/ui/workbench/app.js +124 -6
- package/workflows/README.md +19 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// wiring/capability-table/pipeline.ts — MILESTONE 6+7 (plan, run.drive*,
|
|
3
|
+
// dispatch, result, commit, commit.summary) + MILESTONE 11's run.export/
|
|
4
|
+
// import/verify-import/inspect-archive/restore CLI bindings. Split out of
|
|
5
|
+
// core/capability-table.ts, byte-for-byte (extracted with sed, not
|
|
6
|
+
// retyped).
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const registry_core_1 = require("./registry-core");
|
|
9
|
+
const io_1 = require("../../cli/io");
|
|
10
|
+
const io_2 = require("../../cli/io");
|
|
11
|
+
// MILESTONE 6+7 (combined; see docs/rebuild/PLAN.md Open risk 10) CLI bindings:
|
|
12
|
+
// plan, quickstart, run --drive, run drive (preview), dispatch, result,
|
|
13
|
+
// commit. Handler BODIES live in shell/pipeline-cli.ts (impure — they
|
|
14
|
+
// plan/drive/dispatch/commit real run state on disk); this table only
|
|
15
|
+
// wires argv shape -> handler call, per cli/dispatch.ts's generic
|
|
16
|
+
// executor contract.
|
|
17
|
+
// ---------------------------------------------------------------------
|
|
18
|
+
// This file is required unconditionally at startup for every command, so
|
|
19
|
+
// a top-level import of pipeline-cli/commit-summary would cost every
|
|
20
|
+
// invocation, not just plan/run/dispatch/result/commit/commit.summary ones.
|
|
21
|
+
function loadPipelineCli() {
|
|
22
|
+
return require("../../shell/pipeline-cli");
|
|
23
|
+
}
|
|
24
|
+
function loadCommitSummary() {
|
|
25
|
+
return require("../../shell/commit-summary");
|
|
26
|
+
}
|
|
27
|
+
(0, registry_core_1.attachCliBinding)("plan", {
|
|
28
|
+
path: ["plan"],
|
|
29
|
+
jsonMode: "default",
|
|
30
|
+
handler: (args) => {
|
|
31
|
+
const workflowId = (0, io_2.optionalArg)(args.positionals[0]);
|
|
32
|
+
if (!workflowId) {
|
|
33
|
+
throw new Error('Missing workflow id.\n Tip: plan an architecture review with "cw plan architecture-review"');
|
|
34
|
+
}
|
|
35
|
+
return { json: loadPipelineCli().planRun({ ...args.options, workflowId }) };
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
// `cw run <app> --drive [--once]` and `cw run drive <run-id> [--step]`
|
|
39
|
+
// share the single `run` dispatch path (byte-exact to the old build's
|
|
40
|
+
// handleRun: a run-REGISTRY subcommand keyword is never hijacked by the
|
|
41
|
+
// bare `--drive` intercept just because it carries its own --drive/--step
|
|
42
|
+
// flag). Both rows below dispatch on `["run"]`; the FIRST one registered
|
|
43
|
+
// (run.drive.step) is found first by findCapabilityByCliPath's linear
|
|
44
|
+
// scan, so its handler carries the full branch — the second row exists
|
|
45
|
+
// only so `cw help run` lists both capabilities.
|
|
46
|
+
(0, registry_core_1.attachCliBinding)("run.drive.step", {
|
|
47
|
+
path: ["run"],
|
|
48
|
+
helpPath: ["run", "drive"],
|
|
49
|
+
jsonMode: "default",
|
|
50
|
+
handler: async (args) => {
|
|
51
|
+
const registrySubcommands = new Set(["drive", "search", "list", "show", "resume", "archive", "rerun", "export", "import", "verify-import", "inspect-archive", "restore"]);
|
|
52
|
+
const target = args.positionals[0];
|
|
53
|
+
if (args.options.drive && !registrySubcommands.has(String(target || ""))) {
|
|
54
|
+
const runId = (0, io_2.optionalArg)(args.options.run) || (0, io_2.optionalArg)(args.options.runId);
|
|
55
|
+
if (args.options.preview)
|
|
56
|
+
return { json: loadPipelineCli().runDrivePreview({ ...args.options, runId: runId || target }) };
|
|
57
|
+
const driveArgs = { ...args.options };
|
|
58
|
+
if (runId)
|
|
59
|
+
driveArgs.runId = runId;
|
|
60
|
+
else
|
|
61
|
+
driveArgs.appId = target;
|
|
62
|
+
return { json: await loadPipelineCli().runDriveStep(driveArgs) };
|
|
63
|
+
}
|
|
64
|
+
const [subcommand, id] = args.positionals;
|
|
65
|
+
if (subcommand === "drive") {
|
|
66
|
+
if (args.options.step) {
|
|
67
|
+
const driveArgs = { ...args.options };
|
|
68
|
+
if (id)
|
|
69
|
+
driveArgs.runId = id;
|
|
70
|
+
return { json: await loadPipelineCli().runDriveStep(driveArgs) };
|
|
71
|
+
}
|
|
72
|
+
return { json: loadPipelineCli().runDrivePreview({ ...args.options, runId: (0, io_1.required)(id, "run id") }) };
|
|
73
|
+
}
|
|
74
|
+
// MILESTONE 11 (reporting/run-export) — the archive family. Handler
|
|
75
|
+
// bodies live in shell/run-export-cli.ts; this arm only wires argv
|
|
76
|
+
// shape -> handler call.
|
|
77
|
+
if (subcommand === "export") {
|
|
78
|
+
const result = loadRunExportCli().runExportCli((0, io_1.required)(id, "run id"), args.options);
|
|
79
|
+
return { json: result };
|
|
80
|
+
}
|
|
81
|
+
if (subcommand === "import") {
|
|
82
|
+
const result = loadRunExportCli().runImportCli((0, io_1.required)(id, "archive path"), args.options);
|
|
83
|
+
return { json: result };
|
|
84
|
+
}
|
|
85
|
+
if (subcommand === "verify-import") {
|
|
86
|
+
const result = loadRunExportCli().runVerifyImportCli((0, io_1.required)(id, "run id"), args.options);
|
|
87
|
+
return { json: result, exitCode: args.options.strict && !result.ok ? 1 : undefined };
|
|
88
|
+
}
|
|
89
|
+
if (subcommand === "inspect-archive") {
|
|
90
|
+
const result = loadRunExportCli().runInspectArchiveCli((0, io_1.required)(id, "archive path"), args.options);
|
|
91
|
+
return { json: result, exitCode: result.ok ? undefined : 1 };
|
|
92
|
+
}
|
|
93
|
+
if (subcommand === "restore") {
|
|
94
|
+
const result = loadRunExportCli().runRestoreCli((0, io_1.required)(id, "archive path"), args.options);
|
|
95
|
+
return { json: result, exitCode: result.ok ? undefined : 1 };
|
|
96
|
+
}
|
|
97
|
+
throw new Error("Usage: cw run search|list|show|resume|archive|rerun|drive|export|import|verify-import|inspect-archive|restore [run-id|archive] [--scope repo|home] [--json] | cw run <app> --drive [--once] [--incremental] [--repo R --question Q]");
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
// PARITY: `run.drive` (the read-only MCP preview tool) now ALSO carries
|
|
101
|
+
// its own two-token `cli.path` ["run","drive"], same as the old build's
|
|
102
|
+
// registry row (cli.path ["run","drive"]) and the same reversed-
|
|
103
|
+
// candidate-order pattern already used for run.search/run.list/etc.
|
|
104
|
+
// (see those rows' own comment below): findCapabilityByCliPath tries the
|
|
105
|
+
// 2-token candidate BEFORE the 1-token ["run"] row, so this row — not
|
|
106
|
+
// run.drive.step's combined switch — now serves `cw run drive <run-id>`
|
|
107
|
+
// [--step]. Behavior is unchanged (same runDrivePreview/runDriveStep
|
|
108
|
+
// calls, same --step branch run.drive.step's switch already used); only
|
|
109
|
+
// WHICH row answers the dispatch changes, so run.drive becomes a real
|
|
110
|
+
// both-surface, dual-bound capability for the payload-identity probe.
|
|
111
|
+
(0, registry_core_1.attachCliBinding)("run.drive", {
|
|
112
|
+
path: ["run", "drive"],
|
|
113
|
+
jsonMode: "default",
|
|
114
|
+
handler: async (args) => {
|
|
115
|
+
const id = args.positionals[0];
|
|
116
|
+
if (args.options.step) {
|
|
117
|
+
const driveArgs = { ...args.options };
|
|
118
|
+
if (id)
|
|
119
|
+
driveArgs.runId = id;
|
|
120
|
+
return { json: await loadPipelineCli().runDriveStep(driveArgs) };
|
|
121
|
+
}
|
|
122
|
+
return { json: loadPipelineCli().runDrivePreview({ ...args.options, runId: (0, io_1.required)(id, "run id") }) };
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.drive").mcp.handler = (args) => loadPipelineCli().runDrivePreview(args);
|
|
126
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.drive.step").mcp.handler = (args) => loadPipelineCli().runDriveStep(args);
|
|
127
|
+
// PARITY: `run.drive.step` advances the run by spawning the external
|
|
128
|
+
// agent per worker and recording attested output — not a read probe.
|
|
129
|
+
// CLI (--drive/--step) and MCP route through the same drive() core; the
|
|
130
|
+
// opt-out is the documented divergence, not undocumented drift.
|
|
131
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.drive.step").payloadIdentical = false;
|
|
132
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.drive.step").reason =
|
|
133
|
+
"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.";
|
|
134
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("plan").mcp.handler = (args) => loadPipelineCli().planRun(args);
|
|
135
|
+
// GAP #24: dispatchRun reads the sandbox profile from `args.sandbox` only
|
|
136
|
+
// (the CLI's --sandbox flag). The cw_dispatch MCP tool also accepts the
|
|
137
|
+
// `sandboxProfile`/`sandboxProfileId` aliases (its declared properties), so
|
|
138
|
+
// normalize them onto `sandbox` here — mirrors the old build's
|
|
139
|
+
// sandboxProfileIdFrom() alias set — before handing off.
|
|
140
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("dispatch").mcp.handler = (args) => loadPipelineCli().dispatchRun({ ...args, sandbox: args.sandbox ?? args.sandboxProfile ?? args.sandboxProfileId });
|
|
141
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("result").mcp.handler = (args) => loadPipelineCli().recordResultRun(args);
|
|
142
|
+
// `cw_commit` returns the FLAT commit envelope (verifierGated/checkpoint/
|
|
143
|
+
// selectionId/… at the top level, plus a nested `commit`), matching the old
|
|
144
|
+
// build's commitEnvelope. `commitRun` (CLI shape) returns `{ runId, commit }`;
|
|
145
|
+
// lift the commit's key fields to the top for the MCP surface.
|
|
146
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("commit").mcp.handler = (args) => {
|
|
147
|
+
const result = loadPipelineCli().commitRun(args);
|
|
148
|
+
const commit = result.commit || {};
|
|
149
|
+
return {
|
|
150
|
+
runId: result.runId,
|
|
151
|
+
commitId: commit.id,
|
|
152
|
+
verifierGated: commit.verifierGated,
|
|
153
|
+
checkpoint: commit.checkpoint,
|
|
154
|
+
verifierNodeId: commit.verifierNodeId,
|
|
155
|
+
candidateId: commit.candidateId,
|
|
156
|
+
selectionId: commit.selectionId,
|
|
157
|
+
evidenceCount: Array.isArray(commit.evidence) ? commit.evidence.length : 0,
|
|
158
|
+
snapshotPath: commit.snapshotPath,
|
|
159
|
+
commit,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
// PARITY: `commit` is the one declared payload projection (byte-compat
|
|
163
|
+
// item 5 above). Both surfaces route through the single core entry
|
|
164
|
+
// runner.commit (commitRun); the CLI keeps the raw StateCommitResult for
|
|
165
|
+
// scripting while cw_commit lifts an operator-facing envelope on top (see
|
|
166
|
+
// the mcp.handler just above). Marked here, not silently let drift, so
|
|
167
|
+
// the parity payload probe (core/capability-table.ts's
|
|
168
|
+
// payloadIdenticalCapabilities) skips it with a paper trail instead of
|
|
169
|
+
// tripping on an undocumented divergence.
|
|
170
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("commit").payloadIdentical = false;
|
|
171
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("commit").reason =
|
|
172
|
+
"Both surfaces route through the single core entry runner.commit. The CLI emits the raw StateCommitResult for scripting (commit.id, commit.evidence, commit.gate); cw_commit emits the operator commit envelope (commitId, verifierGated, checkpoint, evidenceCount, snapshotPath, nextActions, plus the raw result under `commit`). Declared projection, not drift.";
|
|
173
|
+
// MILESTONE 11 — run.export/import/verify-import/inspect-archive/restore
|
|
174
|
+
// MCP handlers (the CLI side is served by run.drive.step's combined
|
|
175
|
+
// handler above; these tools are called directly by name over MCP, so
|
|
176
|
+
// each needs its own mcp.handler per byte-compat item 5's two-field
|
|
177
|
+
// row shape).
|
|
178
|
+
// Same lazy-load reasoning as loadPipelineCli/loadCommitSummary above, for
|
|
179
|
+
// the run.export/import/verify-import/inspect-archive/restore family.
|
|
180
|
+
function loadRunExportCli() {
|
|
181
|
+
return require("../../shell/run-export-cli");
|
|
182
|
+
}
|
|
183
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.export").mcp.handler = (args) => loadRunExportCli().runExportCli((0, io_1.required)((0, io_2.optionalArg)(args.runId), "run id"), args);
|
|
184
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.import").mcp.handler = (args) => loadRunExportCli().runImportCli((0, io_1.required)((0, io_2.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
|
|
185
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.verify-import").mcp.handler = (args) => loadRunExportCli().runVerifyImportCli((0, io_1.required)((0, io_2.optionalArg)(args.runId), "run id"), args);
|
|
186
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.inspect-archive").mcp.handler = (args) => loadRunExportCli().runInspectArchiveCli((0, io_1.required)((0, io_2.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
|
|
187
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("run.restore").mcp.handler = (args) => loadRunExportCli().runRestoreCli((0, io_1.required)((0, io_2.optionalArg)(args.archive || args.path || args.file), "archive path"), args);
|
|
188
|
+
// `run export|import|verify-import|inspect-archive|restore` each carry their
|
|
189
|
+
// own two-token cli.path (found before the ["run"] run.drive.step catch-all
|
|
190
|
+
// per the reversed candidate order), calling the same shell fns with the
|
|
191
|
+
// same [subcommand, id] positional mapping and exit-code shape the catch-all
|
|
192
|
+
// switch already used. `hiddenFromHelp` keeps the byte-pinned `cw help run`
|
|
193
|
+
// fixture's rows coming from the single literal COMMAND_HELP_ROWS.run block.
|
|
194
|
+
(0, registry_core_1.attachCliBinding)("run.export", {
|
|
195
|
+
path: ["run", "export"],
|
|
196
|
+
jsonMode: "default",
|
|
197
|
+
hiddenFromHelp: true,
|
|
198
|
+
handler: (args) => ({ json: loadRunExportCli().runExportCli((0, io_1.required)(args.positionals[0], "run id"), args.options) }),
|
|
199
|
+
});
|
|
200
|
+
(0, registry_core_1.attachCliBinding)("run.import", {
|
|
201
|
+
path: ["run", "import"],
|
|
202
|
+
jsonMode: "default",
|
|
203
|
+
hiddenFromHelp: true,
|
|
204
|
+
handler: (args) => ({ json: loadRunExportCli().runImportCli((0, io_1.required)(args.positionals[0], "archive path"), args.options) }),
|
|
205
|
+
});
|
|
206
|
+
(0, registry_core_1.attachCliBinding)("run.verify-import", {
|
|
207
|
+
path: ["run", "verify-import"],
|
|
208
|
+
jsonMode: "default",
|
|
209
|
+
hiddenFromHelp: true,
|
|
210
|
+
handler: (args) => {
|
|
211
|
+
const result = loadRunExportCli().runVerifyImportCli((0, io_1.required)(args.positionals[0], "run id"), args.options);
|
|
212
|
+
return { json: result, exitCode: args.options.strict && !result.ok ? 1 : undefined };
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
(0, registry_core_1.attachCliBinding)("run.inspect-archive", {
|
|
216
|
+
path: ["run", "inspect-archive"],
|
|
217
|
+
jsonMode: "default",
|
|
218
|
+
hiddenFromHelp: true,
|
|
219
|
+
handler: (args) => {
|
|
220
|
+
const result = loadRunExportCli().runInspectArchiveCli((0, io_1.required)(args.positionals[0], "archive path"), args.options);
|
|
221
|
+
return { json: result, exitCode: result.ok ? undefined : 1 };
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
(0, registry_core_1.attachCliBinding)("run.restore", {
|
|
225
|
+
path: ["run", "restore"],
|
|
226
|
+
jsonMode: "default",
|
|
227
|
+
hiddenFromHelp: true,
|
|
228
|
+
handler: (args) => {
|
|
229
|
+
const result = loadRunExportCli().runRestoreCli((0, io_1.required)(args.positionals[0], "archive path"), args.options);
|
|
230
|
+
return { json: result, exitCode: result.ok ? undefined : 1 };
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
(0, registry_core_1.addCliOnlyCapability)("quickstart", "ONE-COMMAND quickstart: --check preflights without writes; otherwise plan(app, default architecture-review) -> run --drive -> report in a single invocation (--preview for a read-only dry run; --bundle [--with-trust-key K] seals a completed run into a self-verified portable bundle).", {
|
|
234
|
+
path: ["quickstart"],
|
|
235
|
+
// `audit-run` is a CLI-only alias that dispatches to the same quickstart
|
|
236
|
+
// wrapper (byte-behavior port of the old build's caseTokens).
|
|
237
|
+
caseTokens: ["quickstart", "audit-run"],
|
|
238
|
+
jsonMode: "default",
|
|
239
|
+
handler: async (args) => {
|
|
240
|
+
const appId = (0, io_2.optionalArg)(args.positionals[0]);
|
|
241
|
+
const result = (await loadPipelineCli().quickstartRun({ ...args.options, appId }));
|
|
242
|
+
// Fail closed on both known bad outcomes: a --check preflight that
|
|
243
|
+
// found a blocking gap, OR a --bundle that did not self-verify.
|
|
244
|
+
const bundle = result.bundle;
|
|
245
|
+
const bundleFailed = Boolean(bundle && bundle.ok === false);
|
|
246
|
+
const exitCode = (result.mode === "check" && result.ok === false) || bundleFailed ? 1 : undefined;
|
|
247
|
+
return { json: result, exitCode };
|
|
248
|
+
},
|
|
249
|
+
}, "quickstart composes plan/runDrive/report; SPEC/mcp.md's declared cli-only list names it explicitly (no MCP peer). `audit-run` is a CLI-only alias of the same wrapper.", "quickstart");
|
|
250
|
+
(0, registry_core_1.attachCliBinding)("dispatch", {
|
|
251
|
+
path: ["dispatch"],
|
|
252
|
+
jsonMode: "default",
|
|
253
|
+
handler: (args) => {
|
|
254
|
+
const runId = (0, io_1.required)((0, io_2.optionalArg)(args.positionals[0]), "run id");
|
|
255
|
+
return { json: loadPipelineCli().dispatchRun({ ...args.options, runId }) };
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
(0, registry_core_1.attachCliBinding)("result", {
|
|
259
|
+
path: ["result"],
|
|
260
|
+
jsonMode: "default",
|
|
261
|
+
handler: (args) => {
|
|
262
|
+
const runId = (0, io_1.required)((0, io_2.optionalArg)(args.positionals[0]), "run id");
|
|
263
|
+
const taskId = (0, io_1.required)((0, io_2.optionalArg)(args.positionals[1]), "task id");
|
|
264
|
+
const resultPath = (0, io_1.required)((0, io_2.optionalArg)(args.positionals[2]), "result file path");
|
|
265
|
+
return { json: loadPipelineCli().recordResultRun({ ...args.options, runId, taskId, resultPath }) };
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
(0, registry_core_1.attachCliBinding)("commit", {
|
|
269
|
+
path: ["commit"],
|
|
270
|
+
jsonMode: "default",
|
|
271
|
+
handler: (args) => {
|
|
272
|
+
const runId = (0, io_1.required)((0, io_2.optionalArg)(args.positionals[0]), "run id");
|
|
273
|
+
return { json: loadPipelineCli().commitRun({ ...args.options, runId }) };
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
// GAP #26: restore `cw commit summary <run-id>` (CLI + help row). The old
|
|
277
|
+
// build had commit.summary with cli path ["commit","summary"] surface "both"
|
|
278
|
+
// (capability-registry.ts:260-266); v2 kept only the cw_commit_summary MCP
|
|
279
|
+
// tool and dropped both the CLI binding and the COMMAND_HELP_ROWS entry, so
|
|
280
|
+
// `cw commit summary` mis-read "summary" as the run id. Path ["commit","summary"]
|
|
281
|
+
// is 2 tokens; dispatch consumes 1, so positionals[0] is the run id.
|
|
282
|
+
(0, registry_core_1.attachCliBinding)("commit.summary", {
|
|
283
|
+
path: ["commit", "summary"],
|
|
284
|
+
jsonMode: "flag",
|
|
285
|
+
handler: (args) => {
|
|
286
|
+
const commitSummary = loadCommitSummary();
|
|
287
|
+
const summary = commitSummary.commitSummaryCli({ ...args.options, runId: (0, io_1.required)(args.positionals[0], "run id") });
|
|
288
|
+
return { json: summary, text: `${commitSummary.formatCommitSummaryText(summary)}\n` };
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
registry_core_1.REGISTRY_BY_CAPABILITY.get("commit.summary").mcp.handler = (args) => loadCommitSummary().commitSummaryCli(args);
|
|
292
|
+
// ---------------------------------------------------------------------
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// wiring/capability-table/registry-core.ts — the shared machinery every
|
|
3
|
+
// domain slice registers into: REGISTRY, REGISTRY_BY_CAPABILITY,
|
|
4
|
+
// attachCliBinding, addCliOnlyCapability, and the read-only query
|
|
5
|
+
// functions (findCapability*, cliCapabilities, mcpToolDefinitions,
|
|
6
|
+
// declaredMcpTools). Also owns the small set of capability BODIES that
|
|
7
|
+
// must be in scope when MCP_TOOL_DATA.map() builds REGISTRY at module
|
|
8
|
+
// load (MCP_REAL_HANDLERS below) — kept here, not in a domain slice, to
|
|
9
|
+
// avoid a circular import (a slice needing attachCliBinding from this
|
|
10
|
+
// file, while this file would need a handler body FROM that slice).
|
|
11
|
+
//
|
|
12
|
+
// No slice file imports another slice file; every slice imports ONLY
|
|
13
|
+
// from this file, core/capability-data.ts, and shell/core as needed.
|
|
14
|
+
// index.ts imports this file plus every slice and composes them in the
|
|
15
|
+
// exact original source order (REGISTRY order is a pinned behavior —
|
|
16
|
+
// tools/list order, gen-parity-doc's byte-diff gate, cw help line order).
|
|
17
|
+
//
|
|
18
|
+
// Split out of core/capability-table.ts's "Public table-derived API"
|
|
19
|
+
// section, byte-for-byte (this file's body is the ORIGINAL file's own
|
|
20
|
+
// text, extracted with sed line ranges, not retyped).
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.REGISTRY_BY_CAPABILITY = exports.REGISTRY = void 0;
|
|
23
|
+
exports.listBundledWorkflows = listBundledWorkflows;
|
|
24
|
+
exports.listBundledSandboxProfiles = listBundledSandboxProfiles;
|
|
25
|
+
exports.statusPayload = statusPayload;
|
|
26
|
+
exports.attachCliBinding = attachCliBinding;
|
|
27
|
+
exports.addCliOnlyCapability = addCliOnlyCapability;
|
|
28
|
+
exports.findCapability = findCapability;
|
|
29
|
+
exports.findCapabilityByCliPath = findCapabilityByCliPath;
|
|
30
|
+
exports.cliCapabilities = cliCapabilities;
|
|
31
|
+
exports.mcpToolDefinitions = mcpToolDefinitions;
|
|
32
|
+
exports.declaredMcpTools = declaredMcpTools;
|
|
33
|
+
exports.findCapabilityByMcpTool = findCapabilityByMcpTool;
|
|
34
|
+
const capability_data_1 = require("../../core/capability-data");
|
|
35
|
+
const io_1 = require("../../cli/io");
|
|
36
|
+
// Every capability-table module (this file plus each domain slice) is
|
|
37
|
+
// required unconditionally at CLI/MCP startup, for every single command
|
|
38
|
+
// (index.ts's whole point is to populate REGISTRY before dispatch can
|
|
39
|
+
// look anything up) — so a top-level `import` of a shell module here
|
|
40
|
+
// means EVERY invocation pays that module's full load cost, even the
|
|
41
|
+
// 99% of commands that never touch `status`/`summary.refresh`/`list`.
|
|
42
|
+
// Requiring these 4 lazily (inside the handler that actually uses them)
|
|
43
|
+
// measured live: this file alone was ~30-45ms of a ~75-100ms `cw --version`
|
|
44
|
+
// require chain, the single largest slice. The 8 domain slices have the
|
|
45
|
+
// same shape and are a natural follow-up, not attempted here.
|
|
46
|
+
function loadRunStore() {
|
|
47
|
+
return require("../../shell/run-store");
|
|
48
|
+
}
|
|
49
|
+
function loadOperatorUx() {
|
|
50
|
+
return require("../../shell/operator-ux");
|
|
51
|
+
}
|
|
52
|
+
function loadWorkflowAppLoader() {
|
|
53
|
+
return require("../../shell/workflow-app-loader");
|
|
54
|
+
}
|
|
55
|
+
function loadStateExplosionCli() {
|
|
56
|
+
return require("../../shell/state-explosion-cli");
|
|
57
|
+
}
|
|
58
|
+
/** Real handlers implemented at THIS milestone, keyed by capability id.
|
|
59
|
+
* Every tool row not listed here gets `notYetImplemented`. Kept as a
|
|
60
|
+
* small side table (rather than inlined into MCP_TOOL_DATA above) so the
|
|
61
|
+
* 196-row literal above stays a pure, mechanically-checkable transcript
|
|
62
|
+
* of the spec table — handler wiring is a separate, obviously-later-
|
|
63
|
+
* editable concern. */
|
|
64
|
+
const MCP_REAL_HANDLERS = {
|
|
65
|
+
list: () => listBundledWorkflows(),
|
|
66
|
+
"sandbox.list": () => listBundledSandboxProfiles(),
|
|
67
|
+
status: (args) => statusPayload(optionalString(args.runId)),
|
|
68
|
+
"summary.refresh": (args) => loadStateExplosionCli().summaryRefreshCli((0, io_1.required)(optionalString(args.runId), "run id"), args),
|
|
69
|
+
"summary.show": (args) => loadStateExplosionCli().summaryShowCli((0, io_1.required)(optionalString(args.runId), "run id"), args),
|
|
70
|
+
};
|
|
71
|
+
function optionalString(value) {
|
|
72
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
73
|
+
}
|
|
74
|
+
/** `cw list` / `cw_list` (MILESTONE 12) — the real discovery over every
|
|
75
|
+
* `apps/*\/app.json` + legacy `workflows/*.workflow.js` on disk, per
|
|
76
|
+
* `listWorkflowsShallow` (shell/workflow-app-loader.ts). */
|
|
77
|
+
function listBundledWorkflows() {
|
|
78
|
+
return loadWorkflowAppLoader().listWorkflowsShallow();
|
|
79
|
+
}
|
|
80
|
+
/** PLACEHOLDER (milestone 5, execution-backend/sandbox) — the real
|
|
81
|
+
* `sandbox.list` resolves and stamps each of the 4 bundled profiles
|
|
82
|
+
* (default/readonly/workspace-write/locked-down) with real path lists
|
|
83
|
+
* via `resolveSandboxProfile` (SPEC/execution-backend.md). This
|
|
84
|
+
* milestone reproduces only the id/title/schemaVersion subset that
|
|
85
|
+
* mcp-basic.case.js checks. */
|
|
86
|
+
function listBundledSandboxProfiles() {
|
|
87
|
+
return [
|
|
88
|
+
{ schemaVersion: 1, id: "default", title: "Default Worker Boundary" },
|
|
89
|
+
{ schemaVersion: 1, id: "readonly", title: "Readonly Workspace" },
|
|
90
|
+
{ schemaVersion: 1, id: "workspace-write", title: "Workspace Write" },
|
|
91
|
+
{ schemaVersion: 1, id: "locked-down", title: "Locked Down" },
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
/** `cw status` / `cw_status` — SPEC/cli-surface.md pins the no-id JSON
|
|
95
|
+
* shape exactly (`{runId:null, nextActions}`); a real run id resolves to
|
|
96
|
+
* `summarizeRun`'s payload (MILESTONE 11, reporting/observability). */
|
|
97
|
+
function statusPayload(runId, cwd) {
|
|
98
|
+
const operatorUx = loadOperatorUx();
|
|
99
|
+
if (!runId) {
|
|
100
|
+
return { runId: null, nextActions: operatorUx.adviseNoRun() };
|
|
101
|
+
}
|
|
102
|
+
const run = loadRunStore().loadRunFromCwd(runId, cwd || process.cwd());
|
|
103
|
+
return operatorUx.summarizeRun(run);
|
|
104
|
+
}
|
|
105
|
+
// ---------------------------------------------------------------------
|
|
106
|
+
// Public table-derived API
|
|
107
|
+
// ---------------------------------------------------------------------
|
|
108
|
+
function buildMcpBinding(row) {
|
|
109
|
+
const handler = MCP_REAL_HANDLERS[row.capability] ?? (0, capability_data_1.notYetImplemented)(row.capability);
|
|
110
|
+
// A transcript entry like "runId, workerId" is TWO AND-required args (the
|
|
111
|
+
// spec table's comma form), while "topicId|id" is one OR-group. mcp/dispatch's
|
|
112
|
+
// validator only splits on `|`, so expand each comma-joined transcript entry
|
|
113
|
+
// into its separate AND-groups here (the one place the row shape is turned
|
|
114
|
+
// into the runtime McpBinding.requiredArgs contract).
|
|
115
|
+
const requiredArgs = row.requiredArgs.flatMap((group) => group.split(",").map((entry) => entry.trim()).filter(Boolean));
|
|
116
|
+
return {
|
|
117
|
+
tool: row.tool,
|
|
118
|
+
requiredArgs: requiredArgs.length ? requiredArgs : undefined,
|
|
119
|
+
properties: row.properties,
|
|
120
|
+
description: row.description,
|
|
121
|
+
handler,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/** The full capability table: one row per MCP tool (196, per SPEC/mcp.md),
|
|
125
|
+
* in the exact source order `tools/list` must report. CLI bindings are
|
|
126
|
+
* layered on top for the small set of capabilities this milestone also
|
|
127
|
+
* exposes on the CLI front door (see `CLI_ROWS` below); every other row
|
|
128
|
+
* is MCP-only AT THIS MILESTONE (not a permanent `mcp-only` declaration —
|
|
129
|
+
* just not yet CLI-wired; later milestones add the `cli` binding without
|
|
130
|
+
* touching this array's mcp side). */
|
|
131
|
+
exports.REGISTRY = capability_data_1.MCP_TOOL_DATA.map((row) => ({
|
|
132
|
+
capability: row.capability,
|
|
133
|
+
summary: row.description,
|
|
134
|
+
surface: "both",
|
|
135
|
+
mcp: buildMcpBinding(row),
|
|
136
|
+
}));
|
|
137
|
+
exports.REGISTRY_BY_CAPABILITY = new Map(exports.REGISTRY.map((row) => [row.capability, row]));
|
|
138
|
+
/** Attach (or replace) a CLI binding for an already-declared MCP capability.
|
|
139
|
+
* Used once below to wire `list`/`status`/`sandbox.list` onto the CLI
|
|
140
|
+
* front door too, without duplicating their row data. */
|
|
141
|
+
function attachCliBinding(capability, cli) {
|
|
142
|
+
const row = exports.REGISTRY_BY_CAPABILITY.get(capability);
|
|
143
|
+
if (!row)
|
|
144
|
+
throw new Error(`capability-table: cannot attach cli binding to undeclared capability ${capability}`);
|
|
145
|
+
row.cli = cli;
|
|
146
|
+
}
|
|
147
|
+
/** Declare a capability that is CLI-only at this milestone (`help`,
|
|
148
|
+
* `version` — both are permanently `cli-only` per SPEC/mcp.md's
|
|
149
|
+
* declared one-surface list, so no mcp row is created for them). */
|
|
150
|
+
function addCliOnlyCapability(capability, summary, cli, reason, entry) {
|
|
151
|
+
const row = { capability, summary, surface: "cli-only", cli, reason, ...(entry ? { entry } : {}) };
|
|
152
|
+
exports.REGISTRY.push(row);
|
|
153
|
+
exports.REGISTRY_BY_CAPABILITY.set(capability, row);
|
|
154
|
+
}
|
|
155
|
+
/** Returns the declared row for a capability id, or undefined. */
|
|
156
|
+
function findCapability(capability) {
|
|
157
|
+
return exports.REGISTRY_BY_CAPABILITY.get(capability);
|
|
158
|
+
}
|
|
159
|
+
/** Returns the declared row whose `cli.path` matches `path` exactly
|
|
160
|
+
* (path[0] is the verb). Used by cli/dispatch.ts's generic executor.
|
|
161
|
+
* A single-token command also matches a row's `caseTokens` alias list, so
|
|
162
|
+
* an alias (e.g. `audit-run`) dispatches to the same handler as its verb. */
|
|
163
|
+
function findCapabilityByCliPath(path) {
|
|
164
|
+
for (const row of exports.REGISTRY) {
|
|
165
|
+
if (row.cli && row.cli.path.length === path.length && row.cli.path.every((p, i) => p === path[i])) {
|
|
166
|
+
return row;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (path.length === 1) {
|
|
170
|
+
for (const row of exports.REGISTRY) {
|
|
171
|
+
if (row.cli && row.cli.caseTokens && row.cli.caseTokens.includes(path[0]))
|
|
172
|
+
return row;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
/** Every capability row that declares a `cli` binding, in registry order.
|
|
178
|
+
* Used to derive `formatCommandHelp`'s per-verb subcommand rows. */
|
|
179
|
+
function cliCapabilities() {
|
|
180
|
+
return exports.REGISTRY.filter((row) => Boolean(row.cli));
|
|
181
|
+
}
|
|
182
|
+
/** `tools/list`'s exact array, in the pinned source order. */
|
|
183
|
+
function mcpToolDefinitions() {
|
|
184
|
+
const definitions = [];
|
|
185
|
+
for (const row of exports.REGISTRY) {
|
|
186
|
+
if (!row.mcp)
|
|
187
|
+
continue;
|
|
188
|
+
const overrides = capability_data_1.PROPERTY_OVERRIDES[row.mcp.tool] ?? {};
|
|
189
|
+
const properties = {};
|
|
190
|
+
for (const propName of row.mcp.properties) {
|
|
191
|
+
properties[propName] = overrides[propName] ?? (0, capability_data_1.stringProperty)(propName);
|
|
192
|
+
}
|
|
193
|
+
definitions.push({
|
|
194
|
+
name: row.mcp.tool,
|
|
195
|
+
description: row.mcp.description,
|
|
196
|
+
inputSchema: { type: "object", properties, additionalProperties: true },
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return definitions;
|
|
200
|
+
}
|
|
201
|
+
/** Every declared MCP tool name, in `tools/list` order. */
|
|
202
|
+
function declaredMcpTools() {
|
|
203
|
+
return exports.REGISTRY.filter((row) => row.mcp).map((row) => row.mcp.tool);
|
|
204
|
+
}
|
|
205
|
+
/** Look up a capability row by its MCP tool name. */
|
|
206
|
+
function findCapabilityByMcpTool(tool) {
|
|
207
|
+
return exports.REGISTRY.find((row) => row.mcp && row.mcp.tool === tool);
|
|
208
|
+
}
|