@mono-agent/agent-app 0.12.0 → 0.13.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 (159) hide show
  1. package/README.md +33 -7
  2. package/dist/adapter-send-tools.d.ts.map +1 -1
  3. package/dist/adapter-send-tools.js +126 -34
  4. package/dist/adapter-send-tools.js.map +1 -1
  5. package/dist/app-controller-lifecycle.d.ts.map +1 -1
  6. package/dist/app-controller-lifecycle.js +2 -6
  7. package/dist/app-controller-lifecycle.js.map +1 -1
  8. package/dist/app-controller-maintenance.d.ts.map +1 -1
  9. package/dist/app-controller-maintenance.js +2 -1
  10. package/dist/app-controller-maintenance.js.map +1 -1
  11. package/dist/app-controller-memory-health.d.ts +1 -1
  12. package/dist/app-controller-memory-health.d.ts.map +1 -1
  13. package/dist/app-controller-memory-health.js +5 -1
  14. package/dist/app-controller-memory-health.js.map +1 -1
  15. package/dist/app-controller-responder.d.ts.map +1 -1
  16. package/dist/app-controller-responder.js +8 -3
  17. package/dist/app-controller-responder.js.map +1 -1
  18. package/dist/app-controller-traceability.d.ts.map +1 -1
  19. package/dist/app-controller-traceability.js +15 -1
  20. package/dist/app-controller-traceability.js.map +1 -1
  21. package/dist/app-controller.d.ts +14 -1
  22. package/dist/app-controller.d.ts.map +1 -1
  23. package/dist/app-controller.js +61 -9
  24. package/dist/app-controller.js.map +1 -1
  25. package/dist/audit-runs.d.ts.map +1 -1
  26. package/dist/audit-runs.js +12 -2
  27. package/dist/audit-runs.js.map +1 -1
  28. package/dist/background-runtime.d.ts +26 -0
  29. package/dist/background-runtime.d.ts.map +1 -1
  30. package/dist/background-runtime.js +874 -46
  31. package/dist/background-runtime.js.map +1 -1
  32. package/dist/background.d.ts +10 -2
  33. package/dist/background.d.ts.map +1 -1
  34. package/dist/background.js +193 -38
  35. package/dist/background.js.map +1 -1
  36. package/dist/channel-drivers/live.d.ts +3 -2
  37. package/dist/channel-drivers/live.d.ts.map +1 -1
  38. package/dist/channel-drivers/live.js +3 -2
  39. package/dist/channel-drivers/live.js.map +1 -1
  40. package/dist/channel-drivers/slack.d.ts.map +1 -1
  41. package/dist/channel-drivers/slack.js +6 -0
  42. package/dist/channel-drivers/slack.js.map +1 -1
  43. package/dist/channel-drivers/telegram.d.ts.map +1 -1
  44. package/dist/channel-drivers/telegram.js +20 -4
  45. package/dist/channel-drivers/telegram.js.map +1 -1
  46. package/dist/channel-runtime-controls.d.ts +23 -0
  47. package/dist/channel-runtime-controls.d.ts.map +1 -0
  48. package/dist/channel-runtime-controls.js +63 -0
  49. package/dist/channel-runtime-controls.js.map +1 -0
  50. package/dist/channel-status-display.d.ts +15 -0
  51. package/dist/channel-status-display.d.ts.map +1 -0
  52. package/dist/channel-status-display.js +48 -0
  53. package/dist/channel-status-display.js.map +1 -0
  54. package/dist/cli-args.d.ts +17 -22
  55. package/dist/cli-args.d.ts.map +1 -1
  56. package/dist/cli-args.js +107 -75
  57. package/dist/cli-args.js.map +1 -1
  58. package/dist/cli-background-command.d.ts +1 -0
  59. package/dist/cli-background-command.d.ts.map +1 -1
  60. package/dist/cli-background-command.js +72 -16
  61. package/dist/cli-background-command.js.map +1 -1
  62. package/dist/cli-commands.d.ts +2 -2
  63. package/dist/cli-commands.d.ts.map +1 -1
  64. package/dist/cli-commands.js +35 -53
  65. package/dist/cli-commands.js.map +1 -1
  66. package/dist/cli-help.d.ts +19 -1
  67. package/dist/cli-help.d.ts.map +1 -1
  68. package/dist/cli-help.js +209 -67
  69. package/dist/cli-help.js.map +1 -1
  70. package/dist/cli-init-command.d.ts.map +1 -1
  71. package/dist/cli-init-command.js +4 -18
  72. package/dist/cli-init-command.js.map +1 -1
  73. package/dist/cli-install-skill-command.d.ts.map +1 -1
  74. package/dist/cli-install-skill-command.js +32 -3
  75. package/dist/cli-install-skill-command.js.map +1 -1
  76. package/dist/cli-runs-command.d.ts +13 -0
  77. package/dist/cli-runs-command.d.ts.map +1 -0
  78. package/dist/cli-runs-command.js +70 -0
  79. package/dist/cli-runs-command.js.map +1 -0
  80. package/dist/cli-sandbox-command.d.ts +1 -1
  81. package/dist/cli-sandbox-command.d.ts.map +1 -1
  82. package/dist/cli-sandbox-command.js +14 -2
  83. package/dist/cli-sandbox-command.js.map +1 -1
  84. package/dist/cli-validate-config-command.d.ts +24 -5
  85. package/dist/cli-validate-config-command.d.ts.map +1 -1
  86. package/dist/cli-validate-config-command.js +120 -41
  87. package/dist/cli-validate-config-command.js.map +1 -1
  88. package/dist/config-reference.js +1 -1
  89. package/dist/docs-mcp-pairing.d.ts +35 -0
  90. package/dist/docs-mcp-pairing.d.ts.map +1 -0
  91. package/dist/docs-mcp-pairing.js +311 -0
  92. package/dist/docs-mcp-pairing.js.map +1 -0
  93. package/dist/doctor.d.ts +6 -0
  94. package/dist/doctor.d.ts.map +1 -1
  95. package/dist/doctor.js +3 -3
  96. package/dist/doctor.js.map +1 -1
  97. package/dist/install-skill.d.ts +2 -0
  98. package/dist/install-skill.d.ts.map +1 -1
  99. package/dist/install-skill.js +10 -4
  100. package/dist/install-skill.js.map +1 -1
  101. package/dist/interaction-bridge.d.ts +2 -0
  102. package/dist/interaction-bridge.d.ts.map +1 -1
  103. package/dist/interaction-bridge.js +46 -1
  104. package/dist/interaction-bridge.js.map +1 -1
  105. package/dist/launchd.d.ts +2 -0
  106. package/dist/launchd.d.ts.map +1 -1
  107. package/dist/launchd.js +2 -0
  108. package/dist/launchd.js.map +1 -1
  109. package/dist/managed-runtime-publication.d.ts +22 -0
  110. package/dist/managed-runtime-publication.d.ts.map +1 -0
  111. package/dist/managed-runtime-publication.js +91 -0
  112. package/dist/managed-runtime-publication.js.map +1 -0
  113. package/dist/managed-startup.d.ts +8 -0
  114. package/dist/managed-startup.d.ts.map +1 -0
  115. package/dist/managed-startup.js +12 -0
  116. package/dist/managed-startup.js.map +1 -0
  117. package/dist/memory-retrieval.d.ts.map +1 -1
  118. package/dist/memory-retrieval.js +31 -18
  119. package/dist/memory-retrieval.js.map +1 -1
  120. package/dist/metrics.d.ts.map +1 -1
  121. package/dist/metrics.js +12 -2
  122. package/dist/metrics.js.map +1 -1
  123. package/dist/posted-reply-history.d.ts.map +1 -1
  124. package/dist/posted-reply-history.js +7 -0
  125. package/dist/posted-reply-history.js.map +1 -1
  126. package/dist/request-model-override.d.ts +2 -2
  127. package/dist/request-model-override.js +8 -4
  128. package/dist/request-model-override.js.map +1 -1
  129. package/dist/run-history.d.ts.map +1 -1
  130. package/dist/run-history.js +35 -22
  131. package/dist/run-history.js.map +1 -1
  132. package/dist/runtime-provenance.d.ts.map +1 -1
  133. package/dist/runtime-provenance.js +10 -5
  134. package/dist/runtime-provenance.js.map +1 -1
  135. package/dist/tui-command.d.ts.map +1 -1
  136. package/dist/tui-command.js +2 -1
  137. package/dist/tui-command.js.map +1 -1
  138. package/dist/wizard/from-flags.d.ts +0 -1
  139. package/dist/wizard/from-flags.d.ts.map +1 -1
  140. package/dist/wizard/from-flags.js +1 -8
  141. package/dist/wizard/from-flags.js.map +1 -1
  142. package/dist/wizard/index.d.ts +1 -1
  143. package/dist/wizard/index.d.ts.map +1 -1
  144. package/dist/wizard/index.js +1 -1
  145. package/dist/wizard/index.js.map +1 -1
  146. package/dist/wizard/presets.d.ts +3 -12
  147. package/dist/wizard/presets.d.ts.map +1 -1
  148. package/dist/wizard/presets.js +3 -15
  149. package/dist/wizard/presets.js.map +1 -1
  150. package/package.json +15 -16
  151. package/schema/mono-agent.config.schema.json +2 -2
  152. package/skills/mono-agent-composer/SKILL.md +13 -5
  153. package/skills/mono-agent-composer/agents/openai.yaml +1 -1
  154. package/skills/mono-agent-composer/references/config-blueprint.md +17 -9
  155. package/skills/mono-agent-composer/references/discovery-questions.md +8 -5
  156. package/skills/mono-agent-composer/references/feature-coverage.md +9 -8
  157. package/skills/mono-agent-composer/references/package-map.md +10 -4
  158. package/skills/mono-agent-composer/references/playbooks.md +5 -5
  159. package/skills/mono-agent-composer/references/validation.md +4 -2
