@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,7 @@
32
32
  * head).
33
33
  * 2. A transaction that touches several sessions locks them in ascending id
34
34
  * order, with `lockSessions` (`./locking.ts`), before writing any of them.
35
- * 3. A sandbox resource's row (`sandboxResource(id, { lock: true })`, which orders its
35
+ * 3. An Environment's row (`environment(id, { lock: true })`, which orders its
36
36
  * lifecycle stream) is locked after every session row the transaction locks, never
37
37
  * before one.
38
38
  *
@@ -50,15 +50,15 @@
50
50
  */
51
51
  import { AsyncLocalStorage } from "node:async_hooks";
52
52
  import { randomUUID } from "node:crypto";
53
- import { and, count, eq, getTableColumns, gte, gt, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
54
- import { appendEvent, appendSandboxEvent } from "../../record/index.js";
53
+ import { and, count, desc, eq, getTableColumns, gte, gt, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
54
+ import { appendEnvironmentEvent, appendEvent } from "../../record/index.js";
55
55
  import { OwnershipLostError, PrincipalRoleConflict } from "../ownership.js";
56
56
  import { followControlSignals, pruneSignals, writeSignal } from "./control.js";
57
57
  import { database, driverError } from "./db.js";
58
58
  import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
59
59
  import { createPostgresRecordReader } from "./record.js";
60
- import { postgresRecordWriter, postgresSandboxRecordWriter } from "./record-writer.js";
61
- import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, sandboxEvents, sandboxResources, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, sandboxSignals, wakes, } from "./schema.js";
60
+ import { postgresEnvironmentRecordWriter, postgresRecordWriter } from "./record-writer.js";
61
+ import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, environmentEvents, environments, environmentManifests, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, sandboxSignals, wakes, } from "./schema.js";
62
62
  export function createPostgresSessionStore(options) {
63
63
  return new PostgresSessionStore(options);
64
64
  }
@@ -240,14 +240,25 @@ function ownership(row) {
240
240
  ownerExpiresAt: row.ownerExpiresAt?.toISOString() ?? null,
241
241
  };
242
242
  }
