@tangle-network/agent-runtime 0.116.0 → 0.119.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 (95) hide show
  1. package/README.md +9 -1
  2. package/dist/{activation-DuqQhee6.js → activation-DdIpwQ0k.js} +3 -3
  3. package/dist/{activation-DuqQhee6.js.map → activation-DdIpwQ0k.js.map} +1 -1
  4. package/dist/agent.d.ts +3 -64
  5. package/dist/agent.js +5 -207
  6. package/dist/agent.js.map +1 -1
  7. package/dist/{analyst-loop-BoNIG2hA.js → analyst-loop-DvSciOfB.js} +2 -2
  8. package/dist/{analyst-loop-BoNIG2hA.js.map → analyst-loop-DvSciOfB.js.map} +1 -1
  9. package/dist/analyst-loop.js +1 -1
  10. package/dist/candidate-execution/index.d.ts +3 -3
  11. package/dist/candidate-execution/index.js +5 -5
  12. package/dist/{candidate-execution-CfpJrd3o.js → candidate-execution-DDkSRPjY.js} +4 -4
  13. package/dist/{candidate-execution-CfpJrd3o.js.map → candidate-execution-DDkSRPjY.js.map} +1 -1
  14. package/dist/{environment-provider-CWsRh6Uz.d.ts → environment-provider-Bh4nX2qt.d.ts} +306 -32
  15. package/dist/{environment-provider-CCaEhA-l.js → environment-provider-Cr75N-rU.js} +141 -32
  16. package/dist/environment-provider-Cr75N-rU.js.map +1 -0
  17. package/dist/environment-provider.d.ts +1 -1
  18. package/dist/environment-provider.js +1 -1
  19. package/dist/{improvement-cycle-C1cmjvPD.js → improvement-cycle-zjR-MXwK.js} +163 -22
  20. package/dist/improvement-cycle-zjR-MXwK.js.map +1 -0
  21. package/dist/{index-C-FYUuFG.d.ts → index-B3bHsVLw.d.ts} +2 -2
  22. package/dist/{index-CYkDeM5L.d.ts → index-BLsKcxNd.d.ts} +3 -3
  23. package/dist/{index-COumPQka.d.ts → index-CGADWaa_.d.ts} +864 -437
  24. package/dist/{index-DcLMNnG5.d.ts → index-I35151Fr.d.ts} +9 -9
  25. package/dist/index.d.ts +9 -9
  26. package/dist/index.js +13 -13
  27. package/dist/index.js.map +1 -1
  28. package/dist/intelligence.d.ts +10 -9
  29. package/dist/intelligence.js +15 -9
  30. package/dist/intelligence.js.map +1 -1
  31. package/dist/kernel.d.ts +4 -4
  32. package/dist/kernel.js +9 -8
  33. package/dist/{knowledge-DOzbywZT.js → knowledge-I1e9zQGj.js} +7 -7
  34. package/dist/knowledge-I1e9zQGj.js.map +1 -0
  35. package/dist/knowledge.d.ts +1 -1
  36. package/dist/knowledge.js +1 -1
  37. package/dist/{local-harness-t6cDWDQ2.d.ts → local-harness-BIajef4A.d.ts} +29 -7
  38. package/dist/{loop-runner-bin-BFrhPLKt.d.ts → loop-runner-bin-BeG9vTdE.d.ts} +3 -3
  39. package/dist/{loop-runner-bin-BuQjc5DR.js → loop-runner-bin-L996YVPS.js} +4 -4
  40. package/dist/{loop-runner-bin-BuQjc5DR.js.map → loop-runner-bin-L996YVPS.js.map} +1 -1
  41. package/dist/loop-runner-bin.d.ts +1 -1
  42. package/dist/loop-runner-bin.js +1 -1
  43. package/dist/mcp/bin.js +43 -10
  44. package/dist/mcp/bin.js.map +1 -1
  45. package/dist/mcp/index.d.ts +5 -45
  46. package/dist/mcp/index.js +8 -212
  47. package/dist/mcp/index.js.map +1 -1
  48. package/dist/{openai-tools-_Wyp4udO.js → openai-tools-CvFEzw6f.js} +2 -2
  49. package/dist/{openai-tools-_Wyp4udO.js.map → openai-tools-CvFEzw6f.js.map} +1 -1
  50. package/dist/{prepare-BHQBb02e.js → prepare-DpV6np9e.js} +47 -34
  51. package/dist/prepare-DpV6np9e.js.map +1 -0
  52. package/dist/primeintellect/index.d.ts +1 -1
  53. package/dist/{protected-model-port-BP6Z4eau.d.ts → protected-model-port-CoJOiINX.d.ts} +11 -3
  54. package/dist/{protected-model-port-DqAH1Z2M.js → protected-model-port-vQLBRoAQ.js} +2 -2
  55. package/dist/{protected-model-port-DqAH1Z2M.js.map → protected-model-port-vQLBRoAQ.js.map} +1 -1
  56. package/dist/{redact-BEtQtvd6.d.ts → redact-PQzmE1Jn.d.ts} +4 -4
  57. package/dist/run-layout-C2FGmZ3v.js +158 -0
  58. package/dist/run-layout-C2FGmZ3v.js.map +1 -0
  59. package/dist/{runtime-Ut1pkd2n.js → runtime-D4e3GP5K.js} +147 -190
  60. package/dist/runtime-D4e3GP5K.js.map +1 -0
  61. package/dist/{sandbox-events-DeI5xX8P.js → sandbox-events-Yhd1GYWl.js} +4 -2
  62. package/dist/sandbox-events-Yhd1GYWl.js.map +1 -0
  63. package/dist/spawn-journal-IeXpidO2.js +857 -0
  64. package/dist/spawn-journal-IeXpidO2.js.map +1 -0
  65. package/dist/{structural-rollout-CVY_0hJp.js → structural-rollout-DQHO3b2Y.js} +4 -4
  66. package/dist/structural-rollout-DQHO3b2Y.js.map +1 -0
  67. package/dist/{supervise-BUR9ByF7.js → supervise-Cq50UT5-.js} +2874 -1892
  68. package/dist/supervise-Cq50UT5-.js.map +1 -0
  69. package/dist/{supervisor-BBbPBXpe.js → supervisor-CpT9yAxL.js} +2896 -983
  70. package/dist/supervisor-CpT9yAxL.js.map +1 -0
  71. package/dist/testing.js +98 -76
  72. package/dist/testing.js.map +1 -1
  73. package/dist/top-app-5unxqovu.js +1088 -0
  74. package/dist/top-app-5unxqovu.js.map +1 -0
  75. package/dist/tui/bin.d.ts +1 -0
  76. package/dist/tui/bin.js +19 -0
  77. package/dist/tui/bin.js.map +1 -0
  78. package/dist/tui/index.d.ts +209 -0
  79. package/dist/tui/index.js +2 -0
  80. package/dist/{util-Cc9g9Y-o.js → util-MVgdwuIS.js} +2 -2
  81. package/dist/{util-Cc9g9Y-o.js.map → util-MVgdwuIS.js.map} +1 -1
  82. package/dist/{workspace-archive-DXzJq7WP.js → workspace-archive-B4SkNJjw.js} +2 -2
  83. package/dist/{workspace-archive-DXzJq7WP.js.map → workspace-archive-B4SkNJjw.js.map} +1 -1
  84. package/package.json +8 -2
  85. package/dist/environment-provider-CCaEhA-l.js.map +0 -1
  86. package/dist/improvement-cycle-C1cmjvPD.js.map +0 -1
  87. package/dist/knowledge-DOzbywZT.js.map +0 -1
  88. package/dist/prepare-BHQBb02e.js.map +0 -1
  89. package/dist/runtime-Ut1pkd2n.js.map +0 -1
  90. package/dist/sandbox-events-DeI5xX8P.js.map +0 -1
  91. package/dist/spawn-journal-DCPbicXB.js +0 -457
  92. package/dist/spawn-journal-DCPbicXB.js.map +0 -1
  93. package/dist/structural-rollout-CVY_0hJp.js.map +0 -1
  94. package/dist/supervise-BUR9ByF7.js.map +0 -1
  95. package/dist/supervisor-BBbPBXpe.js.map +0 -1
