@nylorun/runtime 0.23.0-beta → 0.25.0-beta

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 (301) hide show
  1. package/CHANGELOG.md +252 -0
  2. package/README.md +87 -28
  3. package/dist/adapters/execution/restate.js +1 -1
  4. package/dist/adapters/replication/pgoutput.d.ts +2 -0
  5. package/dist/adapters/replication/pgoutput.js +6 -3
  6. package/dist/adapters/sandbox/local.d.ts +9 -1
  7. package/dist/adapters/sandbox/local.js +16 -4
  8. package/dist/adapters/sandbox/virtual.js +4 -1
  9. package/dist/api/a2a/card.d.ts +11 -1
  10. package/dist/api/a2a/card.js +26 -2
  11. package/dist/api/a2a/endpoint.js +9 -3
  12. package/dist/api/a2a/protocol.d.ts +25 -2
  13. package/dist/api/a2a/protocol.js +20 -3
  14. package/dist/api/a2a/routes.d.ts +6 -1
  15. package/dist/api/a2a/routes.js +67 -9
  16. package/dist/api/a2a/tasks.js +2 -1
  17. package/dist/api/ag-ui/endpoint.js +8 -3
  18. package/dist/api/ag-ui/history.d.ts +6 -1
  19. package/dist/api/ag-ui/history.js +39 -3
  20. package/dist/api/ag-ui/routes.d.ts +4 -1
  21. package/dist/api/ag-ui/routes.js +63 -20
  22. package/dist/api/ag-ui/translate.js +3 -2
  23. package/dist/api/components.d.ts +5327 -1091
  24. package/dist/api/components.js +40 -16
  25. package/dist/api/gate/keys.d.ts +2 -1
  26. package/dist/api/gate/keys.js +14 -1
  27. package/dist/api/gate/routes.d.ts +6 -0
  28. package/dist/api/gate/routes.js +52 -3
  29. package/dist/api/http/app.js +17 -6
  30. package/dist/api/http/body.d.ts +3 -3
  31. package/dist/api/http/body.js +7 -7
  32. package/dist/api/http/define.d.ts +6 -0
  33. package/dist/api/http/define.js +13 -1
  34. package/dist/api/http/respond.js +1 -1
  35. package/dist/api/http/routes/artifacts.js +35 -8
  36. package/dist/api/http/routes/coverage.d.ts +9 -0
  37. package/dist/api/http/routes/coverage.js +34 -0
  38. package/dist/api/http/routes/environment-manifests.d.ts +9 -0
  39. package/dist/api/http/routes/environment-manifests.js +118 -0
  40. package/dist/api/http/routes/environments.d.ts +11 -0
  41. package/dist/api/http/routes/environments.js +332 -0
  42. package/dist/api/http/routes/mcp.d.ts +1 -1
  43. package/dist/api/http/routes/mcp.js +2 -2
  44. package/dist/api/http/routes/me.js +1 -1
  45. package/dist/api/http/routes/reads.d.ts +94 -9
  46. package/dist/api/http/routes/reads.js +54 -5
  47. package/dist/api/http/routes/sessions.js +24 -9
  48. package/dist/api/http/routes/tenant.js +65 -15
  49. package/dist/api/inbound-files.d.ts +65 -0
  50. package/dist/api/inbound-files.js +115 -0
  51. package/dist/api/openapi.js +48 -28
  52. package/dist/artifacts/disk.d.ts +59 -0
  53. package/dist/artifacts/disk.js +569 -0
  54. package/dist/artifacts/export.d.ts +1 -1
  55. package/dist/artifacts/export.js +2 -3
  56. package/dist/artifacts/folders.d.ts +6 -3
  57. package/dist/artifacts/folders.js +17 -12
  58. package/dist/artifacts/media-types.d.ts +15 -0
  59. package/dist/artifacts/media-types.js +56 -4
  60. package/dist/artifacts/parts.d.ts +12 -3
  61. package/dist/artifacts/parts.js +15 -4
  62. package/dist/artifacts/service.d.ts +2 -1
  63. package/dist/artifacts/service.js +6 -1
  64. package/dist/artifacts/workspace.d.ts +5 -5
  65. package/dist/artifacts/workspace.js +7 -19
  66. package/dist/core/flow-host.d.ts +3 -4
  67. package/dist/core/flow-host.js +5 -2
  68. package/dist/core/provider.d.ts +3 -2
  69. package/dist/core/provider.js +5 -37
  70. package/dist/core/sandbox-routes.d.ts +2 -21
  71. package/dist/core/sandbox-routes.js +11 -44
  72. package/dist/core/turn-manifest.d.ts +3 -2
  73. package/dist/core/turn-manifest.js +29 -5
  74. package/dist/execution/types.d.ts +1 -1
  75. package/dist/gates/contract.d.ts +3 -24
  76. package/dist/gates/contract.js +1 -36
  77. package/dist/gates/egress-credentials.d.ts +9 -0
  78. package/dist/gates/egress-credentials.js +11 -4
  79. package/dist/gates/egress.d.ts +22 -1
  80. package/dist/gates/egress.js +116 -10
  81. package/dist/gates/fixture-model.d.ts +28 -0
  82. package/dist/gates/fixture-model.js +92 -0
  83. package/dist/gates/handler.js +4 -4
  84. package/dist/gates/http-tool.d.ts +9 -6
  85. package/dist/gates/http-tool.js +11 -17
  86. package/dist/gates/in-process.d.ts +5 -0
  87. package/dist/gates/in-process.js +12 -1
  88. package/dist/gates/journal.d.ts +30 -0
  89. package/dist/gates/journal.js +51 -0
  90. package/dist/gates/mcp-handler.d.ts +4 -0
  91. package/dist/gates/mcp-handler.js +7 -4
  92. package/dist/gates/meter.d.ts +10 -2
  93. package/dist/gates/meter.js +20 -5
  94. package/dist/gates/policy.d.ts +49 -0
  95. package/dist/gates/policy.js +132 -0
  96. package/dist/gates/tenant-vaults.d.ts +7 -7
  97. package/dist/gates/tenant-vaults.js +5 -5
  98. package/dist/gates/tool-calls.d.ts +10 -5
  99. package/dist/gates/tool-calls.js +28 -10
  100. package/dist/gates/tool-client.d.ts +8 -0
  101. package/dist/gates/tool-client.js +27 -11
  102. package/dist/gates/tool-contract.d.ts +11 -69
  103. package/dist/gates/tool-contract.js +1 -85
  104. package/dist/gates/tool-gate.d.ts +1 -1
  105. package/dist/harness/calls.d.ts +14 -7
  106. package/dist/harness/calls.js +30 -24
  107. package/dist/harness/executors.js +12 -9
  108. package/dist/harness/main.js +24 -5
  109. package/dist/harness/pod.d.ts +39 -0
  110. package/dist/harness/pod.js +46 -0
  111. package/dist/harness/service.d.ts +0 -1
  112. package/dist/harness/service.js +17 -9
  113. package/dist/harness/setup.d.ts +29 -0
  114. package/dist/harness/setup.js +174 -0
  115. package/dist/harness/ws-client.js +3 -2
  116. package/dist/harness/ws-port.d.ts +1 -5
  117. package/dist/harness/ws-port.js +1 -5
  118. package/dist/harness-api/in-process.js +3 -3
  119. package/dist/harness-api/record.d.ts +15 -1
  120. package/dist/harness-api/record.js +180 -50
  121. package/dist/harness-api/redact.d.ts +3 -0
  122. package/dist/harness-api/redact.js +45 -0
  123. package/dist/harness-api/server.d.ts +35 -4
  124. package/dist/harness-api/server.js +130 -17
  125. package/dist/harness-api/start.d.ts +10 -3
  126. package/dist/harness-api/start.js +40 -10
  127. package/dist/harness-api/tool-journal.d.ts +105 -0
  128. package/dist/harness-api/tool-journal.js +132 -0
  129. package/dist/harness-api/tool-status.d.ts +13 -0
  130. package/dist/harness-api/tool-status.js +26 -0
  131. package/dist/harness-api/workspace.d.ts +12 -7
  132. package/dist/harness-api/workspace.js +47 -25
  133. package/dist/harness-api/ws-server.d.ts +11 -3
  134. package/dist/harness-api/ws-server.js +94 -15
  135. package/dist/host/gates.d.ts +2 -1
  136. package/dist/host/gates.js +10 -2
  137. package/dist/host/main.js +54 -5
  138. package/dist/host/operate.js +67 -5
  139. package/dist/host/stack-config.d.ts +64 -0
  140. package/dist/host/stack-config.js +62 -2
  141. package/dist/keys/client.js +4 -1
  142. package/dist/keys/keys.d.ts +13 -6
  143. package/dist/keys/keys.js +9 -8
  144. package/dist/management-openapi.json +1264 -2171
  145. package/dist/mcp/connect.d.ts +26 -22
  146. package/dist/mcp/connect.js +30 -34
  147. package/dist/mcp/pool.d.ts +3 -6
  148. package/dist/mcp/pool.js +14 -28
  149. package/dist/mcp/preview.d.ts +3 -3
  150. package/dist/mcp/preview.js +10 -21
  151. package/dist/mcp/snapshot.d.ts +16 -24
  152. package/dist/mcp/snapshot.js +33 -45
  153. package/dist/model/capabilities.d.ts +26 -0
  154. package/dist/model/capabilities.js +44 -0
  155. package/dist/model/catalog.d.ts +34 -3
  156. package/dist/model/catalog.js +38 -2
  157. package/dist/model/models.d.ts +2 -0
  158. package/dist/model/models.js +1 -1
  159. package/dist/model/native-blocks.d.ts +35 -0
  160. package/dist/model/native-blocks.js +170 -0
  161. package/dist/model/pi-model.js +114 -94
  162. package/dist/openapi.json +12822 -3943
  163. package/dist/reads/types.d.ts +16 -3
  164. package/dist/record/append.d.ts +3 -1
  165. package/dist/record/append.js +1 -0
  166. package/dist/record/envelope.d.ts +5 -1
  167. package/dist/record/envelope.js +7 -3
  168. package/dist/record/environment.d.ts +25 -0
  169. package/dist/record/environment.js +44 -0
  170. package/dist/record/index.d.ts +1 -1
  171. package/dist/record/index.js +1 -1
  172. package/dist/sandbox/disk-fs.d.ts +95 -0
  173. package/dist/sandbox/disk-fs.js +206 -0
  174. package/dist/sandbox/join.d.ts +17 -18
  175. package/dist/sandbox/join.js +46 -15
  176. package/dist/sandbox/manager.d.ts +47 -21
  177. package/dist/sandbox/manager.js +162 -107
  178. package/dist/sandbox/placement.d.ts +14 -13
  179. package/dist/sandbox/placement.js +31 -14
  180. package/dist/sandbox/pods/client.d.ts +9 -2
  181. package/dist/sandbox/pods/lifecycle.d.ts +36 -27
  182. package/dist/sandbox/pods/lifecycle.js +29 -26
  183. package/dist/sandbox/pods/reconcile.js +18 -12
  184. package/dist/sandbox/pods/spec.d.ts +15 -13
  185. package/dist/sandbox/pods/spec.js +17 -20
  186. package/dist/sandbox/records.d.ts +2 -2
  187. package/dist/sandbox/records.js +3 -3
  188. package/dist/sandbox/resolve.d.ts +37 -27
  189. package/dist/sandbox/resolve.js +73 -41
  190. package/dist/sandbox/runtime-tools.d.ts +9 -0
  191. package/dist/sandbox/runtime-tools.js +16 -0
  192. package/dist/sandbox/session-sandbox.d.ts +4 -6
  193. package/dist/sandbox/session-sandbox.js +47 -94
  194. package/dist/sandbox/setup.d.ts +64 -0
  195. package/dist/sandbox/setup.js +160 -0
  196. package/dist/sandbox/share.d.ts +21 -26
  197. package/dist/sandbox/share.js +36 -63
  198. package/dist/sandbox/skills.d.ts +8 -6
  199. package/dist/sandbox/skills.js +24 -23
  200. package/dist/sandbox/tenant-config.d.ts +12 -14
  201. package/dist/sandbox/tenant-config.js +12 -17
  202. package/dist/sandbox/types.d.ts +6 -0
  203. package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
  204. package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
  205. package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
  206. package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
  207. package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
  208. package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
  209. package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
  210. package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
  211. package/dist/store/postgres/drizzle/meta/_journal.json +56 -0
  212. package/dist/store/postgres/reads.js +123 -17
  213. package/dist/store/postgres/record-writer.d.ts +4 -4
  214. package/dist/store/postgres/record-writer.js +9 -9
  215. package/dist/store/postgres/record.d.ts +7 -0
  216. package/dist/store/postgres/record.js +23 -2
  217. package/dist/store/postgres/schema.d.ts +1126 -736
  218. package/dist/store/postgres/schema.js +136 -73
  219. package/dist/store/postgres/store.js +195 -67
  220. package/dist/store/types.d.ts +165 -50
  221. package/dist/tenant/advance.d.ts +7 -6
  222. package/dist/tenant/advance.js +118 -42
  223. package/dist/tenant/artifact-tool.d.ts +1 -1
  224. package/dist/tenant/artifact-tool.js +46 -26
  225. package/dist/tenant/commands.d.ts +15 -2
  226. package/dist/tenant/commands.js +115 -14
  227. package/dist/tenant/context.d.ts +56 -24
  228. package/dist/tenant/context.js +4 -15
  229. package/dist/tenant/effects.d.ts +1 -1
  230. package/dist/tenant/effects.js +44 -29
  231. package/dist/tenant/environment-manifests.d.ts +57 -0
  232. package/dist/tenant/environment-manifests.js +200 -0
  233. package/dist/tenant/environments.d.ts +174 -0
  234. package/dist/tenant/environments.js +1044 -0
  235. package/dist/tenant/harness-tokens.d.ts +21 -0
  236. package/dist/tenant/harness-tokens.js +61 -0
  237. package/dist/tenant/host-token.d.ts +1 -1
  238. package/dist/tenant/host-token.js +2 -4
  239. package/dist/tenant/identity-file.d.ts +4 -4
  240. package/dist/tenant/identity-file.js +17 -8
  241. package/dist/tenant/issuers.js +3 -3
  242. package/dist/tenant/model-setting.d.ts +14 -0
  243. package/dist/tenant/model-setting.js +51 -0
  244. package/dist/tenant/principals.js +1 -1
  245. package/dist/tenant/reset.js +3 -3
  246. package/dist/tenant/runtime.d.ts +6 -1
  247. package/dist/tenant/runtime.js +7 -1
  248. package/dist/tenant/session.d.ts +3 -3
  249. package/dist/tenant/session.js +0 -14
  250. package/dist/tenant/sessions.d.ts +18 -14
  251. package/dist/tenant/sessions.js +99 -143
  252. package/dist/tenant/signing-keys.d.ts +5 -1
  253. package/dist/tenant/skill-tool.d.ts +3 -3
  254. package/dist/tenant/skill-tool.js +6 -11
  255. package/dist/tenant/status.js +3 -3
  256. package/dist/tenant/sweep.js +13 -7
  257. package/dist/tenant/tool-results.js +1 -1
  258. package/dist/tenant/tool-search.d.ts +7 -11
  259. package/dist/tenant/tool-search.js +8 -5
  260. package/dist/tenant/transcript.d.ts +245 -36
  261. package/dist/tenant/transcript.js +64 -12
  262. package/dist/tenant/turn-timing.d.ts +43 -0
  263. package/dist/tenant/turn-timing.js +39 -0
  264. package/dist/tenant/types.d.ts +2 -0
  265. package/dist/traces/ids.d.ts +41 -0
  266. package/dist/traces/ids.js +81 -0
  267. package/dist/traces/key.d.ts +6 -0
  268. package/dist/traces/key.js +37 -0
  269. package/dist/traces/map.d.ts +113 -0
  270. package/dist/traces/map.js +289 -0
  271. package/dist/traces/options.d.ts +7 -0
  272. package/dist/traces/options.js +1 -0
  273. package/dist/traces/otlp.d.ts +42 -0
  274. package/dist/traces/otlp.js +84 -0
  275. package/dist/traces/projector.d.ts +58 -0
  276. package/dist/traces/projector.js +200 -0
  277. package/dist/traces/read.d.ts +23 -0
  278. package/dist/traces/read.js +16 -0
  279. package/dist/vault/coverage.d.ts +26 -0
  280. package/dist/vault/coverage.js +62 -0
  281. package/dist/vault/error.d.ts +11 -1
  282. package/dist/vault/error.js +5 -1
  283. package/dist/vault/host-model.d.ts +4 -1
  284. package/dist/vault/host-model.js +10 -2
  285. package/dist/vault/service.d.ts +92 -48
  286. package/dist/vault/service.js +462 -376
  287. package/dist/vault/sources.d.ts +5 -16
  288. package/dist/vault/sources.js +6 -8
  289. package/dist/version.d.ts +1 -1
  290. package/dist/version.js +2 -2
  291. package/package.json +13 -13
  292. package/dist/api/http/routes/sandboxes.d.ts +0 -9
  293. package/dist/api/http/routes/sandboxes.js +0 -153
  294. package/dist/api/http/routes/vaults.d.ts +0 -10
  295. package/dist/api/http/routes/vaults.js +0 -139
  296. package/dist/record/sandbox.d.ts +0 -25
  297. package/dist/record/sandbox.js +0 -43
  298. package/dist/sandbox/capability.d.ts +0 -3
  299. package/dist/sandbox/capability.js +0 -10
  300. package/dist/tenant/sandboxes.d.ts +0 -123
  301. package/dist/tenant/sandboxes.js +0 -566
