@tangle-network/agent-runtime 0.193.1 → 0.194.0

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 (113) hide show
  1. package/dist/{activation-BismttgN.js → activation-BQFIiyUG.js} +3 -3
  2. package/dist/{activation-BismttgN.js.map → activation-BQFIiyUG.js.map} +1 -1
  3. package/dist/agent.d.ts +1 -1
  4. package/dist/agent.js +2 -2
  5. package/dist/candidate-execution/index.js +4 -4
  6. package/dist/{candidate-execution-BSkZErxD.js → candidate-execution-B6CDW-fp.js} +4 -4
  7. package/dist/{candidate-execution-BSkZErxD.js.map → candidate-execution-B6CDW-fp.js.map} +1 -1
  8. package/dist/{conversation-DILnmy84.js → conversation-BXPWMOSd.js} +4 -5
  9. package/dist/{conversation-DILnmy84.js.map → conversation-BXPWMOSd.js.map} +1 -1
  10. package/dist/conversation.d.ts +1 -1
  11. package/dist/conversation.js +1 -1
  12. package/dist/{coordination-driver-DujHiIGa.js → coordination-driver-iSN-m3VX.js} +281 -244
  13. package/dist/coordination-driver-iSN-m3VX.js.map +1 -0
  14. package/dist/{authoring-DWiqKSDY.js → delegate-DCC2muUd.js} +56 -13
  15. package/dist/delegate-DCC2muUd.js.map +1 -0
  16. package/dist/delegation-status-BlsbSeOB.js +358 -0
  17. package/dist/delegation-status-BlsbSeOB.js.map +1 -0
  18. package/dist/durable.d.ts +2 -2
  19. package/dist/durable.js +3 -3
  20. package/dist/{environment-provider-DEwsolvi.js → environment-provider-Dr-wfnHg.js} +422 -8
  21. package/dist/environment-provider-Dr-wfnHg.js.map +1 -0
  22. package/dist/{environment-provider-DpPGJfK-.d.ts → environment-provider-adVa6X7a.d.ts} +2 -2
  23. package/dist/environment-provider.d.ts +1 -1
  24. package/dist/environment-provider.js +1 -1
  25. package/dist/{graph-DORfp9WX.js → graph-DghidDx5.js} +138 -5
  26. package/dist/graph-DghidDx5.js.map +1 -0
  27. package/dist/graph.d.ts +3 -3
  28. package/dist/graph.js +4 -5
  29. package/dist/graph.js.map +1 -1
  30. package/dist/{improve-Bn1zpWHF.d.ts → improve-COGzLCiY.d.ts} +3 -3
  31. package/dist/{improvement-cycle-BbsiYcpH.js → improvement-cycle-DeS1ZC5B.js} +6 -6
  32. package/dist/{improvement-cycle-BbsiYcpH.js.map → improvement-cycle-DeS1ZC5B.js.map} +1 -1
  33. package/dist/{index-DV1lzp9p.d.ts → index-BEPjOPwH.d.ts} +49 -50
  34. package/dist/{index-Vz-13VZq.d.ts → index-CrBgLCIf.d.ts} +4 -4
  35. package/dist/{index-RM2oRI9s.d.ts → index-DO6DHgRP.d.ts} +2 -2
  36. package/dist/index.d.ts +8 -8
  37. package/dist/index.js +13 -13
  38. package/dist/intelligence.d.ts +5 -5
  39. package/dist/intelligence.js +6 -6
  40. package/dist/{executable-spec-DxuiDFAU.js → jsonl-file-Bh1Q9nt0.js} +59 -3
  41. package/dist/jsonl-file-Bh1Q9nt0.js.map +1 -0
  42. package/dist/kernel.d.ts +6 -6
  43. package/dist/kernel.js +11 -12
  44. package/dist/{knowledge-RW1pbZCH.js → knowledge-B5okOzBQ.js} +6 -6
  45. package/dist/{knowledge-RW1pbZCH.js.map → knowledge-B5okOzBQ.js.map} +1 -1
  46. package/dist/knowledge.d.ts +1 -1
  47. package/dist/knowledge.js +1 -1
  48. package/dist/{loop-runner-bin-CGraqNiA.d.ts → loop-runner-bin-Clc5IAwu.d.ts} +3 -3
  49. package/dist/{loop-runner-bin-sBwcyQTc.js → loop-runner-bin-U1J6x_UF.js} +3 -3
  50. package/dist/{loop-runner-bin-sBwcyQTc.js.map → loop-runner-bin-U1J6x_UF.js.map} +1 -1
  51. package/dist/loop-runner-bin.d.ts +1 -1
  52. package/dist/loop-runner-bin.js +1 -1
  53. package/dist/{materialization-CekWK6OO.js → materialization-vZssF9Nx.js} +28 -3
  54. package/dist/materialization-vZssF9Nx.js.map +1 -0
  55. package/dist/mcp/bin.js +3 -3
  56. package/dist/mcp/index.d.ts +4 -4
  57. package/dist/mcp/index.js +8 -8
  58. package/dist/mcp/index.js.map +1 -1
  59. package/dist/{openai-tools-6jUqkGG7.js → openai-tools-DmvmaG0a.js} +2 -2
  60. package/dist/{openai-tools-6jUqkGG7.js.map → openai-tools-DmvmaG0a.js.map} +1 -1
  61. package/dist/{prepare-B5fJ7mLS.js → prepare-C29kNAon.js} +9 -14
  62. package/dist/prepare-C29kNAon.js.map +1 -0
  63. package/dist/primeintellect/index.d.ts +1 -1
  64. package/dist/profiles.js +1 -1
  65. package/dist/{protected-model-port-B0xFSAjt.js → protected-model-port-CKYND416.js} +2 -2
  66. package/dist/{protected-model-port-B0xFSAjt.js.map → protected-model-port-CKYND416.js.map} +1 -1
  67. package/dist/{provision-supervisor-CddfH9mg.js → provision-supervisor-CRPbnJiB.js} +6 -8
  68. package/dist/{provision-supervisor-CddfH9mg.js.map → provision-supervisor-CRPbnJiB.js.map} +1 -1
  69. package/dist/{redact-D0OzQsyt.js → redact-BOU77QfQ.js} +1013 -24
  70. package/dist/redact-BOU77QfQ.js.map +1 -0
  71. package/dist/{researcher-hgPa5p9i.js → researcher-Cp4JRbFp.js} +2 -2
  72. package/dist/researcher-Cp4JRbFp.js.map +1 -0
  73. package/dist/{runtime-V91N6sPc.d.ts → runtime-B8x43nGP.d.ts} +5 -4
  74. package/dist/{runtime-ZM4i-jEF.js → runtime-BVrqSu0-.js} +22 -21
  75. package/dist/{runtime-ZM4i-jEF.js.map → runtime-BVrqSu0-.js.map} +1 -1
  76. package/dist/server-D6XmE1Du.js +1311 -0
  77. package/dist/server-D6XmE1Du.js.map +1 -0
  78. package/dist/{stream-agent-turn-1ahpdeIo.d.ts → stream-agent-turn-B-gtBlOy.d.ts} +2 -2
  79. package/dist/{stream-agent-turn-DWWe_7bh.js → stream-agent-turn-DOtEsvCV.js} +3 -3
  80. package/dist/{stream-agent-turn-DWWe_7bh.js.map → stream-agent-turn-DOtEsvCV.js.map} +1 -1
  81. package/dist/{structural-rollout-CktnUTCC.js → structural-rollout-BcPXFzVb.js} +16 -43
  82. package/dist/structural-rollout-BcPXFzVb.js.map +1 -0
  83. package/dist/{supervise-Dj6zd2C7.js → supervise-C0V3pZXK.js} +154 -1961
  84. package/dist/supervise-C0V3pZXK.js.map +1 -0
  85. package/dist/testing.d.ts +2 -2
  86. package/dist/testing.js +13 -13
  87. package/dist/tui/index.d.ts +1 -1
  88. package/dist/tui/index.js +1 -1
  89. package/dist/{types-CGez_ZHQ.d.ts → types-B_pNTBjK.d.ts} +5 -2
  90. package/dist/{workspace-archive-yAPDklLV.js → workspace-archive-BCezkeIk.js} +2 -2
  91. package/dist/{workspace-archive-yAPDklLV.js.map → workspace-archive-BCezkeIk.js.map} +1 -1
  92. package/package.json +1 -1
  93. package/skills/codemode/SKILL.md +2 -2
  94. package/skills/supervise/SKILL.md +24 -6
  95. package/dist/authoring-DWiqKSDY.js.map +0 -1
  96. package/dist/coordination-driver-DujHiIGa.js.map +0 -1
  97. package/dist/environment-provider-DEwsolvi.js.map +0 -1
  98. package/dist/executable-spec-DxuiDFAU.js.map +0 -1
  99. package/dist/graph-DORfp9WX.js.map +0 -1
  100. package/dist/jsonl-file-CDfsCI5s.js +0 -59
  101. package/dist/jsonl-file-CDfsCI5s.js.map +0 -1
  102. package/dist/materialization-CekWK6OO.js.map +0 -1
  103. package/dist/prepare-B5fJ7mLS.js.map +0 -1
  104. package/dist/redact-D0OzQsyt.js.map +0 -1
  105. package/dist/researcher-hgPa5p9i.js.map +0 -1
  106. package/dist/snapshot-CTAf4uuA.js +0 -26
  107. package/dist/snapshot-CTAf4uuA.js.map +0 -1
  108. package/dist/spawn-journal-B9eTmVAn.js +0 -999
  109. package/dist/spawn-journal-B9eTmVAn.js.map +0 -1
  110. package/dist/structural-rollout-CktnUTCC.js.map +0 -1
  111. package/dist/supervise-Dj6zd2C7.js.map +0 -1
  112. package/dist/util-mCNUeboW.js +0 -419
  113. package/dist/util-mCNUeboW.js.map +0 -1
