@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
@@ -69,14 +69,14 @@ export const sessions = nylorun.table("sessions", {
69
69
  ownerExpiresAt: timestamp({ withTimezone: true, mode: "date" }),
70
70
  /** The session owner (`ownerUserId`), not the lease column `owner`. */
71
71
  ownerUserId: field("->>'ownerUserId'"),
72
- /** The sandbox resource the session is attached to (`sandbox: { id }`). */
73
- sandboxId: field("->>'sandboxId'"),
72
+ /** The Environment the session names (`environment`, protocol 11). */
73
+ environmentId: field("->>'environmentId'"),
74
74
  }, (t) => [
75
75
  index("sessions_created").on(t.createdAt.desc().nullsLast(), t.id.desc().nullsFirst()),
76
76
  index("sessions_status").on(t.status, t.ownerExpiresAt),
77
77
  index("sessions_agent").on(t.agentId),
78
78
  index("sessions_owner_user").on(t.ownerUserId),
79
- index("sessions_sandbox").on(t.sandboxId),
79
+ index("sessions_environment").on(t.environmentId),
80
80
  ]);
81
81
  export const commands = documents("commands");
82
82
  export const effects = nylorun.table("effects", {
@@ -107,22 +107,126 @@ export const principals = nylorun.table("principals", {
107
107
  idempotencyKey: text(),
108
108
  createdAt: text().notNull(),
109
109
  });
110
+ /**
111
+ * An Environment (D55, protocol 11): its id, kind, labels, the recipe the app asked for and the
112
+ * recipe its compute runs (`applied`, copied from `recipe` when a stopped pod is asked to run),
113
+ * the owner guard, and when it was last used. Kind `pod` adds the pod's lifecycle columns.
114
+ * Sessions name it by id (the session body's `environmentId`). Not the `sandboxes` document
115
+ * table, which holds the virtual backend's compute records, keyed by workspace key.
116
+ */
117
+ export const environments = nylorun.table("environments", {
118
+ id: textC().primaryKey(),
119
+ kind: text({ enum: ["virtual", "pod", "none"] }).notNull(),
120
+ /** `{ key: value }`, filtered through `nylorun.doc(labels)`. */
121
+ labels: jsonText().notNull(),
122
+ /** What the app asked for (`EnvironmentRecipe`), resolved against the Tenant's limits. */
123
+ recipe: jsonText().notNull(),
124
+ /** The recipe the current pod or workspace runs. */
125
+ applied: jsonText().notNull(),
126
+ version: integer().notNull().default(1),
127
+ appliedVersion: integer().notNull().default(1),
128
+ /** The owner guard: only this owner's sessions may name the Environment. */
129
+ ownerUserId: text(),
130
+ /** A turn's end, a recipe change, a secret write, a stop or a reset (`lifecycle.deleteAfter`). */
131
+ lastUsedAt: timestamp({ withTimezone: true, mode: "string" }).notNull().defaultNow(),
132
+ createdAt: textC().notNull(),
133
+ updatedAt: textC().notNull(),
134
+ // Kind `pod` (F7.2, D34): null otherwise. `tenant/environments.ts` and the `Sandbox`
135
+ // object's reconcile (`sandbox/pods/reconcile.ts`) are the only writers.
136
+ /** The agent-sandbox Sandbox's name, `sbx-<16 base32>-g<volume_gen>` (`podName`). */
137
+ k8sName: textC(),
138
+ /** Bumped by every reset: a new Sandbox on a new volume. */
139
+ volumeGen: integer().notNull().default(0),
140
+ /** `running`, `suspended` or `deleted`. */
141
+ desired: text({ enum: ["running", "suspended", "deleted"] }),
142
+ /** `creating`, `running`, `suspended`, `lost`, `failed` or `deleting`. */
143
+ observed: text({ enum: ["creating", "running", "suspended", "lost", "failed", "deleting"] }),
144
+ /** The UID of the pod that last joined. */
145
+ podUid: text(),
146
+ /**
147
+ * Bumped by every join (`host.join`), relaunch, loss and reset: host and egress tokens carry
148
+ * it (`epc`), and one of an older epoch is refused (egress-gate reads it too).
149
+ */
150
+ hostEpoch: integer().notNull().default(0),
151
+ /** sha256 (hex) of the incarnation's join token; the token itself is never stored. */
152
+ joinTokenHash: text(),
153
+ /** Bumped by every change the Runtime asks of the pod: the sandboxes service's `opId`. */
154
+ rev: integer().notNull().default(0),
155
+ /** When a turn last ended on it, for the idle timer. */
156
+ lastActiveAt: timestamp({ withTimezone: true }),
157
+ /** When the current incarnation was asked to run, for the ready deadline. */
158
+ startedAt: timestamp({ withTimezone: true }),
159
+ /** Why it failed or was lost. */
160
+ reason: text(),
161
+ /** An earlier incarnation's Sandbox still to delete (after a reset or a loss). */
162
+ retiring: textC(),
163
+ /**
164
+ * The id the engine keeps on the volume (`/harness/volume-id`), recorded at the first join:
165
+ * a join with another one means the volume was replaced (its files are gone), so `lost`.
166
+ */
167
+ volumeId: text(),
168
+ /** The workload image by digest, from the first ready pod on (Q14): later pods run it. */
169
+ imageDigest: textC(),
170
+ /**
171
+ * The disk lease (R2d step 3): `{ kind, version?, startedAt, until }` while a snapshot, a
172
+ * restore or a seed copies the disk; turns are refused until it ends or `until` passes.
173
+ */
174
+ diskOp: jsonText(),
175
+ /**
176
+ * The disk version the next volume starts from: `{ artifactId, version }` (R2d step 3). A
177
+ * fork onto other setup adds `setup: true` (Q17): once the version is written (`written`),
178
+ * the seed stays until the engine reports the setup done, and turns wait for both.
179
+ */
180
+ diskSeed: jsonText(),
181
+ /**
182
+ * The environment manifest it was made from and its version (D63): null for an Environment
183
+ * made from an inline manifest. Never changed after creation.
184
+ */
185
+ manifestName: textC(),
186
+ manifestVersion: integer(),
187
+ /** The hash of what it runs (`recipe`), from creation on. */
188
+ manifestHash: textC(),
189
+ /** The Environment it was forked from: `{ environment, disk }` (Q15). Never changed. */
190
+ forkedFrom: jsonText(),
191
+ }, (t) => [
192
+ check("environments_kind_check", sql `${t.kind} IN ('virtual', 'pod', 'none')`),
193
+ index("environments_manifest").on(t.manifestName, t.manifestVersion),
194
+ ]);
195
+ /**
196
+ * An environment manifest's versions (D63): a named, versioned definition of a kind of
197
+ * Environment, saved like an agent. A version is written once and never changed; a save whose
198
+ * body hashes the same as the latest writes nothing.
199
+ */
200
+ export const environmentManifests = nylorun.table("environment_manifests", {
201
+ name: textC().notNull(),
202
+ version: integer().notNull(),
203
+ /** The manifest (`EnvironmentManifest`) as saved. */
204
+ body: jsonText().notNull(),
205
+ hash: textC().notNull(),
206
+ /** `{ actor }`: the subject the save acted for, else `application`. */
207
+ savedBy: jsonText().notNull(),
208
+ createdAt: textC().notNull(),
209
+ }, (t) => [primaryKey({ name: "environment_manifests_pkey", columns: [t.name, t.version] })]);
210
+ /**
211
+ * A vault (D56): the host model's (`id = 'host'`), or one Environment's, created and deleted with
212
+ * it (`environment_id`, unique, deleted with the Environment's row). No other vault exists.
213
+ */
110
214
  export const vaults = nylorun.table("vaults", {
111
215
  id: textC().primaryKey(),
112
216
  name: text().notNull(),
113
- ownerUserId: text().notNull(),
114
217
  /** JSON text, or null. */
115
218
  metadataJson: text(),
116
219
  createdAt: textC().notNull(),
117
- /**
118
- * `user`: one person's (owner `ownerUserId`); `installation`: the installation's own,
119
- * attachable to any session (owner `installation`); `host`: the model vault, never attached.
120
- */
121
- scope: text({ enum: ["user", "installation", "host"] }).notNull().default("user"),
220
+ /** The Environment the vault belongs to; null only for the host vault. */
221
+ environmentId: textC(),
122
222
  }, (t) => [
123
- index("vaults_owner").on(t.ownerUserId, t.createdAt, t.id),
124
- uniqueIndex("vaults_one_host").on(t.scope).where(sql `scope = 'host'`),
125
- check("vaults_scope_check", sql `scope IN ('user', 'installation', 'host')`),
223
+ uniqueIndex("vaults_environment").on(t.environmentId),
224
+ foreignKey({
225
+ name: "vaults_environment_id_fkey",
226
+ columns: [t.environmentId],
227
+ foreignColumns: [environments.id],
228
+ }).onDelete("cascade"),
229
+ check("vaults_owner_check", sql `(${t.id} = 'host') = (${t.environmentId} IS NULL)`),
126
230
  ]);
127
231
  /** A credential of a vault: its binding in the clear, its secret sealed. */
128
232
  export const vaultCredentials = nylorun.table("vault_credentials", {
@@ -146,6 +250,7 @@ export const vaultCredentials = nylorun.table("vault_credentials", {
146
250
  foreignColumns: [vaults.id],
147
251
  }).onDelete("cascade"),
148
252
  index("vault_credentials_vault").on(t.vaultId, t.createdAt, t.id),
253
+ uniqueIndex("vault_credentials_name").on(t.vaultId, t.name),
149
254
  ]);
150
255
  export const vaultAudit = nylorun.table("vault_audit", {
151
256
  ord: bigint({ mode: "number" }).primaryKey().generatedAlwaysAsIdentity(),
@@ -198,7 +303,9 @@ export const signingKeys = nylorun.table("signing_keys", {
198
303
  * The model usage ledger (P1.3): one row per model call a gate served, written after the call.
199
304
  * A second row for the same effect (a call the gate ran again after a gateway restart) is
200
305
  * flagged `duplicate`; both were billed. Budgets read their spend from it. Token counts are 0
201
- * when the provider sent none.
306
+ * when the provider sent none. `startedAt`, `endedAt` and `firstTokenMs` are the gate's own
307
+ * timing of the call (R7.1, migration 0022); null on rows written before, and `firstTokenMs`
308
+ * when the provider streamed nothing.
202
309
  */
203
310
  export const modelUsage = nylorun.table("model_usage", {
204
311
  id: textC().primaryKey(),
@@ -222,6 +329,12 @@ export const modelUsage = nylorun.table("model_usage", {
222
329
  /** True when an earlier row has the same `effectKey`: the provider billed the call twice. */
223
330
  duplicate: boolean().notNull(),
224
331
  createdAt: text().notNull(),
332
+ /** When the gate sent the call to the provider. */
333
+ startedAt: text(),
334
+ /** When the provider's answer was complete. */
335
+ endedAt: text(),
336
+ /** From `startedAt` to the provider's first stream event. */
337
+ firstTokenMs: integer(),
225
338
  }, (t) => [
226
339
  index("model_usage_session").on(t.sessionId, t.createdAt, t.id),
227
340
  index("model_usage_export").on(t.txid, t.id),
@@ -260,60 +373,6 @@ export const toolCrossings = nylorun.table("tool_crossings", {
260
373
  /** The gate's answer (`McpAnswer`), once the call ended; null while it runs or once lost. */
261
374
  answer: jsonText(),
262
375
  }, (t) => [index("tool_crossings_settled").on(t.settledAt)]);
263
- /**
264
- * A sandbox resource (blueprint D39, F7.1): its id, kind, the spec resolved against the
265
- * Tenant's limits when it was created, and the developer's labels. Sessions attach to it by id
266
- * (the session body's `sandboxId`). Not the `sandboxes` document table, which holds the virtual
267
- * backend's compute records, keyed by workspace key.
268
- */
269
- export const sandboxResources = nylorun.table("sandbox_resources", {
270
- id: textC().primaryKey(),
271
- kind: text({ enum: ["virtual", "pod"] }).notNull(),
272
- /** The resolved `SandboxManifest`. */
273
- spec: jsonText().notNull(),
274
- /** `{ key: value }`, filtered through `nylorun.doc(labels)`. */
275
- labels: jsonText().notNull(),
276
- createdAt: textC().notNull(),
277
- updatedAt: textC().notNull(),
278
- // Kind `pod` (F7.2, D34): null for a virtual sandbox. `tenant/sandboxes.ts` and the
279
- // `Sandbox` object's reconcile (`sandbox/pods/reconcile.ts`) are the only writers.
280
- /** The agent-sandbox Sandbox's name, `sbx-<16 base32>-g<volume_gen>` (`podName`). */
281
- k8sName: textC(),
282
- /** Bumped by every reset: a new Sandbox on a new volume. */
283
- volumeGen: integer().notNull().default(0),
284
- /** `running`, `suspended` or `deleted`. */
285
- desired: text({ enum: ["running", "suspended", "deleted"] }),
286
- /** `creating`, `running`, `suspended`, `expired`, `lost`, `failed` or `deleting`. */
287
- observed: text({
288
- enum: ["creating", "running", "suspended", "expired", "lost", "failed", "deleting"],
289
- }),
290
- /** The UID of the pod that last joined. */
291
- podUid: text(),
292
- /**
293
- * Bumped by every join (`host.join`), relaunch, loss and reset: host and egress tokens carry
294
- * it (`epc`), and one of an older epoch is refused (egress-gate reads it too).
295
- */
296
- hostEpoch: integer().notNull().default(0),
297
- /** sha256 (hex) of the incarnation's join token; the token itself is never stored. */
298
- joinTokenHash: text(),
299
- /** Bumped by every change the Runtime asks of the pod: the sandboxes service's `opId`. */
300
- rev: integer().notNull().default(0),
301
- /** When a turn last ended on it, for the idle timer. */
302
- lastActiveAt: timestamp({ withTimezone: true }),
303
- /** When its TTL passes (`createdAt + lifecycle.ttl`). */
304
- expiresAt: timestamp({ withTimezone: true }),
305
- /** When the current incarnation was asked to run, for the ready deadline. */
306
- startedAt: timestamp({ withTimezone: true }),
307
- /** Why it failed or was lost. */
308
- reason: text(),
309
- /** An earlier incarnation's Sandbox still to delete (after a reset or a loss). */
310
- retiring: textC(),
311
- /**
312
- * The id the engine keeps on the volume (`/harness/volume-id`), recorded at the first join:
313
- * a join with another one means the volume was replaced (its files are gone), so `lost`.
314
- */
315
- volumeId: text(),
316
- });
317
376
  /**
318
377
  * Artifacts (blueprint D35, F8.1 and F8.2): an id, a name and numbered versions. The bytes are in
319
378
  * the Object store under each version's `blobKey` (a folder's: its manifest); a blob counts only
@@ -331,8 +390,12 @@ export const artifacts = nylorun.table("artifacts", {
331
390
  labelsJson: text(),
332
391
  createdAt: textC().notNull(),
333
392
  updatedAt: text().notNull(),
393
+ /** The Environment whose disk versions this folder holds (R2d step 3); one per Environment. */
394
+ environmentId: textC(),
334
395
  }, (t) => [
335
396
  index("artifacts_session").on(t.sessionId, t.createdAt, t.id),
397
+ uniqueIndex("artifacts_environment_disk").on(t.environmentId).where(sql `environment_id IS NOT NULL`),
398
+ index("artifacts_creation_order").on(t.createdAt, t.id),
336
399
  check("artifacts_kind_check", sql `kind IN ('file', 'folder')`),
337
400
  ]);
338
401
  /** The versions of an artifact, immutable once written. */
@@ -344,7 +407,7 @@ export const artifactVersions = nylorun.table("artifact_versions", {
344
407
  size: bigint({ mode: "number" }).notNull(),
345
408
  sha256: text().notNull(),
346
409
  contentType: text().notNull(),
347
- source: text({ enum: ["upload", "engine", "export"] }).notNull(),
410
+ source: text({ enum: ["upload", "engine", "export", "snapshot"] }).notNull(),
348
411
  createdAt: textC().notNull(),
349
412
  }, (t) => [
350
413
  primaryKey({ name: "artifact_versions_pkey", columns: [t.artifactId, t.version] }),
@@ -471,16 +534,16 @@ export const sandboxSignals = nylorun.table("sandbox_signals", {
471
534
  // ---------------------------------------------------------------------------
472
535
  // nylorun_streams: the record
473
536
  /**
474
- * Each sandbox's lifecycle stream (`nylorun.sandbox-event/1`), numbered from 0 per sandbox id.
475
- * Written only by the record module; not published to the stream relay.
537
+ * Each Environment's lifecycle stream (`nylorun.environment-event/1`), numbered from 0 per
538
+ * Environment id. Written only by the record module; not published to the stream relay.
476
539
  */
477
- export const sandboxEvents = nylorunStreams.table("sandbox_events", {
478
- sandboxId: textC().notNull(),
540
+ export const environmentEvents = nylorunStreams.table("environment_events", {
541
+ environmentId: textC().notNull(),
479
542
  seq: bigint({ mode: "number" }).notNull(),
480
543
  type: text().notNull(),
481
544
  body: jsonText().notNull(),
482
545
  committedAt: timestamp({ withTimezone: true, mode: "string" }).notNull().defaultNow(),
483
- }, (t) => [primaryKey({ name: "sandbox_events_pkey", columns: [t.sandboxId, t.seq] })]);
546
+ }, (t) => [primaryKey({ name: "environment_events_pkey", columns: [t.environmentId, t.seq] })]);
484
547
  /** Each session's log head: the next seq and the basin generation its events go to. */
485
548
  export const sessionLogHeads = nylorunStreams.table("session_log_heads", {
486
549
  sessionId: textC().primaryKey(),