cool-workflow 0.1.78

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.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +20 -0
  2. package/.codex-plugin/mcp.json +10 -0
  3. package/.codex-plugin/plugin.json +38 -0
  4. package/.mcp.json +10 -0
  5. package/LICENSE +24 -0
  6. package/README.md +638 -0
  7. package/apps/architecture-review/app.json +51 -0
  8. package/apps/architecture-review/workflow.js +116 -0
  9. package/apps/end-to-end-golden-path/app.json +30 -0
  10. package/apps/end-to-end-golden-path/workflow.js +33 -0
  11. package/apps/pr-review-fix-ci/app.json +59 -0
  12. package/apps/pr-review-fix-ci/workflow.js +90 -0
  13. package/apps/release-cut/app.json +54 -0
  14. package/apps/release-cut/workflow.js +82 -0
  15. package/apps/research-synthesis/app.json +50 -0
  16. package/apps/research-synthesis/workflow.js +76 -0
  17. package/apps/workflow-app-framework-demo/app.json +29 -0
  18. package/apps/workflow-app-framework-demo/workflow.js +44 -0
  19. package/dist/agent-config.js +223 -0
  20. package/dist/candidate-scoring.js +715 -0
  21. package/dist/capability-core.js +630 -0
  22. package/dist/capability-dispatcher.js +86 -0
  23. package/dist/capability-registry.js +523 -0
  24. package/dist/cli.js +1276 -0
  25. package/dist/collaboration.js +727 -0
  26. package/dist/commit.js +570 -0
  27. package/dist/contract-migration.js +234 -0
  28. package/dist/coordinator.js +1163 -0
  29. package/dist/daemon.js +44 -0
  30. package/dist/dispatch.js +201 -0
  31. package/dist/drive.js +503 -0
  32. package/dist/error-feedback.js +415 -0
  33. package/dist/evidence-grounding.js +179 -0
  34. package/dist/evidence-reasoning.js +733 -0
  35. package/dist/execution-backend.js +1279 -0
  36. package/dist/harness.js +61 -0
  37. package/dist/mcp-server.js +1615 -0
  38. package/dist/multi-agent-eval.js +857 -0
  39. package/dist/multi-agent-host.js +764 -0
  40. package/dist/multi-agent-operator-ux.js +537 -0
  41. package/dist/multi-agent-trust.js +366 -0
  42. package/dist/multi-agent.js +1173 -0
  43. package/dist/node-snapshot.js +270 -0
  44. package/dist/observability.js +922 -0
  45. package/dist/operator-ux.js +971 -0
  46. package/dist/orchestrator/audit-operations.js +182 -0
  47. package/dist/orchestrator/candidate-operations.js +117 -0
  48. package/dist/orchestrator/cli-options.js +288 -0
  49. package/dist/orchestrator/collaboration-operations.js +86 -0
  50. package/dist/orchestrator/feedback-operations.js +81 -0
  51. package/dist/orchestrator/host-operations.js +78 -0
  52. package/dist/orchestrator/lifecycle-operations.js +462 -0
  53. package/dist/orchestrator/migration-operations.js +44 -0
  54. package/dist/orchestrator/multi-agent-operations.js +362 -0
  55. package/dist/orchestrator/report.js +369 -0
  56. package/dist/orchestrator/topology-operations.js +84 -0
  57. package/dist/orchestrator.js +874 -0
  58. package/dist/pipeline-contract.js +92 -0
  59. package/dist/pipeline-runner.js +285 -0
  60. package/dist/reclamation.js +882 -0
  61. package/dist/result-normalize.js +194 -0
  62. package/dist/run-export.js +64 -0
  63. package/dist/run-registry.js +1347 -0
  64. package/dist/run-state-schema.js +67 -0
  65. package/dist/sandbox-profile.js +471 -0
  66. package/dist/scheduler.js +266 -0
  67. package/dist/scheduling.js +184 -0
  68. package/dist/schema-validate.js +98 -0
  69. package/dist/state-explosion.js +1213 -0
  70. package/dist/state-migrations.js +463 -0
  71. package/dist/state-node.js +301 -0
  72. package/dist/state.js +308 -0
  73. package/dist/telemetry-attestation.js +156 -0
  74. package/dist/telemetry-ledger.js +145 -0
  75. package/dist/topology.js +527 -0
  76. package/dist/triggers.js +159 -0
  77. package/dist/trust-audit.js +475 -0
  78. package/dist/types/blackboard.js +2 -0
  79. package/dist/types/boundary.js +29 -0
  80. package/dist/types/candidate.js +2 -0
  81. package/dist/types/collaboration.js +2 -0
  82. package/dist/types/core.js +2 -0
  83. package/dist/types/drive.js +10 -0
  84. package/dist/types/error-feedback.js +2 -0
  85. package/dist/types/evidence-reasoning.js +2 -0
  86. package/dist/types/execution-backend.js +2 -0
  87. package/dist/types/multi-agent.js +2 -0
  88. package/dist/types/observability.js +2 -0
  89. package/dist/types/pipeline.js +2 -0
  90. package/dist/types/reclamation.js +8 -0
  91. package/dist/types/result.js +2 -0
  92. package/dist/types/run-registry.js +2 -0
  93. package/dist/types/run.js +2 -0
  94. package/dist/types/sandbox.js +2 -0
  95. package/dist/types/schedule.js +2 -0
  96. package/dist/types/state-node.js +2 -0
  97. package/dist/types/topology.js +2 -0
  98. package/dist/types/trust.js +2 -0
  99. package/dist/types/workbench.js +2 -0
  100. package/dist/types/worker.js +2 -0
  101. package/dist/types/workflow-app.js +2 -0
  102. package/dist/types.js +43 -0
  103. package/dist/verifier-registry.js +46 -0
  104. package/dist/verifier.js +78 -0
  105. package/dist/version.js +8 -0
  106. package/dist/workbench-host.js +172 -0
  107. package/dist/workbench.js +190 -0
  108. package/dist/worker-isolation.js +1028 -0
  109. package/dist/workflow-api.js +98 -0
  110. package/dist/workflow-app-framework.js +626 -0
  111. package/docs/agent-delegation-drive.7.md +190 -0
  112. package/docs/agent-framework.md +176 -0
  113. package/docs/candidate-scoring.7.md +106 -0
  114. package/docs/canonical-workflow-apps.7.md +137 -0
  115. package/docs/capability-topology-registry.7.md +168 -0
  116. package/docs/cli-mcp-parity.7.md +373 -0
  117. package/docs/contract-migration-tooling.7.md +123 -0
  118. package/docs/control-plane-scheduling.7.md +110 -0
  119. package/docs/coordinator-blackboard.7.md +183 -0
  120. package/docs/dogfood/architecture-review-cool-workflow.md +16 -0
  121. package/docs/dogfood-one-real-repo.7.md +168 -0
  122. package/docs/durable-state-and-locking.7.md +107 -0
  123. package/docs/end-to-end-golden-path.7.md +117 -0
  124. package/docs/error-feedback.7.md +153 -0
  125. package/docs/evidence-adoption-reasoning-chain.7.md +270 -0
  126. package/docs/execution-backends.7.md +300 -0
  127. package/docs/getting-started.md +99 -0
  128. package/docs/index.md +41 -0
  129. package/docs/mcp-app-surface.7.md +235 -0
  130. package/docs/multi-agent-cli-mcp-surface.7.md +265 -0
  131. package/docs/multi-agent-eval-replay-harness.7.md +302 -0
  132. package/docs/multi-agent-operator-ux.7.md +314 -0
  133. package/docs/multi-agent-runtime-core.7.md +231 -0
  134. package/docs/multi-agent-topologies.7.md +103 -0
  135. package/docs/multi-agent-trust-policy-audit.7.md +154 -0
  136. package/docs/node-snapshot-diff-replay.7.md +135 -0
  137. package/docs/observability-cost-accounting.7.md +194 -0
  138. package/docs/operator-ux.7.md +180 -0
  139. package/docs/pipeline-runner.7.md +136 -0
  140. package/docs/project-index.md +261 -0
  141. package/docs/real-execution-backends.7.md +142 -0
  142. package/docs/release-and-migration.7.md +280 -0
  143. package/docs/release-tooling.7.md +159 -0
  144. package/docs/routines.md +48 -0
  145. package/docs/run-registry-control-plane.7.md +312 -0
  146. package/docs/run-retention-reclamation.7.md +191 -0
  147. package/docs/sandbox-profiles.7.md +137 -0
  148. package/docs/scheduled-tasks.md +80 -0
  149. package/docs/security-trust-hardening.7.md +117 -0
  150. package/docs/state-explosion-management.7.md +264 -0
  151. package/docs/state-node.7.md +96 -0
  152. package/docs/team-collaboration.7.md +207 -0
  153. package/docs/unix-principles.md +192 -0
  154. package/docs/verifier-gated-commit.7.md +140 -0
  155. package/docs/web-desktop-workbench.7.md +215 -0
  156. package/docs/worker-isolation.7.md +167 -0
  157. package/docs/workflow-app-framework.7.md +274 -0
  158. package/manifest/README.md +43 -0
  159. package/manifest/plugin.manifest.json +316 -0
  160. package/manifest/pricing.policy.json +14 -0
  161. package/package.json +79 -0
  162. package/scripts/agents/claude-p-agent.js +104 -0
  163. package/scripts/agents/claude-p-agent.sh +9 -0
  164. package/scripts/agents/cw-attest-keygen.js +55 -0
  165. package/scripts/agents/cw-attest-wrap.js +143 -0
  166. package/scripts/block-unapproved-tag.sh +39 -0
  167. package/scripts/bump-version.js +249 -0
  168. package/scripts/canonical-apps.js +171 -0
  169. package/scripts/cw.js +4 -0
  170. package/scripts/dist-drift-check.js +79 -0
  171. package/scripts/dogfood-architecture-review.js +237 -0
  172. package/scripts/dogfood-release.js +624 -0
  173. package/scripts/forward-ref-docs.js +73 -0
  174. package/scripts/gen-manifests.js +232 -0
  175. package/scripts/golden-path.js +300 -0
  176. package/scripts/mcp-server.js +4 -0
  177. package/scripts/new-feature.js +121 -0
  178. package/scripts/parity-check.js +213 -0
  179. package/scripts/release-check.js +118 -0
  180. package/scripts/release-flow.js +272 -0
  181. package/scripts/release-gate.sh +85 -0
  182. package/scripts/sync-project-index.js +387 -0
  183. package/scripts/validate-run-state-schema.js +126 -0
  184. package/scripts/verify-container-selfref.js +64 -0
  185. package/scripts/version-sync-check.js +237 -0
  186. package/skills/cool-workflow/SKILL.md +162 -0
  187. package/skills/cool-workflow/references/commands.md +282 -0
  188. package/tsconfig.json +16 -0
  189. package/ui/workbench/app.css +76 -0
  190. package/ui/workbench/app.js +159 -0
  191. package/ui/workbench/index.html +32 -0
  192. package/workflows/architecture-review.workflow.js +84 -0
  193. package/workflows/research-synthesis.workflow.js +47 -0