@@ -1,999 +0,0 @@
1
- import { m as ValidationError } from "./errors-CDZ8XsVj.js";
2
- import { n as detachedSnapshot } from "./snapshot-CTAf4uuA.js";
3
- import { b as zeroSpend, i as cloneSpend, t as addSpend } from "./util-mCNUeboW.js";
4
- import { i as writeAllBytes, n as parseCommittedJsonLines, r as prepareJsonlAppend, t as isNoEntError } from "./jsonl-file-CDfsCI5s.js";
5
- import { isToolSpan, toolSpansToTraceAnalysisStore } from "@tangle-network/agent-eval";
6
- import { createHash } from "node:crypto";
7
- //#region src/durable/content-address.ts
8
- /** Stable content address shared by result and trace artifacts. */
9
- function contentAddress(artifact) {
10
- return `sha256:${createHash("sha256").update(stableStringify(artifact), "utf-8").digest("hex")}`;
11
- }
12
- function stableStringify(value) {
13
- if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
14
- if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
15
- return `{${Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
16
- }
17
- //#endregion
18
- //#region src/runtime/supervise/trace-evidence.ts
19
- /**
20
- * Durable structured tool evidence for supervised workers.
21
- *
22
- * The executor-owned `TraceSource` is collected before teardown, snapshotted into the shared
23
- * content-addressed blob store, and only then referenced by a settlement. Analysis reconstructs
24
- * agent-eval's bounded `TraceAnalysisStore` from those exact bytes. Worker output is never accepted
25
- * as a substitute for tool evidence.
26
- *
27
- * @experimental
28
- */
29
- /** Schema version for content-addressed worker tool-trace artifacts. */
30
- const WORKER_TOOL_TRACE_SCHEMA_VERSION = 1;
31
- /** Structural guard for the official bounded trace-analysis read contract. */
32
- function isTraceAnalysisStore(value) {
33
- if (value === null || typeof value !== "object") return false;
34
- const store = value;
35
- return typeof store.getOverview === "function" && typeof store.queryTraces === "function" && typeof store.countTraces === "function" && typeof store.viewTrace === "function" && typeof store.viewSpans === "function" && typeof store.searchTrace === "function" && typeof store.searchSpan === "function";
36
- }
37
- /** Collect and persist one executor's structured tool trace without changing its task outcome. */
38
- async function captureWorkerTraceEvidence(readSource, blobs, executed) {
39
- if (!executed) return unavailable("execution-did-not-start");
40
- if (readSource === void 0) return unavailable("executor-did-not-expose-trace-source");
41
- let source;
42
- try {
43
- source = readSource();
44
- } catch {
45
- return unavailable("trace-source-unavailable");
46
- }
47
- if (source === void 0) return unavailable("trace-source-unavailable");
48
- let collected;
49
- try {
50
- collected = await source.collect();
51
- } catch {
52
- return unavailable("trace-collection-failed");
53
- }
54
- if (!Array.isArray(collected) || collected.some((span) => !isToolSpanValue(span))) return unavailable("invalid-tool-spans");
55
- if (collected.length === 0) return unavailable("no-tool-spans-captured");
56
- let artifact;
57
- let traceRef;
58
- try {
59
- const snapshot = structuredClone(collected);
60
- toolSpansToTraceAnalysisStore(snapshot);
61
- artifact = {
62
- schemaVersion: 1,
63
- spans: snapshot
64
- };
65
- traceRef = contentAddress(artifact);
66
- } catch {
67
- return unavailable("invalid-tool-spans");
68
- }
69
- try {
70
- await blobs.put(traceRef, artifact);
71
- } catch {
72
- return unavailable("trace-persistence-failed");
73
- }
74
- return Object.freeze({
75
- status: "available",
76
- traceRef,
77
- spanCount: artifact.spans.length
78
- });
79
- }
80
- /** Rehydrate exact persisted spans through agent-eval's one bounded trace-analysis adapter. */
81
- async function workerTraceAnalysisStore(evidence, blobs) {
82
- if (evidence.status === "unavailable") return toolSpansToTraceAnalysisStore(void 0);
83
- const raw = await blobs.get(evidence.traceRef);
84
- if (raw === void 0) throw new ValidationError(`worker trace blob '${evidence.traceRef}' is missing; the settlement evidence is incomplete`);
85
- const artifact = parseWorkerToolTraceArtifact(raw, evidence.traceRef);
86
- if (artifact.spans.length !== evidence.spanCount) throw new ValidationError(`worker trace blob '${evidence.traceRef}' has ${artifact.spans.length} spans but its settlement records ${evidence.spanCount}`);
87
- return toolSpansToTraceAnalysisStore(artifact.spans);
88
- }
89
- /** Validate a stored trace artifact before an analyst or replay trusts it. */
90
- function parseWorkerToolTraceArtifact(value, traceRef = "<unknown>") {
91
- if (value === null || typeof value !== "object" || value.schemaVersion !== 1 || !Array.isArray(value.spans)) throw new ValidationError(`worker trace blob '${traceRef}' is not a version-1 tool trace artifact`);
92
- const spans = value.spans;
93
- if (spans.length === 0) return {
94
- schemaVersion: 1,
95
- spans
96
- };
97
- if (spans.some((span) => !isToolSpanValue(span))) throw new ValidationError(`worker trace blob '${traceRef}' contains a non-tool span`);
98
- return {
99
- schemaVersion: 1,
100
- spans
101
- };
102
- }
103
- function unavailable(reason) {
104
- return Object.freeze({
105
- status: "unavailable",
106
- reason
107
- });
108
- }
109
- function isToolSpanValue(value) {
110
- try {
111
- return isToolSpan(value);
112
- } catch {
113
- return false;
114
- }
115
- }
116
- //#endregion
117
- //#region src/runtime/supervise/tree-key.ts
118
- /** Runtime tag used only for a child that owns another supervised scope. */
119
- const driverRuntime = "driver";
120
- const nestedDriverTreeOwners = /* @__PURE__ */ new WeakSet();
121
- /** Canonical journal key for the scope owned by one nested driver node. */
122
- function nestedDriverTreeRoot(parentTreeRoot, driverNodeId) {
123
- return `${parentTreeRoot}/${driverNodeId}`;
124
- }
125
- /** Privately mark the exact recursive executor that will create a nested journal tree. */
126
- function attestNestedDriverTreeOwner(owner) {
127
- nestedDriverTreeOwners.add(owner);
128
- return owner;
129
- }
130
- /** Return the canonical owned tree only for an exact privately marked recursive executor. */
131
- function runtimeOwnedNestedDriverTreeRoot(owner, parentTreeRoot, driverNodeId) {
132
- return nestedDriverTreeOwners.has(owner) ? nestedDriverTreeRoot(parentTreeRoot, driverNodeId) : void 0;
133
- }
134
- //#endregion
135
- //#region src/durable/spawn-journal.ts
136
- /**
137
- *
138
- * Event-sourced spawn journal for the recursive execution atom (build steps 3 + 7).
139
- *
140
- * The supervision tree is journaled as an append-only event log: every `spawned`,
141
- * `settled`, and `cancelled` is recorded AFTER it is observed-committed (never
142
- * speculative), mirroring `ConversationJournal`'s begin/append/load shape. The log
143
- * holds only the THIN decision record — ids, parentage, budget, the spend a decision
144
- * consumed, and a content-addressed `outRef`. The payloads the driver branched on
145
- * (the `out` artifacts) live in a separate `ResultBlobStore`, keyed by `outRef`, so
146
- * the journal stays small (decisions) and replay rehydrates the exact `Settled` from
147
- * the blob store (evidence). This is the decision/payload split the replay argument
148
- * rests on (B1/B2).
149
- *
150
- * Replay determinism (B2): `seq` is the monotonic cursor order `scope.next()` yielded
151
- * each settlement — NOT wall-clock. `replaySpawnTree` sorts strictly by `seq` before
152
- * touching the blob store, so the order in which rehydration `get`s resolve can never
153
- * reorder the replayed `Settled[]`; the result is identical regardless of blob latency.
154
- *
155
- * @stable
156
- */
157
- /**
158
- * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a
159
- * stable JSON encoding. Producers call this to derive the `outRef` they journal and
160
- * `put`; the FS/in-mem stores re-derive it on `put` to verify the supplied ref
161
- * matches (fail loud on a mismatch — a forged ref breaks the replay invariant).
162
- *
163
- * Stable encoding: object keys are sorted recursively so two structurally-equal
164
- * artifacts hash identically regardless of key insertion order.
165
- */
166
- /**
167
- * In-memory `ResultBlobStore`. Content-addressed: `put` verifies the supplied
168
- * `outRef` matches the artifact's hash so a stale/forged ref fails loud rather than
169
- * silently rehydrating the wrong payload. Idempotent on an identical re-put.
170
- *
171
- * @stable
172
- */
173
- var InMemoryResultBlobStore = class {
174
- blobs = /* @__PURE__ */ new Map();
175
- async put(outRef, artifact) {
176
- assertContentAddress(outRef, artifact);
177
- this.blobs.set(outRef, artifact);
178
- }
179
- async get(outRef) {
180
- return this.blobs.has(outRef) ? this.blobs.get(outRef) : void 0;
181
- }
182
- };
183
- /**
184
- * FS `ResultBlobStore`. One JSON file per artifact under `dir`, named by a
185
- * filesystem-safe encoding of the `outRef` (`sha256:<hex>` → `sha256-<hex>.json`).
186
- * `put` fsyncs so a crash between writes never loses an acknowledged blob.
187
- *
188
- * @stable
189
- */
190
- var FileResultBlobStore = class {
191
- dir;
192
- constructor(dir) {
193
- this.dir = dir;
194
- }
195
- async put(outRef, artifact) {
196
- assertContentAddress(outRef, artifact);
197
- const fs = await import("node:fs/promises");
198
- await fs.mkdir(this.dir, { recursive: true });
199
- const fh = await fs.open(this.blobPath(outRef), "w");
200
- try {
201
- await fh.write(JSON.stringify(artifact));
202
- await fh.sync();
203
- } finally {
204
- await fh.close();
205
- }
206
- }
207
- async get(outRef) {
208
- const fs = await import("node:fs/promises");
209
- let text;
210
- try {
211
- text = await fs.readFile(this.blobPath(outRef), "utf8");
212
- } catch (err) {
213
- if (isNoEntError(err)) return void 0;
214
- throw err;
215
- }
216
- return JSON.parse(text);
217
- }
218
- blobPath(outRef) {
219
- return `${this.dir}/${outRef.replace(/:/g, "-")}.json`;
220
- }
221
- };
222
- function assertContentAddress(outRef, artifact) {
223
- const expected = contentAddress(artifact);
224
- if (outRef !== expected) throw new Error(`blob outRef '${outRef}' does not match the artifact content hash '${expected}'; a content-addressed store refuses a mismatched ref (breaks the replay invariant)`);
225
- }
226
- /**
227
- * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces
228
- * the corruption guards a durable replay rests on:
229
- * - an event before `beginTree` is a corrupted tree (fail loud),
230
- * - a duplicate `seq` within a tree is a corrupted cursor (fail loud) — two
231
- * settlements cannot share the cursor position replay orders by.
232
- *
233
- * @stable
234
- */
235
- var InMemorySpawnJournal = class {
236
- trees = /* @__PURE__ */ new Map();
237
- async loadTree(root) {
238
- const tree = this.trees.get(root);
239
- if (!tree) return void 0;
240
- return tree.events.map((ev) => ({ ...ev }));
241
- }
242
- async beginTree(root, at) {
243
- const existing = this.trees.get(root);
244
- if (existing) {
245
- if (existing.begunAt !== at) throw new Error(`spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`);
246
- return;
247
- }
248
- this.trees.set(root, {
249
- begunAt: at,
250
- events: []
251
- });
252
- }
253
- async appendEvent(root, ev) {
254
- const tree = this.trees.get(root);
255
- if (!tree) throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
256
- assertSeqUnique(root, tree.events, ev);
257
- tree.events.push({ ...ev });
258
- }
259
- };
260
- /**
261
- * JSONL on disk. One line per record: the first record is `begin`, subsequent records
262
- * are `event` envelopes wrapping a `SpawnEvent`. `loadTree` replays the whole file,
263
- * filtering by `root`, and applies the same begin-precedes-events + unique-seq
264
- * corruption guards as the in-memory impl. Each append fsyncs so a crash between
265
- * writes never loses an acknowledged event.
266
- *
267
- * @stable
268
- */
269
- var FileSpawnJournal = class {
270
- path;
271
- appendTail = Promise.resolve();
272
- constructor(path) {
273
- this.path = path;
274
- }
275
- async loadTree(root) {
276
- const fs = await import("node:fs/promises");
277
- let text;
278
- try {
279
- text = await fs.readFile(this.path, "utf8");
280
- } catch (err) {
281
- if (isNoEntError(err)) return void 0;
282
- throw err;
283
- }
284
- let begun = false;
285
- const events = [];
286
- for (const record of parseCommittedJsonLines(text, this.path)) {
287
- if (record.root !== root) continue;
288
- if (record.kind === "begin") begun = true;
289
- else {
290
- if (!begun) throw new Error(`spawn journal corrupted: event for tree '${root}' precedes its begin record`);
291
- assertSeqUnique(root, events, record.event);
292
- events.push(record.event);
293
- }
294
- }
295
- return begun ? events : void 0;
296
- }
297
- async beginTree(root, at) {
298
- const existing = await this.loadTreeBegin(root);
299
- if (existing) {
300
- if (existing !== at) throw new Error(`spawn tree '${root}' already begun in ${this.path} at ${existing}; refusing to overwrite with ${at}`);
301
- return;
302
- }
303
- await this.appendRecord({
304
- kind: "begin",
305
- root,
306
- at
307
- });
308
- }
309
- async appendEvent(root, ev) {
310
- const events = await this.loadTree(root);
311
- if (events === void 0) throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
312
- assertSeqUnique(root, events, ev);
313
- await this.appendRecord({
314
- kind: "event",
315
- root,
316
- event: ev
317
- });
318
- }
319
- async loadTreeBegin(root) {
320
- const fs = await import("node:fs/promises");
321
- let text;
322
- try {
323
- text = await fs.readFile(this.path, "utf8");
324
- } catch (err) {
325
- if (isNoEntError(err)) return void 0;
326
- throw err;
327
- }
328
- for (const record of parseCommittedJsonLines(text, this.path)) if (record.root === root && record.kind === "begin") return record.at;
329
- }
330
- async appendRecord(record) {
331
- const append = this.appendTail.then(() => this.writeRecord(record));
332
- this.appendTail = append.catch(() => void 0);
333
- return append;
334
- }
335
- async writeRecord(record) {
336
- const fs = await import("node:fs/promises");
337
- const path = await import("node:path");
338
- await fs.mkdir(path.dirname(this.path), { recursive: true });
339
- const needsSeparator = await prepareJsonlAppend(this.path);
340
- const fh = await fs.open(this.path, "a");
341
- try {
342
- await writeAllBytes(fh, `${needsSeparator ? "\n" : ""}${JSON.stringify(record)}\n`);
343
- await fh.sync();
344
- } finally {
345
- await fh.close();
346
- }
347
- }
348
- };
349
- /**
350
- * Load every journal tree owned by one recursive supervision run and flatten its nodes/events.
351
- *
352
- * Nested driver tree keys are a Runtime implementation detail; callers should use this reader
353
- * instead of deriving or scanning keys themselves. The reader follows only the explicit
354
- * `ownedTreeRoot` written after Runtime privately attested a recursive executor; the open runtime
355
- * string `driver` is never treated as ownership. Legacy records without `ownedTreeRoot` are
356
- * intentionally treated as leaves rather than guessing or scanning convention-derived keys.
357
- * This preserves each tree's independent cursor namespace on flattened events.
358
- * A driver whose subtree was never begun is reported in `missingTrees`; any spawned non-root node
359
- * without a terminal record is reported in `inDoubt`, matching resume's conservative lost-work
360
- * interpretation.
361
- *
362
- * This is a cold/quiescent reader, not a transaction across an actively mutating file. Every value
363
- * returned is a detached immutable snapshot, so later journal writes or caller mutation cannot
364
- * change the result already observed.
365
- */
366
- async function loadSpawnForest(journal, root) {
367
- const rootEvents = await journal.loadTree(root);
368
- if (rootEvents === void 0) throw new Error(`loadSpawnForest: no journaled tree for root '${root}'`);
369
- const trees = [];
370
- const nodes = [];
371
- const events = [];
372
- const inDoubt = [];
373
- const missingTrees = [];
374
- const visited = /* @__PURE__ */ new Set();
375
- const queue = [{
376
- root,
377
- events: rootEvents
378
- }];
379
- for (let cursor = 0; cursor < queue.length; cursor += 1) {
380
- const current = queue[cursor];
381
- if (visited.has(current.root)) throw new Error(`loadSpawnForest: recursive journal tree '${current.root}' was reached twice`);
382
- visited.add(current.root);
383
- const stableEvents = detachedSnapshot(current.events, `loadSpawnForest tree ${JSON.stringify(current.root)}`);
384
- const view = detachedSnapshot(materializeTreeView(current.ownerSpawn === void 0 || stableEvents.some((event) => event.kind === "spawned" && event.id === current.ownerSpawn?.id) ? [...stableEvents] : [ownedTreeRootSpawn(current.ownerSpawn), ...stableEvents]), `loadSpawnForest view ${JSON.stringify(current.root)}`);
385
- trees.push({
386
- root: current.root,
387
- ...current.ownerNodeId === void 0 ? {} : { ownerNodeId: current.ownerNodeId },
388
- ...current.parentTreeRoot === void 0 ? {} : { parentTreeRoot: current.parentTreeRoot },
389
- events: stableEvents,
390
- view
391
- });
392
- nodes.push(...view.nodes.filter((node) => current.ownerNodeId === void 0 || node.id !== current.ownerNodeId).map((node) => ({
393
- treeRoot: current.root,
394
- ...node
395
- })));
396
- events.push(...stableEvents.map((event) => ({
397
- treeRoot: current.root,
398
- event
399
- })));
400
- const terminal = /* @__PURE__ */ new Set();
401
- for (const event of stableEvents) if (event.kind === "settled" || event.kind === "cancelled") terminal.add(event.id);
402
- const spawns = stableEvents.filter((event) => event.kind === "spawned").sort((a, b) => a.seq - b.seq || a.id.localeCompare(b.id));
403
- for (const spawn of spawns) {
404
- if (spawn.parent !== void 0 && !terminal.has(spawn.id)) inDoubt.push({
405
- treeRoot: current.root,
406
- nodeId: spawn.id,
407
- label: spawn.label,
408
- runtime: spawn.runtime
409
- });
410
- if (spawn.ownedTreeRoot === void 0) continue;
411
- const expectedRoot = nestedDriverTreeRoot(current.root, spawn.id);
412
- if (spawn.ownedTreeRoot !== expectedRoot) throw new Error(`loadSpawnForest: node '${spawn.id}' owns non-canonical tree '${spawn.ownedTreeRoot}'; expected '${expectedRoot}'`);
413
- const nestedRoot = spawn.ownedTreeRoot;
414
- const nestedEvents = await journal.loadTree(nestedRoot);
415
- if (nestedEvents === void 0) {
416
- missingTrees.push({
417
- parentTreeRoot: current.root,
418
- ownerNodeId: spawn.id,
419
- root: nestedRoot
420
- });
421
- continue;
422
- }
423
- queue.push({
424
- root: nestedRoot,
425
- events: nestedEvents,
426
- ownerNodeId: spawn.id,
427
- parentTreeRoot: current.root,
428
- ownerSpawn: spawn
429
- });
430
- }
431
- }
432
- return detachedSnapshot({
433
- root,
434
- trees,
435
- nodes,
436
- events,
437
- inDoubt,
438
- missingTrees
439
- }, "loadSpawnForest result");
440
- }
441
- /** Owned journal trees record the owner's turns and descendants, but the owner's spawn belongs to
442
- * the parent tree. Supply a view-only parentless copy so strict materialization can fold root
443
- * metering without weakening its missing-spawn corruption check for ordinary event lists. */
444
- function ownedTreeRootSpawn(spawn) {
445
- const { parent: _parent, ownedTreeRoot: _ownedTreeRoot, ...root } = spawn;
446
- return root;
447
- }
448
- /**
449
- * Aggregate provider-served model evidence across one recursively owned journal forest.
450
- *
451
- * The parent tree records an owned driver's terminal summary, while that driver's own inference
452
- * and descendants live in its owned tree. This reducer follows the forest reader's explicit tree
453
- * edges and consumes each tree's metered attempts plus terminal leaf settlements exactly once.
454
- * A summary node is skipped because its owned tree supplies the source records. Plan materialization
455
- * is intentionally not read: it proves only what Runtime requested, not what a provider served.
456
- *
457
- * Missing legacy evidence, an unfinished node, an unopened owned tree, an identity conflict, and a
458
- * paid attempt without a qualified served snapshot all return unknown. An explicit
459
- * `providerDispatch: "not_started"` arm and Runtime accounting-only metered records are ignored
460
- * for served-model identity, while absent or malformed legacy data remains unknown here.
461
- */
462
- function aggregateProviderModelEvidence(forest) {
463
- const attempts = [];
464
- const observedModels = /* @__PURE__ */ new Set();
465
- const canonicalModels = /* @__PURE__ */ new Set();
466
- const nodes = /* @__PURE__ */ new Map();
467
- let reason;
468
- let sawProviderEvidence = false;
469
- for (const node of forest.nodes) nodes.set(forestNodeKey(node.treeRoot, node.id), node);
470
- if (forest.missingTrees.length > 0 || forest.inDoubt.length > 0) reason = "provider-model-missing";
471
- const markMissing = () => {
472
- reason ??= "provider-model-missing";
473
- };
474
- const markConflict = () => {
475
- reason = "provider-model-conflict";
476
- };
477
- const append = (raw) => {
478
- sawProviderEvidence = true;
479
- if (!isProviderEvidenceObject(raw)) {
480
- markMissing();
481
- return;
482
- }
483
- if (raw.status === "unknown") {
484
- if (raw.reason === "provider-model-conflict") markConflict();
485
- else if (!hasOnlyNotStartedAttempts(raw)) markMissing();
486
- } else if (raw.status !== "known") {
487
- markMissing();
488
- return;
489
- }
490
- if (!Array.isArray(raw.attempts) || !Array.isArray(raw.models)) {
491
- markMissing();
492
- return;
493
- }
494
- const declared = /* @__PURE__ */ new Set();
495
- for (const model of raw.models) if (typeof model !== "string" || model.length === 0) markMissing();
496
- else declared.add(model);
497
- const observedInRecord = /* @__PURE__ */ new Set();
498
- for (const rawAttempt of raw.attempts) {
499
- if (!isProviderAttemptEvidence(rawAttempt)) {
500
- markMissing();
501
- continue;
502
- }
503
- if (rawAttempt.identityConflict === true) markConflict();
504
- const observations = [...rawAttempt.observations];
505
- if (rawAttempt.providerDispatch === "not_started") {
506
- if (observations.length > 0) markMissing();
507
- attempts.push(Object.freeze({
508
- observations: Object.freeze([]),
509
- providerDispatch: "not_started",
510
- ...rawAttempt.identityConflict === true ? { identityConflict: true } : {}
511
- }));
512
- continue;
513
- }
514
- if (observations.length === 0) {
515
- markMissing();
516
- attempts.push(Object.freeze({
517
- observations: Object.freeze([]),
518
- ...rawAttempt.identityConflict === true ? { identityConflict: true } : {}
519
- }));
520
- continue;
521
- }
522
- let base;
523
- let snapshot;
524
- for (const model of observations) {
525
- if (typeof model !== "string" || model.length === 0) {
526
- markMissing();
527
- continue;
528
- }
529
- observedInRecord.add(model);
530
- observedModels.add(model);
531
- const identity = servedIdentityParts(model);
532
- if (identity === void 0) {
533
- markMissing();
534
- continue;
535
- }
536
- if (base !== void 0 && base !== identity.base) markConflict();
537
- if (snapshot !== void 0 && identity.snapshot !== void 0 && snapshot !== identity.snapshot) markConflict();
538
- base = identity.base;
539
- snapshot ??= identity.snapshot;
540
- if (identity.snapshot !== void 0) {
541
- canonicalModels.add(`${identity.base}@${identity.snapshot}`);
542
- if (canonicalModels.size > 1) markConflict();
543
- }
544
- }
545
- if (base === void 0 || snapshot === void 0) markMissing();
546
- attempts.push(Object.freeze({
547
- observations: Object.freeze(observations),
548
- ...rawAttempt.identityConflict === true ? { identityConflict: true } : {}
549
- }));
550
- }
551
- if (declared.size !== observedInRecord.size || [...declared].some((model) => !observedInRecord.has(model))) markMissing();
552
- };
553
- const terminal = (treeRoot, event) => {
554
- const node = nodes.get(forestNodeKey(treeRoot, event.id));
555
- if (node === void 0) {
556
- markMissing();
557
- return;
558
- }
559
- if (node.ownedTreeRoot !== void 0) return;
560
- if (event.kind === "cancelled") {
561
- markMissing();
562
- return;
563
- }
564
- append(event.providerModel ?? node.providerModel);
565
- };
566
- for (const tree of forest.trees) for (const event of tree.events) if (event.kind === "metered") {
567
- if (event.accountingOnly === true) {
568
- if (event.providerModel !== void 0) markMissing();
569
- continue;
570
- }
571
- if (nodes.get(forestNodeKey(tree.root, event.id))?.ownedTreeRoot !== void 0) continue;
572
- const evidence = event.providerModel;
573
- if (evidence === void 0) markMissing();
574
- else append(evidence);
575
- } else if (event.kind === "settled" || event.kind === "cancelled") terminal(tree.root, event);
576
- if (!sawProviderEvidence || attempts.length === 0 || observedModels.size === 0) reason ??= "provider-model-missing";
577
- const models = Object.freeze([...observedModels]);
578
- const frozenAttempts = Object.freeze(attempts);
579
- return Object.freeze(reason === void 0 ? {
580
- status: "known",
581
- attempts: frozenAttempts,
582
- models
583
- } : {
584
- status: "unknown",
585
- attempts: frozenAttempts,
586
- models,
587
- reason
588
- });
589
- }
590
- function forestNodeKey(treeRoot, nodeId) {
591
- return `${treeRoot}\u0000${nodeId}`;
592
- }
593
- function isProviderEvidenceObject(value) {
594
- return typeof value === "object" && value !== null && !Array.isArray(value) && "status" in value;
595
- }
596
- function hasOnlyNotStartedAttempts(evidence) {
597
- return Array.isArray(evidence.attempts) && evidence.attempts.length > 0 && evidence.attempts.every((attempt) => isProviderAttemptEvidence(attempt) && attempt.providerDispatch === "not_started" && attempt.observations.length === 0 && attempt.identityConflict !== true);
598
- }
599
- function isProviderAttemptEvidence(value) {
600
- return typeof value === "object" && value !== null && !Array.isArray(value) && Array.isArray(value.observations) && (value.providerDispatch === void 0 || value.providerDispatch === "not_started");
601
- }
602
- function servedIdentityParts(model) {
603
- const at = model.lastIndexOf("@");
604
- const rawBase = at < 0 ? model : model.slice(0, at);
605
- const base = rawBase.slice(rawBase.lastIndexOf("/") + 1);
606
- if (base.length === 0) return void 0;
607
- const snapshot = at < 0 ? void 0 : model.slice(at + 1);
608
- if (snapshot !== void 0 && snapshot.length === 0) return void 0;
609
- return snapshot === void 0 ? { base } : {
610
- base,
611
- snapshot
612
- };
613
- }
614
- /**
615
- * Two `seq` namespaces share the journal: a `spawned` event's `seq` is the spawn ordinal
616
- * (the order children were created), and a `settled`/`cancelled` event's `seq` is the
617
- * monotonic CURSOR order `scope.next()` yielded that settlement (B2). The uniqueness
618
- * replay rests on is the cursor namespace — two settlements cannot share the position
619
- * replay orders by — so the guard checks only settled/cancelled events. A `spawned`
620
- * ordinal legitimately equals a later `settled` cursor seq and is not a collision.
621
- */
622
- function assertSeqUnique(root, events, ev) {
623
- if (ev.kind === "materialized") {
624
- if (events.some((event) => event.kind === "materialized" && event.id === ev.id)) throw new Error(`spawn journal corrupted: duplicate materialization receipt for node '${ev.id}' in tree '${root}'`);
625
- if (!events.some((event) => event.kind === "spawned" && event.id === ev.id)) throw new Error(`spawn journal corrupted: materialization for node '${ev.id}' precedes its spawn in tree '${root}'`);
626
- }
627
- if (ev.kind === "execution-bound") {
628
- if (events.some((event) => event.kind === "execution-bound" && event.id === ev.id && event.binding.attemptId === ev.binding.attemptId)) throw new Error(`spawn journal corrupted: duplicate execution binding for node '${ev.id}' attempt '${ev.binding.attemptId}' in tree '${root}'`);
629
- if (!events.some((event) => event.kind === "materialized" && event.id === ev.id)) throw new Error(`spawn journal corrupted: execution binding for node '${ev.id}' precedes materialization in tree '${root}'`);
630
- }
631
- if (outsideCursorNamespace(ev)) return;
632
- if (events.some((e) => !outsideCursorNamespace(e) && e.seq === ev.seq)) throw new Error(`spawn journal corrupted: duplicate cursor seq ${ev.seq} in tree '${root}'; the cursor order replay relies on is not unique`);
633
- }
634
- /**
635
- * The records that CLOSE a node's cursor slot: a settlement, a cancellation, or a wait being
636
- * woken. The complement question to {@link outsideCursorNamespace}, and the one a resume needs —
637
- * a kind missing here leaves a finished node looking live, so its budget is never reclaimed and
638
- * its reservation is replayed as still in doubt.
639
- */
640
- function closesCursorSlot(ev) {
641
- return ev.kind === "settled" || ev.kind === "cancelled" || ev.kind === "woken";
642
- }
643
- const outsideKinds = /* @__PURE__ */ new Set([
644
- "spawned",
645
- "waiting",
646
- "metered",
647
- "materialized",
648
- "execution-bound",
649
- "progress",
650
- "edge",
651
- "teardown-unconfirmed",
652
- "trace-unpropagated",
653
- "node-inputs-resolved",
654
- "edge-verdict",
655
- "join-state"
656
- ]);
657
- /** True for a node-CREATION or informational record. Narrows, so a caller keeps the union's arms. */
658
- function outsideCursorNamespace(ev) {
659
- return outsideKinds.has(ev.kind);
660
- }
661
- /** True for a record inside the cursor namespace. Narrows to {@link CursorNamespaceEvent}. */
662
- function insideCursorNamespace(ev) {
663
- return !outsideKinds.has(ev.kind);
664
- }
665
- /**
666
- * Re-feed a journaled spawn tree in strict `seq` order, rehydrating each settled
667
- * child's `out` from the blob store by `outRef`, and return the `Settled[]` exactly
668
- * as `scope.next()` originally delivered them.
669
- *
670
- * Determinism (B2): the events are sorted by `seq` BEFORE any blob `get`, so the
671
- * replay order is the recorded cursor order regardless of how fast each rehydration
672
- * resolves. `at` (wall-clock) is never a replay input. Fail loud on a tree that was
673
- * never begun, a settled-done event missing its `outRef`, or a blob the store can't
674
- * rehydrate — a silent gap would let `act` branch on the wrong evidence.
675
- *
676
- * @stable
677
- */
678
- async function replaySpawnTree(journal, blobs, root) {
679
- const events = await journal.loadTree(root);
680
- if (events === void 0) throw new Error(`replaySpawnTree: no journaled tree for root '${root}'`);
681
- const ordered = [...events].sort((a, b) => a.seq - b.seq);
682
- const labels = /* @__PURE__ */ new Map();
683
- const assignmentIds = /* @__PURE__ */ new Map();
684
- const identities = /* @__PURE__ */ new Map();
685
- const materializations = /* @__PURE__ */ new Map();
686
- const executionBindings = /* @__PURE__ */ new Map();
687
- for (const ev of ordered) {
688
- if (ev.kind === "spawned" || ev.kind === "waiting") labels.set(ev.id, ev.label);
689
- if (ev.kind === "spawned" && ev.assignmentId !== void 0) assignmentIds.set(ev.id, ev.assignmentId);
690
- if (ev.kind === "spawned" && ev.identity !== void 0) identities.set(ev.id, copyFrozenIdentity(ev.identity));
691
- if (ev.kind === "materialized") materializations.set(ev.id, ev.receipt);
692
- if (ev.kind === "execution-bound") {
693
- const bindings = executionBindings.get(ev.id) ?? [];
694
- bindings.push(ev.binding);
695
- executionBindings.set(ev.id, bindings);
696
- }
697
- }
698
- const handleFor = (id, status) => replayHandle(id, labels.get(id) ?? id, status, {
699
- assignmentId: assignmentIds.get(id),
700
- identity: identities.get(id),
701
- materialization: materializations.get(id),
702
- executionBindings: executionBindings.get(id)
703
- });
704
- const settlementTime = (at) => {
705
- const settledAt = Date.parse(at);
706
- return Number.isFinite(settledAt) ? { settledAt } : {};
707
- };
708
- const settled = [];
709
- for (const ev of ordered) {
710
- if (ev.kind === "spawned") continue;
711
- if (ev.kind === "waiting") continue;
712
- if (ev.kind === "metered") continue;
713
- if (ev.kind === "progress") continue;
714
- if (ev.kind === "materialized") continue;
715
- if (ev.kind === "execution-bound") continue;
716
- if (ev.kind === "edge") continue;
717
- if (ev.kind === "teardown-unconfirmed") continue;
718
- if (ev.kind === "trace-unpropagated") continue;
719
- if (ev.kind === "node-inputs-resolved") continue;
720
- if (ev.kind === "edge-verdict") continue;
721
- if (ev.kind === "join-state") continue;
722
- if (ev.kind === "woken") {
723
- if (ev.by === "cancelled" || ev.outRef === void 0) {
724
- settled.push({
725
- kind: "down",
726
- handle: handleFor(ev.id, "cancelled"),
727
- reason: "wait cancelled",
728
- infra: false,
729
- trace: {
730
- status: "unavailable",
731
- reason: "not-an-executor"
732
- },
733
- ...settlementTime(ev.at),
734
- seq: ev.seq
735
- });
736
- continue;
737
- }
738
- const outcome = await blobs.get(ev.outRef);
739
- if (outcome === void 0) throw new Error(`replaySpawnTree: blob store has no wait outcome for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`);
740
- settled.push({
741
- kind: "done",
742
- handle: handleFor(ev.id, "done"),
743
- out: outcome,
744
- outRef: ev.outRef,
745
- spent: zeroSpend(),
746
- trace: {
747
- status: "unavailable",
748
- reason: "not-an-executor"
749
- },
750
- ...settlementTime(ev.at),
751
- seq: ev.seq
752
- });
753
- continue;
754
- }
755
- if (ev.kind === "cancelled") {
756
- settled.push({
757
- kind: "down",
758
- handle: handleFor(ev.id, "cancelled"),
759
- reason: ev.reason,
760
- infra: false,
761
- trace: {
762
- status: "unavailable",
763
- reason: "execution-did-not-start"
764
- },
765
- ...settlementTime(ev.at),
766
- seq: ev.seq
767
- });
768
- continue;
769
- }
770
- if (ev.status === "down") {
771
- const trace = traceEvidenceFor(ev);
772
- if (trace.status === "available") await workerTraceAnalysisStore(trace, blobs);
773
- settled.push({
774
- kind: "down",
775
- handle: handleFor(ev.id, "failed"),
776
- reason: ev.reason ?? ev.verdict?.notes ?? "child down",
777
- infra: ev.infra === true,
778
- ...ev.providerModel === void 0 ? {} : { providerModel: copyProviderModelEvidence(ev.providerModel) },
779
- trace,
780
- ...settlementTime(ev.at),
781
- seq: ev.seq
782
- });
783
- continue;
784
- }
785
- if (ev.outRef === void 0) throw new Error(`replaySpawnTree: settled-done event for '${ev.id}' (seq ${ev.seq}) has no outRef; cannot rehydrate the result the driver branched on`);
786
- const out = await blobs.get(ev.outRef);
787
- if (out === void 0) throw new Error(`replaySpawnTree: blob store has no artifact for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`);
788
- const trace = traceEvidenceFor(ev);
789
- if (trace.status === "available") await workerTraceAnalysisStore(trace, blobs);
790
- settled.push({
791
- kind: "done",
792
- handle: handleFor(ev.id, "done"),
793
- out,
794
- outRef: ev.outRef,
795
- verdict: ev.verdict,
796
- spent: cloneSpend(ev.spent),
797
- ...ev.providerModel === void 0 ? {} : { providerModel: copyProviderModelEvidence(ev.providerModel) },
798
- trace,
799
- ...settlementTime(ev.at),
800
- seq: ev.seq
801
- });
802
- }
803
- return settled;
804
- }
805
- function replayHandle(id, label, status, evidence = {}) {
806
- return Object.freeze({
807
- id,
808
- label,
809
- status,
810
- ...evidence.assignmentId === void 0 ? {} : { assignmentId: evidence.assignmentId },
811
- ...evidence.identity === void 0 ? {} : { identity: evidence.identity },
812
- ...evidence.materialization === void 0 ? {} : { materialization: evidence.materialization },
813
- ...evidence.executionBindings === void 0 ? {} : { executionBindings: Object.freeze([...evidence.executionBindings]) },
814
- abort() {
815
- throw new Error(`cannot abort node '${id}': replayed handles are terminal, not live`);
816
- }
817
- });
818
- }
819
- /** A replayed handle must not retain mutable references into the loaded journal event. */
820
- function copyFrozenIdentity(identity) {
821
- const correlation = identity.correlation === void 0 ? void 0 : Object.freeze({ ...identity.correlation });
822
- return Object.freeze({
823
- ...identity.profileDigest === void 0 ? {} : { profileDigest: identity.profileDigest },
824
- ...identity.taskDigest === void 0 ? {} : { taskDigest: identity.taskDigest },
825
- ...identity.candidateDigest === void 0 ? {} : { candidateDigest: identity.candidateDigest },
826
- ...correlation === void 0 ? {} : { correlation }
827
- });
828
- }
829
- /**
830
- * Materialize a recorded `TreeView` from a journaled event list for inspection. Folds
831
- * `spawned`/`settled`/`cancelled` into a per-node snapshot in `seq` order, then adds each
832
- * `metered` event's driver-inference spend onto its node in a separate additive pass so the view
833
- * matches the recorded cursor. It does not recover live executors or driver state after restart.
834
- */
835
- function materializeTreeView(events) {
836
- const nodes = /* @__PURE__ */ new Map();
837
- let root;
838
- const spawns = events.filter((ev) => ev.kind === "spawned" || ev.kind === "waiting").sort((a, b) => a.seq - b.seq);
839
- const settlements = events.filter((ev) => insideCursorNamespace(ev)).sort((a, b) => a.seq - b.seq);
840
- for (const ev of spawns) {
841
- if (ev.kind === "waiting") {
842
- nodes.set(ev.id, {
843
- id: ev.id,
844
- parent: ev.parent,
845
- label: ev.label,
846
- status: "waiting",
847
- runtime: "wait",
848
- budget: {
849
- maxIterations: 0,
850
- maxTokens: 0
851
- },
852
- spent: zeroSpend()
853
- });
854
- continue;
855
- }
856
- if (ev.parent === void 0 && root === void 0) root = ev.id;
857
- nodes.set(ev.id, {
858
- id: ev.id,
859
- parent: ev.parent,
860
- label: ev.label,
861
- status: "pending",
862
- runtime: ev.runtime,
863
- budget: ev.budget,
864
- ...ev.ownedTreeRoot === void 0 ? {} : { ownedTreeRoot: ev.ownedTreeRoot },
865
- ...ev.assignmentId === void 0 ? {} : { assignmentId: ev.assignmentId },
866
- ...ev.identity ? { identity: ev.identity } : {},
867
- spent: zeroSpend()
868
- });
869
- }
870
- for (const ev of settlements) if (ev.kind === "settled") {
871
- const node = requireNode(nodes, ev.id);
872
- node.status = ev.status === "done" ? "done" : "failed";
873
- node.spent = cloneSpend(ev.spent);
874
- node.providerModel = copyProviderModelEvidence(ev.providerModel);
875
- node.outRef = ev.outRef;
876
- node.trace = traceEvidenceFor(ev);
877
- const settledAt = Date.parse(ev.at);
878
- if (Number.isFinite(settledAt)) node.settledAt = settledAt;
879
- } else if (ev.kind === "woken") {
880
- const node = requireNode(nodes, ev.id);
881
- node.status = ev.by === "cancelled" ? "cancelled" : "done";
882
- node.outRef = ev.outRef;
883
- node.trace = {
884
- status: "unavailable",
885
- reason: "not-an-executor"
886
- };
887
- const settledAt = Date.parse(ev.at);
888
- if (Number.isFinite(settledAt)) node.settledAt = settledAt;
889
- } else {
890
- const node = requireNode(nodes, ev.id);
891
- node.status = "cancelled";
892
- node.trace = {
893
- status: "unavailable",
894
- reason: "execution-did-not-start"
895
- };
896
- const settledAt = Date.parse(ev.at);
897
- if (Number.isFinite(settledAt)) node.settledAt = settledAt;
898
- }
899
- for (const ev of events) {
900
- if (ev.kind !== "materialized") continue;
901
- const node = requireNode(nodes, ev.id);
902
- node.materialization = ev.receipt;
903
- node.runtime = ev.receipt.runtime;
904
- }
905
- for (const ev of events) {
906
- if (ev.kind !== "execution-bound") continue;
907
- const node = requireNode(nodes, ev.id);
908
- node.executionBindings ??= [];
909
- node.executionBindings.push(ev.binding);
910
- }
911
- for (const ev of events) {
912
- if (ev.kind !== "metered") continue;
913
- const node = requireNode(nodes, ev.id);
914
- node.spent = addSpend(node.spent, ev.spend);
915
- }
916
- const snapshots = [...nodes.values()].map(freezeSnapshot);
917
- return {
918
- root: root ?? snapshots[0]?.id ?? "",
919
- nodes: snapshots,
920
- inFlight: snapshots.filter((n) => n.status === "running" || n.status === "acquiring").length,
921
- waiting: snapshots.filter((n) => n.status === "waiting").length
922
- };
923
- }
924
- /**
925
- * The waits a journaled tree shows as ARMED but never woken — what a resumed run re-arms with the
926
- * ORIGINAL absolute deadline. Reading it from the journal (rather than from any live state) is
927
- * what makes "SIGKILL a waiting tree, a new process keeps waiting to the same instant" true.
928
- */
929
- function pendingWaits(events) {
930
- const woken = /* @__PURE__ */ new Set();
931
- for (const ev of events) if (ev.kind === "woken") woken.add(ev.id);
932
- const pending = [];
933
- for (const ev of events) {
934
- if (ev.kind !== "waiting" || woken.has(ev.id)) continue;
935
- pending.push({
936
- id: ev.id,
937
- label: ev.label,
938
- spec: ev.spec,
939
- armedAt: ev.armedAt,
940
- ordinal: ev.seq
941
- });
942
- }
943
- return pending.sort((a, b) => a.ordinal - b.ordinal);
944
- }
945
- /** Copy provider evidence at the journal boundary so replay never exposes mutable event state. */
946
- function copyProviderModelEvidence(evidence) {
947
- if (evidence === void 0) return void 0;
948
- const attempts = Object.freeze(evidence.attempts.map((attempt) => Object.freeze({
949
- observations: Object.freeze([...attempt.observations]),
950
- ...attempt.identityConflict ? { identityConflict: true } : {},
951
- ...attempt.providerDispatch === "not_started" ? { providerDispatch: "not_started" } : {}
952
- })));
953
- const models = Object.freeze([...evidence.models]);
954
- return Object.freeze(evidence.status === "unknown" ? {
955
- status: "unknown",
956
- attempts,
957
- models,
958
- reason: evidence.reason
959
- } : {
960
- status: "known",
961
- attempts,
962
- models
963
- });
964
- }
965
- function requireNode(nodes, id) {
966
- const node = nodes.get(id);
967
- if (!node) throw new Error(`spawn journal corrupted: settle/cancel for node '${id}' with no prior spawn`);
968
- return node;
969
- }
970
- function freezeSnapshot(node) {
971
- return {
972
- id: node.id,
973
- parent: node.parent,
974
- label: node.label,
975
- status: node.status,
976
- runtime: node.runtime,
977
- budget: node.budget,
978
- ownedTreeRoot: node.ownedTreeRoot,
979
- assignmentId: node.assignmentId,
980
- identity: node.identity,
981
- materialization: node.materialization,
982
- executionBindings: node.executionBindings === void 0 ? void 0 : Object.freeze([...node.executionBindings]),
983
- spent: node.spent,
984
- providerModel: node.providerModel,
985
- outRef: node.outRef,
986
- trace: node.trace,
987
- settledAt: node.settledAt
988
- };
989
- }
990
- function traceEvidenceFor(event) {
991
- return event.trace ?? {
992
- status: "unavailable",
993
- reason: "legacy-settlement-without-trace-evidence"
994
- };
995
- }
996
- //#endregion
997
- export { captureWorkerTraceEvidence as _, aggregateProviderModelEvidence as a, workerTraceAnalysisStore as b, loadSpawnForest as c, replaySpawnTree as d, attestNestedDriverTreeOwner as f, WORKER_TOOL_TRACE_SCHEMA_VERSION as g, runtimeOwnedNestedDriverTreeRoot as h, InMemorySpawnJournal as i, materializeTreeView as l, nestedDriverTreeRoot as m, FileSpawnJournal as n, closesCursorSlot as o, driverRuntime as p, InMemoryResultBlobStore as r, insideCursorNamespace as s, FileResultBlobStore as t, pendingWaits as u, isTraceAnalysisStore as v, contentAddress as x, parseWorkerToolTraceArtifact as y };
998
-
999
- //# sourceMappingURL=spawn-journal-B9eTmVAn.js.map