@@ -32,7 +32,9 @@
32
32
  * which check failed.
33
33
  */
34
34
  import { createHash, timingSafeEqual } from "node:crypto";
35
- import { isSandboxId } from "@nylorun/core/contracts";
35
+ import { isEnvironmentId } from "@nylorun/core/contracts";
36
+ import { recoverLostVolume, runPendingSeed } from "../artifacts/disk.js";
37
+ import { recordSetup, setupFile, setupPlanOf, setupState, } from "./setup.js";
36
38
  import { mintHostTokens, staleHost, verifyHostToken, } from "../tenant/host-token.js";
37
39
  /** A refused join, renewal or host connection. */
38
40
  export class HostAuthError extends Error {
@@ -84,7 +86,7 @@ export function hostAuthority(ctx) {
84
86
  return {
85
87
  async join(request) {
86
88
  const { sandboxId, podUid, joinToken, volumeId } = request;
87
- if (!isSandboxId(sandboxId) ||
89
+ if (!isEnvironmentId(sandboxId) ||
88
90
  typeof podUid !== "string" ||
89
91
  !POD_UID.test(podUid) ||
90
92
  typeof joinToken !== "string" ||
@@ -107,11 +109,11 @@ export function hostAuthority(ctx) {
107
109
  // A pod being stopped joins nothing: its sandbox runs again only when asked to.
108
110
  if (pod.desired !== "running")
109
111
  return refuse("the sandbox is stopped");
110
- if (pod.observed === "lost" || pod.observed === "expired")
111
- return refuse(`the sandbox is ${pod.observed}`);
112
+ if (pod.observed === "lost")
113
+ return refuse("the sandbox is lost");
112
114
  return pod;
113
115
  };
114
- const readRow = () => ctx.store.tx((t) => t.sandboxResource(sandboxId));
116
+ const readRow = () => ctx.store.tx((t) => t.environment(sandboxId));
115
117
  const before = usable(await readRow());
116
118
  let current;
117
119
  try {
@@ -123,7 +125,7 @@ export function hostAuthority(ctx) {
123
125
  if (current !== podUid)
124
126
  refuse("the pod is not the sandbox's current pod");
125
127
  const joined = await ctx.store.tx(async (t) => {
126
- const row = await t.sandboxResource(sandboxId, { lock: true });
128
+ const row = await t.environment(sandboxId, { lock: true });
127
129
  const pod = usable(row);
128
130
  if (pod.k8sName !== before.k8sName)
129
131
  refuse("the sandbox was reset during the join");
@@ -132,14 +134,14 @@ export function hostAuthority(ctx) {
132
134
  if (pod.volumeId !== undefined && volumeId !== pod.volumeId) {
133
135
  // A new, empty volume under the same Sandbox: the sandbox's files are gone.
134
136
  const reason = "The sandbox's volume was replaced: its files are gone";
135
- await t.updateSandboxPod(sandboxId, { observed: "lost", reason, hostEpoch: epoch }, now);
136
- await t.sandboxEvent(sandboxId, "sandbox.lost", { reason });
137
+ await t.updateEnvironmentPod(sandboxId, { observed: "lost", reason, hostEpoch: epoch }, now);
138
+ await t.environmentEvent(sandboxId, "environment.lost", { reason });
137
139
  // Its Sandbox is deleted; only a reset brings the sandbox back.
138
140
  await t.signal({ type: "host.revoked", sandboxId, epoch });
139
141
  await t.signalSandbox(sandboxId, { kind: "reconcile" });
140
142
  return { lost: epoch };
141
143
  }
142
- await t.updateSandboxPod(sandboxId, {
144
+ await t.updateEnvironmentPod(sandboxId, {
143
145
  hostEpoch: epoch,
144
146
  podUid,
145
147
  ...(pod.volumeId === undefined && volumeId !== undefined ? { volumeId } : {}),
@@ -147,23 +149,52 @@ export function hostAuthority(ctx) {
147
149
  }, now);
148
150
  if (pod.podUid !== podUid) {
149
151
  if (pod.podUid !== undefined)
150
- await t.sandboxEvent(sandboxId, "sandbox.relaunched", { hostEpoch: epoch });
152
+ await t.environmentEvent(sandboxId, "environment.relaunched", { hostEpoch: epoch });
151
153
  else
152
- await t.sandboxEvent(sandboxId, "sandbox.running", { hostEpoch: epoch });
154
+ await t.environmentEvent(sandboxId, "environment.running", { hostEpoch: epoch });
153
155
  }
154
156
  // The previous host's connection (an older epoch) serves nothing more, on any process.
155
157
  await t.signal({ type: "host.revoked", sandboxId, epoch });
156
- return epoch;
158
+ return {
159
+ epoch,
160
+ setup: row ? await setupPlanOf(ctx, t, row) : undefined,
161
+ seeded: row?.diskSeed !== undefined,
162
+ afterSeed: row?.diskSeed?.setup === true,
163
+ };
157
164
  });
158
- if (typeof joined === "object")
165
+ if ("lost" in joined) {
166
+ // With a disk version, a new volume seeded from the latest one (R2d step 3).
167
+ void recoverLostVolume(ctx, sandboxId).catch(() => undefined);
159
168
  return refuse("the volume was replaced: the sandbox is lost");
160
- ctx.config.logger.info("sandbox host joined", { sandboxId, epoch: joined });
161
- return answerOf(await mintHostTokens(ctx, { sandboxId, epoch: joined, podUid }), await ctx.keys.egressCa());
169
+ }
170
+ ctx.config.logger.info("sandbox host joined", { sandboxId, epoch: joined.epoch });
171
+ const answer = answerOf(await mintHostTokens(ctx, { sandboxId, epoch: joined.epoch, podUid }), await ctx.keys.egressCa());
172
+ if (joined.seeded) {
173
+ // The engine connects next; the seed waits for it, then writes the version.
174
+ void runPendingSeed(ctx, sandboxId);
175
+ // A fork onto other setup (Q17): the engine runs it once the version is written.
176
+ if (joined.afterSeed)
177
+ return { ...answer, seeded: true, afterSeed: true, ...(joined.setup ? { setup: joined.setup } : {}) };
178
+ return { ...answer, seeded: true };
179
+ }
180
+ return joined.setup ? { ...answer, setup: joined.setup } : answer;
162
181
  },
163
182
  async renew(hostToken) {
164
183
  const claims = await verified(hostToken);
165
184
  return answerOf(await mintHostTokens(ctx, claims), await ctx.keys.egressCa());
166
185
  },
167
186
  verify: verified,
187
+ async setup(hostToken) {
188
+ const claims = await verified(hostToken);
189
+ return setupState(ctx, claims.sandboxId);
190
+ },
191
+ async reportSetup(hostToken, report) {
192
+ const claims = await verified(hostToken);
193
+ await recordSetup(ctx, claims.sandboxId, claims.epoch, report);
194
+ },
195
+ async setupFile(hostToken, index, path) {
196
+ const claims = await verified(hostToken);
197
+ return setupFile(ctx, claims.sandboxId, index, path);
198
+ },
168
199
  };
169
200
  }
@@ -2,8 +2,11 @@
2
2
  * Sandbox Manager: owns sandbox lifecycle for the Runtime. One workspace per sandbox resource
3
3
  * (`sandbox: { id }`, keyed by the sandbox id), or per owning session for a sandbox chosen
4
4
  * inline or by the Tenant default (keyed by the session id); created on the first sandbox tool
5
- * call, stopped after its idle timeout, reattached on the next call. Commands against one
6
- * workspace run one at a time, whichever session sends them.
5
+ * call, stopped after its idle timeout, reattached on the next call. Each session's calls on a
6
+ * workspace run in the order it sends them, and different sessions' calls run at the same time
7
+ * (D66): the sessions of one Environment run their turns at once. Opening, stopping and removing
8
+ * a workspace run alone: a stop or removal waits for the calls running, and calls that come after
9
+ * it wait for it.
7
10
  *
8
11
  * The manager keeps no timers and reaches no store: it keeps its compute records through a
9
12
  * `SandboxRecords` port (the Tenant's `sandboxes` table in core's process, a file in a harness's)
@@ -12,17 +15,18 @@
12
15
  * (after a restart); `reconcile` removes workspaces whose owner is gone. `sweep` does both, the
13
16
  * reconcile once per process, as the Tenant sweep does in core's process.
14
17
  *
15
- * A session's skills (track R2 M4) are mounted on its workspace, read-only under
16
- * `/skills/<name>/`, before the first call that opens it (`skills.ts`); their bytes come
17
- * through the `definitionFile` port.
18
+ * A session's skills (track R2 M4) are mounted on its workspace, read-only, one folder per
19
+ * version (`/skills/<name>@<hash>/`, D66), before the first call that needs them (`skills.ts`);
20
+ * their bytes come through the `definitionFile` port.
18
21
  */
19
22
  import type { EventPayload } from "@nylorun/core/contracts";
20
- import { type AgentManifest, type CapabilityManifest, type SandboxToolName } from "@nylorun/core/define";
23
+ import { type AgentManifest, type SandboxManifest, type SandboxToolName } from "@nylorun/core/define";
21
24
  import { type SandboxRecord, type SandboxRecords } from "./records.js";
22
25
  import { type SandboxSelection, type SandboxSelectionReport } from "./select.js";
26
+ import { type DiskAnswer, type DiskOp } from "./disk-fs.js";
23
27
  import { type SandboxToolOutcome } from "./tools.js";
24
28
  import { type SandboxBackend, type SandboxListing } from "./types.js";
25
- export { sandboxCapabilityOf } from "./capability.js";
29
+ export { sandboxToolSpec } from "./runtime-tools.js";
26
30
  export type { SandboxRecord, SandboxRecords, SandboxState } from "./records.js";
27
31
  export interface SandboxSessionRef {
28
32
  /** The session whose log records the workspace's events: the owning session. */
@@ -33,7 +37,12 @@ export interface SandboxSessionRef {
33
37
  * The sandbox resource the owning session is attached to. Its workspace is keyed by this id,
34
38
  * so every session attached to it shares the files; absent, the workspace is the session's.
35
39
  */
36
- readonly sandboxId?: string;
40
+ readonly environmentId?: string;
41
+ /**
42
+ * For a pod Environment: the host epoch it is at, so the call reaches a host that joined at
43
+ * that epoch or later, never one a restore or a lost volume retired.
44
+ */
45
+ readonly hostEpoch?: number;
37
46
  /** Variables every command of the call gets (R2c): secret names set to the sentinel, plain values. */
38
47
  readonly environment?: Readonly<Record<string, string>>;
39
48
  /**
@@ -55,7 +64,7 @@ export interface SandboxSweepOptions {
55
64
  /** Whether a session still exists; sandboxes of deleted sessions are removed. */
56
65
  readonly sessionExists: (sessionId: string) => boolean | Promise<boolean>;
57
66
  /** Whether a sandbox resource still exists. Default: every one does. */
58
- readonly sandboxExists?: (sandboxId: string) => boolean | Promise<boolean>;
67
+ readonly sandboxExists?: (environmentId: string) => boolean | Promise<boolean>;
59
68
  }
60
69
  export interface SandboxManagerOptions {
61
70
  /** Distinguishes this Runtime's sandboxes from other Runtimes on the same machine: the Tenant id. */
@@ -77,7 +86,7 @@ export interface SandboxManagerOptions {
77
86
  readonly emit: <T extends SandboxEventType>(sessionId: string, turnId: string | null, type: T, payload: EventPayload<T>, meta: SandboxEventMeta) => void | Promise<void>;
78
87
  }
79
88
  /** The session events a sandbox writes. */
80
- export type SandboxEventType = "sandbox.state" | "sandbox.exec";
89
+ export type SandboxEventType = "environment.state" | "environment.exec";
81
90
  export declare class SandboxManager {
82
91
  private readonly options;
83
92
  private selection?;
@@ -104,19 +113,28 @@ export declare class SandboxManager {
104
113
  /** Whether any sandbox was ever recorded, so startup can skip probing for agents without one. */
105
114
  hasRecords(): Promise<boolean>;
106
115
  keyOf(sessionId: string): string;
107
- /** The workspace key of sandbox resource `sandboxId` (`sandboxWorkspaceKey`). */
108
- sandboxKeyOf(sandboxId: string): string;
116
+ /** The workspace key of sandbox resource `environmentId` (`sandboxWorkspaceKey`). */
117
+ sandboxKeyOf(environmentId: string): string;
109
118
  private keyFor;
110
119
  report(): Promise<SandboxSelectionReport & {
111
120
  readonly defaultImage: string;
112
121
  }>;
113
- run(session: SandboxSessionRef, capability: CapabilityManifest, toolName: SandboxToolName, input: unknown, signal: AbortSignal): Promise<SandboxToolOutcome>;
122
+ run(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, toolName: SandboxToolName, input: unknown, signal: AbortSignal): Promise<SandboxToolOutcome>;
123
+ /**
124
+ * Runs `call` in session `sessionId`'s queue on `live`: after its earlier calls, and after any
125
+ * stop or removal pending, beside other sessions' calls (D66).
126
+ */
127
+ private inLane;
128
+ /** Runs `step` on `live` alone: after the calls running, before the calls that come after it. */
129
+ private alone;
130
+ /** The workspace's handle, opened once for the calls that need it at the same time. */
131
+ private handleOf;
114
132
  /**
115
133
  * The bytes of one file in the session's sandbox, for `save_artifact` (F8.1), in the same queue
116
134
  * as its tool calls: `missing` when there is no such file, a failed outcome when the sandbox
117
135
  * cannot open or the file is larger than `maxBytes`. Relative paths resolve in the workspace.
118
136
  */
119
- readBytes(session: SandboxSessionRef, capability: CapabilityManifest, path: string, maxBytes: number, signal: AbortSignal): Promise<{
137
+ readBytes(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, path: string, maxBytes: number, signal: AbortSignal): Promise<{
120
138
  kind: "read";
121
139
  path: string;
122
140
  bytes: Uint8Array;
@@ -131,7 +149,7 @@ export declare class SandboxManager {
131
149
  * the same queue as its tool calls. `missing` when the sandbox was never created (nothing is
132
150
  * started to look) or `dir` is not a directory. Relative paths resolve in the workspace.
133
151
  */
134
- listFiles(session: SandboxSessionRef, capability: CapabilityManifest, dir: string, maxEntries: number, signal: AbortSignal): Promise<{
152
+ listFiles(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, dir: string, maxEntries: number, signal: AbortSignal): Promise<{
135
153
  kind: "listed";
136
154
  path: string;
137
155
  listing: SandboxListing;
@@ -141,6 +159,13 @@ export declare class SandboxManager {
141
159
  } | Extract<SandboxToolOutcome, {
142
160
  kind: "failed";
143
161
  }>>;
162
+ /**
163
+ * One operation on the disk of the session's sandbox (R2d step 3, `sandbox/disk-fs.ts`), in the
164
+ * same queue as its tool calls, starting it first when it is stopped.
165
+ */
166
+ disk(session: SandboxSessionRef, sandbox: SandboxManifest | undefined, op: DiskOp, signal: AbortSignal): Promise<DiskAnswer | Extract<SandboxToolOutcome, {
167
+ kind: "failed";
168
+ }>>;
144
169
  /** Runs `use` on the session's sandbox in its queue, starting it first when it is stopped. */
145
170
  private withHandle;
146
171
  /** The session's live sandbox entry and spec, or why it cannot run here. */
@@ -148,9 +173,10 @@ export declare class SandboxManager {
148
173
  private execute;
149
174
  private executeOpen;
150
175
  /**
151
- * Mounts the session's skills the workspace does not hold as they are: on a handle just opened
152
- * all of them, later only those another session brought or changed. A failed outcome when
153
- * one cannot be mounted; nothing is marked mounted then, so the next call tries again.
176
+ * Mounts the skill folders the session needs that the workspace does not hold (D66): on a
177
+ * handle just opened all of them, later only versions another session has not mounted. Calls
178
+ * that need one folder at once share its mount. A failed outcome when one cannot be mounted;
179
+ * the folder is not marked mounted then, so the next call tries again.
154
180
  */
155
181
  private mountSkills;
156
182
  private open;
@@ -159,16 +185,16 @@ export declare class SandboxManager {
159
185
  /** The sandbox record for a session, if one was ever created. */
160
186
  status(sessionId: string): Promise<SandboxRecord | undefined>;
161
187
  /**
162
- * Deletes sandbox resource `sandboxId`'s workspace, its files and its compute record, after
188
+ * Deletes sandbox resource `environmentId`'s workspace, its files and its compute record, after
163
189
  * any command queued on it. Called once the resource is deleted.
164
190
  */
165
- removeSandbox(sandboxId: string): Promise<void>;
191
+ removeSandbox(environmentId: string): Promise<void>;
166
192
  /** Deletes the workspace `key`, its files and its record, after any command queued on it. */
167
193
  remove(key: string): Promise<void>;
168
194
  /**
169
195
  * Delete workspaces this Runtime owns whose owner is gone: a session's when `sessionExists`
170
196
  * says the session is gone, a sandbox resource's when `sandboxExists` says the resource is.
171
197
  */
172
- reconcile(sessionExists: (sessionId: string) => boolean | Promise<boolean>, sandboxExists: (sandboxId: string) => boolean | Promise<boolean>): Promise<void>;
198
+ reconcile(sessionExists: (sessionId: string) => boolean | Promise<boolean>, sandboxExists: (environmentId: string) => boolean | Promise<boolean>): Promise<void>;
173
199
  close(): Promise<void>;
174
200
  }