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,463 @@
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.RUN_STATE_MIGRATIONS = void 0;
7
+ exports.findMigrationPath = findMigrationPath;
8
+ exports.migrateRunState = migrateRunState;
9
+ exports.reverseRunState = reverseRunState;
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const version_1 = require("./version");
12
+ const run_state_schema_1 = require("./run-state-schema");
13
+ exports.RUN_STATE_MIGRATIONS = [
14
+ {
15
+ from: version_1.LEGACY_RUN_STATE_SCHEMA_VERSION,
16
+ to: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION,
17
+ description: "Mark legacy run state without schemaVersion as run-state schema 1.",
18
+ migrate(state, context) {
19
+ setDefault(state, "schemaVersion", version_1.CURRENT_RUN_STATE_SCHEMA_VERSION, context, "legacy run state did not declare schemaVersion");
20
+ },
21
+ reverse(state, context) {
22
+ // Reverse: remove schemaVersion to return to legacy format.
23
+ // Only removes if the value equals CURRENT_RUN_STATE_SCHEMA_VERSION (fail-closed).
24
+ if (state.schemaVersion === version_1.CURRENT_RUN_STATE_SCHEMA_VERSION) {
25
+ delete state.schemaVersion;
26
+ context.changes.push({ path: "schemaVersion", before: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION, after: undefined, reason: "reverse: legacy run state unmarks schemaVersion" });
27
+ }
28
+ }
29
+ }
30
+ ];
31
+ // BSD discipline: mechanism — BFS shortest-path resolver over a directed graph of
32
+ // migration steps. Forward edges use `from -> to`; reverse edges use `to -> from`
33
+ // when a step has a `reverse()` function. Fail-closed: no path → named refusal.
34
+ function findMigrationPath(steps, fromVersion, toVersion) {
35
+ if (fromVersion === toVersion)
36
+ return { reachable: true, path: [] };
37
+ // Build adjacency: for each step, record forward (from->to) and optional reverse (to->from)
38
+ const forward = new Map();
39
+ const reverse = new Map();
40
+ for (const step of steps) {
41
+ if (!forward.has(step.from))
42
+ forward.set(step.from, []);
43
+ forward.get(step.from).push({ edge: step, reverse: false });
44
+ if (step.reverse) {
45
+ if (!reverse.has(step.to))
46
+ reverse.set(step.to, []);
47
+ reverse.get(step.to).push({ edge: step, reverse: true });
48
+ }
49
+ }
50
+ const visited = new Set();
51
+ const queue = [{ version: fromVersion, path: [] }];
52
+ visited.add(fromVersion);
53
+ while (queue.length > 0) {
54
+ const current = queue.shift();
55
+ // Try forward moves
56
+ const fwd = forward.get(current.version) || [];
57
+ for (const move of fwd) {
58
+ const next = move.edge.to;
59
+ if (next === toVersion)
60
+ return { reachable: true, path: [...current.path, { edge: move.edge, reverse: false }] };
61
+ if (!visited.has(next)) {
62
+ visited.add(next);
63
+ queue.push({ version: next, path: [...current.path, { edge: move.edge, reverse: false }] });
64
+ }
65
+ }
66
+ // Try reverse moves (only when reverse() is defined on the step)
67
+ const rev = reverse.get(current.version) || [];
68
+ for (const move of rev) {
69
+ const next = move.edge.from; // reverse direction
70
+ if (next === toVersion)
71
+ return { reachable: true, path: [...current.path, { edge: move.edge, reverse: true }] };
72
+ if (!visited.has(next)) {
73
+ visited.add(next);
74
+ queue.push({ version: next, path: [...current.path, { edge: move.edge, reverse: true }] });
75
+ }
76
+ }
77
+ }
78
+ return { reachable: false, path: [], error: `no migration path from schemaVersion ${fromVersion} to ${toVersion}` };
79
+ }
80
+ function migrateRunState(input, options = {}) {
81
+ const report = {
82
+ status: "current",
83
+ statePath: options.statePath,
84
+ detectedSchemaVersion: detectSchemaVersion(input),
85
+ currentSchemaVersion: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION,
86
+ supportedSchemaVersions: {
87
+ min: version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION,
88
+ max: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION
89
+ },
90
+ dryRun: Boolean(options.dryRun),
91
+ writeRequired: false,
92
+ changes: [],
93
+ warnings: [],
94
+ errors: []
95
+ };
96
+ if (!isRecord(input)) {
97
+ report.status = "unsupported";
98
+ report.errors.push("Run state must be a JSON object.");
99
+ return { run: {}, report };
100
+ }
101
+ if (report.detectedSchemaVersion < version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION) {
102
+ report.status = "unsupported";
103
+ report.errors.push(`Unsupported run-state schemaVersion ${schemaVersionDescription(input, report.detectedSchemaVersion)}.`);
104
+ return { run: clone(input), report };
105
+ }
106
+ if (report.detectedSchemaVersion > version_1.CURRENT_RUN_STATE_SCHEMA_VERSION) {
107
+ report.status = "unsupported";
108
+ report.errors.push(`Run state schemaVersion ${schemaVersionDescription(input, report.detectedSchemaVersion)} is newer than this CW runtime (${version_1.CURRENT_RUN_STATE_SCHEMA_VERSION}).`);
109
+ return { run: clone(input), report };
110
+ }
111
+ const state = clone(input);
112
+ const context = { statePath: options.statePath, changes: report.changes, errors: report.errors };
113
+ const resolved = findMigrationPath(exports.RUN_STATE_MIGRATIONS, report.detectedSchemaVersion, version_1.CURRENT_RUN_STATE_SCHEMA_VERSION);
114
+ if (!resolved.reachable) {
115
+ report.status = "unsupported";
116
+ report.errors.push(resolved.error || `No migration path from run-state schemaVersion ${report.detectedSchemaVersion}.`);
117
+ return { run: state, report };
118
+ }
119
+ for (const step of resolved.path) {
120
+ if (step.reverse) {
121
+ step.edge.reverse(state, context);
122
+ }
123
+ else {
124
+ step.edge.migrate(state, context);
125
+ }
126
+ }
127
+ normalizeRunState(state, context);
128
+ validateMigratedRunState(state, report);
129
+ report.writeRequired = report.changes.length > 0;
130
+ if (report.errors.length > 0)
131
+ report.status = "unsupported";
132
+ else if (report.detectedSchemaVersion < version_1.CURRENT_RUN_STATE_SCHEMA_VERSION)
133
+ report.status = "migrated";
134
+ else if (report.changes.length > 0)
135
+ report.status = "normalized";
136
+ else
137
+ report.status = "current";
138
+ return { run: state, report };
139
+ }
140
+ // BSD discipline: mechanism — reverse migration along the DAG graph. The caller
141
+ // supplies a target version; the graph resolver finds a path (which may include
142
+ // forward steps AND reverse steps). Fail-closed: no path => named refusal.
143
+ // POLICY (kept out of the kernel): whether to reverse, and to which version.
144
+ function reverseRunState(input, targetSchemaVersion, options = {}) {
145
+ const report = {
146
+ status: "current",
147
+ statePath: options.statePath,
148
+ detectedSchemaVersion: detectSchemaVersion(input),
149
+ currentSchemaVersion: targetSchemaVersion,
150
+ supportedSchemaVersions: {
151
+ min: version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION,
152
+ max: version_1.CURRENT_RUN_STATE_SCHEMA_VERSION
153
+ },
154
+ dryRun: Boolean(options.dryRun),
155
+ writeRequired: false,
156
+ changes: [],
157
+ warnings: [],
158
+ errors: []
159
+ };
160
+ if (!isRecord(input)) {
161
+ report.status = "unsupported";
162
+ report.errors.push("Run state must be a JSON object.");
163
+ return { run: {}, report };
164
+ }
165
+ if (targetSchemaVersion < version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION) {
166
+ report.status = "unsupported";
167
+ report.errors.push(`Target schemaVersion ${targetSchemaVersion} is below the minimum supported ${version_1.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION}.`);
168
+ return { run: clone(input), report };
169
+ }
170
+ if (targetSchemaVersion > version_1.CURRENT_RUN_STATE_SCHEMA_VERSION) {
171
+ report.status = "unsupported";
172
+ report.errors.push(`Target schemaVersion ${targetSchemaVersion} is newer than this CW runtime (${version_1.CURRENT_RUN_STATE_SCHEMA_VERSION}).`);
173
+ return { run: clone(input), report };
174
+ }
175
+ const state = clone(input);
176
+ const context = { statePath: options.statePath, changes: report.changes, errors: report.errors };
177
+ const resolved = findMigrationPath(exports.RUN_STATE_MIGRATIONS, report.detectedSchemaVersion, targetSchemaVersion);
178
+ if (!resolved.reachable) {
179
+ report.status = "unsupported";
180
+ report.errors.push(resolved.error || `No reverse path from schemaVersion ${report.detectedSchemaVersion} to ${targetSchemaVersion}.`);
181
+ return { run: state, report };
182
+ }
183
+ // Apply each step along the path; reverse=true calls edge.reverse(), false calls edge.migrate()
184
+ for (const step of resolved.path) {
185
+ if (step.reverse) {
186
+ step.edge.reverse(state, context);
187
+ }
188
+ else {
189
+ step.edge.migrate(state, context);
190
+ }
191
+ }
192
+ // warn on destructive changes (reverse steps that mutate or remove data)
193
+ for (const change of report.changes) {
194
+ if (change.after === undefined && change.before !== undefined) {
195
+ report.warnings.push(`Destructive reverse change at ${change.path}: removed ${JSON.stringify(change.before)}`);
196
+ }
197
+ }
198
+ report.writeRequired = report.changes.length > 0;
199
+ if (report.errors.length > 0)
200
+ report.status = "unsupported";
201
+ else if (report.detectedSchemaVersion !== targetSchemaVersion)
202
+ report.status = "migrated";
203
+ else if (report.changes.length > 0)
204
+ report.status = "normalized";
205
+ else
206
+ report.status = "current";
207
+ return { run: state, report };
208
+ }
209
+ function normalizeRunState(state, context) {
210
+ const runDir = context.statePath ? node_path_1.default.dirname(context.statePath) : undefined;
211
+ const id = stringValue(state.id) || (runDir ? node_path_1.default.basename(runDir) : "unknown-run");
212
+ const now = new Date(0).toISOString();
213
+ setDefault(state, "id", id, context, "run id is required");
214
+ setDefault(state, "createdAt", stringValue(state.updatedAt) || now, context, "createdAt is required");
215
+ setDefault(state, "updatedAt", stringValue(state.createdAt) || now, context, "updatedAt is required");
216
+ setDefault(state, "cwd", runDir ? node_path_1.default.resolve(runDir, "..", "..", "..") : process.cwd(), context, "cwd is required");
217
+ setDefault(state, "inputs", {}, context, "inputs must be present");
218
+ setDefault(state, "loopStage", "interpret", context, "loopStage is required");
219
+ if (!isLoopStage(state.loopStage))
220
+ setValue(state, "loopStage", "interpret", context, "unsupported loopStage normalized");
221
+ const workflow = ensureRecord(state, "workflow", context, "workflow metadata is required");
222
+ setDefault(workflow, "id", stringValue(state.workflowId) || "unknown-workflow", context, "workflow.id is required", "workflow.id");
223
+ setDefault(workflow, "title", titleize(String(workflow.id)), context, "workflow.title is required", "workflow.title");
224
+ setDefault(workflow, "summary", "", context, "workflow.summary is required", "workflow.summary");
225
+ setDefault(workflow, "limits", { maxAgents: 8, maxConcurrentAgents: 4 }, context, "workflow.limits is required", "workflow.limits");
226
+ const paths = ensureRecord(state, "paths", context, "run paths are required");
227
+ const baseRunDir = stringValue(paths.runDir) || runDir || node_path_1.default.join(String(state.cwd), ".cw", "runs", id);
228
+ setDefault(paths, "runDir", baseRunDir, context, "paths.runDir is required", "paths.runDir");
229
+ setDefault(paths, "state", node_path_1.default.join(baseRunDir, "state.json"), context, "paths.state is required", "paths.state");
230
+ setDefault(paths, "report", node_path_1.default.join(baseRunDir, "report.md"), context, "paths.report is required", "paths.report");
231
+ setDefault(paths, "tasksDir", node_path_1.default.join(baseRunDir, "tasks"), context, "paths.tasksDir is required", "paths.tasksDir");
232
+ setDefault(paths, "resultsDir", node_path_1.default.join(baseRunDir, "results"), context, "paths.resultsDir is required", "paths.resultsDir");
233
+ setDefault(paths, "dispatchesDir", node_path_1.default.join(baseRunDir, "dispatches"), context, "paths.dispatchesDir is required", "paths.dispatchesDir");
234
+ setDefault(paths, "artifactsDir", node_path_1.default.join(baseRunDir, "artifacts"), context, "paths.artifactsDir is required", "paths.artifactsDir");
235
+ setDefault(paths, "commitsDir", node_path_1.default.join(baseRunDir, "commits"), context, "paths.commitsDir is required", "paths.commitsDir");
236
+ setDefault(paths, "stateNodesDir", node_path_1.default.join(baseRunDir, "nodes"), context, "paths.stateNodesDir is required", "paths.stateNodesDir");
237
+ setDefault(paths, "feedbackDir", node_path_1.default.join(baseRunDir, "feedback"), context, "paths.feedbackDir is required", "paths.feedbackDir");
238
+ setDefault(paths, "auditDir", node_path_1.default.join(baseRunDir, "audit"), context, "paths.auditDir is required", "paths.auditDir");
239
+ setDefault(paths, "workersDir", node_path_1.default.join(baseRunDir, "workers"), context, "paths.workersDir is required", "paths.workersDir");
240
+ setDefault(paths, "candidatesDir", node_path_1.default.join(baseRunDir, "candidates"), context, "paths.candidatesDir is required", "paths.candidatesDir");
241
+ setDefault(paths, "multiAgentDir", node_path_1.default.join(baseRunDir, "multi-agent"), context, "paths.multiAgentDir is required", "paths.multiAgentDir");
242
+ setDefault(paths, "blackboardDir", node_path_1.default.join(baseRunDir, "blackboard"), context, "paths.blackboardDir is required", "paths.blackboardDir");
243
+ setDefault(paths, "topologiesDir", node_path_1.default.join(baseRunDir, "topologies"), context, "paths.topologiesDir is required", "paths.topologiesDir");
244
+ ensureArray(state, "tasks", context);
245
+ ensureArray(state, "dispatches", context);
246
+ ensureArray(state, "commits", context);
247
+ ensureArray(state, "nodes", context);
248
+ ensureArray(state, "contracts", context);
249
+ ensureArray(state, "feedback", context);
250
+ if (!isRecord(state.audit)) {
251
+ if (state.audit !== undefined)
252
+ context.errors.push("audit must be an object when present.");
253
+ setValue(state, "audit", {
254
+ schemaVersion: 1,
255
+ eventLogPath: node_path_1.default.join(String(paths.auditDir), "events.jsonl"),
256
+ summaryPath: node_path_1.default.join(String(paths.auditDir), "summary.json"),
257
+ indexPath: node_path_1.default.join(String(paths.auditDir), "index.json")
258
+ }, context, "audit metadata is required");
259
+ }
260
+ ensureArray(state, "workers", context);
261
+ ensureArray(state, "sandboxProfiles", context);
262
+ ensureArray(state, "candidates", context);
263
+ ensureArray(state, "candidateSelections", context);
264
+ if (!isRecord(state.multiAgent)) {
265
+ if (state.multiAgent !== undefined)
266
+ context.errors.push("multiAgent must be an object when present.");
267
+ setValue(state, "multiAgent", {
268
+ schemaVersion: 1,
269
+ runs: [],
270
+ roles: [],
271
+ groups: [],
272
+ memberships: [],
273
+ fanouts: [],
274
+ fanins: []
275
+ }, context, "multiAgent state is required");
276
+ }
277
+ else {
278
+ const multiAgent = state.multiAgent;
279
+ setDefault(multiAgent, "schemaVersion", 1, context, "multiAgent.schemaVersion is required", "multiAgent.schemaVersion");
280
+ for (const key of ["runs", "roles", "groups", "memberships", "fanouts", "fanins"]) {
281
+ if (!Array.isArray(multiAgent[key])) {
282
+ if (multiAgent[key] !== undefined)
283
+ context.errors.push(`multiAgent.${key} must be an array when present.`);
284
+ setValue(multiAgent, key, [], context, `multiAgent.${key} must be an array`, `multiAgent.${key}`);
285
+ }
286
+ }
287
+ }
288
+ if (!isRecord(state.blackboard)) {
289
+ if (state.blackboard !== undefined)
290
+ context.errors.push("blackboard must be an object when present.");
291
+ setValue(state, "blackboard", {
292
+ schemaVersion: 1,
293
+ boards: [],
294
+ topics: [],
295
+ messages: [],
296
+ contexts: [],
297
+ artifacts: [],
298
+ snapshots: [],
299
+ decisions: []
300
+ }, context, "blackboard state is required");
301
+ }
302
+ else {
303
+ const blackboard = state.blackboard;
304
+ setDefault(blackboard, "schemaVersion", 1, context, "blackboard.schemaVersion is required", "blackboard.schemaVersion");
305
+ for (const key of ["boards", "topics", "messages", "contexts", "artifacts", "snapshots", "decisions"]) {
306
+ if (!Array.isArray(blackboard[key])) {
307
+ if (blackboard[key] !== undefined)
308
+ context.errors.push(`blackboard.${key} must be an array when present.`);
309
+ setValue(blackboard, key, [], context, `blackboard.${key} must be an array`, `blackboard.${key}`);
310
+ }
311
+ }
312
+ }
313
+ if (!isRecord(state.topologies)) {
314
+ if (state.topologies !== undefined)
315
+ context.errors.push("topologies must be an object when present.");
316
+ setValue(state, "topologies", {
317
+ schemaVersion: 1,
318
+ runs: []
319
+ }, context, "topologies state is required");
320
+ }
321
+ else {
322
+ const topologies = state.topologies;
323
+ setDefault(topologies, "schemaVersion", 1, context, "topologies.schemaVersion is required", "topologies.schemaVersion");
324
+ if (!Array.isArray(topologies.runs)) {
325
+ if (topologies.runs !== undefined)
326
+ context.errors.push("topologies.runs must be an array when present.");
327
+ setValue(topologies, "runs", [], context, "topologies.runs must be an array", "topologies.runs");
328
+ }
329
+ }
330
+ // Team Collaboration (v0.1.32) is purely additive: pre-v0.1.32 runs carry no
331
+ // `collaboration` and load unchanged (absent => no approvals, no review gate).
332
+ // When present, normalize its append-only arrays so a partial object is honest.
333
+ if (state.collaboration !== undefined) {
334
+ if (!isRecord(state.collaboration)) {
335
+ context.errors.push("collaboration must be an object when present.");
336
+ setValue(state, "collaboration", { schemaVersion: 1, approvals: [], comments: [], handoffs: [] }, context, "collaboration must be an object");
337
+ }
338
+ else {
339
+ const collaboration = state.collaboration;
340
+ setDefault(collaboration, "schemaVersion", 1, context, "collaboration.schemaVersion is required", "collaboration.schemaVersion");
341
+ for (const key of ["approvals", "comments", "handoffs"]) {
342
+ if (!Array.isArray(collaboration[key])) {
343
+ if (collaboration[key] !== undefined)
344
+ context.errors.push(`collaboration.${key} must be an array when present.`);
345
+ setValue(collaboration, key, [], context, `collaboration.${key} must be an array`, `collaboration.${key}`);
346
+ }
347
+ }
348
+ }
349
+ }
350
+ if (!Array.isArray(state.phases)) {
351
+ if (state.phases !== undefined)
352
+ context.errors.push("phases must be an array when present.");
353
+ const phases = derivePhases(Array.isArray(state.tasks) ? state.tasks : []);
354
+ setValue(state, "phases", phases, context, "phases derived from tasks");
355
+ }
356
+ }
357
+ function validateMigratedRunState(state, report) {
358
+ for (const key of run_state_schema_1.REQUIRED_TOP_LEVEL_KEYS) {
359
+ if (!(key in state))
360
+ report.errors.push(`Missing required run-state field: ${key}.`);
361
+ }
362
+ if (state.schemaVersion !== version_1.CURRENT_RUN_STATE_SCHEMA_VERSION) {
363
+ report.errors.push(`Expected schemaVersion ${version_1.CURRENT_RUN_STATE_SCHEMA_VERSION}; found ${String(state.schemaVersion)}.`);
364
+ }
365
+ for (const key of run_state_schema_1.REQUIRED_RECORD_KEYS) {
366
+ if (key in state && !isRecord(state[key]))
367
+ report.errors.push(`${key} must be an object.`);
368
+ }
369
+ for (const key of run_state_schema_1.REQUIRED_ARRAY_KEYS) {
370
+ if (!Array.isArray(state[key]))
371
+ report.errors.push(`${key} must be an array.`);
372
+ }
373
+ }
374
+ function detectSchemaVersion(value) {
375
+ if (!isRecord(value) || value.schemaVersion === undefined)
376
+ return version_1.LEGACY_RUN_STATE_SCHEMA_VERSION;
377
+ if (!Number.isInteger(value.schemaVersion))
378
+ return Number.POSITIVE_INFINITY;
379
+ return Number(value.schemaVersion);
380
+ }
381
+ function schemaVersionDescription(input, detected) {
382
+ if (!isRecord(input))
383
+ return "non-object";
384
+ if (input.schemaVersion === undefined)
385
+ return String(version_1.LEGACY_RUN_STATE_SCHEMA_VERSION);
386
+ if (Number.isFinite(detected))
387
+ return String(detected);
388
+ return `invalid (${typeof input.schemaVersion}: ${String(input.schemaVersion)})`;
389
+ }
390
+ function ensureRecord(state, key, context, reason) {
391
+ if (isRecord(state[key]))
392
+ return state[key];
393
+ if (state[key] !== undefined)
394
+ context.errors.push(`${key} must be an object when present.`);
395
+ setValue(state, key, {}, context, reason);
396
+ return state[key];
397
+ }
398
+ function ensureArray(state, key, context) {
399
+ if (Array.isArray(state[key]))
400
+ return;
401
+ if (state[key] !== undefined)
402
+ context.errors.push(`${key} must be an array when present.`);
403
+ setValue(state, key, [], context, `${key} must be an array`);
404
+ }
405
+ function setDefault(state, key, value, context, reason, reportPath = key) {
406
+ if (state[key] !== undefined)
407
+ return;
408
+ setValue(state, key, value, context, reason, reportPath);
409
+ }
410
+ function setValue(state, key, value, context, reason, reportPath = key) {
411
+ const before = state[key];
412
+ state[key] = value;
413
+ context.changes.push({ path: reportPath, before, after: value, reason });
414
+ }
415
+ function derivePhases(tasks) {
416
+ const byPhase = new Map();
417
+ for (const task of tasks) {
418
+ if (!isRecord(task))
419
+ continue;
420
+ const phase = stringValue(task.phase) || "Workflow";
421
+ const taskId = stringValue(task.id);
422
+ if (!taskId)
423
+ continue;
424
+ byPhase.set(phase, [...(byPhase.get(phase) || []), taskId]);
425
+ }
426
+ if (byPhase.size === 0)
427
+ return [];
428
+ return Array.from(byPhase.entries()).map(([name, taskIds]) => ({
429
+ id: slugify(name),
430
+ name,
431
+ status: tasksForPhaseCompleted(tasks, taskIds) ? "completed" : "pending",
432
+ taskIds
433
+ }));
434
+ }
435
+ function tasksForPhaseCompleted(tasks, taskIds) {
436
+ return taskIds.every((taskId) => {
437
+ const task = tasks.find((candidate) => isRecord(candidate) && candidate.id === taskId);
438
+ return isRecord(task) && task.status === "completed";
439
+ });
440
+ }
441
+ function titleize(value) {
442
+ return value
443
+ .split(/[-_\s]+/g)
444
+ .filter(Boolean)
445
+ .map((part) => part.slice(0, 1).toUpperCase() + part.slice(1))
446
+ .join(" ") || "Workflow";
447
+ }
448
+ function slugify(value) {
449
+ const slug = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
450
+ return slug || "workflow";
451
+ }
452
+ function stringValue(value) {
453
+ return typeof value === "string" && value.trim() ? value : undefined;
454
+ }
455
+ function isLoopStage(value) {
456
+ return ["interpret", "act", "observe", "adjust", "checkpoint"].includes(String(value));
457
+ }
458
+ function isRecord(value) {
459
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
460
+ }
461
+ function clone(value) {
462
+ return JSON.parse(JSON.stringify(value));
463
+ }