@tangle-network/agent-runtime 0.349.0 → 0.352.1

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 (139) hide show
  1. package/dist/{activation-wBipBkCf.d.ts → activation-BidzGkUQ.d.ts} +2 -24
  2. package/dist/{activation-tNGW73Y9.js → activation-C6zNC2kx.js} +12 -14
  3. package/dist/{activation-tNGW73Y9.js.map → activation-C6zNC2kx.js.map} +1 -1
  4. package/dist/agent.d.ts +8 -12
  5. package/dist/agent.js +9 -12
  6. package/dist/agent.js.map +1 -1
  7. package/dist/{analyst-loop-DZw5QWT9.js → analyst-loop-BZvXCDKy.js} +2 -3
  8. package/dist/{analyst-loop-DZw5QWT9.js.map → analyst-loop-BZvXCDKy.js.map} +1 -1
  9. package/dist/analyst-loop.d.ts +3 -5
  10. package/dist/analyst-loop.js +1 -2
  11. package/dist/{bundle-1xaJEgjq.js → bundle-DeDkJbsr.js} +3 -4
  12. package/dist/{bundle-1xaJEgjq.js.map → bundle-DeDkJbsr.js.map} +1 -1
  13. package/dist/candidate-execution/index.d.ts +13 -33
  14. package/dist/candidate-execution/index.js +16 -18
  15. package/dist/candidate-execution/index.js.map +1 -1
  16. package/dist/chat-turn.d.ts +2 -0
  17. package/dist/chat-turn.js +1 -0
  18. package/dist/{coordination-manager-B2Z_MmL9.js → coordination-manager-B7QadgrI.js} +101 -132
  19. package/dist/{coordination-manager-B2Z_MmL9.js.map → coordination-manager-B7QadgrI.js.map} +1 -1
  20. package/dist/{delegate-Dr-63jFl.js → delegate-CoscoyEo.js} +19 -21
  21. package/dist/delegate-CoscoyEo.js.map +1 -0
  22. package/dist/durable.d.ts +16 -149
  23. package/dist/durable.js +57 -980
  24. package/dist/durable.js.map +1 -1
  25. package/dist/{errors-DodWX-cb.js → errors-AzSuGI23.js} +5 -3
  26. package/dist/errors-AzSuGI23.js.map +1 -0
  27. package/dist/execution-handle-Bd2_nUB6.js +167 -0
  28. package/dist/execution-handle-Bd2_nUB6.js.map +1 -0
  29. package/dist/execution-handle-CujvqgCn.d.ts +130 -0
  30. package/dist/{graph-DPejYB3C.js → graph-mojMML8e.js} +192 -14
  31. package/dist/graph-mojMML8e.js.map +1 -0
  32. package/dist/{improve-DwSahPi1.js → improve-Dm5ZE8mr.js} +36 -53
  33. package/dist/{improve-DwSahPi1.js.map → improve-Dm5ZE8mr.js.map} +1 -1
  34. package/dist/{improvement-adapter-sIthWkcN.d.ts → improvement-adapter-D5GRU1eY.d.ts} +2 -6
  35. package/dist/index.d.ts +41 -89
  36. package/dist/index.js +45 -61
  37. package/dist/index.js.map +1 -1
  38. package/dist/intelligence.d.ts +39 -59
  39. package/dist/intelligence.js +24 -33
  40. package/dist/intelligence.js.map +1 -1
  41. package/dist/journal-store-BJPMUydp.js +3925 -0
  42. package/dist/journal-store-BJPMUydp.js.map +1 -0
  43. package/dist/kernel.d.ts +5 -5
  44. package/dist/kernel.js +12 -11
  45. package/dist/{loop-runner-CP6MfO1b.js → loop-runner-5cL_vZi0.js} +5 -6
  46. package/dist/{loop-runner-CP6MfO1b.js.map → loop-runner-5cL_vZi0.js.map} +1 -1
  47. package/dist/{loop-runner-C6pGq-2l.d.ts → loop-runner-DyLD-aNb.d.ts} +3 -5
  48. package/dist/loop-runner-bin.d.ts +5 -8
  49. package/dist/loop-runner-bin.js +2 -3
  50. package/dist/mcp/bin.js +6 -8
  51. package/dist/mcp/bin.js.map +1 -1
  52. package/dist/mcp/index.d.ts +8 -18
  53. package/dist/mcp/index.js +17 -25
  54. package/dist/mcp/index.js.map +1 -1
  55. package/dist/mcp/memory-bin.js +4 -6
  56. package/dist/mcp/memory-bin.js.map +1 -1
  57. package/dist/{model-policy-CyCUwHed.js → model-policy-C-RGAUW4.js} +11 -13
  58. package/dist/{model-policy-CyCUwHed.js.map → model-policy-C-RGAUW4.js.map} +1 -1
  59. package/dist/placement.d.ts +12 -14
  60. package/dist/placement.js +1 -2
  61. package/dist/platform.d.ts +7 -13
  62. package/dist/platform.js +3 -6
  63. package/dist/platform.js.map +1 -1
  64. package/dist/{prepare-B9wWffjO.js → prepare-XWwsOh8O.js} +50 -69
  65. package/dist/{prepare-B9wWffjO.js.map → prepare-XWwsOh8O.js.map} +1 -1
  66. package/dist/{profile-JLJd2wFG.js → profile-C01SQZKa.js} +58 -92
  67. package/dist/profile-C01SQZKa.js.map +1 -0
  68. package/dist/{profile-materialization-bPm0gGLO.d.ts → profile-materialization-BRY22Oh8.d.ts} +1 -3
  69. package/dist/profiles.d.ts +25 -12
  70. package/dist/profiles.js +52 -11
  71. package/dist/profiles.js.map +1 -1
  72. package/dist/{protected-model-port-DVVh-hEk.d.ts → protected-model-port-IKqhTypD.d.ts} +2 -14
  73. package/dist/{protected-redaction-DFCeo4vg.js → protected-redaction-DilFZch5.js} +2 -3
  74. package/dist/{protected-redaction-DFCeo4vg.js.map → protected-redaction-DilFZch5.js.map} +1 -1
  75. package/dist/{provision-supervisor-C4v2vqDo.js → provision-supervisor-D9pO-iPl.js} +11 -15
  76. package/dist/{provision-supervisor-C4v2vqDo.js.map → provision-supervisor-D9pO-iPl.js.map} +1 -1
  77. package/dist/{run-cancellation-CzFhQGMa.js → run-cancellation-CoJRKvih.js} +6 -7
  78. package/dist/{run-cancellation-CzFhQGMa.js.map → run-cancellation-CoJRKvih.js.map} +1 -1
  79. package/dist/{runtime-CsvGCQpl.js → runtime-BJPXHWbc.js} +652 -215
  80. package/dist/runtime-BJPXHWbc.js.map +1 -0
  81. package/dist/{runtime-hooks-tXpAarhW.js → runtime-hooks-CsW2pfFk.js} +2 -3
  82. package/dist/{runtime-hooks-tXpAarhW.js.map → runtime-hooks-CsW2pfFk.js.map} +1 -1
  83. package/dist/{runtime-hooks-nsqxSUFL.d.ts → runtime-hooks-ZQqPw-0g.d.ts} +1 -3
  84. package/dist/{sandbox-profile-compat-DtuJWFrM.js → sandbox-profile-compat-CXjozdWL.js} +52 -653
  85. package/dist/sandbox-profile-compat-CXjozdWL.js.map +1 -0
  86. package/dist/{search-executor-CCb82Umc.js → search-executor-CQEHMXoT.js} +12 -15
  87. package/dist/{search-executor-CCb82Umc.js.map → search-executor-CQEHMXoT.js.map} +1 -1
  88. package/dist/{server-CKPwZU-I.js → server-U9NGgudQ.js} +19 -30
  89. package/dist/{server-CKPwZU-I.js.map → server-U9NGgudQ.js.map} +1 -1
  90. package/dist/{structural-rollout-DylC_fwU.js → structural-rollout-wMSxE7bn.js} +71 -70
  91. package/dist/structural-rollout-wMSxE7bn.js.map +1 -0
  92. package/dist/{substrate-CGDFTSRh.js → substrate-Db2pp6y3.js} +2 -3
  93. package/dist/{substrate-CGDFTSRh.js.map → substrate-Db2pp6y3.js.map} +1 -1
  94. package/dist/{supervise-BGfm2GlY.js → supervise-CNNhX0ab.js} +460 -195
  95. package/dist/supervise-CNNhX0ab.js.map +1 -0
  96. package/dist/supervision-discovery-CewADdEs.js +772 -0
  97. package/dist/supervision-discovery-CewADdEs.js.map +1 -0
  98. package/dist/{supervisor-wS9Ehz_x.js → supervisor-rK5Y8en6.js} +521 -4320
  99. package/dist/supervisor-rK5Y8en6.js.map +1 -0
  100. package/dist/{task-queue-0fKkoweu.d.ts → task-queue-kefGy79U.d.ts} +1 -3
  101. package/dist/task-queue.d.ts +1 -1
  102. package/dist/task-queue.js +1 -2
  103. package/dist/testing.d.ts +7 -15
  104. package/dist/testing.js +241 -244
  105. package/dist/testing.js.map +1 -1
  106. package/dist/tool-loop.d.ts +16 -19
  107. package/dist/tool-loop.js +2 -3
  108. package/dist/{tool-server-XV4aJwoQ.js → tool-server-CZWd_Opp.js} +3 -4
  109. package/dist/{tool-server-XV4aJwoQ.js.map → tool-server-CZWd_Opp.js.map} +1 -1
  110. package/dist/{top-snapshot-CflmaDgk.js → top-snapshot-DcV7VG4m.js} +179 -163
  111. package/dist/top-snapshot-DcV7VG4m.js.map +1 -0
  112. package/dist/tui/bin.js +50 -81
  113. package/dist/tui/bin.js.map +1 -1
  114. package/dist/tui/index.d.ts +27 -58
  115. package/dist/tui/index.js +2 -2
  116. package/dist/{types-C8BGOCBn.d.ts → types-0uzVKtFW.d.ts} +388 -484
  117. package/dist/{types-Cwrea-bU.d.ts → types-qsqfyQoY.d.ts} +1 -3
  118. package/dist/util-ebWMWzY0.js +624 -0
  119. package/dist/util-ebWMWzY0.js.map +1 -0
  120. package/dist/workspace-store/index.d.ts +12 -22
  121. package/dist/workspace-store/index.js +13 -10
  122. package/dist/workspace-store/index.js.map +1 -1
  123. package/dist/{workspace-streams-BiS4ABah.d.ts → workspace-streams-Dq2Fzk3c.d.ts} +1 -11
  124. package/package.json +31 -26
  125. package/skills/agent-graphs/SKILL.md +17 -4
  126. package/skills/be-ambitious/SKILL.md +46 -0
  127. package/skills/graph-designer/SKILL.md +9 -2
  128. package/dist/delegate-Dr-63jFl.js.map +0 -1
  129. package/dist/errors-DodWX-cb.js.map +0 -1
  130. package/dist/graph-DPejYB3C.js.map +0 -1
  131. package/dist/profile-JLJd2wFG.js.map +0 -1
  132. package/dist/record-events-D93DkpAx.js +0 -263
  133. package/dist/record-events-D93DkpAx.js.map +0 -1
  134. package/dist/runtime-CsvGCQpl.js.map +0 -1
  135. package/dist/sandbox-profile-compat-DtuJWFrM.js.map +0 -1
  136. package/dist/structural-rollout-DylC_fwU.js.map +0 -1
  137. package/dist/supervise-BGfm2GlY.js.map +0 -1
  138. package/dist/supervisor-wS9Ehz_x.js.map +0 -1
  139. package/dist/top-snapshot-CflmaDgk.js.map +0 -1
