cool-workflow 0.1.80 → 0.1.82

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 (122) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +42 -2
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +1 -1
  6. package/apps/end-to-end-golden-path/app.json +1 -1
  7. package/apps/pr-review-fix-ci/app.json +1 -1
  8. package/apps/release-cut/app.json +1 -1
  9. package/apps/research-synthesis/app.json +1 -1
  10. package/dist/agent-config.js +21 -7
  11. package/dist/candidate-scoring.js +62 -48
  12. package/dist/capability-core.js +152 -96
  13. package/dist/capability-registry.js +160 -174
  14. package/dist/cli.js +90 -100
  15. package/dist/collaboration.js +5 -6
  16. package/dist/commit.js +232 -209
  17. package/dist/compare.js +18 -0
  18. package/dist/coordinator/classify.js +45 -0
  19. package/dist/coordinator/paths.js +42 -0
  20. package/dist/coordinator/util.js +126 -0
  21. package/dist/coordinator.js +127 -300
  22. package/dist/dispatch.js +46 -3
  23. package/dist/drive.js +7 -7
  24. package/dist/error-feedback.js +8 -4
  25. package/dist/evidence-reasoning.js +5 -2
  26. package/dist/execution-backend/agent.js +294 -0
  27. package/dist/execution-backend/probes.js +96 -0
  28. package/dist/execution-backend/util.js +47 -0
  29. package/dist/execution-backend.js +77 -450
  30. package/dist/gates.js +48 -0
  31. package/dist/mcp-server.js +34 -173
  32. package/dist/multi-agent/graph.js +84 -0
  33. package/dist/multi-agent/helpers.js +141 -0
  34. package/dist/multi-agent/ids.js +20 -0
  35. package/dist/multi-agent/paths.js +22 -0
  36. package/dist/multi-agent-eval/format.js +194 -0
  37. package/dist/multi-agent-eval/normalize.js +51 -0
  38. package/dist/multi-agent-eval.js +63 -242
  39. package/dist/multi-agent-host.js +53 -40
  40. package/dist/multi-agent-operator-ux.js +2 -1
  41. package/dist/multi-agent-trust.js +5 -5
  42. package/dist/multi-agent.js +125 -314
  43. package/dist/node-projection.js +59 -0
  44. package/dist/node-snapshot.js +11 -21
  45. package/dist/observability/format.js +61 -0
  46. package/dist/observability/intake.js +98 -0
  47. package/dist/observability.js +14 -160
  48. package/dist/operator-ux/format.js +364 -0
  49. package/dist/operator-ux.js +22 -363
  50. package/dist/orchestrator/lifecycle-operations.js +22 -1
  51. package/dist/orchestrator/report.js +8 -0
  52. package/dist/orchestrator.js +41 -10
  53. package/dist/reclamation.js +32 -55
  54. package/dist/run-export.js +138 -14
  55. package/dist/run-registry/derive.js +172 -0
  56. package/dist/run-registry/format.js +124 -0
  57. package/dist/run-registry/gc.js +251 -0
  58. package/dist/run-registry/policy.js +16 -0
  59. package/dist/run-registry/queue.js +116 -0
  60. package/dist/run-registry.js +78 -593
  61. package/dist/run-state-schema.js +1 -0
  62. package/dist/sandbox-profile.js +43 -2
  63. package/dist/scheduler.js +34 -4
  64. package/dist/state-explosion/format.js +159 -0
  65. package/dist/state-explosion/helpers.js +82 -0
  66. package/dist/state-explosion.js +65 -283
  67. package/dist/state-node.js +19 -4
  68. package/dist/telemetry-attestation.js +55 -0
  69. package/dist/telemetry-demo.js +15 -3
  70. package/dist/telemetry-ledger.js +60 -15
  71. package/dist/topology.js +50 -12
  72. package/dist/triggers.js +33 -14
  73. package/dist/trust-audit.js +215 -71
  74. package/dist/validation.js +328 -0
  75. package/dist/version.js +1 -1
  76. package/dist/worker-isolation/helpers.js +51 -0
  77. package/dist/worker-isolation/paths.js +46 -0
  78. package/dist/worker-isolation.js +182 -173
  79. package/docs/agent-delegation-drive.7.md +14 -0
  80. package/docs/cli-mcp-parity.7.md +5 -0
  81. package/docs/contract-migration-tooling.7.md +3 -0
  82. package/docs/control-plane-scheduling.7.md +3 -0
  83. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  84. package/docs/durable-state-and-locking.7.md +5 -0
  85. package/docs/evidence-adoption-reasoning-chain.7.md +3 -0
  86. package/docs/execution-backends.7.md +3 -0
  87. package/docs/index.md +1 -0
  88. package/docs/launch/launch-kit.md +46 -23
  89. package/docs/launch/pre-launch-checklist.md +14 -14
  90. package/docs/multi-agent-cli-mcp-surface.7.md +5 -0
  91. package/docs/multi-agent-eval-replay-harness.7.md +3 -0
  92. package/docs/multi-agent-operator-ux.7.md +3 -0
  93. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  94. package/docs/node-snapshot-diff-replay.7.md +3 -0
  95. package/docs/observability-cost-accounting.7.md +3 -0
  96. package/docs/project-index.md +23 -6
  97. package/docs/real-execution-backends.7.md +3 -0
  98. package/docs/release-and-migration.7.md +5 -0
  99. package/docs/release-tooling.7.md +35 -2
  100. package/docs/run-registry-control-plane.7.md +55 -8
  101. package/docs/run-retention-reclamation.7.md +5 -0
  102. package/docs/state-explosion-management.7.md +3 -0
  103. package/docs/team-collaboration.7.md +3 -0
  104. package/docs/trust-model.md +267 -0
  105. package/docs/vendor-manifest-loadability.7.md +43 -0
  106. package/docs/web-desktop-workbench.7.md +3 -0
  107. package/manifest/plugin.manifest.json +1 -1
  108. package/manifest/source-context-profiles.json +1 -1
  109. package/package.json +4 -2
  110. package/scripts/agents/builtin-templates.json +7 -0
  111. package/scripts/bump-version.js +5 -11
  112. package/scripts/canonical-apps-list.js +64 -0
  113. package/scripts/canonical-apps.js +19 -4
  114. package/scripts/children/batch-delegate-child.js +58 -0
  115. package/scripts/children/http-delegate-child.js +39 -0
  116. package/scripts/dogfood-release.js +1 -1
  117. package/scripts/golden-path.js +4 -4
  118. package/scripts/parity-check.js +5 -0
  119. package/scripts/release-check.js +5 -1
  120. package/scripts/release-flow.js +181 -5
  121. package/scripts/version-sync-check.js +5 -8
  122. package/dist/capability-dispatcher.js +0 -86