@@ -0,0 +1,630 @@
1
+ "use strict";
2
+ // Shared capability core: the SINGLE source of truth for composite capabilities
3
+ // whose payload is assembled from more than one orchestrator call.
4
+ //
5
+ // BSD discipline (mechanism vs policy): these functions are MECHANISM. They live
6
+ // here — never in cli.ts or mcp-server.ts — so the CLI and the MCP surface are
7
+ // two renderings of ONE data source. Any capability that composes multiple
8
+ // runner calls (plan summary, app run, sandbox choice, commit envelope) MUST be
9
+ // expressed here and called identically by both surfaces. A composite that lives
10
+ // in only one surface is exactly the cross-surface drift v0.1.27 forbids.
11
+ //
12
+ // From v0.1.46: each exported entry function SHOULD self-register its capability
13
+ // metadata via registerCapability() from capability-registry.ts. This replaces
14
+ // the manual "add an entry to the giant array in capability-registry.ts" workflow
15
+ // with automatic discovery. New capabilities just add a registerCapability() call
16
+ // next to their implementation — no need to touch capability-registry.ts.
17
+ //
18
+ // See docs/cli-mcp-parity.7.md and src/capability-registry.ts.
19
+ var __importDefault = (this && this.__importDefault) || function (mod) {
20
+ return (mod && mod.__esModule) ? mod : { "default": mod };
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.QUICKSTART_DEFAULT_APP = void 0;
24
+ exports.planSummary = planSummary;
25
+ exports.appRun = appRun;
26
+ exports.sandboxChoose = sandboxChoose;
27
+ exports.commitEnvelope = commitEnvelope;
28
+ exports.compactOperatorStatus = compactOperatorStatus;
29
+ exports.runRegistryFor = runRegistryFor;
30
+ exports.runRegistryRefresh = runRegistryRefresh;
31
+ exports.runRegistryShow = runRegistryShow;
32
+ exports.runSearch = runSearch;
33
+ exports.runList = runList;
34
+ exports.runShow = runShow;
35
+ exports.runResume = runResume;
36
+ exports.runArchive = runArchive;
37
+ exports.runRerun = runRerun;
38
+ exports.queueAdd = queueAdd;
39
+ exports.queueList = queueList;
40
+ exports.queueDrain = queueDrain;
41
+ exports.queueShow = queueShow;
42
+ exports.schedPlan = schedPlan;
43
+ exports.schedLease = schedLease;
44
+ exports.schedRelease = schedRelease;
45
+ exports.schedComplete = schedComplete;
46
+ exports.schedReclaim = schedReclaim;
47
+ exports.schedReset = schedReset;
48
+ exports.schedPolicyShow = schedPolicyShow;
49
+ exports.schedPolicySet = schedPolicySet;
50
+ exports.runDrivePreview = runDrivePreview;
51
+ exports.runDrive = runDrive;
52
+ exports.quickstart = quickstart;
53
+ exports.backendAgentConfigShow = backendAgentConfigShow;
54
+ exports.backendAgentConfigSet = backendAgentConfigSet;
55
+ exports.gcPlan = gcPlan;
56
+ exports.gcRun = gcRun;
57
+ exports.gcVerify = gcVerify;
58
+ exports.runHistory = runHistory;
59
+ exports.metricsSummary = metricsSummary;
60
+ exports.sandboxProfileIdFrom = sandboxProfileIdFrom;
61
+ exports.withoutRuntimeKeys = withoutRuntimeKeys;
62
+ exports.optionalString = optionalString;
63
+ exports.isRecord = isRecord;
64
+ const capability_registry_1 = require("./capability-registry");
65
+ const drive_1 = require("./drive");
66
+ const agent_config_1 = require("./agent-config");
67
+ const run_registry_1 = require("./run-registry");
68
+ const observability_1 = require("./observability");
69
+ const state_1 = require("./state");
70
+ const node_fs_1 = __importDefault(require("node:fs"));
71
+ const node_path_1 = __importDefault(require("node:path"));
72
+ const scheduling_1 = require("./scheduling");
73
+ // ---- canonical plan payload -----------------------------------------------
74
+ // Both `cw plan` (default + --json) and `cw_plan` resolve to this exact object.
75
+ function planSummary(runner, workflowId, options) {
76
+ const run = runner.plan(workflowId, options);
77
+ return {
78
+ runId: run.id,
79
+ workflowId: run.workflow.id,
80
+ statePath: run.paths.state,
81
+ reportPath: run.paths.report,
82
+ pendingTasks: run.tasks.filter((task) => task.status === "pending").length
83
+ };
84
+ }
85
+ // Auto-register with the capability registry (v0.1.46 — no need to edit capability-registry.ts)
86
+ (0, capability_registry_1.registerCapability)({ capability: "plan", summary: "Plan a workflow run on a repo + app.", entry: "planSummary", surface: "both", cli: { path: ["plan"], jsonMode: "default" }, mcp: { tool: "cw_plan" } });
87
+ // ---- canonical app-run payload --------------------------------------------
88
+ // Both `cw app run` and `cw_app_run` resolve to this exact object. Structured
89
+ // app inputs + optional sandbox resolution, then a compact operator status.
90
+ function appRun(runner, args) {
91
+ const appId = String(args.appId || args.workflowId || "");
92
+ const inputs = isRecord(args.inputs) ? args.inputs : {};
93
+ const planOptions = { ...inputs, ...withoutRuntimeKeys(args) };
94
+ const sandboxProfileId = sandboxProfileIdFrom(args);
95
+ const resolvedSandbox = sandboxProfileId ? runner.showSandboxProfile(sandboxProfileId, args) : undefined;
96
+ const run = runner.plan(appId, planOptions);
97
+ const status = runner.operatorStatus(run.id);
98
+ return {
99
+ runId: run.id,
100
+ workflowId: run.workflow.id,
101
+ appId: run.workflow.app?.id || appId,
102
+ appVersion: run.workflow.app?.version,
103
+ statePath: run.paths.state,
104
+ reportPath: run.paths.report,
105
+ pendingTasks: run.tasks.filter((task) => task.status === "pending").length,
106
+ operatorStatus: compactOperatorStatus(status),
107
+ nextActions: status.nextActions,
108
+ sandboxProfileId,
109
+ sandboxProfile: resolvedSandbox
110
+ };
111
+ }
112
+ (0, capability_registry_1.registerCapability)({ capability: "app.run", summary: "Plan a run on a named app with structured inputs.", entry: "appRun", surface: "both", cli: { path: ["app", "run"], caseTokens: ["app"], jsonMode: "default" }, mcp: { tool: "cw_app_run" } });
113
+ // ---- canonical sandbox choice payload -------------------------------------
114
+ // Both `cw sandbox choose|resolve` and `cw_sandbox_choose|cw_sandbox_resolve`
115
+ // resolve to this exact object.
116
+ function sandboxChoose(runner, args) {
117
+ const profileId = sandboxProfileIdFrom(args) || "readonly";
118
+ const profile = runner.showSandboxProfile(profileId, args);
119
+ return {
120
+ profileId,
121
+ sandboxProfileId: profile.id,
122
+ valid: true,
123
+ profile
124
+ };
125
+ }
126
+ // ---- canonical commit envelope --------------------------------------------
127
+ // `cw_commit` resolves to this operator-facing envelope. The CLI `commit`
128
+ // command intentionally emits the raw StateCommitResult for scripting; both
129
+ // derive from the single core entry runner.commit (declared, not drift — see
130
+ // the capability registry's `commit` descriptor).
131
+ function commitEnvelope(runner, runId, args) {
132
+ const result = runner.commit(runId, args);
133
+ const commit = result.commit;
134
+ const status = runner.operatorStatus(runId);
135
+ return {
136
+ runId,
137
+ commitId: commit.id,
138
+ verifierGated: commit.verifierGated,
139
+ checkpoint: commit.checkpoint,
140
+ verifierNodeId: commit.verifierNodeId,
141
+ candidateId: commit.candidateId,
142
+ selectionId: commit.selectionId,
143
+ evidenceCount: (commit.evidence || []).length,
144
+ snapshotPath: commit.snapshotPath,
145
+ nextActions: status.nextActions,
146
+ commit
147
+ };
148
+ }
149
+ (0, capability_registry_1.registerCapability)({ capability: "commit", summary: "Create a verifier-gated state commit with evidence.", entry: "commitEnvelope", surface: "both", cli: { path: ["commit"], jsonMode: "default" }, mcp: { tool: "cw_commit" }, payloadIdentical: false, reason: "CLI renders a human summary with path hints; MCP returns the structured commit payload alone." });
150
+ function compactOperatorStatus(status) {
151
+ return {
152
+ runId: status.runId,
153
+ workflowId: status.workflowId,
154
+ appId: status.appId,
155
+ appVersion: status.appVersion,
156
+ loopStage: status.loopStage,
157
+ activePhase: status.activePhase,
158
+ blocked: status.blocked,
159
+ blockedReasons: status.blockedReasons,
160
+ pendingTasks: status.tasks.pending.length,
161
+ runningTasks: status.tasks.running.length,
162
+ completedTasks: status.tasks.completed.length,
163
+ nextActions: status.nextActions
164
+ };
165
+ }
166
+ // ---- run registry / control plane (v0.1.28) -------------------------------
167
+ // MECHANISM, ONE SOURCE: the CLI and MCP surfaces both route through these
168
+ // functions so `cw <cmd> --json` is byte-identical to `cw_<tool>`. Each accepts
169
+ // the raw CLI options OR the raw MCP arguments and normalizes them identically,
170
+ // then calls the single RunRegistry method. The registry is constructed from the
171
+ // same resolved cwd on both surfaces (CLI: --cwd|process.cwd(); MCP chdir'd to
172
+ // args.cwd), so repo/home roots line up.
173
+ function runRegistryFor(args, planner) {
174
+ return new run_registry_1.RunRegistry(String(args.cwd || process.cwd()), planner);
175
+ }
176
+ function scopeOf(args, fallback) {
177
+ if (args.scope === "repo")
178
+ return "repo";
179
+ if (args.scope === "home")
180
+ return "home";
181
+ return fallback;
182
+ }
183
+ function lifecycleOf(value) {
184
+ return (0, run_registry_1.isRunLifecycleState)(value) ? value : undefined;
185
+ }
186
+ function flag(value) {
187
+ if (value === undefined)
188
+ return undefined;
189
+ if (value === false || value === "false" || value === "no" || value === "0")
190
+ return false;
191
+ return Boolean(value);
192
+ }
193
+ function runRegistryRefresh(reg, args) {
194
+ return reg.refresh({ scope: scopeOf(args, "repo") });
195
+ }
196
+ function runRegistryShow(reg, args) {
197
+ return reg.show({ scope: scopeOf(args, "repo") });
198
+ }
199
+ function runSearch(reg, args) {
200
+ return reg.search({
201
+ scope: scopeOf(args, "home"),
202
+ text: optionalString(args.text || args.q || args.query),
203
+ app: optionalString(args.app || args.appId),
204
+ status: lifecycleOf(args.status),
205
+ repo: optionalString(args.repo),
206
+ since: optionalString(args.since),
207
+ until: optionalString(args.until),
208
+ includeArchived: flag(args.includeArchived ?? args["include-archived"]),
209
+ limit: args.limit === undefined ? undefined : Number(args.limit),
210
+ offset: args.offset === undefined ? undefined : Number(args.offset)
211
+ });
212
+ }
213
+ function runList(reg, args) {
214
+ return reg.list({
215
+ scope: scopeOf(args, "home"),
216
+ includeArchived: flag(args.includeArchived ?? args["include-archived"]),
217
+ limit: args.limit === undefined ? undefined : Number(args.limit),
218
+ offset: args.offset === undefined ? undefined : Number(args.offset)
219
+ });
220
+ }
221
+ function runShow(reg, runId, args) {
222
+ return reg.showRun(runId, { scope: scopeOf(args, "home") });
223
+ }
224
+ function runResume(reg, runId, args) {
225
+ return reg.resume(runId, {
226
+ scope: scopeOf(args, "home"),
227
+ limit: args.limit === undefined ? undefined : Number(args.limit)
228
+ });
229
+ }
230
+ function runArchive(reg, runId, args) {
231
+ if (runId) {
232
+ return reg.archive(runId, {
233
+ scope: scopeOf(args, "home"),
234
+ reason: optionalString(args.reason),
235
+ unarchive: flag(args.unarchive)
236
+ });
237
+ }
238
+ const days = Number(args.olderThanDays ?? args["older-than-days"]);
239
+ const states = parseLifecycleList(args.state ?? args.status);
240
+ return reg.archiveByPolicy({
241
+ schemaVersion: 1,
242
+ archiveOlderThanDays: Number.isFinite(days) ? days : 0,
243
+ archiveStates: states.length ? states : ["completed", "failed"],
244
+ defaultQueuePriority: 100
245
+ }, { scope: scopeOf(args, "home") });
246
+ }
247
+ function runRerun(reg, runId, args) {
248
+ return reg.rerun(runId, { scope: scopeOf(args, "home"), reason: optionalString(args.reason) });
249
+ }
250
+ function queueAdd(reg, args) {
251
+ return reg.queueAdd({
252
+ runId: optionalString(args.runId),
253
+ appId: optionalString(args.appId || args.app),
254
+ workflowId: optionalString(args.workflowId || args.workflow),
255
+ repo: optionalString(args.repo),
256
+ priority: args.priority === undefined ? undefined : Number(args.priority),
257
+ note: optionalString(args.note),
258
+ id: optionalString(args.id)
259
+ });
260
+ }
261
+ function queueList(reg, args) {
262
+ const status = optionalString(args.status);
263
+ return reg.queueList({
264
+ status: status,
265
+ repo: optionalString(args.repo)
266
+ });
267
+ }
268
+ function queueDrain(reg, args) {
269
+ return reg.queueDrain({
270
+ limit: args.limit === undefined ? undefined : Number(args.limit),
271
+ repo: optionalString(args.repo)
272
+ });
273
+ }
274
+ function queueShow(reg, id) {
275
+ return reg.queueShow(id);
276
+ }
277
+ // ---- control-plane scheduling (v0.1.37) -----------------------------------
278
+ function loadSchedulingPolicy(reg) {
279
+ const file = reg.schedulingPolicyPath();
280
+ if (node_fs_1.default.existsSync(file)) {
281
+ try {
282
+ return { policy: (0, scheduling_1.normalizeSchedulingPolicy)((0, state_1.readJson)(file)), source: "file" };
283
+ }
284
+ catch {
285
+ /* fall through to default */
286
+ }
287
+ }
288
+ return { policy: scheduling_1.DEFAULT_SCHEDULING_POLICY, source: "default" };
289
+ }
290
+ function schedNow(args) {
291
+ return optionalString(args.now) || new Date().toISOString();
292
+ }
293
+ function isTrue(value) {
294
+ return value === true || value === "true" || value === "1";
295
+ }
296
+ function schedPlan(reg, args) {
297
+ return (0, scheduling_1.planSchedule)(reg.loadQueueEntries(), loadSchedulingPolicy(reg).policy, schedNow(args));
298
+ }
299
+ function schedLease(reg, args) {
300
+ const now = schedNow(args);
301
+ const policy = loadSchedulingPolicy(reg).policy;
302
+ const limit = args.limit === undefined ? undefined : Number(args.limit);
303
+ const { entries, leases } = (0, scheduling_1.applyLease)(reg.loadQueueEntries(), policy, now, limit);
304
+ reg.saveQueueEntries(entries);
305
+ return { schemaVersion: 1, now, granted: leases.length, leases };
306
+ }
307
+ function schedRelease(reg, args) {
308
+ const now = schedNow(args);
309
+ const failed = isTrue(args.failed);
310
+ const { entries, matched } = (0, scheduling_1.leaseRelease)(reg.loadQueueEntries(), String(args.leaseId || ""), loadSchedulingPolicy(reg).policy, now, {
311
+ failed,
312
+ reason: optionalString(args.reason)
313
+ });
314
+ if (!matched)
315
+ throw new Error(`No active lease to release: ${args.leaseId}`);
316
+ reg.saveQueueEntries(entries);
317
+ return { schemaVersion: 1, released: String(args.leaseId || ""), failed };
318
+ }
319
+ function schedComplete(reg, args) {
320
+ const { entries, matched } = (0, scheduling_1.leaseComplete)(reg.loadQueueEntries(), String(args.leaseId || ""), schedNow(args));
321
+ if (!matched)
322
+ throw new Error(`No active lease to complete: ${args.leaseId}`);
323
+ reg.saveQueueEntries(entries);
324
+ return { schemaVersion: 1, completed: String(args.leaseId || "") };
325
+ }
326
+ function schedReclaim(reg, args) {
327
+ const now = schedNow(args);
328
+ const { entries, reclaimed } = (0, scheduling_1.reclaimExpired)(reg.loadQueueEntries(), loadSchedulingPolicy(reg).policy, now);
329
+ reg.saveQueueEntries(entries);
330
+ return { schemaVersion: 1, now, reclaimed };
331
+ }
332
+ function schedReset(reg, args) {
333
+ const { entries, matched } = (0, scheduling_1.resetEntry)(reg.loadQueueEntries(), String(args.id || ""));
334
+ if (!matched)
335
+ throw new Error(`No parked entry to reset: ${args.id}`);
336
+ reg.saveQueueEntries(entries);
337
+ return { schemaVersion: 1, reset: String(args.id || "") };
338
+ }
339
+ function schedPolicyShow(reg) {
340
+ const { policy, source } = loadSchedulingPolicy(reg);
341
+ return { schemaVersion: 1, policy, source };
342
+ }
343
+ function schedPolicySet(reg, args) {
344
+ const current = loadSchedulingPolicy(reg).policy;
345
+ const patch = {};
346
+ for (const key of ["maxConcurrent", "maxAttempts", "leaseTtlMs", "backoffBaseMs", "backoffFactor", "backoffCapMs"]) {
347
+ if (args[key] !== undefined)
348
+ patch[key] = Number(args[key]);
349
+ }
350
+ const policy = (0, scheduling_1.normalizeSchedulingPolicy)({ ...current, ...patch });
351
+ (0, state_1.writeJson)(reg.schedulingPolicyPath(), policy);
352
+ return { schemaVersion: 1, policy, source: "file" };
353
+ }
354
+ // ---- agent delegation drive (v0.1.38) -------------------------------------
355
+ // MECHANISM, ONE SOURCE: both surfaces route drive/preview/config through these.
356
+ // The read-only preview + config-show payloads are deterministic (counts from
357
+ // state, host-stable config path) with NO now-derived numeric field, so
358
+ // `cw <cmd> --json` is byte-identical to `cw_<tool>`.
359
+ /** Read-only, deterministic preview of a run's NEXT drive step. */
360
+ function runDrivePreview(runner, args) {
361
+ return (0, drive_1.drivePreview)(runner, String(args.runId || ""), args);
362
+ }
363
+ const DRIVE_RUNTIME_KEYS = [
364
+ "once",
365
+ "now",
366
+ "preview",
367
+ "step",
368
+ "drive",
369
+ "json",
370
+ "format",
371
+ "run",
372
+ "runId",
373
+ "cwd",
374
+ "agentCommand",
375
+ "agent-command",
376
+ "agentArgs",
377
+ "agent-args",
378
+ "agentEndpoint",
379
+ "agent-endpoint",
380
+ "agentModel",
381
+ "agent-model",
382
+ "agentTimeoutMs",
383
+ "agent-timeout-ms"
384
+ ];
385
+ function planInputsFor(args) {
386
+ const copy = withoutRuntimeKeys(args);
387
+ for (const key of DRIVE_RUNTIME_KEYS)
388
+ delete copy[key];
389
+ return copy;
390
+ }
391
+ /** Mutating drive step/run. Plans a fresh run for an app id, or continues a run id.
392
+ * The agent hop goes ONLY through the agent backend; this composes existing verbs.
393
+ *
394
+ * The run lives under its repo's `.cw/` and every runner verb resolves a run from
395
+ * the process cwd, so the drive operates WITH the run's repo as cwd (exactly how
396
+ * the golden path runs each verb from the repo dir) — then restores cwd. This lets
397
+ * `cw run <app> --drive --repo X` work when invoked from anywhere. */
398
+ function runDrive(runner, args) {
399
+ const cwd0 = process.cwd();
400
+ try {
401
+ let runId = optionalString(args.runId || args.run);
402
+ let repoCwd = optionalString(args.repo);
403
+ if (!runId) {
404
+ const appId = String(args.appId || args.workflowId || args.app || "");
405
+ if (!appId)
406
+ throw new Error("run --drive requires an app id (or --run <run-id> to continue)");
407
+ const run = runner.plan(appId, planInputsFor(args));
408
+ runId = run.id;
409
+ repoCwd = run.cwd;
410
+ }
411
+ if (repoCwd && repoCwd !== process.cwd() && node_fs_1.default.existsSync(repoCwd))
412
+ process.chdir(repoCwd);
413
+ return (0, drive_1.drive)(runner, runId, { once: isTrue(args.once), now: optionalString(args.now), args });
414
+ }
415
+ finally {
416
+ if (process.cwd() !== cwd0)
417
+ process.chdir(cwd0);
418
+ }
419
+ }
420
+ /** The app the one-command quickstart plans when none is named. */
421
+ exports.QUICKSTART_DEFAULT_APP = "architecture-review";
422
+ /** ONE-COMMAND quickstart (v0.1.38+): plan(app) -> run --drive -> report in a single
423
+ * invocation, so a newcomer gets a cited risk report from one command on a target
424
+ * repo. This is a THIN UX wrapper — NOT a new engine: it composes the EXISTING
425
+ * `runDrive` core (which already plans the run, then delegates every worker to the
426
+ * configured agent backend and commits) and then writes the report. It introduces
427
+ * no second executor, queue, or scheduler, and imports no model SDK.
428
+ *
429
+ * RED LINE (DIRECTION.md): worker execution still DELEGATES to the operator's own
430
+ * agent backend (claude -p / codex exec / HTTP endpoint). With no agent configured
431
+ * the drive fails closed (status=blocked) and we never fabricate a completion. */
432
+ function quickstart(runner, args) {
433
+ const appId = String(args.appId || args.app || args.workflowId || exports.QUICKSTART_DEFAULT_APP);
434
+ const agentConfigured = Boolean((0, agent_config_1.resolveAgentConfig)(args).command || (0, agent_config_1.resolveAgentConfig)(args).endpoint);
435
+ // `--preview`: read-only, deterministic next-step projection (no spawn, no commit).
436
+ // Plan a fresh run (the read-only first verb) then project the next drive step.
437
+ if (isTrue(args.preview)) {
438
+ const cwd0 = process.cwd();
439
+ try {
440
+ let runId = optionalString(args.runId || args.run);
441
+ let repoCwd = optionalString(args.repo);
442
+ if (!runId) {
443
+ const run = runner.plan(appId, planInputsFor(args));
444
+ runId = run.id;
445
+ repoCwd = run.cwd;
446
+ }
447
+ if (repoCwd && repoCwd !== process.cwd() && node_fs_1.default.existsSync(repoCwd))
448
+ process.chdir(repoCwd);
449
+ return (0, drive_1.drivePreview)(runner, runId, args);
450
+ }
451
+ finally {
452
+ if (process.cwd() !== cwd0)
453
+ process.chdir(cwd0);
454
+ }
455
+ }
456
+ // Drive end-to-end (or one `--once` step). runDrive plans the run, delegates each
457
+ // worker to the agent backend, and commits — we add only the report write + a
458
+ // single assembled payload. No orchestration is duplicated here.
459
+ const result = runDrive(runner, { ...args, appId });
460
+ // Always (re)write the report so the one command yields a report.md on disk, even
461
+ // when the drive blocked/parked (a partial report is still useful triage).
462
+ const cwd0 = process.cwd();
463
+ let reportPath = result.reportPath;
464
+ try {
465
+ // runDrive restored cwd, so the runs root would resolve against the CALLER's
466
+ // cwd here — orphaning the run when quickstart is invoked cross-directory
467
+ // (cwd = plugin dir, --repo elsewhere: the README's headline command). The
468
+ // run's statePath (<repo>/.cw/runs/<id>/state.json) is authoritative however
469
+ // the run was planned or continued; chdir to ITS repo BEFORE any run read.
470
+ const runRepoCwd = node_path_1.default.resolve(node_path_1.default.dirname(result.statePath), "..", "..", "..");
471
+ if (runRepoCwd !== process.cwd() && node_fs_1.default.existsSync(runRepoCwd))
472
+ process.chdir(runRepoCwd);
473
+ reportPath = runner.report(result.runId).path;
474
+ }
475
+ finally {
476
+ if (process.cwd() !== cwd0)
477
+ process.chdir(cwd0);
478
+ }
479
+ let hint;
480
+ if (!agentConfigured) {
481
+ hint =
482
+ "agent backend not configured — set CW_AGENT_COMMAND (e.g. \"claude -p\") or pass --agent-command, then re-run. The one command DELEGATES worker execution to YOUR agent; it never executes a model itself.";
483
+ }
484
+ else if (result.status === "parked") {
485
+ hint = `a worker parked past its retry budget — inspect: cw run show ${result.runId}`;
486
+ }
487
+ else if (result.status === "blocked") {
488
+ hint = `the drive is blocked — inspect: cw run drive ${result.runId}`;
489
+ }
490
+ else if (result.status === "in-progress") {
491
+ hint = `one step advanced (--once) — continue: cw quickstart ${appId} --run ${result.runId} --once`;
492
+ }
493
+ return {
494
+ schemaVersion: 1,
495
+ appId,
496
+ runId: result.runId,
497
+ workflowId: result.workflowId,
498
+ status: result.status,
499
+ plannedWorkers: result.plannedWorkers,
500
+ completedWorkers: result.completedWorkers,
501
+ parkedWorkers: result.parkedWorkers,
502
+ commitId: result.commitId,
503
+ reportPath,
504
+ statePath: result.statePath,
505
+ agentConfigured,
506
+ steps: result.steps,
507
+ hint
508
+ };
509
+ }
510
+ /** Read-only, deterministic projection of the effective agent config (secret-stripped). */
511
+ function backendAgentConfigShow(args) {
512
+ return (0, agent_config_1.agentConfigShow)(args);
513
+ }
514
+ /** Persist the durable agent config (secret-stripped) and return the new state. */
515
+ function backendAgentConfigSet(args) {
516
+ (0, agent_config_1.setAgentConfigFile)(args);
517
+ return (0, agent_config_1.agentConfigShow)(args);
518
+ }
519
+ // ---- run retention & provable reclamation (v0.1.39) -----------------------
520
+ // MECHANISM, ONE SOURCE: both surfaces route gc plan/run/verify through these.
521
+ // `gc plan`/`gc verify` are read-only + deterministic (only `generatedAt` is
522
+ // now-derived ISO, allowed by the parity rule); `gc run` is the disk-freeing tier.
523
+ function reclaimPolicyFrom(args) {
524
+ const policy = {};
525
+ const days = Number(args.reclaimAfterArchiveDays ?? args["reclaim-after-archive-days"] ?? args.olderThanDays ?? args["older-than-days"]);
526
+ if (Number.isFinite(days))
527
+ policy.reclaimAfterArchiveDays = days;
528
+ const keepScratch = flag(args.keepScratch ?? args["keep-scratch"]);
529
+ if (keepScratch !== undefined)
530
+ policy.keepScratch = keepScratch;
531
+ const keepSnapshots = flag(args.keepSnapshots ?? args["keep-snapshots"]);
532
+ if (keepSnapshots !== undefined)
533
+ policy.keepSnapshots = keepSnapshots;
534
+ const maxRuns = Number(args.maxReclaimRuns ?? args["max-reclaim-runs"]);
535
+ if (Number.isFinite(maxRuns))
536
+ policy.maxReclaimRuns = maxRuns;
537
+ const maxBytes = Number(args.maxReclaimBytes ?? args["max-reclaim-bytes"]);
538
+ if (Number.isFinite(maxBytes))
539
+ policy.maxReclaimBytes = maxBytes;
540
+ const states = parseLifecycleList(args.state ?? args.status);
541
+ if (states.length)
542
+ policy.reclaimStates = states;
543
+ return policy;
544
+ }
545
+ function gcPlan(reg, runId, args) {
546
+ return reg.gcPlan({ scope: scopeOf(args, "home"), runId: runId || optionalString(args.runId), policy: reclaimPolicyFrom(args), now: optionalString(args.now) });
547
+ }
548
+ function gcRun(reg, runId, args) {
549
+ return reg.gcRun({
550
+ scope: scopeOf(args, "home"),
551
+ runId: runId || optionalString(args.runId),
552
+ policy: reclaimPolicyFrom(args),
553
+ now: optionalString(args.now),
554
+ actor: optionalString(args.actor),
555
+ limit: args.limit === undefined ? undefined : Number(args.limit)
556
+ });
557
+ }
558
+ function gcVerify(reg, runId, args) {
559
+ return reg.gcVerify(runId, { scope: scopeOf(args, "home") });
560
+ }
561
+ function runHistory(reg, args) {
562
+ return reg.history({
563
+ scope: scopeOf(args, "home"),
564
+ app: optionalString(args.app || args.appId),
565
+ status: lifecycleOf(args.status),
566
+ limit: args.limit === undefined ? undefined : Number(args.limit),
567
+ offset: args.offset === undefined ? undefined : Number(args.offset)
568
+ });
569
+ }
570
+ // ---- observability + cost accounting (v0.1.31) ----------------------------
571
+ // MECHANISM, ONE SOURCE: both `cw metrics summary --json` and `cw_metrics_summary`
572
+ // route through this function. It enumerates the v0.1.28 registry (derived live
573
+ // from source), loads each run's durable state, and DERIVES the cross-repo
574
+ // rollup. Runs whose source is unreadable are counted in `unreadableRuns` (fail
575
+ // closed), never silently dropped. Pricing is POLICY via `--pricing`; `now` is
576
+ // injectable via `args.now` for eval/replay determinism.
577
+ function metricsSummary(reg, runner, args) {
578
+ const scope = scopeOf(args, "repo");
579
+ const report = reg.show({ scope });
580
+ const policy = (0, observability_1.loadCostPolicy)(args, runner.pluginRoot);
581
+ const now = optionalString(args.now) || new Date().toISOString();
582
+ const inputs = [];
583
+ let unreadableRuns = 0;
584
+ for (const record of report.index.records) {
585
+ try {
586
+ const loaded = (0, state_1.loadRunStateFile)(record.statePath, { dryRun: true });
587
+ if (loaded.report.status === "unsupported") {
588
+ unreadableRuns++;
589
+ continue;
590
+ }
591
+ inputs.push({
592
+ run: loaded.run,
593
+ repo: record.repo,
594
+ persistedFingerprint: (0, observability_1.loadPersistedMetricsFingerprint)(loaded.run)
595
+ });
596
+ }
597
+ catch {
598
+ unreadableRuns++;
599
+ }
600
+ }
601
+ return (0, observability_1.deriveMetricsSummary)(inputs, { now, scope, policy, unreadableRuns });
602
+ }
603
+ function parseLifecycleList(value) {
604
+ const raw = Array.isArray(value) ? value : value === undefined ? [] : [value];
605
+ const out = [];
606
+ for (const item of raw) {
607
+ if ((0, run_registry_1.isRunLifecycleState)(item))
608
+ out.push(item);
609
+ }
610
+ return out;
611
+ }
612
+ // ---- shared argument helpers ----------------------------------------------
613
+ function sandboxProfileIdFrom(args) {
614
+ return optionalString(args.sandbox || args.sandboxProfile || args.sandboxProfileId || args.profileId);
615
+ }
616
+ function withoutRuntimeKeys(args) {
617
+ const copy = { ...args };
618
+ for (const key of ["appId", "workflowId", "inputs", "sandbox", "sandboxProfile", "sandboxProfileId", "profileId"]) {
619
+ delete copy[key];
620
+ }
621
+ return copy;
622
+ }
623
+ function optionalString(value) {
624
+ if (value === undefined || value === null || value === "")
625
+ return undefined;
626
+ return String(value);
627
+ }
628
+ function isRecord(value) {
629
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
630
+ }