@@ -1,263 +0,0 @@
1
- import { isRecord } from "@tangle-network/agent-core";
2
- import { createHash, randomUUID } from "node:crypto";
3
- import { tryAcquireAtomicFileLock } from "@tangle-network/agent-eval/ledger-core";
4
- import { closeSync, constants, existsSync, fchmodSync, fstatSync, fsyncSync, linkSync, lstatSync, openSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
5
- import { dirname, join, relative, resolve } from "node:path";
6
- import { AsyncLocalStorage } from "node:async_hooks";
7
- //#region \0rolldown/runtime.js
8
- var __defProp = Object.defineProperty;
9
- var __exportAll = (all, no_symbols) => {
10
- let target = {};
11
- for (var name in all) __defProp(target, name, {
12
- get: all[name],
13
- enumerable: true
14
- });
15
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
16
- return target;
17
- };
18
- //#endregion
19
- //#region src/content-digest.ts
20
- function sha256(value) {
21
- return createHash("sha256").update(value).digest("hex");
22
- }
23
- //#endregion
24
- //#region src/durable/run-fence.ts
25
- const claims = new AsyncLocalStorage();
26
- const publications = new AsyncLocalStorage();
27
- /** Bind asynchronous work, including callbacks, to the generation that admitted it. @internal */
28
- function runWithWriteClaim(claim, operation) {
29
- return claims.run(claim, operation);
30
- }
31
- /** Capture a store's acquisition once, even when later called from an unrelated emitter. @internal */
32
- function captureRunWriteContext() {
33
- let claim = claims.getStore();
34
- return (operation) => {
35
- claim ??= claims.getStore();
36
- return claims.run(claim, operation);
37
- };
38
- }
39
- /** Serialize claim changes and file mutations under the same cross-process guard. @internal */
40
- function mutateRunClaim(path, operation) {
41
- const legacyGuard = `${path}.guard`;
42
- if (existsSync(legacyGuard)) throw new Error(`supervisePursuit: cannot mutate ${path}; inspect ${legacyGuard} and remove it only after confirming no lock mutation is active`);
43
- const deadline = performance.now() + 5e3;
44
- const sleeper = new Int32Array(new SharedArrayBuffer(4));
45
- for (;;) {
46
- const acquisition = tryAcquireAtomicFileLock({ lockPath: `${path}.mutation` });
47
- if (acquisition.acquired) try {
48
- return operation();
49
- } finally {
50
- acquisition.lock.release();
51
- }
52
- if (performance.now() >= deadline) throw new Error(`run directory mutation is held: ${path}`);
53
- Atomics.wait(sleeper, 0, 0, 10);
54
- }
55
- }
56
- /**
57
- * Fence an actual file mutation, not an earlier advisory check. No await occurs between the
58
- * ownership check and publication, and acquire/release use this same guard. Unclaimed standalone
59
- * stores retain their existing single-writer contract; pursuit-owned work always carries a claim.
60
- * @internal
61
- */
62
- function fenceRunWrite(operation) {
63
- const claim = claims.getStore();
64
- if (claim === void 0) return operation();
65
- const publication = publications.getStore();
66
- if (publication?.active && publication.claim.path === claim.path && publication.claim.generation === claim.generation) return operation();
67
- return mutateRunClaim(claim.path, () => {
68
- let holder;
69
- try {
70
- const fd = openSync(claim.path, "r");
71
- try {
72
- const stat = fstatSync(fd, { bigint: true });
73
- if (stat.dev.toString() !== claim.lock.dev || stat.ino.toString() !== claim.lock.ino || stat.birthtimeNs.toString() !== claim.lock.birthtimeNs) throw new Error("run lock inode changed");
74
- holder = JSON.parse(readFileSync(fd, "utf8"));
75
- } finally {
76
- closeSync(fd);
77
- }
78
- } catch (cause) {
79
- throw new Error(`run directory generation ${claim.generation} lost its claim`, { cause });
80
- }
81
- if (holder?.generation !== claim.generation || holder.lock?.dev !== claim.lock.dev || holder.lock?.ino !== claim.lock.ino || holder.lock?.birthtimeNs !== claim.lock.birthtimeNs) throw new Error(`run directory generation ${claim.generation} lost its claim`);
82
- const publication = {
83
- claim,
84
- active: true
85
- };
86
- try {
87
- return publications.run(publication, operation);
88
- } finally {
89
- publication.active = false;
90
- }
91
- });
92
- }
93
- /** Persistent generation counter survives a clean release of supervise.lock. @internal */
94
- function runGenerationPath(runDir) {
95
- return resolve(runDir, "supervise.generation");
96
- }
97
- //#endregion
98
- //#region src/runtime/supervise/durable-file.ts
99
- /**
100
- * Small filesystem durability primitives for Runtime-owned state.
101
- *
102
- * Callers must validate their path and parent directory before invoking these functions.
103
- * The exclusive writer protects a no-clobber publication race; the atomic writer replaces one
104
- * state file after its temporary contents reach stable storage.
105
- *
106
- * @internal
107
- */
108
- var durable_file_exports = /* @__PURE__ */ __exportAll({
109
- appendDurableFile: () => appendDurableFile,
110
- assertNoSymlinkDescendant: () => assertNoSymlinkDescendant,
111
- publishExclusiveDurableFile: () => publishExclusiveDurableFile,
112
- syncDurableDirectory: () => syncDurableDirectory,
113
- writeAtomicDurableFile: () => writeAtomicDurableFile
114
- });
115
- /**
116
- * Publish a new file without replacing a concurrent winner. The published entry is a hard link
117
- * of the temporary file, so a content function sees the published file's inode.
118
- */
119
- function publishExclusiveDurableFile(filePath, content, options = {}) {
120
- return fenceRunWrite(() => publishExclusiveDurableFileUnchecked(filePath, content, options));
121
- }
122
- function publishExclusiveDurableFileUnchecked(filePath, content, options = {}) {
123
- const temporaryPath = `${filePath}.${randomUUID()}.tmp`;
124
- let operationFailed = false;
125
- let operationError;
126
- let published = false;
127
- try {
128
- writeExclusiveDurableFile(temporaryPath, content, options);
129
- try {
130
- linkSync(temporaryPath, filePath);
131
- syncDurableDirectory(dirname(filePath));
132
- published = true;
133
- } catch (error) {
134
- if (!isAlreadyExistsError(error)) throw error;
135
- }
136
- } catch (error) {
137
- operationFailed = true;
138
- operationError = error;
139
- }
140
- let cleanupError;
141
- try {
142
- unlinkSync(temporaryPath);
143
- } catch (error) {
144
- if (!isNoEntryError(error)) cleanupError = error;
145
- }
146
- if (operationFailed) throw operationError;
147
- if (cleanupError !== void 0) throw cleanupError;
148
- return published;
149
- }
150
- /** Fsync a directory after publishing a durable file entry. */
151
- function syncDurableDirectory(directoryPath) {
152
- const fd = openSync(directoryPath, "r");
153
- try {
154
- fsyncSync(fd);
155
- } finally {
156
- closeSync(fd);
157
- }
158
- }
159
- /** Fsync one durable file after its contents reach stable storage. */
160
- function syncDurableFile(filePath, exactMode) {
161
- const fd = openSync(filePath, "r");
162
- try {
163
- if (exactMode !== void 0 && process.platform !== "win32") fchmodSync(fd, exactMode);
164
- fsyncSync(fd);
165
- } finally {
166
- closeSync(fd);
167
- }
168
- }
169
- /** Append one record with O_APPEND, then fsync the file and containing directory. */
170
- function appendDurableFile(filePath, content, options = {}) {
171
- fenceRunWrite(() => appendDurableFileUnchecked(filePath, content, options));
172
- }
173
- function appendDurableFileUnchecked(filePath, content, options = {}) {
174
- const fd = openSync(filePath, constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | (typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0), options.mode ?? 384);
175
- try {
176
- if (process.platform !== "win32") fchmodSync(fd, options.mode ?? 384);
177
- const expectedBytes = Buffer.byteLength(content, "utf8");
178
- const writtenBytes = writeSync(fd, content, void 0, "utf8");
179
- if (writtenBytes !== expectedBytes) throw new Error(`durable append wrote ${writtenBytes} of ${expectedBytes} bytes to '${filePath}'`);
180
- fsyncSync(fd);
181
- } finally {
182
- closeSync(fd);
183
- }
184
- syncDurableDirectory(dirname(filePath));
185
- }
186
- /** Reject a path that escapes its run directory or traverses a symbolic link. */
187
- function assertNoSymlinkDescendant(root, target, label = "path") {
188
- const base = resolve(root);
189
- const rel = relative(base, resolve(target));
190
- if (rel === ".." || rel.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`)) throw new Error(`${label} path escapes its run directory`);
191
- if (existsSync(base) && lstatSync(base).isSymbolicLink()) throw new Error(`${label} path contains a symbolic link: ${base}`);
192
- let current = base;
193
- for (const part of rel.split(/[\\/]/u).filter(Boolean)) {
194
- current = join(current, part);
195
- if (!existsSync(current)) continue;
196
- if (lstatSync(current).isSymbolicLink()) throw new Error(`${label} path contains a symbolic link: ${current}`);
197
- }
198
- }
199
- /** Write, fsync, atomically replace, and fsync one Runtime-owned state file.
200
- * preserveMode retains ordinary access permissions despite the current umask; a new
201
- * file keeps normal creation semantics. Callers still own path validation and write exclusion. */
202
- function writeAtomicDurableFile(filePath, content, options = {}) {
203
- fenceRunWrite(() => writeAtomicDurableFileUnchecked(filePath, content, options));
204
- }
205
- function writeAtomicDurableFileUnchecked(filePath, content, options = {}) {
206
- const temporaryPath = `${filePath}.${randomUUID()}.tmp`;
207
- let operationFailed = false;
208
- let operationError;
209
- try {
210
- let mode = options.mode;
211
- let exactMode = false;
212
- if (options.preserveMode) try {
213
- mode = statSync(filePath).mode & 511;
214
- exactMode = true;
215
- } catch (error) {
216
- if (!isNoEntryError(error)) throw error;
217
- }
218
- writeExclusiveDurableFile(temporaryPath, content, { mode }, exactMode);
219
- renameSync(temporaryPath, filePath);
220
- syncDurableDirectory(dirname(filePath));
221
- } catch (error) {
222
- operationFailed = true;
223
- operationError = error;
224
- }
225
- let cleanupError;
226
- try {
227
- unlinkSync(temporaryPath);
228
- } catch (error) {
229
- if (!isNoEntryError(error)) cleanupError = error;
230
- }
231
- if (operationFailed) throw operationError;
232
- if (cleanupError !== void 0) throw cleanupError;
233
- }
234
- function writeExclusiveDurableFile(filePath, content, options, exactMode = false) {
235
- const fd = openSync(filePath, "wx", options.mode ?? 438);
236
- try {
237
- writeFileSync(fd, typeof content === "string" ? content : content(fstatSync(fd, { bigint: true })), "utf8");
238
- } finally {
239
- closeSync(fd);
240
- }
241
- syncDurableFile(filePath, exactMode ? options.mode : void 0);
242
- }
243
- function isAlreadyExistsError(error) {
244
- return error !== null && typeof error === "object" && "code" in error && error.code === "EEXIST";
245
- }
246
- function isNoEntryError(error) {
247
- return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
248
- }
249
- //#endregion
250
- //#region src/durable/spawn-journal/record-events.ts
251
- /** Decode the file journal's historical single-event and atomic-group envelopes. @internal */
252
- function spawnJournalRecordEvents(record) {
253
- if (!isRecord(record)) throw new Error("spawn journal corrupted: record must be an object");
254
- if (record.kind === "begin") return [];
255
- if (record.kind === "event") return [record.event];
256
- if (record.kind !== "events") throw new Error(`spawn journal corrupted: unknown record kind '${String(record.kind)}'`);
257
- if (!Array.isArray(record.events)) throw new Error("spawn journal group has no events array");
258
- return record.events;
259
- }
260
- //#endregion
261
- export { publishExclusiveDurableFile as a, captureRunWriteContext as c, runGenerationPath as d, runWithWriteClaim as f, durable_file_exports as i, fenceRunWrite as l, __exportAll as m, appendDurableFile as n, syncDurableDirectory as o, sha256 as p, assertNoSymlinkDescendant as r, writeAtomicDurableFile as s, spawnJournalRecordEvents as t, mutateRunClaim as u };
262
-
263
- //# sourceMappingURL=record-events-D93DkpAx.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"record-events-D93DkpAx.js","names":["fsConstants"],"sources":["../src/content-digest.ts","../src/durable/run-fence.ts","../src/runtime/supervise/durable-file.ts","../src/durable/spawn-journal/record-events.ts"],"sourcesContent":["import { createHash } from 'node:crypto'\n\nexport function sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex')\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\nimport { closeSync, existsSync, fstatSync, openSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { tryAcquireAtomicFileLock } from '@tangle-network/agent-eval/ledger-core'\nimport type { LockIdentity } from '@tangle-network/agent-eval/lock-holder'\n\n/** The immutable claim carried by every write in one directory execution. @internal */\nexport interface RunWriteClaim {\n readonly path: string\n readonly generation: number\n readonly lock: LockIdentity\n}\n\nconst claims = new AsyncLocalStorage<RunWriteClaim | undefined>()\nconst publications = new AsyncLocalStorage<{ readonly claim: RunWriteClaim; active: boolean }>()\n\n/** Bind asynchronous work, including callbacks, to the generation that admitted it. @internal */\nexport function runWithWriteClaim<T>(claim: RunWriteClaim, operation: () => T): T {\n return claims.run(claim, operation)\n}\n\n/** Capture a store's acquisition once, even when later called from an unrelated emitter. @internal */\nexport function captureRunWriteContext(): <T>(operation: () => T) => T {\n let claim = claims.getStore()\n return <T>(operation: () => T): T => {\n claim ??= claims.getStore()\n return claims.run(claim, operation)\n }\n}\n\n/** Serialize claim changes and file mutations under the same cross-process guard. @internal */\nexport function mutateRunClaim<T>(path: string, operation: () => T): T {\n // Old writers use an unowned directory guard. Never race one or guess that it is stale.\n const legacyGuard = `${path}.guard`\n if (existsSync(legacyGuard)) {\n throw new Error(\n `supervisePursuit: cannot mutate ${path}; inspect ${legacyGuard} and remove it only after confirming no lock mutation is active`,\n )\n }\n const deadline = performance.now() + 5_000\n const sleeper = new Int32Array(new SharedArrayBuffer(4))\n for (;;) {\n const acquisition = tryAcquireAtomicFileLock({ lockPath: `${path}.mutation` })\n if (acquisition.acquired) {\n try {\n return operation()\n } finally {\n acquisition.lock.release()\n }\n }\n if (performance.now() >= deadline) throw new Error(`run directory mutation is held: ${path}`)\n Atomics.wait(sleeper, 0, 0, 10)\n }\n}\n\n/**\n * Fence an actual file mutation, not an earlier advisory check. No await occurs between the\n * ownership check and publication, and acquire/release use this same guard. Unclaimed standalone\n * stores retain their existing single-writer contract; pursuit-owned work always carries a claim.\n * @internal\n */\nexport function fenceRunWrite<T>(operation: () => T): T {\n const claim = claims.getStore()\n if (claim === undefined) return operation()\n const publication = publications.getStore()\n if (\n publication?.active &&\n publication.claim.path === claim.path &&\n publication.claim.generation === claim.generation\n )\n return operation()\n return mutateRunClaim(claim.path, () => {\n let holder: Partial<RunWriteClaim> | undefined\n try {\n const fd = openSync(claim.path, 'r')\n try {\n const stat = fstatSync(fd, { bigint: true })\n if (\n stat.dev.toString() !== claim.lock.dev ||\n stat.ino.toString() !== claim.lock.ino ||\n stat.birthtimeNs.toString() !== claim.lock.birthtimeNs\n ) {\n throw new Error('run lock inode changed')\n }\n holder = JSON.parse(readFileSync(fd, 'utf8')) as Partial<RunWriteClaim>\n } finally {\n closeSync(fd)\n }\n } catch (cause) {\n throw new Error(`run directory generation ${claim.generation} lost its claim`, { cause })\n }\n if (\n holder?.generation !== claim.generation ||\n holder.lock?.dev !== claim.lock.dev ||\n holder.lock?.ino !== claim.lock.ino ||\n holder.lock?.birthtimeNs !== claim.lock.birthtimeNs\n ) {\n throw new Error(`run directory generation ${claim.generation} lost its claim`)\n }\n // Nested synchronous primitives share the guard. A callback queued here keeps its claim,\n // but cannot inherit a live guard after this publication has returned.\n const publication = { claim, active: true }\n try {\n return publications.run(publication, operation)\n } finally {\n publication.active = false\n }\n })\n}\n\n/** Persistent generation counter survives a clean release of supervise.lock. @internal */\nexport function runGenerationPath(runDir: string): string {\n return resolve(runDir, 'supervise.generation')\n}\n","/**\n * Small filesystem durability primitives for Runtime-owned state.\n *\n * Callers must validate their path and parent directory before invoking these functions.\n * The exclusive writer protects a no-clobber publication race; the atomic writer replaces one\n * state file after its temporary contents reach stable storage.\n *\n * @internal\n */\n\nimport { randomUUID } from 'node:crypto'\nimport {\n type BigIntStats,\n closeSync,\n existsSync,\n fchmodSync,\n constants as fsConstants,\n fstatSync,\n fsyncSync,\n linkSync,\n lstatSync,\n openSync,\n renameSync,\n statSync,\n unlinkSync,\n writeFileSync,\n writeSync,\n} from 'node:fs'\nimport { dirname, join, relative, resolve } from 'node:path'\nimport { fenceRunWrite } from '../../durable/run-fence'\n\ninterface DurableFileOptions {\n readonly mode?: number\n}\n\n/**\n * File content, or content computed from the new file's own stat when it must name the file's\n * inode (a lock record that later proves it was written for this very file).\n */\ntype DurableFileContent = string | ((file: BigIntStats) => string)\n\n/**\n * Publish a new file without replacing a concurrent winner. The published entry is a hard link\n * of the temporary file, so a content function sees the published file's inode.\n */\nexport function publishExclusiveDurableFile(\n filePath: string,\n content: DurableFileContent,\n options: DurableFileOptions = {},\n): boolean {\n return fenceRunWrite(() => publishExclusiveDurableFileUnchecked(filePath, content, options))\n}\n\nfunction publishExclusiveDurableFileUnchecked(\n filePath: string,\n content: DurableFileContent,\n options: DurableFileOptions = {},\n): boolean {\n const temporaryPath = `${filePath}.${randomUUID()}.tmp`\n let operationFailed = false\n let operationError: unknown\n let published = false\n try {\n writeExclusiveDurableFile(temporaryPath, content, options)\n try {\n linkSync(temporaryPath, filePath)\n syncDurableDirectory(dirname(filePath))\n published = true\n } catch (error) {\n if (!isAlreadyExistsError(error)) throw error\n }\n } catch (error) {\n operationFailed = true\n operationError = error\n }\n let cleanupError: unknown\n try {\n unlinkSync(temporaryPath)\n } catch (error) {\n if (!isNoEntryError(error)) cleanupError = error\n }\n if (operationFailed) throw operationError\n if (cleanupError !== undefined) throw cleanupError\n return published\n}\n\n/** Fsync a directory after publishing a durable file entry. */\nexport function syncDurableDirectory(directoryPath: string): void {\n const fd = openSync(directoryPath, 'r')\n try {\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n}\n\n/** Fsync one durable file after its contents reach stable storage. */\nfunction syncDurableFile(filePath: string, exactMode?: number): void {\n const fd = openSync(filePath, 'r')\n try {\n if (exactMode !== undefined && process.platform !== 'win32') fchmodSync(fd, exactMode)\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n}\n\n/** Append one record with O_APPEND, then fsync the file and containing directory. */\nexport function appendDurableFile(\n filePath: string,\n content: string,\n options: DurableFileOptions = {},\n): void {\n fenceRunWrite(() => appendDurableFileUnchecked(filePath, content, options))\n}\n\nfunction appendDurableFileUnchecked(\n filePath: string,\n content: string,\n options: DurableFileOptions = {},\n): void {\n const flags =\n fsConstants.O_APPEND |\n fsConstants.O_CREAT |\n fsConstants.O_WRONLY |\n (typeof fsConstants.O_NOFOLLOW === 'number' ? fsConstants.O_NOFOLLOW : 0)\n const fd = openSync(filePath, flags, options.mode ?? 0o600)\n try {\n if (process.platform !== 'win32') fchmodSync(fd, options.mode ?? 0o600)\n const expectedBytes = Buffer.byteLength(content, 'utf8')\n const writtenBytes = writeSync(fd, content, undefined, 'utf8')\n if (writtenBytes !== expectedBytes) {\n throw new Error(\n `durable append wrote ${writtenBytes} of ${expectedBytes} bytes to '${filePath}'`,\n )\n }\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n syncDurableDirectory(dirname(filePath))\n}\n\n/** Reject a path that escapes its run directory or traverses a symbolic link. */\nexport function assertNoSymlinkDescendant(root: string, target: string, label = 'path'): void {\n const base = resolve(root)\n const exact = resolve(target)\n const rel = relative(base, exact)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} path escapes its run directory`)\n }\n if (existsSync(base) && lstatSync(base).isSymbolicLink()) {\n throw new Error(`${label} path contains a symbolic link: ${base}`)\n }\n let current = base\n for (const part of rel.split(/[\\\\/]/u).filter(Boolean)) {\n current = join(current, part)\n if (!existsSync(current)) continue\n if (lstatSync(current).isSymbolicLink()) {\n throw new Error(`${label} path contains a symbolic link: ${current}`)\n }\n }\n}\n\n/** Write, fsync, atomically replace, and fsync one Runtime-owned state file.\n * preserveMode retains ordinary access permissions despite the current umask; a new\n * file keeps normal creation semantics. Callers still own path validation and write exclusion. */\nexport function writeAtomicDurableFile(\n filePath: string,\n content: string,\n options: DurableFileOptions & { readonly preserveMode?: boolean } = {},\n): void {\n fenceRunWrite(() => writeAtomicDurableFileUnchecked(filePath, content, options))\n}\n\nfunction writeAtomicDurableFileUnchecked(\n filePath: string,\n content: string,\n options: DurableFileOptions & { readonly preserveMode?: boolean } = {},\n): void {\n const temporaryPath = `${filePath}.${randomUUID()}.tmp`\n let operationFailed = false\n let operationError: unknown\n try {\n let mode = options.mode\n let exactMode = false\n if (options.preserveMode) {\n try {\n mode = statSync(filePath).mode & 0o777\n exactMode = true\n } catch (error) {\n if (!isNoEntryError(error)) throw error\n }\n }\n writeExclusiveDurableFile(temporaryPath, content, { mode }, exactMode)\n renameSync(temporaryPath, filePath)\n syncDurableDirectory(dirname(filePath))\n } catch (error) {\n operationFailed = true\n operationError = error\n }\n let cleanupError: unknown\n try {\n unlinkSync(temporaryPath)\n } catch (error) {\n if (!isNoEntryError(error)) cleanupError = error\n // A successful rename removes the temporary directory entry.\n }\n if (operationFailed) throw operationError\n if (cleanupError !== undefined) throw cleanupError\n}\n\nfunction writeExclusiveDurableFile(\n filePath: string,\n content: DurableFileContent,\n options: DurableFileOptions,\n exactMode = false,\n): void {\n const fd = openSync(filePath, 'wx', options.mode ?? 0o666)\n try {\n const text = typeof content === 'string' ? content : content(fstatSync(fd, { bigint: true }))\n writeFileSync(fd, text, 'utf8')\n } finally {\n closeSync(fd)\n }\n syncDurableFile(filePath, exactMode ? options.mode : undefined)\n}\n\nfunction isAlreadyExistsError(error: unknown): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === 'EEXIST'\n )\n}\n\nfunction isNoEntryError(error: unknown): boolean {\n return (\n error !== null &&\n typeof error === 'object' &&\n 'code' in error &&\n (error as { code?: unknown }).code === 'ENOENT'\n )\n}\n","import { isRecord } from '@tangle-network/agent-core'\nimport type { SpawnEvent } from '../../runtime/supervise/types'\n\n/** Decode the file journal's historical single-event and atomic-group envelopes. @internal */\nexport function spawnJournalRecordEvents(record: unknown): ReadonlyArray<SpawnEvent> {\n if (!isRecord(record)) throw new Error('spawn journal corrupted: record must be an object')\n if (record.kind === 'begin') return []\n if (record.kind === 'event') return [record.event as SpawnEvent]\n if (record.kind !== 'events') {\n throw new Error(`spawn journal corrupted: unknown record kind '${String(record.kind)}'`)\n }\n if (!Array.isArray(record.events)) throw new Error('spawn journal group has no events array')\n return record.events as SpawnEvent[]\n}\n"],"mappings":"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"}