@@ -0,0 +1,857 @@
1
+ import { u as ValidationError } from "./errors-DEAvWQPy.js";
2
+ import { f as zeroTokenUsage } from "./util-MVgdwuIS.js";
3
+ import { isToolSpan, toolSpansToTraceAnalysisStore } from "@tangle-network/agent-eval";
4
+ import { createHash } from "node:crypto";
5
+ //#region src/runtime/supervise/snapshot.ts
6
+ /** Deeply detach and freeze untrusted data at a runtime decision boundary. The clone prevents the
7
+ * caller from mutating it later; the freeze prevents downstream code from mutating the snapshot. */
8
+ function detachedSnapshot(value, context) {
9
+ try {
10
+ return deepFreeze(structuredClone(value));
11
+ } catch (error) {
12
+ throw new ValidationError(`${context}: input must be structured-cloneable`, { cause: error });
13
+ }
14
+ }
15
+ function deepFreeze(value, seen = /* @__PURE__ */ new Set()) {
16
+ if (value === null || typeof value !== "object" || seen.has(value)) return value;
17
+ seen.add(value);
18
+ for (const child of Object.values(value)) deepFreeze(child, seen);
19
+ return Object.freeze(value);
20
+ }
21
+ //#endregion
22
+ //#region src/durable/content-address.ts
23
+ /** Stable content address shared by result and trace artifacts. */
24
+ function contentAddress(artifact) {
25
+ return `sha256:${createHash("sha256").update(stableStringify(artifact), "utf-8").digest("hex")}`;
26
+ }
27
+ function stableStringify(value) {
28
+ if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
29
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
30
+ 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(",")}}`;
31
+ }
32
+ //#endregion
33
+ //#region src/runtime/supervise/trace-evidence.ts
34
+ /**
35
+ * Durable structured tool evidence for supervised workers.
36
+ *
37
+ * The executor-owned `TraceSource` is collected before teardown, snapshotted into the shared
38
+ * content-addressed blob store, and only then referenced by a settlement. Analysis reconstructs
39
+ * agent-eval's bounded `TraceAnalysisStore` from those exact bytes. Worker output is never accepted
40
+ * as a substitute for tool evidence.
41
+ *
42
+ * @experimental
43
+ */
44
+ /** Schema version for content-addressed worker tool-trace artifacts. */
45
+ const WORKER_TOOL_TRACE_SCHEMA_VERSION = 1;
46
+ /** Structural guard for the official bounded trace-analysis read contract. */
47
+ function isTraceAnalysisStore(value) {
48
+ if (value === null || typeof value !== "object") return false;
49
+ const store = value;
50
+ 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";
51
+ }
52
+ /** Collect and persist one executor's structured tool trace without changing its task outcome. */
53
+ async function captureWorkerTraceEvidence(readSource, blobs, executed) {
54
+ if (!executed) return unavailable("execution-did-not-start");
55
+ if (readSource === void 0) return unavailable("executor-did-not-expose-trace-source");
56
+ let source;
57
+ try {
58
+ source = readSource();
59
+ } catch {
60
+ return unavailable("trace-source-unavailable");
61
+ }
62
+ if (source === void 0) return unavailable("trace-source-unavailable");
63
+ let collected;
64
+ try {
65
+ collected = await source.collect();
66
+ } catch {
67
+ return unavailable("trace-collection-failed");
68
+ }
69
+ if (!Array.isArray(collected) || collected.some((span) => !isToolSpanValue(span))) return unavailable("invalid-tool-spans");
70
+ if (collected.length === 0) return unavailable("no-tool-spans-captured");
71
+ let artifact;
72
+ let traceRef;
73
+ try {
74
+ const snapshot = structuredClone(collected);
75
+ toolSpansToTraceAnalysisStore(snapshot);
76
+ artifact = {
77
+ schemaVersion: 1,
78
+ spans: snapshot
79
+ };
80
+ traceRef = contentAddress(artifact);
81
+ } catch {
82
+ return unavailable("invalid-tool-spans");
83
+ }
84
+ try {
85
+ await blobs.put(traceRef, artifact);
86
+ } catch {
87
+ return unavailable("trace-persistence-failed");
88
+ }
89
+ return Object.freeze({
90
+ status: "available",
91
+ traceRef,
92
+ spanCount: artifact.spans.length
93
+ });
94
+ }
95
+ /** Rehydrate exact persisted spans through agent-eval's one bounded trace-analysis adapter. */
96
+ async function workerTraceAnalysisStore(evidence, blobs) {
97
+ if (evidence.status === "unavailable") return toolSpansToTraceAnalysisStore(void 0);
98
+ const raw = await blobs.get(evidence.traceRef);
99
+ if (raw === void 0) throw new ValidationError(`worker trace blob '${evidence.traceRef}' is missing; the settlement evidence is incomplete`);
100
+ const artifact = parseWorkerToolTraceArtifact(raw, evidence.traceRef);
101
+ 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}`);
102
+ return toolSpansToTraceAnalysisStore(artifact.spans);
103
+ }
104
+ /** Validate a stored trace artifact before an analyst or replay trusts it. */
105
+ function parseWorkerToolTraceArtifact(value, traceRef = "<unknown>") {
106
+ 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`);
107
+ const spans = value.spans;
108
+ if (spans.length === 0) return {
109
+ schemaVersion: 1,
110
+ spans
111
+ };
112
+ if (spans.some((span) => !isToolSpanValue(span))) throw new ValidationError(`worker trace blob '${traceRef}' contains a non-tool span`);
113
+ return {
114
+ schemaVersion: 1,
115
+ spans
116
+ };
117
+ }
118
+ function unavailable(reason) {
119
+ return Object.freeze({
120
+ status: "unavailable",
121
+ reason
122
+ });
123
+ }
124
+ function isToolSpanValue(value) {
125
+ try {
126
+ return isToolSpan(value);
127
+ } catch {
128
+ return false;
129
+ }
130
+ }
131
+ //#endregion
132
+ //#region src/runtime/supervise/tree-key.ts
133
+ /** Runtime tag used only for a child that owns another supervised scope. */
134
+ const driverRuntime = "driver";
135
+ const nestedDriverTreeOwners = /* @__PURE__ */ new WeakSet();
136
+ /** Canonical journal key for the scope owned by one nested driver node. */
137
+ function nestedDriverTreeRoot(parentTreeRoot, driverNodeId) {
138
+ return `${parentTreeRoot}/${driverNodeId}`;
139
+ }
140
+ /** Privately mark the exact recursive executor that will create a nested journal tree. */
141
+ function attestNestedDriverTreeOwner(owner) {
142
+ nestedDriverTreeOwners.add(owner);
143
+ return owner;
144
+ }
145
+ /** Return the canonical owned tree only for an exact privately marked recursive executor. */
146
+ function runtimeOwnedNestedDriverTreeRoot(owner, parentTreeRoot, driverNodeId) {
147
+ return nestedDriverTreeOwners.has(owner) ? nestedDriverTreeRoot(parentTreeRoot, driverNodeId) : void 0;
148
+ }
149
+ //#endregion
150
+ //#region src/durable/jsonl-file.ts
151
+ /** Parse an append-only JSONL file without treating a torn final write as committed data.
152
+ * A malformed newline-terminated or non-final record is corruption and fails loud. */
153
+ function parseCommittedJsonLines(text, source) {
154
+ const lines = text.split("\n");
155
+ const finalIndex = lines.length - 1;
156
+ const records = [];
157
+ for (const [index, line] of lines.entries()) {
158
+ if (line.length === 0) continue;
159
+ try {
160
+ records.push(JSON.parse(line));
161
+ } catch (cause) {
162
+ if (index === finalIndex && !text.endsWith("\n")) break;
163
+ throw new Error(`${source}: malformed JSONL record at line ${index + 1}`, { cause });
164
+ }
165
+ }
166
+ return records;
167
+ }
168
+ /** FileHandle.write may legally make a short write. Loop until every byte is appended. */
169
+ async function writeAllBytes(handle, value) {
170
+ const bytes = typeof value === "string" ? Buffer.from(value) : Buffer.from(value);
171
+ let offset = 0;
172
+ while (offset < bytes.byteLength) {
173
+ const { bytesWritten } = await handle.write(bytes, offset, bytes.byteLength - offset, null);
174
+ if (bytesWritten <= 0) throw new Error(`append-only file write made no progress at byte ${offset}`);
175
+ offset += bytesWritten;
176
+ }
177
+ }
178
+ /** Prepare a recovered JSONL file for its next append. A valid unterminated final value is retained
179
+ * and needs a separator; an invalid unterminated tail was never committed and is truncated. */
180
+ async function prepareJsonlAppend(path) {
181
+ const fs = await import("node:fs/promises");
182
+ let bytes;
183
+ try {
184
+ bytes = await fs.readFile(path);
185
+ } catch (error) {
186
+ if (isNoEntError$1(error)) return false;
187
+ throw error;
188
+ }
189
+ if (bytes.byteLength === 0 || bytes[bytes.byteLength - 1] === 10) return false;
190
+ const lastNewline = bytes.lastIndexOf(10);
191
+ const tail = bytes.subarray(lastNewline + 1).toString("utf8");
192
+ try {
193
+ JSON.parse(tail);
194
+ return true;
195
+ } catch {
196
+ await fs.truncate(path, lastNewline + 1);
197
+ return false;
198
+ }
199
+ }
200
+ function isNoEntError$1(error) {
201
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
202
+ }
203
+ //#endregion
204
+ //#region src/durable/spawn-journal.ts
205
+ /**
206
+ *
207
+ * Event-sourced spawn journal for the recursive execution atom (build steps 3 + 7).
208
+ *
209
+ * The supervision tree is journaled as an append-only event log: every `spawned`,
210
+ * `settled`, and `cancelled` is recorded AFTER it is observed-committed (never
211
+ * speculative), mirroring `ConversationJournal`'s begin/append/load shape. The log
212
+ * holds only the THIN decision record — ids, parentage, budget, the spend a decision
213
+ * consumed, and a content-addressed `outRef`. The payloads the driver branched on
214
+ * (the `out` artifacts) live in a separate `ResultBlobStore`, keyed by `outRef`, so
215
+ * the journal stays small (decisions) and replay rehydrates the exact `Settled` from
216
+ * the blob store (evidence). This is the decision/payload split the replay argument
217
+ * rests on (B1/B2).
218
+ *
219
+ * Replay determinism (B2): `seq` is the monotonic cursor order `scope.next()` yielded
220
+ * each settlement — NOT wall-clock. `replaySpawnTree` sorts strictly by `seq` before
221
+ * touching the blob store, so the order in which rehydration `get`s resolve can never
222
+ * reorder the replayed `Settled[]`; the result is identical regardless of blob latency.
223
+ *
224
+ * @experimental
225
+ */
226
+ /**
227
+ * Mint the content-addressed `outRef` for a result artifact: `sha256:<hex>` over a
228
+ * stable JSON encoding. Producers call this to derive the `outRef` they journal and
229
+ * `put`; the FS/in-mem stores re-derive it on `put` to verify the supplied ref
230
+ * matches (fail loud on a mismatch — a forged ref breaks the replay invariant).
231
+ *
232
+ * Stable encoding: object keys are sorted recursively so two structurally-equal
233
+ * artifacts hash identically regardless of key insertion order.
234
+ */
235
+ /**
236
+ * In-memory `ResultBlobStore`. Content-addressed: `put` verifies the supplied
237
+ * `outRef` matches the artifact's hash so a stale/forged ref fails loud rather than
238
+ * silently rehydrating the wrong payload. Idempotent on an identical re-put.
239
+ */
240
+ var InMemoryResultBlobStore = class {
241
+ blobs = /* @__PURE__ */ new Map();
242
+ async put(outRef, artifact) {
243
+ assertContentAddress(outRef, artifact);
244
+ this.blobs.set(outRef, artifact);
245
+ }
246
+ async get(outRef) {
247
+ return this.blobs.has(outRef) ? this.blobs.get(outRef) : void 0;
248
+ }
249
+ };
250
+ /**
251
+ * FS `ResultBlobStore`. One JSON file per artifact under `dir`, named by a
252
+ * filesystem-safe encoding of the `outRef` (`sha256:<hex>` → `sha256-<hex>.json`).
253
+ * `put` fsyncs so a crash between writes never loses an acknowledged blob.
254
+ */
255
+ var FileResultBlobStore = class {
256
+ dir;
257
+ constructor(dir) {
258
+ this.dir = dir;
259
+ }
260
+ async put(outRef, artifact) {
261
+ assertContentAddress(outRef, artifact);
262
+ const fs = await import("node:fs/promises");
263
+ await fs.mkdir(this.dir, { recursive: true });
264
+ const fh = await fs.open(this.blobPath(outRef), "w");
265
+ try {
266
+ await fh.write(JSON.stringify(artifact));
267
+ await fh.sync();
268
+ } finally {
269
+ await fh.close();
270
+ }
271
+ }
272
+ async get(outRef) {
273
+ const fs = await import("node:fs/promises");
274
+ let text;
275
+ try {
276
+ text = await fs.readFile(this.blobPath(outRef), "utf8");
277
+ } catch (err) {
278
+ if (isNoEntError(err)) return void 0;
279
+ throw err;
280
+ }
281
+ return JSON.parse(text);
282
+ }
283
+ blobPath(outRef) {
284
+ return `${this.dir}/${outRef.replace(/:/g, "-")}.json`;
285
+ }
286
+ };
287
+ function assertContentAddress(outRef, artifact) {
288
+ const expected = contentAddress(artifact);
289
+ 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)`);
290
+ }
291
+ /**
292
+ * In-memory `SpawnJournal`. Appends are observed-committed only; the impl enforces
293
+ * the corruption guards a durable replay rests on:
294
+ * - an event before `beginTree` is a corrupted tree (fail loud),
295
+ * - a duplicate `seq` within a tree is a corrupted cursor (fail loud) — two
296
+ * settlements cannot share the cursor position replay orders by.
297
+ */
298
+ var InMemorySpawnJournal = class {
299
+ trees = /* @__PURE__ */ new Map();
300
+ async loadTree(root) {
301
+ const tree = this.trees.get(root);
302
+ if (!tree) return void 0;
303
+ return tree.events.map((ev) => ({ ...ev }));
304
+ }
305
+ async beginTree(root, at) {
306
+ const existing = this.trees.get(root);
307
+ if (existing) {
308
+ if (existing.begunAt !== at) throw new Error(`spawn tree '${root}' already begun at ${existing.begunAt}; refusing to overwrite with ${at}`);
309
+ return;
310
+ }
311
+ this.trees.set(root, {
312
+ begunAt: at,
313
+ events: []
314
+ });
315
+ }
316
+ async appendEvent(root, ev) {
317
+ const tree = this.trees.get(root);
318
+ if (!tree) throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
319
+ assertSeqUnique(root, tree.events, ev);
320
+ tree.events.push({ ...ev });
321
+ }
322
+ };
323
+ /**
324
+ * JSONL on disk. One line per record: the first record is `begin`, subsequent records
325
+ * are `event` envelopes wrapping a `SpawnEvent`. `loadTree` replays the whole file,
326
+ * filtering by `root`, and applies the same begin-precedes-events + unique-seq
327
+ * corruption guards as the in-memory impl. Each append fsyncs so a crash between
328
+ * writes never loses an acknowledged event.
329
+ */
330
+ var FileSpawnJournal = class {
331
+ path;
332
+ appendTail = Promise.resolve();
333
+ constructor(path) {
334
+ this.path = path;
335
+ }
336
+ async loadTree(root) {
337
+ const fs = await import("node:fs/promises");
338
+ let text;
339
+ try {
340
+ text = await fs.readFile(this.path, "utf8");
341
+ } catch (err) {
342
+ if (isNoEntError(err)) return void 0;
343
+ throw err;
344
+ }
345
+ let begun = false;
346
+ const events = [];
347
+ for (const record of parseCommittedJsonLines(text, this.path)) {
348
+ if (record.root !== root) continue;
349
+ if (record.kind === "begin") begun = true;
350
+ else {
351
+ if (!begun) throw new Error(`spawn journal corrupted: event for tree '${root}' precedes its begin record`);
352
+ assertSeqUnique(root, events, record.event);
353
+ events.push(record.event);
354
+ }
355
+ }
356
+ return begun ? events : void 0;
357
+ }
358
+ async beginTree(root, at) {
359
+ const existing = await this.loadTreeBegin(root);
360
+ if (existing) {
361
+ if (existing !== at) throw new Error(`spawn tree '${root}' already begun in ${this.path} at ${existing}; refusing to overwrite with ${at}`);
362
+ return;
363
+ }
364
+ await this.appendRecord({
365
+ kind: "begin",
366
+ root,
367
+ at
368
+ });
369
+ }
370
+ async appendEvent(root, ev) {
371
+ const events = await this.loadTree(root);
372
+ if (events === void 0) throw new Error(`appendEvent called for unknown spawn tree '${root}'; call beginTree first`);
373
+ assertSeqUnique(root, events, ev);
374
+ await this.appendRecord({
375
+ kind: "event",
376
+ root,
377
+ event: ev
378
+ });
379
+ }
380
+ async loadTreeBegin(root) {
381
+ const fs = await import("node:fs/promises");
382
+ let text;
383
+ try {
384
+ text = await fs.readFile(this.path, "utf8");
385
+ } catch (err) {
386
+ if (isNoEntError(err)) return void 0;
387
+ throw err;
388
+ }
389
+ for (const record of parseCommittedJsonLines(text, this.path)) if (record.root === root && record.kind === "begin") return record.at;
390
+ }
391
+ async appendRecord(record) {
392
+ const append = this.appendTail.then(() => this.writeRecord(record));
393
+ this.appendTail = append.catch(() => void 0);
394
+ return append;
395
+ }
396
+ async writeRecord(record) {
397
+ const fs = await import("node:fs/promises");
398
+ const path = await import("node:path");
399
+ await fs.mkdir(path.dirname(this.path), { recursive: true });
400
+ const needsSeparator = await prepareJsonlAppend(this.path);
401
+ const fh = await fs.open(this.path, "a");
402
+ try {
403
+ await writeAllBytes(fh, `${needsSeparator ? "\n" : ""}${JSON.stringify(record)}\n`);
404
+ await fh.sync();
405
+ } finally {
406
+ await fh.close();
407
+ }
408
+ }
409
+ };
410
+ /**
411
+ * Load every journal tree owned by one recursive supervision run and flatten its nodes/events.
412
+ *
413
+ * Nested driver tree keys are a Runtime implementation detail; callers should use this reader
414
+ * instead of deriving or scanning keys themselves. The reader follows only the explicit
415
+ * `ownedTreeRoot` written after Runtime privately attested a recursive executor; the open runtime
416
+ * string `driver` is never treated as ownership. Legacy records without `ownedTreeRoot` are
417
+ * intentionally treated as leaves rather than guessing or scanning convention-derived keys.
418
+ * This preserves each tree's independent cursor namespace on flattened events.
419
+ * A driver whose subtree was never begun is reported in `missingTrees`; any spawned non-root node
420
+ * without a terminal record is reported in `inDoubt`, matching resume's conservative lost-work
421
+ * interpretation.
422
+ *
423
+ * This is a cold/quiescent reader, not a transaction across an actively mutating file. Every value
424
+ * returned is a detached immutable snapshot, so later journal writes or caller mutation cannot
425
+ * change the result already observed.
426
+ */
427
+ async function loadSpawnForest(journal, root) {
428
+ const rootEvents = await journal.loadTree(root);
429
+ if (rootEvents === void 0) throw new Error(`loadSpawnForest: no journaled tree for root '${root}'`);
430
+ const trees = [];
431
+ const nodes = [];
432
+ const events = [];
433
+ const inDoubt = [];
434
+ const missingTrees = [];
435
+ const visited = /* @__PURE__ */ new Set();
436
+ const queue = [{
437
+ root,
438
+ events: rootEvents
439
+ }];
440
+ for (let cursor = 0; cursor < queue.length; cursor += 1) {
441
+ const current = queue[cursor];
442
+ if (visited.has(current.root)) throw new Error(`loadSpawnForest: recursive journal tree '${current.root}' was reached twice`);
443
+ visited.add(current.root);
444
+ const stableEvents = detachedSnapshot(current.events, `loadSpawnForest tree ${JSON.stringify(current.root)}`);
445
+ const view = detachedSnapshot(materializeTreeView([...stableEvents]), `loadSpawnForest view ${JSON.stringify(current.root)}`);
446
+ trees.push({
447
+ root: current.root,
448
+ ...current.ownerNodeId === void 0 ? {} : { ownerNodeId: current.ownerNodeId },
449
+ ...current.parentTreeRoot === void 0 ? {} : { parentTreeRoot: current.parentTreeRoot },
450
+ events: stableEvents,
451
+ view
452
+ });
453
+ nodes.push(...view.nodes.map((node) => ({
454
+ treeRoot: current.root,
455
+ ...node
456
+ })));
457
+ events.push(...stableEvents.map((event) => ({
458
+ treeRoot: current.root,
459
+ event
460
+ })));
461
+ const terminal = /* @__PURE__ */ new Set();
462
+ for (const event of stableEvents) if (event.kind === "settled" || event.kind === "cancelled") terminal.add(event.id);
463
+ const spawns = stableEvents.filter((event) => event.kind === "spawned").sort((a, b) => a.seq - b.seq || a.id.localeCompare(b.id));
464
+ for (const spawn of spawns) {
465
+ if (spawn.parent !== void 0 && !terminal.has(spawn.id)) inDoubt.push({
466
+ treeRoot: current.root,
467
+ nodeId: spawn.id,
468
+ label: spawn.label,
469
+ runtime: spawn.runtime
470
+ });
471
+ if (spawn.ownedTreeRoot === void 0) continue;
472
+ const expectedRoot = nestedDriverTreeRoot(current.root, spawn.id);
473
+ if (spawn.ownedTreeRoot !== expectedRoot) throw new Error(`loadSpawnForest: node '${spawn.id}' owns non-canonical tree '${spawn.ownedTreeRoot}'; expected '${expectedRoot}'`);
474
+ const nestedRoot = spawn.ownedTreeRoot;
475
+ const nestedEvents = await journal.loadTree(nestedRoot);
476
+ if (nestedEvents === void 0) {
477
+ missingTrees.push({
478
+ parentTreeRoot: current.root,
479
+ ownerNodeId: spawn.id,
480
+ root: nestedRoot
481
+ });
482
+ continue;
483
+ }
484
+ queue.push({
485
+ root: nestedRoot,
486
+ events: nestedEvents,
487
+ ownerNodeId: spawn.id,
488
+ parentTreeRoot: current.root
489
+ });
490
+ }
491
+ }
492
+ return detachedSnapshot({
493
+ root,
494
+ trees,
495
+ nodes,
496
+ events,
497
+ inDoubt,
498
+ missingTrees
499
+ }, "loadSpawnForest result");
500
+ }
501
+ /**
502
+ * Two `seq` namespaces share the journal: a `spawned` event's `seq` is the spawn ordinal
503
+ * (the order children were created), and a `settled`/`cancelled` event's `seq` is the
504
+ * monotonic CURSOR order `scope.next()` yielded that settlement (B2). The uniqueness
505
+ * replay rests on is the cursor namespace — two settlements cannot share the position
506
+ * replay orders by — so the guard checks only settled/cancelled events. A `spawned`
507
+ * ordinal legitimately equals a later `settled` cursor seq and is not a collision.
508
+ */
509
+ function assertSeqUnique(root, events, ev) {
510
+ if (ev.kind === "materialized") {
511
+ 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}'`);
512
+ 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}'`);
513
+ }
514
+ if (ev.kind === "execution-bound") {
515
+ 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}'`);
516
+ 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}'`);
517
+ }
518
+ if (outsideCursorNamespace(ev)) return;
519
+ 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`);
520
+ }
521
+ /** Node-CREATION and informational records — outside the cursor namespace whose uniqueness replay
522
+ * ordering rests on. The single predicate both the guard's sides read, so a new event kind is
523
+ * classified once. */
524
+ function outsideCursorNamespace(ev) {
525
+ return ev.kind === "spawned" || ev.kind === "waiting" || ev.kind === "metered" || ev.kind === "materialized" || ev.kind === "execution-bound";
526
+ }
527
+ /**
528
+ * Re-feed a journaled spawn tree in strict `seq` order, rehydrating each settled
529
+ * child's `out` from the blob store by `outRef`, and return the `Settled[]` exactly
530
+ * as `scope.next()` originally delivered them.
531
+ *
532
+ * Determinism (B2): the events are sorted by `seq` BEFORE any blob `get`, so the
533
+ * replay order is the recorded cursor order regardless of how fast each rehydration
534
+ * resolves. `at` (wall-clock) is never a replay input. Fail loud on a tree that was
535
+ * never begun, a settled-done event missing its `outRef`, or a blob the store can't
536
+ * rehydrate — a silent gap would let `act` branch on the wrong evidence.
537
+ */
538
+ async function replaySpawnTree(journal, blobs, root) {
539
+ const events = await journal.loadTree(root);
540
+ if (events === void 0) throw new Error(`replaySpawnTree: no journaled tree for root '${root}'`);
541
+ const ordered = [...events].sort((a, b) => a.seq - b.seq);
542
+ const labels = /* @__PURE__ */ new Map();
543
+ const assignmentIds = /* @__PURE__ */ new Map();
544
+ const identities = /* @__PURE__ */ new Map();
545
+ const materializations = /* @__PURE__ */ new Map();
546
+ const executionBindings = /* @__PURE__ */ new Map();
547
+ for (const ev of ordered) {
548
+ if (ev.kind === "spawned" || ev.kind === "waiting") labels.set(ev.id, ev.label);
549
+ if (ev.kind === "spawned" && ev.assignmentId !== void 0) assignmentIds.set(ev.id, ev.assignmentId);
550
+ if (ev.kind === "spawned" && ev.identity !== void 0) identities.set(ev.id, copyFrozenIdentity(ev.identity));
551
+ if (ev.kind === "materialized") materializations.set(ev.id, ev.receipt);
552
+ if (ev.kind === "execution-bound") {
553
+ const bindings = executionBindings.get(ev.id) ?? [];
554
+ bindings.push(ev.binding);
555
+ executionBindings.set(ev.id, bindings);
556
+ }
557
+ }
558
+ const handleFor = (id, status) => replayHandle(id, labels.get(id) ?? id, status, {
559
+ assignmentId: assignmentIds.get(id),
560
+ identity: identities.get(id),
561
+ materialization: materializations.get(id),
562
+ executionBindings: executionBindings.get(id)
563
+ });
564
+ const settlementTime = (at) => {
565
+ const settledAt = Date.parse(at);
566
+ return Number.isFinite(settledAt) ? { settledAt } : {};
567
+ };
568
+ const settled = [];
569
+ for (const ev of ordered) {
570
+ if (ev.kind === "spawned") continue;
571
+ if (ev.kind === "waiting") continue;
572
+ if (ev.kind === "metered") continue;
573
+ if (ev.kind === "materialized") continue;
574
+ if (ev.kind === "execution-bound") continue;
575
+ if (ev.kind === "woken") {
576
+ if (ev.by === "cancelled" || ev.outRef === void 0) {
577
+ settled.push({
578
+ kind: "down",
579
+ handle: handleFor(ev.id, "cancelled"),
580
+ reason: "wait cancelled",
581
+ infra: false,
582
+ restartCount: 0,
583
+ trace: {
584
+ status: "unavailable",
585
+ reason: "not-an-executor"
586
+ },
587
+ ...settlementTime(ev.at),
588
+ seq: ev.seq
589
+ });
590
+ continue;
591
+ }
592
+ const outcome = await blobs.get(ev.outRef);
593
+ if (outcome === void 0) throw new Error(`replaySpawnTree: blob store has no wait outcome for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`);
594
+ settled.push({
595
+ kind: "done",
596
+ handle: handleFor(ev.id, "done"),
597
+ out: outcome,
598
+ outRef: ev.outRef,
599
+ spent: zeroSpend(),
600
+ trace: {
601
+ status: "unavailable",
602
+ reason: "not-an-executor"
603
+ },
604
+ ...settlementTime(ev.at),
605
+ seq: ev.seq
606
+ });
607
+ continue;
608
+ }
609
+ if (ev.kind === "cancelled") {
610
+ settled.push({
611
+ kind: "down",
612
+ handle: handleFor(ev.id, "cancelled"),
613
+ reason: ev.reason,
614
+ infra: false,
615
+ restartCount: 0,
616
+ trace: {
617
+ status: "unavailable",
618
+ reason: "execution-did-not-start"
619
+ },
620
+ ...settlementTime(ev.at),
621
+ seq: ev.seq
622
+ });
623
+ continue;
624
+ }
625
+ if (ev.status === "down") {
626
+ const trace = traceEvidenceFor(ev);
627
+ if (trace.status === "available") await workerTraceAnalysisStore(trace, blobs);
628
+ settled.push({
629
+ kind: "down",
630
+ handle: handleFor(ev.id, "failed"),
631
+ reason: ev.reason ?? ev.verdict?.notes ?? "child down",
632
+ infra: ev.infra === true,
633
+ restartCount: 0,
634
+ trace,
635
+ ...settlementTime(ev.at),
636
+ seq: ev.seq
637
+ });
638
+ continue;
639
+ }
640
+ 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`);
641
+ const out = await blobs.get(ev.outRef);
642
+ if (out === void 0) throw new Error(`replaySpawnTree: blob store has no artifact for outRef '${ev.outRef}' (node '${ev.id}', seq ${ev.seq})`);
643
+ const trace = traceEvidenceFor(ev);
644
+ if (trace.status === "available") await workerTraceAnalysisStore(trace, blobs);
645
+ settled.push({
646
+ kind: "done",
647
+ handle: handleFor(ev.id, "done"),
648
+ out,
649
+ outRef: ev.outRef,
650
+ verdict: ev.verdict,
651
+ spent: ev.spent,
652
+ trace,
653
+ ...settlementTime(ev.at),
654
+ seq: ev.seq
655
+ });
656
+ }
657
+ return settled;
658
+ }
659
+ function replayHandle(id, label, status, evidence = {}) {
660
+ return Object.freeze({
661
+ id,
662
+ label,
663
+ status,
664
+ ...evidence.assignmentId === void 0 ? {} : { assignmentId: evidence.assignmentId },
665
+ ...evidence.identity === void 0 ? {} : { identity: evidence.identity },
666
+ ...evidence.materialization === void 0 ? {} : { materialization: evidence.materialization },
667
+ ...evidence.executionBindings === void 0 ? {} : { executionBindings: Object.freeze([...evidence.executionBindings]) },
668
+ abort() {
669
+ throw new Error(`cannot abort node '${id}': replayed handles are terminal, not live`);
670
+ }
671
+ });
672
+ }
673
+ /** A replayed handle must not retain mutable references into the loaded journal event. */
674
+ function copyFrozenIdentity(identity) {
675
+ const correlation = identity.correlation === void 0 ? void 0 : Object.freeze({ ...identity.correlation });
676
+ return Object.freeze({
677
+ ...identity.profileDigest === void 0 ? {} : { profileDigest: identity.profileDigest },
678
+ ...identity.taskDigest === void 0 ? {} : { taskDigest: identity.taskDigest },
679
+ ...identity.candidateDigest === void 0 ? {} : { candidateDigest: identity.candidateDigest },
680
+ ...correlation === void 0 ? {} : { correlation }
681
+ });
682
+ }
683
+ /**
684
+ * Materialize a recorded `TreeView` from a journaled event list for inspection. Folds
685
+ * `spawned`/`settled`/`cancelled` into a per-node snapshot in `seq` order, then adds each
686
+ * `metered` event's driver-inference spend onto its node in a separate additive pass so the view
687
+ * matches the recorded cursor. It does not recover live executors or driver state after restart.
688
+ */
689
+ function materializeTreeView(events) {
690
+ const nodes = /* @__PURE__ */ new Map();
691
+ let root;
692
+ const spawns = events.filter((ev) => ev.kind === "spawned" || ev.kind === "waiting").sort((a, b) => a.seq - b.seq);
693
+ const settlements = events.filter((ev) => ev.kind !== "spawned" && ev.kind !== "waiting" && ev.kind !== "metered" && ev.kind !== "materialized" && ev.kind !== "execution-bound").sort((a, b) => a.seq - b.seq);
694
+ for (const ev of spawns) {
695
+ if (ev.kind === "waiting") {
696
+ nodes.set(ev.id, {
697
+ id: ev.id,
698
+ parent: ev.parent,
699
+ label: ev.label,
700
+ status: "waiting",
701
+ runtime: "wait",
702
+ budget: {
703
+ maxIterations: 0,
704
+ maxTokens: 0
705
+ },
706
+ spent: zeroSpend()
707
+ });
708
+ continue;
709
+ }
710
+ if (ev.parent === void 0 && root === void 0) root = ev.id;
711
+ nodes.set(ev.id, {
712
+ id: ev.id,
713
+ parent: ev.parent,
714
+ label: ev.label,
715
+ status: "pending",
716
+ runtime: ev.runtime,
717
+ budget: ev.budget,
718
+ ...ev.ownedTreeRoot === void 0 ? {} : { ownedTreeRoot: ev.ownedTreeRoot },
719
+ ...ev.assignmentId === void 0 ? {} : { assignmentId: ev.assignmentId },
720
+ ...ev.identity ? { identity: ev.identity } : {},
721
+ spent: zeroSpend()
722
+ });
723
+ }
724
+ for (const ev of settlements) if (ev.kind === "settled") {
725
+ const node = requireNode(nodes, ev.id);
726
+ node.status = ev.status === "done" ? "done" : "failed";
727
+ node.spent = ev.spent;
728
+ node.outRef = ev.outRef;
729
+ node.trace = traceEvidenceFor(ev);
730
+ const settledAt = Date.parse(ev.at);
731
+ if (Number.isFinite(settledAt)) node.settledAt = settledAt;
732
+ } else if (ev.kind === "woken") {
733
+ const node = requireNode(nodes, ev.id);
734
+ node.status = ev.by === "cancelled" ? "cancelled" : "done";
735
+ node.outRef = ev.outRef;
736
+ node.trace = {
737
+ status: "unavailable",
738
+ reason: "not-an-executor"
739
+ };
740
+ const settledAt = Date.parse(ev.at);
741
+ if (Number.isFinite(settledAt)) node.settledAt = settledAt;
742
+ } else {
743
+ const node = requireNode(nodes, ev.id);
744
+ node.status = "cancelled";
745
+ node.trace = {
746
+ status: "unavailable",
747
+ reason: "execution-did-not-start"
748
+ };
749
+ const settledAt = Date.parse(ev.at);
750
+ if (Number.isFinite(settledAt)) node.settledAt = settledAt;
751
+ }
752
+ for (const ev of events) {
753
+ if (ev.kind !== "materialized") continue;
754
+ const node = requireNode(nodes, ev.id);
755
+ node.materialization = ev.receipt;
756
+ node.runtime = ev.receipt.runtime;
757
+ }
758
+ for (const ev of events) {
759
+ if (ev.kind !== "execution-bound") continue;
760
+ const node = requireNode(nodes, ev.id);
761
+ node.executionBindings ??= [];
762
+ node.executionBindings.push(ev.binding);
763
+ }
764
+ for (const ev of events) {
765
+ if (ev.kind !== "metered") continue;
766
+ const node = requireNode(nodes, ev.id);
767
+ node.spent = addJournalSpend(node.spent, ev.spend);
768
+ }
769
+ const snapshots = [...nodes.values()].map(freezeSnapshot);
770
+ return {
771
+ root: root ?? snapshots[0]?.id ?? "",
772
+ nodes: snapshots,
773
+ inFlight: snapshots.filter((n) => n.status === "running" || n.status === "acquiring").length,
774
+ waiting: snapshots.filter((n) => n.status === "waiting").length
775
+ };
776
+ }
777
+ /**
778
+ * The waits a journaled tree shows as ARMED but never woken — what a resumed run re-arms with the
779
+ * ORIGINAL absolute deadline. Reading it from the journal (rather than from any live state) is
780
+ * what makes "SIGKILL a waiting tree, a new process keeps waiting to the same instant" true.
781
+ */
782
+ function pendingWaits(events) {
783
+ const woken = /* @__PURE__ */ new Set();
784
+ for (const ev of events) if (ev.kind === "woken") woken.add(ev.id);
785
+ const pending = [];
786
+ for (const ev of events) {
787
+ if (ev.kind !== "waiting" || woken.has(ev.id)) continue;
788
+ pending.push({
789
+ id: ev.id,
790
+ label: ev.label,
791
+ spec: ev.spec,
792
+ armedAt: ev.armedAt,
793
+ ordinal: ev.seq
794
+ });
795
+ }
796
+ return pending.sort((a, b) => a.ordinal - b.ordinal);
797
+ }
798
+ function zeroSpend() {
799
+ return {
800
+ iterations: 0,
801
+ tokens: zeroTokenUsage(),
802
+ usd: 0,
803
+ ms: 0
804
+ };
805
+ }
806
+ /** Add a `metered` spend record onto a node's accumulated spend (per channel). */
807
+ function addJournalSpend(a, b) {
808
+ return {
809
+ iterations: a.iterations + b.iterations,
810
+ tokens: {
811
+ input: a.tokens.input + b.tokens.input,
812
+ output: a.tokens.output + b.tokens.output
813
+ },
814
+ ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
815
+ usd: a.usd + b.usd,
816
+ ...a.tokensKnown === false || b.tokensKnown === false ? { tokensKnown: false } : {},
817
+ ...a.usdKnown === false || b.usdKnown === false ? { usdKnown: false } : {},
818
+ ms: a.ms + b.ms
819
+ };
820
+ }
821
+ function requireNode(nodes, id) {
822
+ const node = nodes.get(id);
823
+ if (!node) throw new Error(`spawn journal corrupted: settle/cancel for node '${id}' with no prior spawn`);
824
+ return node;
825
+ }
826
+ function freezeSnapshot(node) {
827
+ return {
828
+ id: node.id,
829
+ parent: node.parent,
830
+ label: node.label,
831
+ status: node.status,
832
+ runtime: node.runtime,
833
+ budget: node.budget,
834
+ ownedTreeRoot: node.ownedTreeRoot,
835
+ assignmentId: node.assignmentId,
836
+ identity: node.identity,
837
+ materialization: node.materialization,
838
+ executionBindings: node.executionBindings === void 0 ? void 0 : Object.freeze([...node.executionBindings]),
839
+ spent: node.spent,
840
+ outRef: node.outRef,
841
+ trace: node.trace,
842
+ settledAt: node.settledAt
843
+ };
844
+ }
845
+ function traceEvidenceFor(event) {
846
+ return event.trace ?? {
847
+ status: "unavailable",
848
+ reason: "legacy-settlement-without-trace-evidence"
849
+ };
850
+ }
851
+ function isNoEntError(err) {
852
+ return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
853
+ }
854
+ //#endregion
855
+ export { detachedSnapshot as S, captureWorkerTraceEvidence as _, loadSpawnForest as a, workerTraceAnalysisStore as b, replaySpawnTree as c, writeAllBytes as d, attestNestedDriverTreeOwner as f, WORKER_TOOL_TRACE_SCHEMA_VERSION as g, runtimeOwnedNestedDriverTreeRoot as h, InMemorySpawnJournal as i, parseCommittedJsonLines as l, nestedDriverTreeRoot as m, FileSpawnJournal as n, materializeTreeView as o, driverRuntime as p, InMemoryResultBlobStore as r, pendingWaits as s, FileResultBlobStore as t, prepareJsonlAppend as u, isTraceAnalysisStore as v, contentAddress as x, parseWorkerToolTraceArtifact as y };
856
+
857
+ //# sourceMappingURL=spawn-journal-IeXpidO2.js.map