@@ -0,0 +1,328 @@
1
+ "use strict";
2
+ // Fail-closed shape guards for persisted per-record types (F5, integrity boundary).
3
+ //
4
+ // `JSON.parse(...) as T` is a LIE: the cast asserts a shape TypeScript never
5
+ // checked at runtime, so a corrupt/forged/old-schema record flows in as if it
6
+ // were a valid T and is used/upserted unvalidated. These guards re-establish the
7
+ // integrity boundary at the read edge: after parse, the raw value is structurally
8
+ // validated against the type def in src/types/* BEFORE it is trusted.
9
+ //
10
+ // Two callers, two error semantics — both fail closed, neither fabricates:
11
+ // - validate*() throw a descriptive Error on mismatch (for readers that
12
+ // already let parse errors propagate / require the record).
13
+ // - tryValidate*() return null on mismatch (for best-effort readers that
14
+ // swallow parse errors and SKIP the record — the downstream
15
+ // gate then fails closed on the absence). Never throws.
16
+ //
17
+ // Dependency-light by construction: imports ONLY from ./types. No fs, no clock,
18
+ // no randomness — pure structural checks, safe in replay/core paths.
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.RecordValidationError = void 0;
21
+ exports.validateWorkerScope = validateWorkerScope;
22
+ exports.tryValidateWorkerScope = tryValidateWorkerScope;
23
+ exports.validateNodeSnapshot = validateNodeSnapshot;
24
+ exports.tryValidateNodeSnapshot = tryValidateNodeSnapshot;
25
+ exports.validateNodeReplayRun = validateNodeReplayRun;
26
+ exports.tryValidateNodeReplayRun = tryValidateNodeReplayRun;
27
+ exports.validateCandidateScore = validateCandidateScore;
28
+ exports.tryValidateCandidateScore = tryValidateCandidateScore;
29
+ exports.validateCandidateRecord = validateCandidateRecord;
30
+ exports.tryValidateCandidateRecord = tryValidateCandidateRecord;
31
+ // ---------------------------------------------------------------------------
32
+ // Primitive predicates — small, total, never throw.
33
+ // ---------------------------------------------------------------------------
34
+ function isRecord(value) {
35
+ return value !== null && typeof value === "object" && !Array.isArray(value);
36
+ }
37
+ function isString(value) {
38
+ return typeof value === "string";
39
+ }
40
+ function isFiniteNumber(value) {
41
+ return typeof value === "number" && Number.isFinite(value);
42
+ }
43
+ function isStringArray(value) {
44
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
45
+ }
46
+ function isObjectArray(value) {
47
+ return Array.isArray(value) && value.every((entry) => isRecord(entry));
48
+ }
49
+ const WORKER_STATUSES = new Set([
50
+ "allocated",
51
+ "running",
52
+ "completed",
53
+ "failed",
54
+ "rejected",
55
+ "verified",
56
+ "orphaned"
57
+ ]);
58
+ const SCORE_VERDICTS = new Set(["pass", "warn", "fail"]);
59
+ const CANDIDATE_STATUSES = new Set([
60
+ "registered",
61
+ "scored",
62
+ "selected",
63
+ "rejected",
64
+ "verified",
65
+ "failed"
66
+ ]);
67
+ const CANDIDATE_KINDS = new Set(["worker-output", "result", "artifact", "manual", "release"]);
68
+ const SNAPSHOT_FRESHNESS = new Set(["valid", "stale", "absent"]);
69
+ /** Descriptive integrity error — the message names the type and the field that
70
+ * broke, so a corrupt record is diagnosable from logs alone. */
71
+ class RecordValidationError extends Error {
72
+ code = "record-shape-invalid";
73
+ typeName;
74
+ field;
75
+ constructor(typeName, reason, field) {
76
+ super(`Invalid persisted ${typeName}: ${reason}`);
77
+ this.name = "RecordValidationError";
78
+ this.typeName = typeName;
79
+ this.field = field;
80
+ }
81
+ }
82
+ exports.RecordValidationError = RecordValidationError;
83
+ // ---------------------------------------------------------------------------
84
+ // WorkerScope — worker-isolation.ts:309 / :905
85
+ // Required (per src/types/worker.ts WorkerScope): schemaVersion===1, id, runId,
86
+ // taskId, createdAt, updatedAt, status (enum), workerDir, inputPath, resultPath,
87
+ // artifactsDir, logsDir are strings; allowedPaths string[]; feedbackIds string[];
88
+ // errors object[]. Optional fields are not enforced (additive, may be absent).
89
+ // ---------------------------------------------------------------------------
90
+ function workerScopeReason(value) {
91
+ if (!isRecord(value))
92
+ return { reason: "not an object" };
93
+ if (value.schemaVersion !== 1)
94
+ return { field: "schemaVersion", reason: "must equal 1" };
95
+ const requiredStrings = [
96
+ "id",
97
+ "runId",
98
+ "taskId",
99
+ "createdAt",
100
+ "updatedAt",
101
+ "workerDir",
102
+ "inputPath",
103
+ "resultPath",
104
+ "artifactsDir",
105
+ "logsDir"
106
+ ];
107
+ for (const field of requiredStrings) {
108
+ if (!isString(value[field]))
109
+ return { field: field, reason: "must be a string" };
110
+ }
111
+ if (!isString(value.status) || !WORKER_STATUSES.has(value.status)) {
112
+ return { field: "status", reason: "must be a valid WorkerIsolationStatus" };
113
+ }
114
+ if (!isStringArray(value.allowedPaths))
115
+ return { field: "allowedPaths", reason: "must be a string[]" };
116
+ if (!isStringArray(value.feedbackIds))
117
+ return { field: "feedbackIds", reason: "must be a string[]" };
118
+ if (!isObjectArray(value.errors))
119
+ return { field: "errors", reason: "must be a StateNodeError[]" };
120
+ return undefined;
121
+ }
122
+ /** Throw-on-mismatch guard for WorkerScope (callers that require the record). */
123
+ function validateWorkerScope(value) {
124
+ const problem = workerScopeReason(value);
125
+ if (problem)
126
+ throw new RecordValidationError("WorkerScope", problem.reason, problem.field);
127
+ return value;
128
+ }
129
+ /** Best-effort variant: returns null on mismatch (caller skips the record). */
130
+ function tryValidateWorkerScope(value) {
131
+ return workerScopeReason(value) ? null : value;
132
+ }
133
+ // ---------------------------------------------------------------------------
134
+ // NodeSnapshotBody — shared by NodeSnapshot.body and NodeReplayRun.body.
135
+ // Required (per src/types/state-node.ts): id, kind, status, loopStage strings;
136
+ // inputs/outputs records; artifacts/evidence/errors object arrays;
137
+ // parents/children string arrays.
138
+ // ---------------------------------------------------------------------------
139
+ function nodeSnapshotBodyReason(value, prefix) {
140
+ if (!isRecord(value))
141
+ return { field: prefix, reason: "must be a NodeSnapshotBody object" };
142
+ const requiredStrings = ["id", "kind", "status", "loopStage"];
143
+ for (const field of requiredStrings) {
144
+ if (!isString(value[field]))
145
+ return { field: `${prefix}.${String(field)}`, reason: "must be a string" };
146
+ }
147
+ if (!isRecord(value.inputs))
148
+ return { field: `${prefix}.inputs`, reason: "must be an object" };
149
+ if (!isRecord(value.outputs))
150
+ return { field: `${prefix}.outputs`, reason: "must be an object" };
151
+ if (!isObjectArray(value.artifacts))
152
+ return { field: `${prefix}.artifacts`, reason: "must be a StateArtifact[]" };
153
+ if (!isObjectArray(value.evidence))
154
+ return { field: `${prefix}.evidence`, reason: "must be a StateEvidence[]" };
155
+ if (!isObjectArray(value.errors))
156
+ return { field: `${prefix}.errors`, reason: "must be a StateNodeError[]" };
157
+ if (!isStringArray(value.parents))
158
+ return { field: `${prefix}.parents`, reason: "must be a string[]" };
159
+ if (!isStringArray(value.children))
160
+ return { field: `${prefix}.children`, reason: "must be a string[]" };
161
+ return undefined;
162
+ }
163
+ // ---------------------------------------------------------------------------
164
+ // NodeSnapshot — node-snapshot.ts:121
165
+ // Required: schemaVersion===1, snapshotId, runId, nodeId, capturedAt,
166
+ // sourceFingerprint strings; body a valid NodeSnapshotBody.
167
+ // ---------------------------------------------------------------------------
168
+ function nodeSnapshotReason(value) {
169
+ if (!isRecord(value))
170
+ return { reason: "not an object" };
171
+ if (value.schemaVersion !== 1)
172
+ return { field: "schemaVersion", reason: "must equal 1" };
173
+ const requiredStrings = ["snapshotId", "runId", "nodeId", "capturedAt", "sourceFingerprint"];
174
+ for (const field of requiredStrings) {
175
+ if (!isString(value[field]))
176
+ return { field: field, reason: "must be a string" };
177
+ }
178
+ return nodeSnapshotBodyReason(value.body, "body");
179
+ }
180
+ /** Throw-on-mismatch guard for NodeSnapshot (read edge requires the record). */
181
+ function validateNodeSnapshot(value) {
182
+ const problem = nodeSnapshotReason(value);
183
+ if (problem)
184
+ throw new RecordValidationError("NodeSnapshot", problem.reason, problem.field);
185
+ return value;
186
+ }
187
+ /** Best-effort variant: returns null on mismatch. */
188
+ function tryValidateNodeSnapshot(value) {
189
+ return nodeSnapshotReason(value) ? null : value;
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // NodeReplayRun — node-snapshot.ts:133
193
+ // Required: schemaVersion===1, replayId, runId, nodeId, snapshotId, replayedAt,
194
+ // outputFingerprint strings; freshness enum; contractValidated boolean; body a
195
+ // valid NodeSnapshotBody.
196
+ // ---------------------------------------------------------------------------
197
+ function nodeReplayRunReason(value) {
198
+ if (!isRecord(value))
199
+ return { reason: "not an object" };
200
+ if (value.schemaVersion !== 1)
201
+ return { field: "schemaVersion", reason: "must equal 1" };
202
+ const requiredStrings = [
203
+ "replayId",
204
+ "runId",
205
+ "nodeId",
206
+ "snapshotId",
207
+ "replayedAt",
208
+ "outputFingerprint"
209
+ ];
210
+ for (const field of requiredStrings) {
211
+ if (!isString(value[field]))
212
+ return { field: field, reason: "must be a string" };
213
+ }
214
+ if (!isString(value.freshness) || !SNAPSHOT_FRESHNESS.has(value.freshness)) {
215
+ return { field: "freshness", reason: "must be a valid NodeSnapshotFreshness" };
216
+ }
217
+ if (typeof value.contractValidated !== "boolean") {
218
+ return { field: "contractValidated", reason: "must be a boolean" };
219
+ }
220
+ return nodeSnapshotBodyReason(value.body, "body");
221
+ }
222
+ /** Throw-on-mismatch guard for NodeReplayRun (read edge requires the record). */
223
+ function validateNodeReplayRun(value) {
224
+ const problem = nodeReplayRunReason(value);
225
+ if (problem)
226
+ throw new RecordValidationError("NodeReplayRun", problem.reason, problem.field);
227
+ return value;
228
+ }
229
+ /** Best-effort variant: returns null on mismatch. */
230
+ function tryValidateNodeReplayRun(value) {
231
+ return nodeReplayRunReason(value) ? null : value;
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // CandidateScore — multi-agent-operator-ux.ts:502 / evidence-reasoning.ts:750
235
+ // Required (per src/types/candidate.ts): schemaVersion===1, id, candidateId,
236
+ // runId, createdAt, scorer strings; criteria record of numbers; total/maxTotal/
237
+ // normalized finite numbers; verdict enum; evidence/artifacts object arrays.
238
+ // ---------------------------------------------------------------------------
239
+ function isNumberRecord(value) {
240
+ return isRecord(value) && Object.values(value).every((entry) => isFiniteNumber(entry));
241
+ }
242
+ function candidateScoreReason(value) {
243
+ if (!isRecord(value))
244
+ return { reason: "not an object" };
245
+ if (value.schemaVersion !== 1)
246
+ return { field: "schemaVersion", reason: "must equal 1" };
247
+ const requiredStrings = ["id", "candidateId", "runId", "createdAt", "scorer"];
248
+ for (const field of requiredStrings) {
249
+ if (!isString(value[field]))
250
+ return { field: field, reason: "must be a string" };
251
+ }
252
+ if (!isNumberRecord(value.criteria))
253
+ return { field: "criteria", reason: "must be a Record<string, number>" };
254
+ if (!isFiniteNumber(value.total))
255
+ return { field: "total", reason: "must be a finite number" };
256
+ if (!isFiniteNumber(value.maxTotal))
257
+ return { field: "maxTotal", reason: "must be a finite number" };
258
+ if (!isFiniteNumber(value.normalized))
259
+ return { field: "normalized", reason: "must be a finite number" };
260
+ if (!isString(value.verdict) || !SCORE_VERDICTS.has(value.verdict)) {
261
+ return { field: "verdict", reason: "must be a valid CandidateScoreVerdict" };
262
+ }
263
+ if (!isObjectArray(value.evidence))
264
+ return { field: "evidence", reason: "must be a StateEvidence[]" };
265
+ if (!isObjectArray(value.artifacts))
266
+ return { field: "artifacts", reason: "must be a StateArtifact[]" };
267
+ return undefined;
268
+ }
269
+ /** Throw-on-mismatch guard for CandidateScore (callers that require the record). */
270
+ function validateCandidateScore(value) {
271
+ const problem = candidateScoreReason(value);
272
+ if (problem)
273
+ throw new RecordValidationError("CandidateScore", problem.reason, problem.field);
274
+ return value;
275
+ }
276
+ /** Best-effort variant: returns null on mismatch (caller skips the record so the
277
+ * downstream score gate fails closed on its absence). */
278
+ function tryValidateCandidateScore(value) {
279
+ return candidateScoreReason(value) ? null : value;
280
+ }
281
+ // ---------------------------------------------------------------------------
282
+ // CandidateRecord — candidate-scoring.ts getCandidate / loadCandidatesFromDisk.
283
+ // Required (per src/types/candidate.ts): schemaVersion===1, id, runId, createdAt,
284
+ // updatedAt strings; kind/status enums; artifacts/evidence object arrays;
285
+ // scores/feedbackIds string arrays. Optional ids (workerId/taskId/…) not enforced.
286
+ // A corrupt/forged candidate record must NOT flow into the run as a trusted T —
287
+ // the gate that backs commit selection reads these fields, so we fail closed at
288
+ // the read edge instead of upserting an unvalidated cast.
289
+ // ---------------------------------------------------------------------------
290
+ function candidateRecordReason(value) {
291
+ if (!isRecord(value))
292
+ return { reason: "not an object" };
293
+ if (value.schemaVersion !== 1)
294
+ return { field: "schemaVersion", reason: "must equal 1" };
295
+ const requiredStrings = ["id", "runId", "createdAt", "updatedAt"];
296
+ for (const field of requiredStrings) {
297
+ if (!isString(value[field]))
298
+ return { field: field, reason: "must be a string" };
299
+ }
300
+ if (!isString(value.kind) || !CANDIDATE_KINDS.has(value.kind)) {
301
+ return { field: "kind", reason: "must be a valid CandidateKind" };
302
+ }
303
+ if (!isString(value.status) || !CANDIDATE_STATUSES.has(value.status)) {
304
+ return { field: "status", reason: "must be a valid CandidateStatus" };
305
+ }
306
+ if (!isObjectArray(value.artifacts))
307
+ return { field: "artifacts", reason: "must be a StateArtifact[]" };
308
+ if (!isObjectArray(value.evidence))
309
+ return { field: "evidence", reason: "must be a StateEvidence[]" };
310
+ if (!isStringArray(value.scores))
311
+ return { field: "scores", reason: "must be a string[]" };
312
+ if (!isStringArray(value.feedbackIds))
313
+ return { field: "feedbackIds", reason: "must be a string[]" };
314
+ return undefined;
315
+ }
316
+ /** Throw-on-mismatch guard for CandidateRecord (callers that require the record
317
+ * at the disk read edge — getCandidate / loadCandidatesFromDisk). */
318
+ function validateCandidateRecord(value) {
319
+ const problem = candidateRecordReason(value);
320
+ if (problem)
321
+ throw new RecordValidationError("CandidateRecord", problem.reason, problem.field);
322
+ return value;
323
+ }
324
+ /** Best-effort variant: returns null on mismatch (caller skips the record so the
325
+ * downstream selection gate fails closed on its absence). */
326
+ function tryValidateCandidateRecord(value) {
327
+ return candidateRecordReason(value) ? null : value;
328
+ }
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION = exports.LEGACY_RUN_STATE_SCHEMA_VERSION = exports.CURRENT_RUN_STATE_SCHEMA_VERSION = exports.WORKFLOW_APP_SCHEMA_VERSION = exports.CURRENT_COOL_WORKFLOW_VERSION = void 0;
4
- exports.CURRENT_COOL_WORKFLOW_VERSION = "0.1.80";
4
+ exports.CURRENT_COOL_WORKFLOW_VERSION = "0.1.82";
5
5
  exports.WORKFLOW_APP_SCHEMA_VERSION = 1;
6
6
  exports.CURRENT_RUN_STATE_SCHEMA_VERSION = 1;
7
7
  exports.LEGACY_RUN_STATE_SCHEMA_VERSION = 0;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.structuredError = structuredError;
4
+ exports.isBoundaryViolation = isBoundaryViolation;
5
+ exports.isStateNodeError = isStateNodeError;
6
+ exports.mergeScopes = mergeScopes;
7
+ exports.unique = unique;
8
+ exports.compactMetadata = compactMetadata;
9
+ exports.countBy = countBy;
10
+ function structuredError(code, message, options = {}) {
11
+ return {
12
+ code,
13
+ message,
14
+ at: new Date().toISOString(),
15
+ path: options.path,
16
+ retryable: options.retryable,
17
+ details: options.details
18
+ };
19
+ }
20
+ function isBoundaryViolation(value) {
21
+ return Boolean(value && typeof value === "object" && "allowedPaths" in value && "message" in value);
22
+ }
23
+ function isStateNodeError(value) {
24
+ return Boolean(value && typeof value === "object" && "code" in value && "message" in value);
25
+ }
26
+ function mergeScopes(left, right) {
27
+ const merged = [...left];
28
+ for (const scope of right) {
29
+ const index = merged.findIndex((candidate) => candidate.id === scope.id);
30
+ if (index >= 0)
31
+ merged[index] = scope;
32
+ else
33
+ merged.push(scope);
34
+ }
35
+ return merged;
36
+ }
37
+ function unique(values) {
38
+ return Array.from(new Set(values.filter(Boolean)));
39
+ }
40
+ function compactMetadata(value) {
41
+ const entries = Object.entries(value).filter(([, entry]) => entry !== undefined);
42
+ return entries.length ? Object.fromEntries(entries) : undefined;
43
+ }
44
+ function countBy(items, key) {
45
+ const counts = {};
46
+ for (const item of items) {
47
+ const value = key(item);
48
+ counts[value] = (counts[value] || 0) + 1;
49
+ }
50
+ return counts;
51
+ }
@@ -0,0 +1,46 @@
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.WORKER_MANIFEST_FILE = exports.WORKER_SCOPE_FILE = void 0;
7
+ exports.manifestPath = manifestPath;
8
+ exports.workerScopePath = workerScopePath;
9
+ exports.workerArtifacts = workerArtifacts;
10
+ exports.createWorkerId = createWorkerId;
11
+ // Path, artifact, and id derivation for worker isolation. Pure functions of a
12
+ // WorkerScope (or run + taskId) — no run-state mutation, no disk I/O. Carved out
13
+ // of worker-isolation.ts following the established router pattern
14
+ // (run-registry/{format,policy}.ts, orchestrator/*-operations.ts).
15
+ //
16
+ // BEHAVIOR-PRESERVING — pure code movement, zero logic change. Re-exported from
17
+ // worker-isolation.ts so the public surface is byte-unchanged.
18
+ const node_path_1 = __importDefault(require("node:path"));
19
+ const state_1 = require("../state");
20
+ exports.WORKER_SCOPE_FILE = "worker.json";
21
+ exports.WORKER_MANIFEST_FILE = "manifest.json";
22
+ function manifestPath(scope) {
23
+ return node_path_1.default.join(scope.workerDir, exports.WORKER_MANIFEST_FILE);
24
+ }
25
+ function workerScopePath(scope) {
26
+ return node_path_1.default.join(scope.workerDir, exports.WORKER_SCOPE_FILE);
27
+ }
28
+ function workerArtifacts(scope) {
29
+ return [
30
+ { id: "worker", kind: "json", path: workerScopePath(scope) },
31
+ { id: "worker-manifest", kind: "json", path: manifestPath(scope) },
32
+ { id: "worker-input", kind: "markdown", path: scope.inputPath }
33
+ ];
34
+ }
35
+ // Deterministic worker id (v0.1.40 self-audit P2): a wall-clock stamp + Math.random()
36
+ // made every dispatch mint a different id, so audit references were not reproducible
37
+ // across re-runs of the same inputs. The id is now derived from the task plus a
38
+ // per-task sequence (count of worker scopes already allocated for that task + 1),
39
+ // so re-running the same workflow yields byte-identical worker ids while retries of
40
+ // the SAME task still get a fresh, unique id. (workerId is excluded from the
41
+ // snapshot source fingerprint, so this does not change replay digests.)
42
+ function createWorkerId(run, taskId) {
43
+ const prefix = `worker-${(0, state_1.safeFileName)(taskId)}-`;
44
+ const seq = (run.workers || []).filter((scope) => scope.id.startsWith(prefix)).length + 1;
45
+ return `${prefix}${String(seq).padStart(4, "0")}`;
46
+ }