@@ -14,6 +14,11 @@ const LOCK_STALE_AFTER_MS = 5 * 60_000;
14
14
  const LOCK_POLL_INTERVAL_MS = 200;
15
15
  const PROVISIONAL_RUNTIME_INSTALLED_AT = "1970-01-01T00:00:00.000Z";
16
16
  const MAX_RUNTIME_MARKER_BYTES = 16 * 1024;
17
+ const MAX_RUNTIME_REUSE_PROOF_BYTES = 64 * 1024 * 1024;
18
+ const RUNTIME_REUSE_PROOF_SCHEMA = "mono-agent.managed-runtime-reuse-proof.v1";
19
+ const RUNTIME_REUSE_STAT_CONCURRENCY = 64;
20
+ const MANAGED_RUNTIME_LAUNCH_PROOF_SCHEMA = "mono-agent.managed-runtime-launch.v1";
21
+ const MAX_MANAGED_RUNTIME_LAUNCH_PROOF_BYTES = 2 * 1024;
17
22
  export function defaultManagedBackgroundRuntimeDeps() {
18
23
  return {
19
24
  now: () => Date.now(),
@@ -52,47 +57,77 @@ export async function ensureManagedBackgroundRuntime(input, deps = defaultManage
52
57
  await assertRegularFile(currentCliPath, "current mono-agent CLI");
53
58
  await assertRegularFile(resolve(input.nodePath), "managed runtime Node executable");
54
59
  const currentCli = await readFile(currentCliPath);
55
- const packageSource = resolve(input.packageSource ?? packageRootForCli(currentCliPath));
56
- const sourceDetails = await lstat(packageSource);
60
+ const packageSourceLexical = resolve(input.packageSource ?? packageRootForCli(currentCliPath));
61
+ const sourceDetails = await lstat(packageSourceLexical);
57
62
  if (!sourceDetails.isDirectory() || sourceDetails.isSymbolicLink()) {
58
- throw new Error(`Managed runtime package source ${packageSource} must be a real directory.`);
63
+ throw new Error(`Managed runtime package source ${packageSourceLexical} must be a real directory.`);
59
64
  }
65
+ const packageSource = await realpath(packageSourceLexical);
60
66
  const additionalPackages = await canonicalAdditionalPackages(input.additionalPackages ?? []);
61
- const sourceClosure = await captureExecutionClosure(packageSource, additionalPackages);
62
67
  const packageVersion = input.packageVersion ?? await packageVersionAt(packageSource);
63
68
  if (!isExactVersion(packageVersion)) {
64
69
  throw new Error(`Cannot install a durable managed runtime for invalid package version ${JSON.stringify(packageVersion)}.`);
65
70
  }
71
+ const cliSha256 = sha256(currentCli);
72
+ const nodeAbi = input.nodeAbi ?? requiredNodeAbi();
73
+ const platform = input.platform ?? process.platform;
74
+ const arch = input.arch ?? process.arch;
75
+ const home = resolve(input.homeDir ?? accountHomeDirectory());
76
+ const versionAbiDir = runtimeVersionAbiDir(home, packageVersion, nodeAbi, platform, arch);
77
+ await ensurePrivateRuntimeAncestors(home, versionAbiDir);
78
+ const fastRuntime = await findFastReusableRuntime({
79
+ home,
80
+ versionAbiDir,
81
+ packageVersion,
82
+ cliSha256,
83
+ nodeAbi,
84
+ platform,
85
+ arch,
86
+ packageSource,
87
+ additionalPackages,
88
+ });
89
+ if (fastRuntime !== undefined) {
90
+ await waitForManagedRuntimeLaunchBoundary(fastRuntime.layout, fastRuntime.identity, deps);
91
+ return await runtimeResult(fastRuntime.layout, fastRuntime.identity, input.nodePath, "fast-reuse");
92
+ }
93
+ const sourceClosure = await captureExecutionClosure(packageSource, additionalPackages);
66
94
  const identity = {
67
95
  packageVersion,
68
- cliSha256: sha256(currentCli),
96
+ cliSha256,
69
97
  sourceClosureSha256: sourceClosure.sourceClosureSha256,
70
- nodeAbi: input.nodeAbi ?? requiredNodeAbi(),
71
- platform: input.platform ?? process.platform,
72
- arch: input.arch ?? process.arch,
98
+ nodeAbi,
99
+ platform,
100
+ arch,
73
101
  };
74
- const home = resolve(input.homeDir ?? accountHomeDirectory());
75
102
  const id = safeSegment(deps.randomId());
76
103
  const layout = runtimeLayout(home, identity, id, deps.now());
77
- await ensurePrivateRuntimeAncestors(home, layout.versionAbiDir);
78
- if (await verifyRuntime(layout, identity, additionalPackages)) {
79
- await waitForManagedRuntimeLaunchBoundary(layout, identity, deps);
80
- return runtimeResult(layout, identity, input.nodePath);
81
- }
82
- const acquired = await acquireRuntimeLock(layout, identity, additionalPackages, deps);
104
+ const runtimeWasPresent = await pathExists(layout.installRoot);
105
+ const acquired = await acquireRuntimeLock(layout, identity, additionalPackages, deps, () => verifyRuntimeFast(layout, identity, packageSource, additionalPackages));
83
106
  if (!acquired) {
84
- // Another installer may have completed between the final lock poll and the
85
- // timeout boundary. Verify one last time before reporting the contention.
107
+ if (await verifyRuntimeFast(layout, identity, packageSource, additionalPackages)) {
108
+ await waitForManagedRuntimeLaunchBoundary(layout, identity, deps);
109
+ return await runtimeResult(layout, identity, input.nodePath, "fast-reuse");
110
+ }
111
+ // Preserve compatibility with a finalized v4 runtime when another process
112
+ // released the lock before it could publish the v5 warm proof.
86
113
  if (await verifyRuntime(layout, identity, additionalPackages)) {
87
114
  await waitForManagedRuntimeLaunchBoundary(layout, identity, deps);
88
- return runtimeResult(layout, identity, input.nodePath);
115
+ return await runtimeResult(layout, identity, input.nodePath, "full-reuse");
89
116
  }
90
117
  throw new Error(`Timed out waiting for the managed runtime installation lock at ${layout.lockDir}.`);
91
118
  }
92
119
  try {
93
120
  if (await verifyRuntime(layout, identity, additionalPackages)) {
121
+ const marker = await readRuntimeMarker(layout.markerPath, identity);
122
+ if (marker === undefined)
123
+ throw new Error("The managed runtime marker changed before warm-proof publication.");
124
+ const sourceReuseProof = await currentSourceReuseProof(packageSource, additionalPackages, sourceClosure);
125
+ await publishRuntimeReuseProof(layout, identity, packageSource, additionalPackages, sourceReuseProof, marker, deps);
126
+ if (!(await verifyRuntimeFast(layout, identity, packageSource, additionalPackages))) {
127
+ throw new Error("The managed runtime warm-reuse proof failed verification after publication.");
128
+ }
94
129
  await waitForManagedRuntimeLaunchBoundary(layout, identity, deps);
95
- return runtimeResult(layout, identity, input.nodePath);
130
+ return await runtimeResult(layout, identity, input.nodePath, "full-reuse");
96
131
  }
97
132
  await assertSourceClosureUnchanged(packageSource, additionalPackages, sourceClosure, "before staging");
98
133
  await rm(layout.stagingDir, { recursive: true, force: true });
@@ -158,10 +193,11 @@ export async function ensureManagedBackgroundRuntime(input, deps = defaultManage
158
193
  if (promotedClosure.sourceClosureSha256 !== identity.sourceClosureSha256) {
159
194
  throw new Error("The promoted managed runtime execution closure does not match its source identity.");
160
195
  }
161
- await writeFinalizedRuntimeMarker(layout.markerPath, {
196
+ const sourceReuseProof = await currentSourceReuseProof(packageSource, additionalPackages, sourceClosure);
197
+ await publishRuntimeReuseProof(layout, identity, packageSource, additionalPackages, sourceReuseProof, {
162
198
  ...marker,
163
199
  executionProofSha256: promotedClosure.filesystemProofSha256,
164
- }, deps);
200
+ }, deps, true);
165
201
  }
166
202
  }
167
203
  catch (error) {
@@ -171,13 +207,139 @@ export async function ensureManagedBackgroundRuntime(input, deps = defaultManage
171
207
  if (!(await verifyRuntime(layout, identity, additionalPackages))) {
172
208
  throw new Error("The managed runtime failed verification after atomic promotion.");
173
209
  }
210
+ if (!(await verifyRuntimeFast(layout, identity, packageSource, additionalPackages))) {
211
+ const marker = await readRuntimeMarker(layout.markerPath, identity);
212
+ if (marker === undefined)
213
+ throw new Error("The managed runtime marker changed before warm-proof publication.");
214
+ const sourceReuseProof = await currentSourceReuseProof(packageSource, additionalPackages, sourceClosure);
215
+ await publishRuntimeReuseProof(layout, identity, packageSource, additionalPackages, sourceReuseProof, marker, deps);
216
+ }
217
+ if (!(await verifyRuntimeFast(layout, identity, packageSource, additionalPackages))) {
218
+ throw new Error("The managed runtime warm-reuse proof failed verification after atomic promotion.");
219
+ }
174
220
  await waitForManagedRuntimeLaunchBoundary(layout, identity, deps);
175
- return runtimeResult(layout, identity, input.nodePath);
221
+ return await runtimeResult(layout, identity, input.nodePath, runtimeWasPresent ? "repaired" : "installed");
176
222
  }
177
223
  finally {
178
224
  await acquired.release().catch(() => undefined);
179
225
  }
180
226
  }
227
+ /**
228
+ * Validate the opaque proof carried by a managed LaunchAgent against the exact
229
+ * CLI that is about to start. This is intentionally lighter than controller
230
+ * attestation: it rechecks the private layout, marker, CLI, and stored closure
231
+ * manifest fingerprints without traversing the entire installed dependency
232
+ * tree on every KeepAlive restart.
233
+ */
234
+ export async function verifyManagedRuntimeLaunch(input) {
235
+ const proof = decodeManagedRuntimeLaunchProof(input.launchProof);
236
+ const currentCliPath = resolve(input.currentCliPath);
237
+ const packageRoot = packageRootForCli(currentCliPath);
238
+ const installRoot = dirname(dirname(dirname(packageRoot)));
239
+ const home = resolve(input.homeDir ?? accountHomeDirectory());
240
+ const initialInstallRoot = await lstat(installRoot, { bigint: true });
241
+ if (!privateRuntimeDirectory(initialInstallRoot)) {
242
+ throw new Error("The managed runtime closure root is not a real owner-private directory.");
243
+ }
244
+ const markerPath = join(installRoot, ".mono-agent-runtime.json");
245
+ const initialBytes = await readPrivateRuntimeMarkerBytes(markerPath);
246
+ if (initialBytes === undefined)
247
+ throw new Error("The managed runtime marker is unavailable or unsafe.");
248
+ const markerValue = parseJson(initialBytes, "managed runtime marker");
249
+ const identity = runtimeIdentityFromMarkerJson(markerValue);
250
+ if (identity === undefined)
251
+ throw new Error("The managed runtime marker has an invalid identity.");
252
+ const marker = runtimeMarkerFromJson(markerValue, identity);
253
+ if (marker === undefined)
254
+ throw new Error("The managed runtime marker is provisional or malformed.");
255
+ const layout = runtimeLayout(home, identity, "launch", 0);
256
+ if (layout.installRoot !== installRoot || layout.cliPath !== currentCliPath) {
257
+ throw new Error("The managed worker CLI is outside its canonical runtime closure.");
258
+ }
259
+ if (!(await verifyPrivateRuntimeAncestors(home, layout.versionAbiDir))) {
260
+ throw new Error("The managed runtime has an unsafe private ancestry.");
261
+ }
262
+ if (sha256(initialBytes) !== proof.markerSha256 || marker.installedAt !== proof.installedAt) {
263
+ throw new Error("The managed runtime marker does not match its LaunchAgent proof.");
264
+ }
265
+ if (!(await verifyInstalledPackage(layout, identity))) {
266
+ throw new Error("The managed runtime CLI or package identity failed verification.");
267
+ }
268
+ if (!(await verifyManagedRuntimeCliFingerprint(layout, identity.cliSha256))) {
269
+ throw new Error("The managed runtime CLI fingerprint is unstable.");
270
+ }
271
+ if (!(await verifyClosureManifestFingerprint(layout, marker.closureManifestSha256))) {
272
+ throw new Error("The managed runtime closure manifest fingerprint is invalid.");
273
+ }
274
+ await waitForLaunchBoundary(marker.installedAt, input.now ?? Date.now, input.sleep ?? sleep);
275
+ const finalBytes = await readPrivateRuntimeMarkerBytes(markerPath);
276
+ if (finalBytes === undefined || sha256(finalBytes) !== proof.markerSha256 || !finalBytes.equals(initialBytes)) {
277
+ throw new Error("The managed runtime marker changed during launch verification.");
278
+ }
279
+ if (!(await verifyManagedRuntimeCliFingerprint(layout, identity.cliSha256))) {
280
+ throw new Error("The managed runtime CLI changed during launch verification.");
281
+ }
282
+ if (!(await verifyClosureManifestFingerprint(layout, marker.closureManifestSha256))) {
283
+ throw new Error("The managed runtime closure manifest changed during launch verification.");
284
+ }
285
+ const finalInstallRoot = await lstat(installRoot, { bigint: true });
286
+ if (!privateRuntimeDirectory(finalInstallRoot) || !sameSourceStats(initialInstallRoot, finalInstallRoot)) {
287
+ throw new Error("The managed runtime closure root changed during launch verification.");
288
+ }
289
+ const closureId = `${identity.cliSha256}-${identity.sourceClosureSha256}`;
290
+ return {
291
+ installRoot,
292
+ provenanceDetail: `Runtime provenance: managed closure ${closureId} (`
293
+ + `${PACKAGE_NAME} ${identity.packageVersion}; ${identity.platform}-${identity.arch}; `
294
+ + `Node ABI ${identity.nodeAbi}; installed ${marker.installedAt}).`,
295
+ };
296
+ }
297
+ function encodeManagedRuntimeLaunchProof(proof) {
298
+ return Buffer.from(JSON.stringify(proof), "utf8").toString("base64url");
299
+ }
300
+ function decodeManagedRuntimeLaunchProof(encoded) {
301
+ if (typeof encoded !== "string"
302
+ || encoded.length === 0
303
+ || encoded.length > MAX_MANAGED_RUNTIME_LAUNCH_PROOF_BYTES * 2
304
+ || !/^[0-9A-Za-z_-]+$/u.test(encoded)) {
305
+ throw new Error("The managed runtime launch proof is malformed.");
306
+ }
307
+ let bytes;
308
+ try {
309
+ bytes = Buffer.from(encoded, "base64url");
310
+ }
311
+ catch {
312
+ throw new Error("The managed runtime launch proof is malformed.");
313
+ }
314
+ if (bytes.length === 0
315
+ || bytes.length > MAX_MANAGED_RUNTIME_LAUNCH_PROOF_BYTES
316
+ || bytes.toString("base64url") !== encoded) {
317
+ throw new Error("The managed runtime launch proof is malformed.");
318
+ }
319
+ const value = parseJson(bytes, "managed runtime launch proof");
320
+ if (!isRecord(value) || Object.keys(value).length !== 3) {
321
+ throw new Error("The managed runtime launch proof has an invalid schema.");
322
+ }
323
+ const installedAtMs = typeof value.installedAt === "string" ? Date.parse(value.installedAt) : Number.NaN;
324
+ if (value.schema !== MANAGED_RUNTIME_LAUNCH_PROOF_SCHEMA
325
+ || typeof value.markerSha256 !== "string"
326
+ || !/^[0-9a-f]{64}$/u.test(value.markerSha256)
327
+ || typeof value.installedAt !== "string"
328
+ || !Number.isFinite(installedAtMs)
329
+ || new Date(installedAtMs).toISOString() !== value.installedAt
330
+ || value.installedAt === PROVISIONAL_RUNTIME_INSTALLED_AT) {
331
+ throw new Error("The managed runtime launch proof has an invalid schema.");
332
+ }
333
+ return value;
334
+ }
335
+ function parseJson(bytes, label) {
336
+ try {
337
+ return JSON.parse(bytes.toString("utf8"));
338
+ }
339
+ catch {
340
+ throw new Error(`The ${label} is not valid JSON.`);
341
+ }
342
+ }
181
343
  /**
182
344
  * Canonically verify the installed package, freshly recomputed execution
183
345
  * closure/filesystem proof, and coherent current manifest behind a provenance
@@ -212,16 +374,8 @@ export async function verifyManagedRuntimeClosureForProvenance(input, deps = {})
212
374
  return false;
213
375
  if (!(await verifyPrivateRuntimeAncestors(home, layout.versionAbiDir)))
214
376
  return false;
215
- const expectedMarker = {
216
- schema: "mono-agent.managed-runtime.v4",
217
- packageName: PACKAGE_NAME,
218
- closureManifestSha256: input.closureManifestSha256,
219
- executionProofSha256: input.executionProofSha256,
220
- ...identity,
221
- installedAt: input.installedAt,
222
- };
223
377
  const markerInitial = await verifiedRuntimeMarker(layout, identity);
224
- if (markerInitial === undefined || !sameRuntimeMarker(markerInitial, expectedMarker))
378
+ if (markerInitial === undefined || !runtimeMarkerMatchesProvenance(markerInitial, input))
225
379
  return false;
226
380
  const additionalPackages = await managedRuntimeAdditionalPackages(layout);
227
381
  if (additionalPackages === undefined)
@@ -242,7 +396,7 @@ export async function verifyManagedRuntimeClosureForProvenance(input, deps = {})
242
396
  const markerFinal = await readRuntimeMarker(layout.markerPath, identity);
243
397
  if (markerFinal === undefined
244
398
  || !sameRuntimeMarker(markerFinal, markerInitial)
245
- || !sameRuntimeMarker(markerFinal, expectedMarker)
399
+ || !runtimeMarkerMatchesProvenance(markerFinal, input)
246
400
  || !(await verifyClosureManifest(layout, markerFinal.closureManifestSha256, deps.beforeFinalManifestProof === undefined
247
401
  ? {}
248
402
  : { beforeFinalProof: deps.beforeFinalManifestProof }))) {
@@ -251,7 +405,7 @@ export async function verifyManagedRuntimeClosureForProvenance(input, deps = {})
251
405
  const markerAfterManifest = await readRuntimeMarker(layout.markerPath, identity);
252
406
  return markerAfterManifest !== undefined
253
407
  && sameRuntimeMarker(markerAfterManifest, markerInitial)
254
- && sameRuntimeMarker(markerAfterManifest, expectedMarker);
408
+ && runtimeMarkerMatchesProvenance(markerAfterManifest, input);
255
409
  }
256
410
  catch {
257
411
  return false;
@@ -569,6 +723,15 @@ async function captureExecutionClosure(packageSource, additionalPackages, filesy
569
723
  sourceClosureSha256: sha256(Buffer.from(JSON.stringify(stable), "utf8")),
570
724
  sourceProofSha256: sha256(Buffer.from(JSON.stringify(proof), "utf8")),
571
725
  filesystemProofSha256: sha256(Buffer.from(JSON.stringify(filesystemProof), "utf8")),
726
+ reuseProof: {
727
+ sourceProofSha256: sha256(Buffer.from(JSON.stringify(proof), "utf8")),
728
+ packages: closure.map((node) => ({
729
+ id: node.id,
730
+ sourceRoot: node.sourceRoot,
731
+ entries: requiredMapValue(proofs, node.id, "source package proof"),
732
+ })),
733
+ links: [...dependencyProofPaths, ...additionalProofPaths],
734
+ },
572
735
  };
573
736
  }
574
737
  /**
@@ -626,6 +789,15 @@ async function assertSourceClosureUnchanged(packageSource, additionalPackages, e
626
789
  throw new Error(`The managed runtime package closure changed ${phase}; no staged runtime was promoted.`);
627
790
  }
628
791
  }
792
+ async function currentSourceReuseProof(packageSource, additionalPackages, expected) {
793
+ if (await verifySourceReuseProofStats(expected.reuseProof))
794
+ return expected.reuseProof;
795
+ const current = await captureExecutionClosure(packageSource, additionalPackages);
796
+ if (current.sourceClosureSha256 !== expected.sourceClosureSha256) {
797
+ throw new Error("The managed runtime source closure changed before warm-proof publication.");
798
+ }
799
+ return current.reuseProof;
800
+ }
629
801
  /**
630
802
  * Capture exactly the package-owned files copied by `materializeExactExecutionClosure`.
631
803
  * `node_modules`, VCS metadata, and dotenv files are deliberately excluded.
@@ -1054,8 +1226,7 @@ async function packageVersionAt(packageRoot) {
1054
1226
  return record.version;
1055
1227
  }
1056
1228
  function runtimeLayout(home, identity, id, nowMs) {
1057
- const platformAbi = `${safeSegment(identity.platform)}-${safeSegment(identity.arch)}-abi-${safeSegment(identity.nodeAbi)}`;
1058
- const versionAbiDir = join(home, ".mono-agent", "runtimes", "agent-app", identity.packageVersion, platformAbi);
1229
+ const versionAbiDir = runtimeVersionAbiDir(home, identity.packageVersion, identity.nodeAbi, identity.platform, identity.arch);
1059
1230
  const closureId = `${identity.cliSha256}-${identity.sourceClosureSha256}`;
1060
1231
  const installRoot = join(versionAbiDir, closureId);
1061
1232
  const suffix = `${Math.max(0, Math.floor(nowMs))}-${id}`;
@@ -1067,11 +1238,17 @@ function runtimeLayout(home, identity, id, nowMs) {
1067
1238
  packageLockPath: join(installRoot, "package-lock.json"),
1068
1239
  closureManifestPath: join(installRoot, ".mono-agent-closure.json"),
1069
1240
  markerPath: join(installRoot, ".mono-agent-runtime.json"),
1241
+ reuseProofDir: join(versionAbiDir, ".reuse-proofs"),
1242
+ reuseProofPath: join(versionAbiDir, ".reuse-proofs", `${closureId}.json`),
1070
1243
  lockDir: join(versionAbiDir, `.${closureId}.lock`),
1071
1244
  stagingDir: join(versionAbiDir, `.${closureId}.staging-${suffix}`),
1072
1245
  quarantineDir: join(versionAbiDir, "quarantine", `${closureId}-${suffix}`),
1073
1246
  };
1074
1247
  }
1248
+ function runtimeVersionAbiDir(home, packageVersion, nodeAbi, platform, arch) {
1249
+ const platformAbi = `${safeSegment(platform)}-${safeSegment(arch)}-abi-${safeSegment(nodeAbi)}`;
1250
+ return join(home, ".mono-agent", "runtimes", "agent-app", packageVersion, platformAbi);
1251
+ }
1075
1252
  function runtimeLayoutForRoot(layout, root) {
1076
1253
  return {
1077
1254
  ...layout,
@@ -1083,7 +1260,552 @@ function runtimeLayoutForRoot(layout, root) {
1083
1260
  markerPath: join(root, ".mono-agent-runtime.json"),
1084
1261
  };
1085
1262
  }
1086
- async function acquireRuntimeLock(layout, identity, additionalPackages, deps) {
1263
+ async function findFastReusableRuntime(input) {
1264
+ let entries;
1265
+ try {
1266
+ entries = await readdir(input.versionAbiDir, { withFileTypes: true });
1267
+ }
1268
+ catch {
1269
+ return undefined;
1270
+ }
1271
+ const prefix = `${input.cliSha256}-`;
1272
+ for (const entry of entries.sort((left, right) => compareCodeUnits(left.name, right.name))) {
1273
+ if (!entry.isDirectory() || !entry.name.startsWith(prefix))
1274
+ continue;
1275
+ const sourceClosureSha256 = entry.name.slice(prefix.length);
1276
+ if (!/^[0-9a-f]{64}$/u.test(sourceClosureSha256))
1277
+ continue;
1278
+ const identity = {
1279
+ packageVersion: input.packageVersion,
1280
+ cliSha256: input.cliSha256,
1281
+ sourceClosureSha256,
1282
+ nodeAbi: input.nodeAbi,
1283
+ platform: input.platform,
1284
+ arch: input.arch,
1285
+ };
1286
+ const layout = runtimeLayout(input.home, identity, "fast-reuse", 0);
1287
+ if (await verifyRuntimeFast(layout, identity, input.packageSource, input.additionalPackages)) {
1288
+ return { layout, identity };
1289
+ }
1290
+ }
1291
+ return undefined;
1292
+ }
1293
+ async function verifyRuntimeFast(layout, identity, packageSource, additionalPackages) {
1294
+ try {
1295
+ const home = dirname(dirname(dirname(dirname(dirname(layout.versionAbiDir)))));
1296
+ if (!(await verifyPrivateRuntimeAncestors(home, layout.versionAbiDir)))
1297
+ return false;
1298
+ const [initialRoot, initialProofDir] = await Promise.all([
1299
+ lstat(layout.installRoot, { bigint: true }),
1300
+ lstat(layout.reuseProofDir, { bigint: true }),
1301
+ ]);
1302
+ if (!privateRuntimeDirectory(initialRoot) || !privateRuntimeDirectory(initialProofDir))
1303
+ return false;
1304
+ const [markerBytes, proofBytes] = await Promise.all([
1305
+ readPrivateRuntimeMarkerBytes(layout.markerPath),
1306
+ readPrivateRuntimeReuseProofBytes(layout.reuseProofPath),
1307
+ ]);
1308
+ if (markerBytes === undefined || proofBytes === undefined)
1309
+ return false;
1310
+ const marker = runtimeMarkerFromJson(parseJson(markerBytes, "managed runtime marker"), identity);
1311
+ if (marker?.schema !== "mono-agent.managed-runtime.v5"
1312
+ || marker.reuseProofSha256 !== sha256(proofBytes)) {
1313
+ return false;
1314
+ }
1315
+ const proof = runtimeReuseProofFromJson(parseJson(proofBytes, "managed runtime reuse proof"), identity, packageSource, additionalPackages, marker);
1316
+ if (proof === undefined)
1317
+ return false;
1318
+ const [installed, cliStable, manifestStable] = await Promise.all([
1319
+ verifyInstalledPackage(layout, identity),
1320
+ verifyManagedRuntimeCliFingerprint(layout, identity.cliSha256),
1321
+ verifyClosureManifestFingerprint(layout, marker.closureManifestSha256),
1322
+ ]);
1323
+ if (!installed
1324
+ || !cliStable
1325
+ || !manifestStable
1326
+ || !(await runtimeReuseProofMatchesManifest(layout, proof.runtime))) {
1327
+ return false;
1328
+ }
1329
+ if (!(await verifyReuseProofStats(layout, proof)))
1330
+ return false;
1331
+ if (!(await verifyReuseProofStats(layout, proof)))
1332
+ return false;
1333
+ const [markerBytesAfter, proofBytesAfter, finalRoot, finalProofDir] = await Promise.all([
1334
+ readPrivateRuntimeMarkerBytes(layout.markerPath),
1335
+ readPrivateRuntimeReuseProofBytes(layout.reuseProofPath),
1336
+ lstat(layout.installRoot, { bigint: true }),
1337
+ lstat(layout.reuseProofDir, { bigint: true }),
1338
+ ]);
1339
+ return markerBytesAfter !== undefined
1340
+ && proofBytesAfter !== undefined
1341
+ && markerBytesAfter.equals(markerBytes)
1342
+ && proofBytesAfter.equals(proofBytes)
1343
+ && privateRuntimeDirectory(finalRoot)
1344
+ && privateRuntimeDirectory(finalProofDir)
1345
+ && sameSourceStats(initialRoot, finalRoot)
1346
+ && sameSourceStats(initialProofDir, finalProofDir);
1347
+ }
1348
+ catch {
1349
+ return false;
1350
+ }
1351
+ }
1352
+ async function publishRuntimeReuseProof(layout, identity, packageSource, additionalPackages, source, marker, deps, finalizeLaunchBoundary = false) {
1353
+ if (!(await verifySourceReuseProofStats(source))) {
1354
+ throw new Error("The managed runtime source closure changed before warm-proof publication.");
1355
+ }
1356
+ const runtime = await captureRuntimeClosureReuseProof(layout, marker);
1357
+ const proof = {
1358
+ schema: RUNTIME_REUSE_PROOF_SCHEMA,
1359
+ identity,
1360
+ packageSource,
1361
+ additionalPackages,
1362
+ source,
1363
+ runtime,
1364
+ };
1365
+ const contents = privateJsonContents(proof);
1366
+ const bytes = Buffer.from(contents, "utf8");
1367
+ if (bytes.length > MAX_RUNTIME_REUSE_PROOF_BYTES) {
1368
+ throw new Error("The managed runtime warm-reuse proof exceeds its safe size limit.");
1369
+ }
1370
+ await ensurePrivateReuseProofDirectory(layout.reuseProofDir);
1371
+ await writeFile(layout.reuseProofPath, contents, { encoding: "utf8", mode: 0o600 });
1372
+ await chmod(layout.reuseProofPath, 0o600);
1373
+ const stored = await readPrivateRuntimeReuseProofBytes(layout.reuseProofPath);
1374
+ if (stored === undefined || !stored.equals(bytes)) {
1375
+ throw new Error("The managed runtime warm-reuse proof changed while it was published.");
1376
+ }
1377
+ const nextMarker = {
1378
+ schema: "mono-agent.managed-runtime.v5",
1379
+ packageName: PACKAGE_NAME,
1380
+ packageVersion: identity.packageVersion,
1381
+ cliSha256: identity.cliSha256,
1382
+ sourceClosureSha256: identity.sourceClosureSha256,
1383
+ nodeAbi: identity.nodeAbi,
1384
+ platform: identity.platform,
1385
+ arch: identity.arch,
1386
+ closureManifestSha256: marker.closureManifestSha256,
1387
+ executionProofSha256: marker.executionProofSha256,
1388
+ reuseProofSha256: sha256(bytes),
1389
+ installedAt: marker.installedAt,
1390
+ };
1391
+ if (finalizeLaunchBoundary) {
1392
+ await writeFinalizedRuntimeMarker(layout.markerPath, nextMarker, deps);
1393
+ }
1394
+ else {
1395
+ await writePrivateJson(layout.markerPath, nextMarker);
1396
+ }
1397
+ if (!(await verifySourceReuseProofStats(source))) {
1398
+ throw new Error("The managed runtime source closure changed during warm-proof publication.");
1399
+ }
1400
+ }
1401
+ async function captureRuntimeClosureReuseProof(layout, marker) {
1402
+ const stored = await fingerprintClosureFile(layout.closureManifestPath, ".mono-agent-closure.json");
1403
+ if (stored.sha256 !== marker.closureManifestSha256) {
1404
+ throw new Error("The managed runtime closure manifest changed before warm-proof capture.");
1405
+ }
1406
+ const manifest = runtimeClosureManifestFromJson(parseJson(stored.bytes, "managed runtime closure manifest"));
1407
+ if (manifest === undefined)
1408
+ throw new Error("The managed runtime closure manifest is malformed.");
1409
+ const excludedRootEntries = new Set([".mono-agent-closure.json", ".mono-agent-runtime.json"]);
1410
+ const rootEntries = (await readdir(layout.installRoot))
1411
+ .filter((name) => !excludedRootEntries.has(name))
1412
+ .sort(compareCodeUnits);
1413
+ const entries = await mapWithConcurrency(manifest.entries, RUNTIME_REUSE_STAT_CONCURRENCY, async (entry) => ({
1414
+ path: entry.path,
1415
+ proof: await captureFilesystemPathProof(runtimePathFromPortableRelative(layout.installRoot, entry.path), entry.path),
1416
+ }));
1417
+ const result = {
1418
+ rootEntries,
1419
+ entries,
1420
+ closureManifestSha256: marker.closureManifestSha256,
1421
+ executionProofSha256: marker.executionProofSha256,
1422
+ };
1423
+ if (!(await verifyRuntimeReuseProofStats(layout, result))) {
1424
+ throw new Error("The managed runtime closure changed during warm-proof capture.");
1425
+ }
1426
+ return result;
1427
+ }
1428
+ async function verifyReuseProofStats(layout, proof) {
1429
+ const [sourceValid, runtimeValid] = await Promise.all([
1430
+ verifySourceReuseProofStats(proof.source),
1431
+ verifyRuntimeReuseProofStats(layout, proof.runtime),
1432
+ ]);
1433
+ return sourceValid && runtimeValid;
1434
+ }
1435
+ async function verifySourceReuseProofStats(proof) {
1436
+ try {
1437
+ const targets = [
1438
+ ...proof.packages.flatMap((pkg) => pkg.entries.map((entry) => ({
1439
+ path: entry.path === "."
1440
+ ? pkg.sourceRoot
1441
+ : runtimePathFromPortableRelative(pkg.sourceRoot, entry.path),
1442
+ logicalPath: entry.path,
1443
+ proof: entry,
1444
+ }))),
1445
+ ...proof.links,
1446
+ ];
1447
+ const matches = await mapWithConcurrency(targets, RUNTIME_REUSE_STAT_CONCURRENCY, async (target) => {
1448
+ const current = await captureFilesystemPathProof(target.path, target.logicalPath);
1449
+ return sameSourceProofEntry(target.proof, current);
1450
+ });
1451
+ return matches.every(Boolean);
1452
+ }
1453
+ catch {
1454
+ return false;
1455
+ }
1456
+ }
1457
+ async function verifyRuntimeReuseProofStats(layout, proof) {
1458
+ try {
1459
+ const excludedRootEntries = new Set([".mono-agent-closure.json", ".mono-agent-runtime.json"]);
1460
+ const rootEntries = (await readdir(layout.installRoot))
1461
+ .filter((name) => !excludedRootEntries.has(name))
1462
+ .sort(compareCodeUnits);
1463
+ if (JSON.stringify(rootEntries) !== JSON.stringify(proof.rootEntries))
1464
+ return false;
1465
+ const matches = await mapWithConcurrency(proof.entries, RUNTIME_REUSE_STAT_CONCURRENCY, async (entry) => {
1466
+ const current = await captureFilesystemPathProof(runtimePathFromPortableRelative(layout.installRoot, entry.path), entry.path);
1467
+ return sameSourceProofEntry(entry.proof, current);
1468
+ });
1469
+ return matches.every(Boolean);
1470
+ }
1471
+ catch {
1472
+ return false;
1473
+ }
1474
+ }
1475
+ async function runtimeReuseProofMatchesManifest(layout, proof) {
1476
+ try {
1477
+ const bytes = await readFile(layout.closureManifestPath);
1478
+ if (sha256(bytes) !== proof.closureManifestSha256)
1479
+ return false;
1480
+ const manifest = runtimeClosureManifestFromJson(parseJson(bytes, "managed runtime closure manifest"));
1481
+ if (manifest === undefined || manifest.entries.length !== proof.entries.length)
1482
+ return false;
1483
+ return manifest.entries.every((entry, index) => {
1484
+ const proven = proof.entries[index];
1485
+ return proven !== undefined
1486
+ && proven.path === entry.path
1487
+ && proven.proof.type === entry.type
1488
+ && fileMode(BigInt(proven.proof.mode)) === entry.mode
1489
+ && (entry.type !== "symlink" || proven.proof.target === entry.target);
1490
+ });
1491
+ }
1492
+ catch {
1493
+ return false;
1494
+ }
1495
+ }
1496
+ async function ensurePrivateReuseProofDirectory(path) {
1497
+ await mkdir(path, { recursive: false, mode: 0o700 }).catch((error) => {
1498
+ if (!isErrno(error, "EEXIST"))
1499
+ throw error;
1500
+ });
1501
+ const details = await lstat(path, { bigint: true });
1502
+ if (!privateRuntimeDirectory(details)) {
1503
+ throw new Error(`Managed runtime reuse-proof directory ${path} must be owner-private.`);
1504
+ }
1505
+ await chmod(path, 0o700);
1506
+ }
1507
+ async function readPrivateRuntimeReuseProofBytes(path) {
1508
+ let handle;
1509
+ try {
1510
+ handle = await open(path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
1511
+ const before = await handle.stat({ bigint: true });
1512
+ if (!privateRuntimeReuseProofFile(before))
1513
+ return undefined;
1514
+ const bytes = await handle.readFile();
1515
+ const [after, named] = await Promise.all([
1516
+ handle.stat({ bigint: true }),
1517
+ lstat(path, { bigint: true }),
1518
+ ]);
1519
+ if (!privateRuntimeReuseProofFile(after)
1520
+ || !privateRuntimeReuseProofFile(named)
1521
+ || !sameSourceStats(before, after)
1522
+ || !sameSourceStats(before, named)) {
1523
+ return undefined;
1524
+ }
1525
+ return bytes;
1526
+ }
1527
+ catch {
1528
+ return undefined;
1529
+ }
1530
+ finally {
1531
+ await handle?.close();
1532
+ }
1533
+ }
1534
+ function privateRuntimeReuseProofFile(details) {
1535
+ const owned = typeof process.getuid !== "function" || details.uid === BigInt(process.getuid());
1536
+ return details.isFile()
1537
+ && !details.isSymbolicLink()
1538
+ && details.nlink === 1n
1539
+ && details.size <= BigInt(MAX_RUNTIME_REUSE_PROOF_BYTES)
1540
+ && (details.mode & 63n) === 0n
1541
+ && owned;
1542
+ }
1543
+ function runtimeReuseProofFromJson(value, identity, packageSource, additionalPackages, marker) {
1544
+ if (!hasExactKeys(value, ["schema", "identity", "packageSource", "additionalPackages", "source", "runtime"])) {
1545
+ return undefined;
1546
+ }
1547
+ if (value.schema !== RUNTIME_REUSE_PROOF_SCHEMA
1548
+ || !sameRuntimeIdentityJson(value.identity, identity)
1549
+ || value.packageSource !== packageSource
1550
+ || !Array.isArray(value.additionalPackages)
1551
+ || JSON.stringify(value.additionalPackages) !== JSON.stringify(additionalPackages)) {
1552
+ return undefined;
1553
+ }
1554
+ const source = sourceClosureReuseProofFromJson(value.source, packageSource);
1555
+ const runtime = runtimeClosureReuseProofFromJson(value.runtime, marker);
1556
+ return source === undefined || runtime === undefined
1557
+ ? undefined
1558
+ : {
1559
+ schema: RUNTIME_REUSE_PROOF_SCHEMA,
1560
+ identity,
1561
+ packageSource,
1562
+ additionalPackages,
1563
+ source,
1564
+ runtime,
1565
+ };
1566
+ }
1567
+ function sourceClosureReuseProofFromJson(value, packageSource) {
1568
+ if (!hasExactKeys(value, ["sourceProofSha256", "packages", "links"]))
1569
+ return undefined;
1570
+ if (typeof value.sourceProofSha256 !== "string"
1571
+ || !/^[0-9a-f]{64}$/u.test(value.sourceProofSha256)
1572
+ || !Array.isArray(value.packages)
1573
+ || !Array.isArray(value.links)) {
1574
+ return undefined;
1575
+ }
1576
+ const packages = [];
1577
+ const roots = new Set();
1578
+ for (const [index, rawPackage] of value.packages.entries()) {
1579
+ if (!hasExactKeys(rawPackage, ["id", "sourceRoot", "entries"]))
1580
+ return undefined;
1581
+ if (rawPackage.id !== index
1582
+ || typeof rawPackage.sourceRoot !== "string"
1583
+ || !isCanonicalAbsolutePath(rawPackage.sourceRoot)
1584
+ || roots.has(rawPackage.sourceRoot)
1585
+ || !Array.isArray(rawPackage.entries)) {
1586
+ return undefined;
1587
+ }
1588
+ const entries = proofEntriesFromJson(rawPackage.entries, true);
1589
+ if (entries === undefined || entries[0]?.path !== ".")
1590
+ return undefined;
1591
+ roots.add(rawPackage.sourceRoot);
1592
+ packages.push({ id: index, sourceRoot: rawPackage.sourceRoot, entries });
1593
+ }
1594
+ if (packages[0]?.sourceRoot !== packageSource)
1595
+ return undefined;
1596
+ const links = [];
1597
+ const linkPaths = new Set();
1598
+ for (const rawLink of value.links) {
1599
+ if (!hasExactKeys(rawLink, ["path", "logicalPath", "proof"]))
1600
+ return undefined;
1601
+ if (typeof rawLink.path !== "string"
1602
+ || !isCanonicalAbsolutePath(rawLink.path)
1603
+ || linkPaths.has(rawLink.path)
1604
+ || typeof rawLink.logicalPath !== "string"
1605
+ || rawLink.logicalPath.length === 0) {
1606
+ return undefined;
1607
+ }
1608
+ const proof = sourceProofEntryFromJson(rawLink.proof);
1609
+ if (proof === undefined || proof.path !== rawLink.logicalPath)
1610
+ return undefined;
1611
+ linkPaths.add(rawLink.path);
1612
+ links.push({ path: rawLink.path, logicalPath: rawLink.logicalPath, proof });
1613
+ }
1614
+ return { sourceProofSha256: value.sourceProofSha256, packages, links };
1615
+ }
1616
+ function runtimeClosureReuseProofFromJson(value, marker) {
1617
+ if (!hasExactKeys(value, [
1618
+ "rootEntries",
1619
+ "entries",
1620
+ "closureManifestSha256",
1621
+ "executionProofSha256",
1622
+ ]))
1623
+ return undefined;
1624
+ if (value.closureManifestSha256 !== marker.closureManifestSha256
1625
+ || value.executionProofSha256 !== marker.executionProofSha256
1626
+ || !Array.isArray(value.rootEntries)
1627
+ || !Array.isArray(value.entries)) {
1628
+ return undefined;
1629
+ }
1630
+ const rootEntries = [];
1631
+ const rootNames = new Set();
1632
+ for (const name of value.rootEntries) {
1633
+ if (typeof name !== "string"
1634
+ || name.length === 0
1635
+ || name === "."
1636
+ || name === ".."
1637
+ || name.includes("/")
1638
+ || name.includes("\\")
1639
+ || name.includes("\0")
1640
+ || rootNames.has(name)
1641
+ || name === ".mono-agent-closure.json"
1642
+ || name === ".mono-agent-runtime.json") {
1643
+ return undefined;
1644
+ }
1645
+ rootNames.add(name);
1646
+ rootEntries.push(name);
1647
+ }
1648
+ if (JSON.stringify(rootEntries) !== JSON.stringify([...rootEntries].sort(compareCodeUnits)))
1649
+ return undefined;
1650
+ const entries = [];
1651
+ const entryPaths = new Set();
1652
+ for (const rawEntry of value.entries) {
1653
+ if (!hasExactKeys(rawEntry, ["path", "proof"]))
1654
+ return undefined;
1655
+ if (typeof rawEntry.path !== "string"
1656
+ || !isSafePortableRelativePath(rawEntry.path)
1657
+ || entryPaths.has(rawEntry.path)) {
1658
+ return undefined;
1659
+ }
1660
+ const proof = sourceProofEntryFromJson(rawEntry.proof);
1661
+ if (proof === undefined || proof.path !== rawEntry.path)
1662
+ return undefined;
1663
+ entryPaths.add(rawEntry.path);
1664
+ entries.push({ path: rawEntry.path, proof });
1665
+ }
1666
+ return {
1667
+ rootEntries,
1668
+ entries,
1669
+ closureManifestSha256: marker.closureManifestSha256,
1670
+ executionProofSha256: marker.executionProofSha256,
1671
+ };
1672
+ }
1673
+ function runtimeClosureManifestFromJson(value) {
1674
+ if (!hasExactKeys(value, ["schema", "entries"]) || value.schema !== "mono-agent.execution-closure.v1") {
1675
+ return undefined;
1676
+ }
1677
+ if (!Array.isArray(value.entries))
1678
+ return undefined;
1679
+ const entries = [];
1680
+ const paths = new Set();
1681
+ for (const rawEntry of value.entries) {
1682
+ if (!isRecord(rawEntry) || typeof rawEntry.type !== "string")
1683
+ return undefined;
1684
+ const expectedKeys = rawEntry.type === "file"
1685
+ ? ["path", "type", "mode", "sha256"]
1686
+ : rawEntry.type === "symlink"
1687
+ ? ["path", "type", "mode", "target"]
1688
+ : ["path", "type", "mode"];
1689
+ if (!hasExactKeys(rawEntry, expectedKeys)
1690
+ || typeof rawEntry.path !== "string"
1691
+ || !isSafePortableRelativePath(rawEntry.path)
1692
+ || paths.has(rawEntry.path)
1693
+ || typeof rawEntry.mode !== "string"
1694
+ || !/^0[0-7]{3}$/u.test(rawEntry.mode)) {
1695
+ return undefined;
1696
+ }
1697
+ if (rawEntry.type === "file") {
1698
+ if (typeof rawEntry.sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(rawEntry.sha256))
1699
+ return undefined;
1700
+ entries.push({ path: rawEntry.path, type: "file", mode: rawEntry.mode, sha256: rawEntry.sha256 });
1701
+ }
1702
+ else if (rawEntry.type === "symlink") {
1703
+ if (typeof rawEntry.target !== "string" || rawEntry.target.includes("\0"))
1704
+ return undefined;
1705
+ entries.push({ path: rawEntry.path, type: "symlink", mode: rawEntry.mode, target: rawEntry.target });
1706
+ }
1707
+ else if (rawEntry.type === "directory") {
1708
+ entries.push({ path: rawEntry.path, type: "directory", mode: rawEntry.mode });
1709
+ }
1710
+ else {
1711
+ return undefined;
1712
+ }
1713
+ paths.add(rawEntry.path);
1714
+ }
1715
+ return { schema: "mono-agent.execution-closure.v1", entries };
1716
+ }
1717
+ function proofEntriesFromJson(values, allowRoot) {
1718
+ const entries = [];
1719
+ const paths = new Set();
1720
+ for (const value of values) {
1721
+ const entry = sourceProofEntryFromJson(value);
1722
+ if (entry === undefined
1723
+ || (entry.path !== "." && !isSafePortableRelativePath(entry.path))
1724
+ || (!allowRoot && entry.path === ".")
1725
+ || paths.has(entry.path)) {
1726
+ return undefined;
1727
+ }
1728
+ paths.add(entry.path);
1729
+ entries.push(entry);
1730
+ }
1731
+ return entries;
1732
+ }
1733
+ function sourceProofEntryFromJson(value) {
1734
+ if (!isRecord(value))
1735
+ return undefined;
1736
+ const type = value.type;
1737
+ const expectedKeys = type === "symlink"
1738
+ ? ["path", "type", "dev", "ino", "nlink", "mode", "size", "mtimeNs", "ctimeNs", "target"]
1739
+ : ["path", "type", "dev", "ino", "nlink", "mode", "size", "mtimeNs", "ctimeNs"];
1740
+ if (!hasExactKeys(value, expectedKeys)
1741
+ || typeof value.path !== "string"
1742
+ || (type !== "directory" && type !== "file" && type !== "symlink")
1743
+ || ![value.dev, value.ino, value.nlink, value.mode, value.size, value.mtimeNs, value.ctimeNs]
1744
+ .every((entry) => typeof entry === "string" && /^-?\d+$/u.test(entry))
1745
+ || (type === "symlink" && (typeof value.target !== "string" || value.target.includes("\0")))) {
1746
+ return undefined;
1747
+ }
1748
+ return value;
1749
+ }
1750
+ function sameRuntimeIdentityJson(value, identity) {
1751
+ return hasExactKeys(value, ["packageVersion", "cliSha256", "sourceClosureSha256", "nodeAbi", "platform", "arch"])
1752
+ && value.packageVersion === identity.packageVersion
1753
+ && value.cliSha256 === identity.cliSha256
1754
+ && value.sourceClosureSha256 === identity.sourceClosureSha256
1755
+ && value.nodeAbi === identity.nodeAbi
1756
+ && value.platform === identity.platform
1757
+ && value.arch === identity.arch;
1758
+ }
1759
+ function hasExactKeys(value, keys) {
1760
+ return isRecord(value)
1761
+ && Object.keys(value).length === keys.length
1762
+ && keys.every((key) => Object.hasOwn(value, key));
1763
+ }
1764
+ function isCanonicalAbsolutePath(path) {
1765
+ return isAbsolute(path) && resolve(path) === path && !path.includes("\0");
1766
+ }
1767
+ function isSafePortableRelativePath(path) {
1768
+ if (path.length === 0 || path === "." || path.includes("\\") || path.includes("\0") || isAbsolute(path)) {
1769
+ return false;
1770
+ }
1771
+ const segments = path.split("/");
1772
+ return segments.every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
1773
+ }
1774
+ function runtimePathFromPortableRelative(root, path) {
1775
+ if (!isSafePortableRelativePath(path)) {
1776
+ throw new Error(`Managed runtime proof path ${JSON.stringify(path)} is unsafe.`);
1777
+ }
1778
+ const target = join(root, ...path.split("/"));
1779
+ assertPathInsideRoot(root, target, `proof path ${path}`);
1780
+ return target;
1781
+ }
1782
+ async function mapWithConcurrency(values, concurrency, mapper) {
1783
+ const results = new Array(values.length);
1784
+ let nextIndex = 0;
1785
+ const workers = Array.from({ length: Math.min(Math.max(1, concurrency), values.length) }, async () => {
1786
+ for (;;) {
1787
+ const index = nextIndex;
1788
+ nextIndex += 1;
1789
+ if (index >= values.length)
1790
+ return;
1791
+ results[index] = await mapper(values[index], index);
1792
+ }
1793
+ });
1794
+ await Promise.all(workers);
1795
+ return results;
1796
+ }
1797
+ async function pathExists(path) {
1798
+ try {
1799
+ await lstat(path);
1800
+ return true;
1801
+ }
1802
+ catch (error) {
1803
+ if (isErrno(error, "ENOENT"))
1804
+ return false;
1805
+ throw error;
1806
+ }
1807
+ }
1808
+ async function acquireRuntimeLock(layout, identity, additionalPackages, deps, isSatisfied = () => verifyRuntime(layout, identity, additionalPackages)) {
1087
1809
  const incarnation = await (deps.currentProcessIncarnation ?? currentProcessIncarnation)();
1088
1810
  return acquireOwnerPrivateLock({
1089
1811
  path: layout.lockDir,
@@ -1110,7 +1832,7 @@ async function acquireRuntimeLock(layout, identity, additionalPackages, deps) {
1110
1832
  : undefined;
1111
1833
  },
1112
1834
  invalidOwner: "ownerless",
1113
- isSatisfied: () => verifyRuntime(layout, identity, additionalPackages),
1835
+ isSatisfied,
1114
1836
  sleep: deps.sleep,
1115
1837
  staleRace: "return",
1116
1838
  beforeStaleRename: async () => {
@@ -1231,7 +1953,22 @@ function sameRuntimeMarker(left, right) {
1231
1953
  && left.nodeAbi === right.nodeAbi
1232
1954
  && left.platform === right.platform
1233
1955
  && left.arch === right.arch
1234
- && left.installedAt === right.installedAt;
1956
+ && left.installedAt === right.installedAt
1957
+ && (left.schema !== "mono-agent.managed-runtime.v5"
1958
+ || (right.schema === "mono-agent.managed-runtime.v5"
1959
+ && left.reuseProofSha256 === right.reuseProofSha256));
1960
+ }
1961
+ function runtimeMarkerMatchesProvenance(marker, input) {
1962
+ return marker.packageName === PACKAGE_NAME
1963
+ && marker.closureManifestSha256 === input.closureManifestSha256
1964
+ && marker.executionProofSha256 === input.executionProofSha256
1965
+ && marker.packageVersion === input.packageVersion
1966
+ && marker.cliSha256 === input.cliSha256
1967
+ && marker.sourceClosureSha256 === input.sourceClosureSha256
1968
+ && marker.nodeAbi === input.nodeAbi
1969
+ && marker.platform === input.platform
1970
+ && marker.arch === input.arch
1971
+ && marker.installedAt === input.installedAt;
1235
1972
  }
1236
1973
  async function verifiedRuntimeMarker(layout, identity) {
1237
1974
  try {
@@ -1250,6 +1987,17 @@ async function verifiedRuntimeMarker(layout, identity) {
1250
1987
  }
1251
1988
  }
1252
1989
  async function readRuntimeMarker(path, identity) {
1990
+ const bytes = await readPrivateRuntimeMarkerBytes(path);
1991
+ if (bytes === undefined)
1992
+ return undefined;
1993
+ try {
1994
+ return runtimeMarkerFromJson(JSON.parse(bytes.toString("utf8")), identity);
1995
+ }
1996
+ catch {
1997
+ return undefined;
1998
+ }
1999
+ }
2000
+ async function readPrivateRuntimeMarkerBytes(path) {
1253
2001
  let handle;
1254
2002
  try {
1255
2003
  handle = await open(path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
@@ -1267,7 +2015,7 @@ async function readRuntimeMarker(path, identity) {
1267
2015
  || !sameSourceStats(before, named)) {
1268
2016
  return undefined;
1269
2017
  }
1270
- return runtimeMarkerFromJson(JSON.parse(bytes.toString("utf8")), identity);
2018
+ return bytes;
1271
2019
  }
1272
2020
  catch {
1273
2021
  return undefined;
@@ -1285,10 +2033,17 @@ function privateRuntimeMarkerFile(details) {
1285
2033
  && (details.mode & 63n) === 0n
1286
2034
  && owned;
1287
2035
  }
2036
+ function privateRuntimeDirectory(details) {
2037
+ const owned = typeof process.getuid !== "function" || details.uid === BigInt(process.getuid());
2038
+ return details.isDirectory()
2039
+ && !details.isSymbolicLink()
2040
+ && (details.mode & 63n) === 0n
2041
+ && owned;
2042
+ }
1288
2043
  function runtimeMarkerFromJson(value, identity) {
1289
2044
  if (!isRecord(value))
1290
2045
  return undefined;
1291
- const exactKeys = [
2046
+ const commonKeys = [
1292
2047
  "schema",
1293
2048
  "packageName",
1294
2049
  "closureManifestSha256",
@@ -1301,10 +2056,13 @@ function runtimeMarkerFromJson(value, identity) {
1301
2056
  "arch",
1302
2057
  "installedAt",
1303
2058
  ];
2059
+ const exactKeys = value.schema === "mono-agent.managed-runtime.v5"
2060
+ ? [...commonKeys, "reuseProofSha256"]
2061
+ : commonKeys;
1304
2062
  const installedAtMs = typeof value.installedAt === "string" ? Date.parse(value.installedAt) : Number.NaN;
1305
2063
  const valid = Object.keys(value).length === exactKeys.length
1306
2064
  && exactKeys.every((key) => Object.hasOwn(value, key))
1307
- && value.schema === "mono-agent.managed-runtime.v4"
2065
+ && (value.schema === "mono-agent.managed-runtime.v4" || value.schema === "mono-agent.managed-runtime.v5")
1308
2066
  && value.packageName === PACKAGE_NAME
1309
2067
  && value.packageVersion === identity.packageVersion
1310
2068
  && value.cliSha256 === identity.cliSha256
@@ -1316,6 +2074,8 @@ function runtimeMarkerFromJson(value, identity) {
1316
2074
  && /^[0-9a-f]{64}$/u.test(value.closureManifestSha256)
1317
2075
  && typeof value.executionProofSha256 === "string"
1318
2076
  && /^[0-9a-f]{64}$/u.test(value.executionProofSha256)
2077
+ && (value.schema !== "mono-agent.managed-runtime.v5"
2078
+ || (typeof value.reuseProofSha256 === "string" && /^[0-9a-f]{64}$/u.test(value.reuseProofSha256)))
1319
2079
  && typeof value.installedAt === "string"
1320
2080
  && Number.isFinite(installedAtMs)
1321
2081
  && new Date(installedAtMs).toISOString() === value.installedAt
@@ -1325,6 +2085,32 @@ function runtimeMarkerFromJson(value, identity) {
1325
2085
  && value.installedAt !== PROVISIONAL_RUNTIME_INSTALLED_AT;
1326
2086
  return valid ? value : undefined;
1327
2087
  }
2088
+ function runtimeIdentityFromMarkerJson(value) {
2089
+ if (!isRecord(value))
2090
+ return undefined;
2091
+ if (typeof value.packageVersion !== "string"
2092
+ || !isExactVersion(value.packageVersion)
2093
+ || typeof value.cliSha256 !== "string"
2094
+ || !/^[0-9a-f]{64}$/u.test(value.cliSha256)
2095
+ || typeof value.sourceClosureSha256 !== "string"
2096
+ || !/^[0-9a-f]{64}$/u.test(value.sourceClosureSha256)
2097
+ || typeof value.nodeAbi !== "string"
2098
+ || value.nodeAbi.length === 0
2099
+ || typeof value.platform !== "string"
2100
+ || value.platform.length === 0
2101
+ || typeof value.arch !== "string"
2102
+ || value.arch.length === 0) {
2103
+ return undefined;
2104
+ }
2105
+ return {
2106
+ packageVersion: value.packageVersion,
2107
+ cliSha256: value.cliSha256,
2108
+ sourceClosureSha256: value.sourceClosureSha256,
2109
+ nodeAbi: value.nodeAbi,
2110
+ platform: value.platform,
2111
+ arch: value.arch,
2112
+ };
2113
+ }
1328
2114
  async function verifyInstalledPackage(layout, identity) {
1329
2115
  try {
1330
2116
  const packageRoot = dirname(layout.packageJsonPath);
@@ -1386,6 +2172,28 @@ async function verifyClosureManifest(layout, expectedSha256, deps = {}) {
1386
2172
  return false;
1387
2173
  }
1388
2174
  }
2175
+ async function verifyClosureManifestFingerprint(layout, expectedSha256) {
2176
+ try {
2177
+ await assertRegularFile(layout.closureManifestPath, "managed runtime closure manifest");
2178
+ const stored = await fingerprintClosureFile(layout.closureManifestPath, ".mono-agent-closure.json");
2179
+ if (stored.sha256 !== expectedSha256)
2180
+ return false;
2181
+ const parsed = JSON.parse(stored.bytes.toString("utf8"));
2182
+ return parsed.schema === "mono-agent.execution-closure.v1" && Array.isArray(parsed.entries);
2183
+ }
2184
+ catch {
2185
+ return false;
2186
+ }
2187
+ }
2188
+ async function verifyManagedRuntimeCliFingerprint(layout, expectedSha256) {
2189
+ try {
2190
+ const captured = await fingerprintClosureFile(layout.cliPath, "node_modules/@mono-agent/agent-app/dist/cli.js");
2191
+ return captured.sha256 === expectedSha256;
2192
+ }
2193
+ catch {
2194
+ return false;
2195
+ }
2196
+ }
1389
2197
  async function captureRuntimeClosureManifest(layout, deps = {}) {
1390
2198
  const entries = [];
1391
2199
  const proofs = [];
@@ -1544,18 +2352,21 @@ async function writeFinalizedRuntimeMarker(path, marker, deps) {
1544
2352
  throw new Error("Could not publish a stable managed runtime launch boundary.");
1545
2353
  }
1546
2354
  async function waitForManagedRuntimeLaunchBoundary(layout, identity, deps) {
1547
- const marker = await verifiedRuntimeMarker(layout, identity);
2355
+ const marker = await readRuntimeMarker(layout.markerPath, identity);
1548
2356
  if (marker === undefined) {
1549
2357
  throw new Error("The managed runtime marker became invalid before launch.");
1550
2358
  }
1551
- const boundaryMs = Date.parse(marker.installedAt);
2359
+ await waitForLaunchBoundary(marker.installedAt, deps.now, deps.sleep);
2360
+ }
2361
+ async function waitForLaunchBoundary(installedAt, now, sleepFor) {
2362
+ const boundaryMs = Date.parse(installedAt);
1552
2363
  const safeStartMs = (Math.floor(boundaryMs / 1_000) + 1) * 1_000;
1553
- const nowMs = deps.now();
2364
+ const nowMs = now();
1554
2365
  if (safeStartMs - nowMs > 5_000) {
1555
2366
  throw new Error("The managed runtime launch boundary is implausibly far in the future.");
1556
2367
  }
1557
2368
  if (nowMs < safeStartMs)
1558
- await deps.sleep(safeStartMs - nowMs);
2369
+ await sleepFor(safeStartMs - nowMs);
1559
2370
  }
1560
2371
  function privateJsonContents(value) {
1561
2372
  return `${JSON.stringify(value, undefined, 2)}\n`;
@@ -1611,7 +2422,15 @@ function ownedPrivately(details) {
1611
2422
  const owned = typeof process.getuid !== "function" || Number(details.uid) === process.getuid();
1612
2423
  return owned && (Number(details.mode) & 0o077) === 0;
1613
2424
  }
1614
- function runtimeResult(layout, identity, nodePath) {
2425
+ async function runtimeResult(layout, identity, nodePath, verificationMode) {
2426
+ const markerBytes = await readPrivateRuntimeMarkerBytes(layout.markerPath);
2427
+ if (markerBytes === undefined) {
2428
+ throw new Error("The managed runtime marker became unsafe before launch proof publication.");
2429
+ }
2430
+ const marker = runtimeMarkerFromJson(parseJson(markerBytes, "managed runtime marker"), identity);
2431
+ if (marker === undefined) {
2432
+ throw new Error("The managed runtime marker became invalid before launch proof publication.");
2433
+ }
1615
2434
  return {
1616
2435
  cliPath: layout.cliPath,
1617
2436
  nodePath: resolve(nodePath),
@@ -1619,8 +2438,17 @@ function runtimeResult(layout, identity, nodePath) {
1619
2438
  packageVersion: identity.packageVersion,
1620
2439
  cliSha256: identity.cliSha256,
1621
2440
  nodeAbi: identity.nodeAbi,
2441
+ verificationMode,
2442
+ launchProof: encodeManagedRuntimeLaunchProof({
2443
+ schema: MANAGED_RUNTIME_LAUNCH_PROOF_SCHEMA,
2444
+ markerSha256: sha256(markerBytes),
2445
+ installedAt: marker.installedAt,
2446
+ }),
1622
2447
  };
1623
2448
  }
2449
+ async function sleep(milliseconds) {
2450
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
2451
+ }
1624
2452
  function requiredNodeAbi() {
1625
2453
  const abi = process.versions.modules;
1626
2454
  if (abi === undefined || abi.trim().length === 0) {