243
- function sandboxResourceOf(row) {
243
+ function environmentOf(row) {
244
244
  return {
245
245
  id: row.id,
246
246
  kind: row.kind,
247
- spec: row.spec,
248
247
  labels: row.labels,
248
+ recipe: row.recipe,
249
+ applied: row.applied,
250
+ version: row.version,
251
+ appliedVersion: row.appliedVersion,
252
+ ...(row.ownerUserId !== null ? { ownerUserId: row.ownerUserId } : {}),
253
+ lastUsedAt: new Date(row.lastUsedAt).toISOString(),
249
254
  createdAt: row.createdAt,
250
255
  updatedAt: row.updatedAt,
256
+ ...(row.diskOp ? { diskOp: row.diskOp } : {}),
257
+ ...(row.diskSeed ? { diskSeed: row.diskSeed } : {}),
258
+ ...(row.manifestName !== null ? { manifestName: row.manifestName } : {}),
259
+ ...(row.manifestVersion !== null ? { manifestVersion: row.manifestVersion } : {}),
260
+ ...(row.manifestHash !== null ? { manifestHash: row.manifestHash } : {}),
261
+ ...(row.forkedFrom ? { forkedFrom: row.forkedFrom } : {}),
251
262
  ...(row.k8sName !== null && row.desired !== null && row.observed !== null
252
263
  ? {
253
264
  pod: {
@@ -260,16 +271,26 @@ function sandboxResourceOf(row) {
260
271
  ...(row.joinTokenHash !== null ? { joinTokenHash: row.joinTokenHash } : {}),
261
272
  rev: row.rev,
262
273
  ...(row.lastActiveAt ? { lastActiveAt: row.lastActiveAt.toISOString() } : {}),
263
- ...(row.expiresAt ? { expiresAt: row.expiresAt.toISOString() } : {}),
264
274
  ...(row.startedAt ? { startedAt: row.startedAt.toISOString() } : {}),
265
275
  ...(row.reason !== null ? { reason: row.reason } : {}),
266
276
  ...(row.retiring !== null ? { retiring: row.retiring } : {}),
267
277
  ...(row.volumeId !== null ? { volumeId: row.volumeId } : {}),
278
+ ...(row.imageDigest !== null ? { imageDigest: row.imageDigest } : {}),
268
279
  },
269
280
  }
270
281
  : {}),
271
282
  };
272
283
  }
284
+ function environmentManifestOf(row) {
285
+ return {
286
+ name: row.name,
287
+ version: row.version,
288
+ body: row.body,
289
+ hash: row.hash,
290
+ savedBy: row.savedBy,
291
+ createdAt: row.createdAt,
292
+ };
293
+ }
273
294
  /** A pod patch as column values: ISO times become dates, `null` clears. */
274
295
  function podColumns(patch) {
275
296
  const date = (value) => value === undefined ? undefined : value === null ? null : new Date(value);
@@ -283,11 +304,11 @@ function podColumns(patch) {
283
304
  joinTokenHash: patch.joinTokenHash,
284
305
  rev: patch.rev,
285
306
  lastActiveAt: date(patch.lastActiveAt),
286
- expiresAt: date(patch.expiresAt),
287
307
  startedAt: date(patch.startedAt),
288
308
  reason: patch.reason,
289
309
  retiring: patch.retiring,
290
310
  volumeId: patch.volumeId,
311
+ imageDigest: patch.imageDigest,
291
312
  };
292
313
  return Object.fromEntries(Object.entries(columns).filter(([, value]) => value !== undefined));
293
314
  }
@@ -389,7 +410,7 @@ class PostgresTx {
389
410
  const [row] = await this.sessions().where(eq(sessions.id, id)).for("update");
390
411
  return row && storedSession(row);
391
412
  }
392
- async event(sessionId, turnId, type, payload) {
413
+ async event(sessionId, turnId, type, payload, writer) {
393
414
  this.check();
394
415
  const db = this.db;
395
416
  // The session row lock orders the session's events; the log head allocates under it.
@@ -408,6 +429,7 @@ class PostgresTx {
408
429
  time: this.now(),
409
430
  type,
410
431
  payload,
432
+ ...(writer ? { writer } : {}),
411
433
  });
412
434
  this.events.push(event);
413
435
  this.generations.push(generation);
@@ -612,88 +634,151 @@ class PostgresTx {
612
634
  this.check();
613
635
  return this.bodies(sandboxes);
614
636
  }
615
- // --- sandbox resources ---------------------------------------------------
616
- async sandboxResource(id, options = {}) {
637
+ // --- Environments ----------------------------------------------------------
638
+ async environment(id, options = {}) {
617
639
  this.check();
618
- const query = this.db.select().from(sandboxResources).where(eq(sandboxResources.id, id));
640
+ const query = this.db.select().from(environments).where(eq(environments.id, id));
619
641
  const [row] = options.lock ? await query.for("update") : await query;
620
- return row && sandboxResourceOf(row);
642
+ return row && environmentOf(row);
621
643
  }
622
- async createSandboxResource(row, limit) {
644
+ async createEnvironment(row, limit) {
623
645
  this.check();
624
646
  // Every create takes this lock, so two never both see room for one more.
625
- await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.sandbox_resources'))`);
647
+ await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.environments'))`);
626
648
  const [found] = await this.db
627
- .select({ id: sandboxResources.id })
628
- .from(sandboxResources)
629
- .where(eq(sandboxResources.id, row.id));
649
+ .select({ id: environments.id })
650
+ .from(environments)
651
+ .where(eq(environments.id, row.id));
630
652
  if (found)
631
653
  return "exists";
632
- const [counted] = await this.db.select({ n: count() }).from(sandboxResources);
654
+ const [counted] = await this.db.select({ n: count() }).from(environments);
633
655
  if ((counted?.n ?? 0) >= limit)
634
656
  return "limit";
635
- const { pod, ...resource } = row;
636
- await this.db.insert(sandboxResources).values({ ...resource, ...(pod ? podColumns(pod) : {}) });
657
+ const { pod, ownerUserId, diskOp, diskSeed, manifestName, manifestVersion, manifestHash, forkedFrom, ...environment } = row;
658
+ await this.db.insert(environments).values({
659
+ ...environment,
660
+ ownerUserId: ownerUserId ?? null,
661
+ diskOp: diskOp ?? null,
662
+ diskSeed: diskSeed ?? null,
663
+ manifestName: manifestName ?? null,
664
+ manifestVersion: manifestVersion ?? null,
665
+ manifestHash: manifestHash ?? null,
666
+ forkedFrom: forkedFrom ?? null,
667
+ ...(pod ? podColumns(pod) : {}),
668
+ });
637
669
  return "created";
638
670
  }
639
- async updateSandboxSpec(id, spec, updatedAt) {
640
- this.check();
641
- await this.db.update(sandboxResources).set({ spec, updatedAt }).where(eq(sandboxResources.id, id));
642
- }
643
- async updateSandboxPod(id, patch, updatedAt) {
671
+ async updateEnvironment(id, patch, updatedAt) {
644
672
  this.check();
673
+ const columns = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined));
645
674
  await this.db
646
- .update(sandboxResources)
647
- .set({ ...podColumns(patch), updatedAt })
648
- .where(eq(sandboxResources.id, id));
675
+ .update(environments)
676
+ .set({ ...columns, updatedAt })
677
+ .where(eq(environments.id, id));
649
678
  }
650
- async updateSandboxLabels(id, labels, updatedAt) {
679
+ async updateEnvironmentPod(id, patch, updatedAt) {
651
680
  this.check();
652
681
  await this.db
653
- .update(sandboxResources)
654
- .set({ labels, updatedAt })
655
- .where(eq(sandboxResources.id, id));
682
+ .update(environments)
683
+ .set({ ...podColumns(patch), updatedAt })
684
+ .where(eq(environments.id, id));
656
685
  }
657
- async deleteSandboxResource(id) {
686
+ async deleteEnvironment(id) {
658
687
  this.check();
659
- await this.db.delete(sandboxResources).where(eq(sandboxResources.id, id));
688
+ // Its vault and credentials go with it (ON DELETE CASCADE).
689
+ await this.db.delete(environments).where(eq(environments.id, id));
660
690
  }
661
- async listSandboxResources(filter = {}) {
691
+ async listEnvironments(filter = {}) {
662
692
  this.check();
663
693
  const labels = filter.labels;
664
694
  const rows = await this.db
665
695
  .select()
666
- .from(sandboxResources)
696
+ .from(environments)
667
697
  .where(labels === undefined || Object.keys(labels).length === 0
668
698
  ? undefined
669
- : sql `nylorun.doc(${sandboxResources.labels}) @> ${toJson(labels)}::jsonb`)
670
- .orderBy(sandboxResources.id);
671
- return rows.map(sandboxResourceOf);
699
+ : sql `nylorun.doc(${environments.labels}) @> ${toJson(labels)}::jsonb`)
700
+ .orderBy(environments.id);
701
+ return rows.map(environmentOf);
702
+ }
703
+ // --- Environment manifests (D63) -----------------------------------------------
704
+ async lockEnvironmentManifest(name) {
705
+ this.check();
706
+ await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext(${`nylorun.environment_manifests:${name}`}))`);
707
+ }
708
+ async environmentManifest(name, version) {
709
+ this.check();
710
+ const [row] = await this.db
711
+ .select()
712
+ .from(environmentManifests)
713
+ .where(version === undefined
714
+ ? eq(environmentManifests.name, name)
715
+ : and(eq(environmentManifests.name, name), eq(environmentManifests.version, version)))
716
+ .orderBy(desc(environmentManifests.version))
717
+ .limit(1);
718
+ return row && environmentManifestOf(row);
719
+ }
720
+ async insertEnvironmentManifest(row) {
721
+ this.check();
722
+ await this.db.insert(environmentManifests).values(row);
672
723
  }
673
- async sessionsOnSandbox(sandboxId) {
724
+ async listEnvironmentManifests() {
725
+ this.check();
726
+ const rows = await this.db
727
+ .selectDistinctOn([environmentManifests.name])
728
+ .from(environmentManifests)
729
+ .orderBy(environmentManifests.name, desc(environmentManifests.version));
730
+ return rows.map(environmentManifestOf);
731
+ }
732
+ async environmentManifestVersions(name) {
733
+ this.check();
734
+ const rows = await this.db
735
+ .select()
736
+ .from(environmentManifests)
737
+ .where(eq(environmentManifests.name, name))
738
+ .orderBy(desc(environmentManifests.version));
739
+ return rows.map(environmentManifestOf);
740
+ }
741
+ async deleteEnvironmentManifest(name) {
742
+ this.check();
743
+ const deleted = await this.db
744
+ .delete(environmentManifests)
745
+ .where(eq(environmentManifests.name, name))
746
+ .returning({ version: environmentManifests.version });
747
+ return deleted.length;
748
+ }
749
+ async environmentsOfManifest(name) {
750
+ this.check();
751
+ const rows = await this.db
752
+ .select({ version: environments.manifestVersion, n: count() })
753
+ .from(environments)
754
+ .where(eq(environments.manifestName, name))
755
+ .groupBy(environments.manifestVersion);
756
+ return new Map(rows.filter((row) => row.version !== null).map((row) => [row.version, row.n]));
757
+ }
758
+ async sessionsOnEnvironment(environmentId) {
674
759
  this.check();
675
760
  const rows = await this.sessions()
676
- .where(eq(sessions.sandboxId, sandboxId))
761
+ .where(eq(sessions.environmentId, environmentId))
677
762
  .orderBy(sessions.id);
678
763
  return rows.map((row) => storedSession(row));
679
764
  }
680
- async sandboxEvent(sandboxId, type, payload) {
765
+ async environmentEvent(environmentId, type, payload) {
681
766
  this.check();
682
- return appendSandboxEvent(postgresSandboxRecordWriter(this.db), {
767
+ return appendEnvironmentEvent(postgresEnvironmentRecordWriter(this.db), {
683
768
  tenantId: this.tenantId,
684
- sandboxId,
769
+ environmentId,
685
770
  time: this.now(),
686
771
  type,
687
772
  payload,
688
773
  });
689
774
  }
690
- async sandboxEvents(sandboxId, options = {}) {
775
+ async environmentEvents(environmentId, options = {}) {
691
776
  this.check();
692
777
  const rows = await this.db
693
- .select({ body: sandboxEvents.body })
694
- .from(sandboxEvents)
695
- .where(and(eq(sandboxEvents.sandboxId, sandboxId), options.fromSeq === undefined ? undefined : gte(sandboxEvents.seq, options.fromSeq)))
696
- .orderBy(sandboxEvents.seq)
778
+ .select({ body: environmentEvents.body })
779
+ .from(environmentEvents)
780
+ .where(and(eq(environmentEvents.environmentId, environmentId), options.fromSeq === undefined ? undefined : gte(environmentEvents.seq, options.fromSeq), options.types === undefined ? undefined : inArray(environmentEvents.type, [...options.types]), options.since === undefined ? undefined : gte(environmentEvents.committedAt, options.since), options.until === undefined ? undefined : lt(environmentEvents.committedAt, options.until)))
781
+ .orderBy(environmentEvents.seq)
697
782
  .limit(options.limit ?? 1000);
698
783
  return rows.map((row) => row.body);
699
784
  }
@@ -831,21 +916,13 @@ class PostgresTx {
831
916
  const [row] = await this.db.select().from(vaults).where(eq(vaults.id, id));
832
917
  return row;
833
918
  }
834
- async vaultsByOwner(ownerUserId) {
835
- this.check();
836
- return this.db
837
- .select()
838
- .from(vaults)
839
- .where(and(eq(vaults.ownerUserId, ownerUserId), eq(vaults.scope, "user")))
840
- .orderBy(vaults.createdAt, vaults.id);
841
- }
842
- async installationVaults() {
919
+ async vaultOfEnvironment(environmentId) {
843
920
  this.check();
844
- return this.db
921
+ const [row] = await this.db
845
922
  .select()
846
923
  .from(vaults)
847
- .where(eq(vaults.scope, "installation"))
848
- .orderBy(vaults.createdAt, vaults.id);
924
+ .where(eq(vaults.environmentId, environmentId));
925
+ return row;
849
926
  }
850
927
  async updateVaultMetadata(id, metadataJson) {
851
928
  this.check();
@@ -868,6 +945,14 @@ class PostgresTx {
868
945
  .where(eq(vaultCredentials.id, id));
869
946
  return row;
870
947
  }
948
+ async credentialByName(vaultId, name) {
949
+ this.check();
950
+ const [row] = await this.db
951
+ .select()
952
+ .from(vaultCredentials)
953
+ .where(and(eq(vaultCredentials.vaultId, vaultId), eq(vaultCredentials.name, name)));
954
+ return row;
955
+ }
871
956
  async credentialsForVault(vaultId, filter = {}) {
872
957
  this.check();
873
958
  return this.db
@@ -976,6 +1061,16 @@ class PostgresTx {
976
1061
  .returning();
977
1062
  return inserted;
978
1063
  }
1064
+ async modelUsageOf(effectKey) {
1065
+ this.check();
1066
+ const [row] = await this.db
1067
+ .select()
1068
+ .from(modelUsage)
1069
+ .where(and(eq(modelUsage.effectKey, effectKey), eq(modelUsage.duplicate, false)))
1070
+ .orderBy(modelUsage.createdAt, modelUsage.id)
1071
+ .limit(1);
1072
+ return row;
1073
+ }
979
1074
  async modelUsageTotals(query) {
980
1075
  this.check();
981
1076
  const [row] = await this.db
@@ -1016,6 +1111,15 @@ class PostgresTx {
1016
1111
  .returning({ key: toolCrossings.key });
1017
1112
  return inserted.length === 1;
1018
1113
  }
1114
+ async restartToolCrossing(row) {
1115
+ this.check();
1116
+ const restarted = await this.db
1117
+ .update(toolCrossings)
1118
+ .set({ startedAt: row.startedAt })
1119
+ .where(and(eq(toolCrossings.key, row.key), eq(toolCrossings.hash, row.hash), isNull(toolCrossings.settledAt)))
1120
+ .returning({ key: toolCrossings.key });
1121
+ return restarted.length === 1;
1122
+ }
1019
1123
  async settleToolCrossing(key, answer, settledAt) {
1020
1124
  this.check();
1021
1125
  await this.db
@@ -1038,6 +1142,12 @@ class PostgresTx {
1038
1142
  const [row] = options.lock ? await query.for("update") : await query;
1039
1143
  return row;
1040
1144
  }
1145
+ async diskArtifact(environmentId, options = {}) {
1146
+ this.check();
1147
+ const query = this.db.select().from(artifacts).where(eq(artifacts.environmentId, environmentId));
1148
+ const [row] = options.lock ? await query.for("update") : await query;
1149
+ return row;
1150
+ }
1041
1151
  async listArtifacts(filter = {}) {
1042
1152
  this.check();
1043
1153
  return this.db
@@ -1088,6 +1198,24 @@ class PostgresTx {
1088
1198
  await this.db.delete(artifacts).where(eq(artifacts.id, id));
1089
1199
  return deleted.map((row) => row.blobKey);
1090
1200
  }
1201
+ async deleteArtifactVersion(artifactId, version) {
1202
+ this.check();
1203
+ const [deleted] = await this.db
1204
+ .delete(artifactVersions)
1205
+ .where(and(eq(artifactVersions.artifactId, artifactId), eq(artifactVersions.version, version)))
1206
+ .returning({ blobKey: artifactVersions.blobKey });
1207
+ if (!deleted)
1208
+ return undefined;
1209
+ const [left] = await this.db
1210
+ .select({ latest: sql `max(${artifactVersions.version})` })
1211
+ .from(artifactVersions)
1212
+ .where(eq(artifactVersions.artifactId, artifactId));
1213
+ await this.db
1214
+ .update(artifacts)
1215
+ .set({ latestVersion: Number(left?.latest ?? 0), updatedAt: new Date().toISOString() })
1216
+ .where(eq(artifacts.id, artifactId));
1217
+ return deleted.blobKey;
1218
+ }
1091
1219
  async lockArtifactQuota() {
1092
1220
  this.check();
1093
1221
  await this.db.execute(sql `SELECT pg_advisory_xact_lock(hashtext('nylorun.artifacts'))`);
@@ -1228,10 +1356,11 @@ class PostgresTx {
1228
1356
  basinGeneration: sql `${tenant.basinGeneration} + 1`,
1229
1357
  });
1230
1358
  }
1231
- if (scope === "sandboxes" || scope === "all") {
1359
+ if (scope === "environments" || scope === "all") {
1232
1360
  await db.delete(sandboxes);
1233
- await db.delete(sandboxResources);
1234
- await db.delete(sandboxEvents);
1361
+ // Their vaults and credentials go with them (ON DELETE CASCADE).
1362
+ await db.delete(environments);
1363
+ await db.delete(environmentEvents);
1235
1364
  await db.delete(sandboxSignals);
1236
1365
  }
1237
1366
  if (scope === "all") {
@@ -1241,7 +1370,6 @@ class PostgresTx {
1241
1370
  await db.delete(modelUsage);
1242
1371
  await db.delete(modelBudgets);
1243
1372
  await db.delete(artifacts);
1244
- await db.delete(vaults).where(ne(vaults.scope, "host"));
1245
1373
  }
1246
1374
  }
1247
1375
  }