@nimbus-sh/worker 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/NOTICE.md +5 -0
  2. package/README.md +10 -0
  3. package/dist/_shared/session-router.d.ts +7 -0
  4. package/dist/_shared/session-router.d.ts.map +1 -1
  5. package/dist/_shared/session-router.js +7 -0
  6. package/dist/bindings/body.d.ts +6 -0
  7. package/dist/bindings/body.d.ts.map +1 -0
  8. package/dist/bindings/body.js +37 -0
  9. package/dist/bindings/kv.d.ts +0 -2
  10. package/dist/bindings/kv.d.ts.map +1 -1
  11. package/dist/bindings/kv.js +3 -42
  12. package/dist/bindings/r2.d.ts +0 -2
  13. package/dist/bindings/r2.d.ts.map +1 -1
  14. package/dist/bindings/r2.js +4 -44
  15. package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
  16. package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
  17. package/dist/esbuild-cli-artifact.generated.js +17 -0
  18. package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
  19. package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
  20. package/dist/esbuild-wasm-bundle.generated.js +24 -24
  21. package/dist/facets/cirrus-real.d.ts.map +1 -1
  22. package/dist/facets/cirrus-real.js +11 -6
  23. package/dist/facets/compose.d.ts +11 -7
  24. package/dist/facets/compose.d.ts.map +1 -1
  25. package/dist/facets/compose.js +8 -31
  26. package/dist/facets/data-plan.d.ts +79 -0
  27. package/dist/facets/data-plan.d.ts.map +1 -0
  28. package/dist/facets/data-plan.js +477 -0
  29. package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
  30. package/dist/facets/esbuild-bundle-pool.js +3 -3
  31. package/dist/facets/esbuild-transform.d.ts +38 -8
  32. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  33. package/dist/facets/esbuild-transform.js +219 -19
  34. package/dist/facets/exec-telemetry.d.ts +7 -3
  35. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  36. package/dist/facets/manager.d.ts +198 -69
  37. package/dist/facets/manager.d.ts.map +1 -1
  38. package/dist/facets/manager.js +1276 -652
  39. package/dist/facets/opencode-staging.d.ts +0 -2
  40. package/dist/facets/opencode-staging.d.ts.map +1 -1
  41. package/dist/facets/opencode-staging.js +5 -11
  42. package/dist/facets/process.d.ts +4 -0
  43. package/dist/facets/process.d.ts.map +1 -1
  44. package/dist/facets/process.js +3 -0
  45. package/dist/facets/read-profile.d.ts +149 -0
  46. package/dist/facets/read-profile.d.ts.map +1 -0
  47. package/dist/facets/read-profile.js +483 -0
  48. package/dist/facets/real-vite-hmr.d.ts +2 -0
  49. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  50. package/dist/facets/real-vite-hmr.js +3 -2
  51. package/dist/facets/resident-identity.d.ts +0 -1
  52. package/dist/facets/resident-identity.d.ts.map +1 -1
  53. package/dist/facets/resident-identity.js +0 -3
  54. package/dist/facets/wasm-swap-registry.d.ts +34 -25
  55. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  56. package/dist/facets/wasm-swap-registry.js +62 -56
  57. package/dist/facets/ws-terminal.d.ts +4 -4
  58. package/dist/facets/ws-terminal.d.ts.map +1 -1
  59. package/dist/facets/ws-terminal.js +4 -5
  60. package/dist/git/commands.d.ts +33 -10
  61. package/dist/git/commands.d.ts.map +1 -1
  62. package/dist/git/commands.js +1891 -197
  63. package/dist/git/network-facet.d.ts +12 -2
  64. package/dist/git/network-facet.d.ts.map +1 -1
  65. package/dist/git/network-facet.js +69 -18
  66. package/dist/git/unified-diff.d.ts +74 -0
  67. package/dist/git/unified-diff.d.ts.map +1 -0
  68. package/dist/git/unified-diff.js +676 -0
  69. package/dist/git-bundle.generated.d.ts +7 -11
  70. package/dist/git-bundle.generated.d.ts.map +1 -1
  71. package/dist/git-bundle.generated.js +7 -11
  72. package/dist/hosted/commands.d.ts.map +1 -1
  73. package/dist/hosted/commands.js +64 -245
  74. package/dist/hosted/runtime.d.ts +22 -15
  75. package/dist/hosted/runtime.d.ts.map +1 -1
  76. package/dist/hosted/runtime.js +72 -14
  77. package/dist/hosted/services.d.ts +8 -1
  78. package/dist/hosted/services.d.ts.map +1 -1
  79. package/dist/hosted/services.js +12 -13
  80. package/dist/hosted/session.d.ts +165 -0
  81. package/dist/hosted/session.d.ts.map +1 -0
  82. package/dist/hosted/session.js +132 -0
  83. package/dist/loaders/generated-workers.d.ts +6 -3
  84. package/dist/loaders/generated-workers.d.ts.map +1 -1
  85. package/dist/loaders/generated-workers.js +8 -5
  86. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  87. package/dist/loaders/npm-resolve-preamble.js +0 -27
  88. package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
  89. package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
  90. package/dist/loaders/pre-bundle-preamble.js +13 -8
  91. package/dist/node-shims-artifact.generated.d.ts +13 -4
  92. package/dist/node-shims-artifact.generated.d.ts.map +1 -1
  93. package/dist/node-shims-artifact.generated.js +16 -7
  94. package/dist/npm/bin-links.d.ts +3 -1
  95. package/dist/npm/bin-links.d.ts.map +1 -1
  96. package/dist/npm/bin-links.js +32 -8
  97. package/dist/npm/cache.d.ts +11 -1
  98. package/dist/npm/cache.d.ts.map +1 -1
  99. package/dist/npm/cache.js +21 -7
  100. package/dist/npm/install-batch-facet.d.ts +4 -2
  101. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  102. package/dist/npm/install-batch-facet.js +32 -18
  103. package/dist/npm/installer.d.ts +23 -3
  104. package/dist/npm/installer.d.ts.map +1 -1
  105. package/dist/npm/installer.js +330 -131
  106. package/dist/npm/npx-install.d.ts +3 -1
  107. package/dist/npm/npx-install.d.ts.map +1 -1
  108. package/dist/npm/npx-install.js +4 -1
  109. package/dist/npm/package-lock.d.ts +32 -0
  110. package/dist/npm/package-lock.d.ts.map +1 -0
  111. package/dist/npm/package-lock.js +65 -0
  112. package/dist/npm/placement.d.ts +16 -0
  113. package/dist/npm/placement.d.ts.map +1 -0
  114. package/dist/npm/placement.js +33 -0
  115. package/dist/npm/pre-bundle-facet.d.ts +1 -30
  116. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  117. package/dist/npm/pre-bundle-facet.js +3 -5
  118. package/dist/npm/r2-cache.d.ts +12 -6
  119. package/dist/npm/r2-cache.d.ts.map +1 -1
  120. package/dist/npm/r2-cache.js +34 -16
  121. package/dist/npm/resolve-one-facet.d.ts +3 -0
  122. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  123. package/dist/npm/resolve-one-facet.js +15 -3
  124. package/dist/npm/resolver.d.ts +11 -13
  125. package/dist/npm/resolver.d.ts.map +1 -1
  126. package/dist/npm/resolver.js +12 -25
  127. package/dist/opencode-artifact.generated.js +2 -2
  128. package/dist/replica/routing.d.ts +2 -38
  129. package/dist/replica/routing.d.ts.map +1 -1
  130. package/dist/replica/routing.js +3 -55
  131. package/dist/router/index.d.ts.map +1 -1
  132. package/dist/router/index.js +15 -2
  133. package/dist/router/public-directory.d.ts +18 -0
  134. package/dist/router/public-directory.d.ts.map +1 -1
  135. package/dist/router/public-directory.js +1 -1
  136. package/dist/router/remote-api.d.ts +3 -1
  137. package/dist/router/remote-api.d.ts.map +1 -1
  138. package/dist/router/remote-api.js +42 -79
  139. package/dist/runtime/bash-repl.js +2 -2
  140. package/dist/runtime/bun-repl.d.ts.map +1 -1
  141. package/dist/runtime/bun-repl.js +2 -13
  142. package/dist/runtime/cpython-resident.d.ts.map +1 -1
  143. package/dist/runtime/cpython-resident.js +2 -10
  144. package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
  145. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  146. package/dist/runtime/esbuild-wasm-bytes.js +66 -92
  147. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  148. package/dist/runtime/facet-loader-host.js +0 -7
  149. package/dist/runtime/git-bundle-artifact.d.ts +17 -0
  150. package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
  151. package/dist/runtime/git-bundle-artifact.js +25 -0
  152. package/dist/runtime/node-repl.d.ts.map +1 -1
  153. package/dist/runtime/node-repl.js +2 -13
  154. package/dist/runtime/node-shims-artifact.d.ts +22 -23
  155. package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
  156. package/dist/runtime/node-shims-artifact.js +48 -78
  157. package/dist/runtime/node-shims.d.ts.map +1 -1
  158. package/dist/runtime/node-shims.js +2358 -996
  159. package/dist/runtime/opencode-artifact.d.ts.map +1 -1
  160. package/dist/runtime/opencode-artifact.js +17 -53
  161. package/dist/runtime/opencode-facet-runner.d.ts +3 -6
  162. package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
  163. package/dist/runtime/opencode-facet-runner.js +45 -10
  164. package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
  165. package/dist/runtime/opentui-wasm-bytes.js +16 -49
  166. package/dist/runtime/package-manager.d.ts +0 -2
  167. package/dist/runtime/package-manager.d.ts.map +1 -1
  168. package/dist/runtime/package-manager.js +0 -3
  169. package/dist/runtime/python-repl.d.ts.map +1 -1
  170. package/dist/runtime/python-repl.js +4 -35
  171. package/dist/runtime/repl-session.d.ts +10 -0
  172. package/dist/runtime/repl-session.d.ts.map +1 -1
  173. package/dist/runtime/repl-session.js +7 -0
  174. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  175. package/dist/runtime/ruby-repl.js +2 -2
  176. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  177. package/dist/runtime/ruby-resident.js +41 -51
  178. package/dist/runtime/runtime-catalog.d.ts +10 -3
  179. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  180. package/dist/runtime/runtime-catalog.js +125 -15
  181. package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
  182. package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
  183. package/dist/runtime/sqlite-wasm-bytes.js +21 -57
  184. package/dist/runtime/staged-source.d.ts +67 -0
  185. package/dist/runtime/staged-source.d.ts.map +1 -0
  186. package/dist/runtime/staged-source.js +113 -0
  187. package/dist/runtime/wasi/preamble.d.ts +0 -22
  188. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  189. package/dist/runtime/wasi/preamble.js +98 -1425
  190. package/dist/runtime-catalog.generated.js +1 -1
  191. package/dist/session/agent.d.ts +14 -2
  192. package/dist/session/agent.d.ts.map +1 -1
  193. package/dist/session/agent.js +57 -19
  194. package/dist/session/ai.d.ts +0 -11
  195. package/dist/session/ai.d.ts.map +1 -1
  196. package/dist/session/ai.js +0 -4
  197. package/dist/session/fs-watch.d.ts +0 -11
  198. package/dist/session/fs-watch.d.ts.map +1 -1
  199. package/dist/session/fs-watch.js +0 -21
  200. package/dist/session/hibernation.d.ts +68 -2
  201. package/dist/session/hibernation.d.ts.map +1 -1
  202. package/dist/session/hibernation.js +95 -1
  203. package/dist/session/init-phases.d.ts +1 -2
  204. package/dist/session/init-phases.d.ts.map +1 -1
  205. package/dist/session/init-phases.js +1 -2
  206. package/dist/session/init.d.ts.map +1 -1
  207. package/dist/session/init.js +7 -20
  208. package/dist/session/keys.d.ts +0 -3
  209. package/dist/session/keys.d.ts.map +1 -1
  210. package/dist/session/keys.js +0 -3
  211. package/dist/session/legacy-reset.d.ts +11 -0
  212. package/dist/session/legacy-reset.d.ts.map +1 -0
  213. package/dist/session/legacy-reset.js +16 -0
  214. package/dist/session/nimbus-session.d.ts +50 -16
  215. package/dist/session/nimbus-session.d.ts.map +1 -1
  216. package/dist/session/nimbus-session.js +77 -71
  217. package/dist/session/npm-install-port.d.ts.map +1 -1
  218. package/dist/session/npm-install-port.js +2 -0
  219. package/dist/session/programmatic.d.ts +13 -18
  220. package/dist/session/programmatic.d.ts.map +1 -1
  221. package/dist/session/programmatic.js +53 -39
  222. package/dist/session/replica-routes.d.ts +2 -3
  223. package/dist/session/replica-routes.d.ts.map +1 -1
  224. package/dist/session/replica-routes.js +3 -10
  225. package/dist/session/routes.d.ts.map +1 -1
  226. package/dist/session/routes.js +11 -12
  227. package/dist/session/rpc.d.ts +108 -21
  228. package/dist/session/rpc.d.ts.map +1 -1
  229. package/dist/session/rpc.js +194 -39
  230. package/dist/session/start-real-vite.js +2 -2
  231. package/dist/session/state-store.d.ts +1 -17
  232. package/dist/session/state-store.d.ts.map +1 -1
  233. package/dist/session/state-store.js +3 -53
  234. package/dist/session/supervisor-op.d.ts +7 -0
  235. package/dist/session/supervisor-op.d.ts.map +1 -1
  236. package/dist/session/supervisor-op.js +6 -1
  237. package/dist/session/supervisor-rpc.d.ts +116 -19
  238. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  239. package/dist/session/supervisor-rpc.js +194 -84
  240. package/dist/session/vite-command.d.ts.map +1 -1
  241. package/dist/session/vite-command.js +17 -14
  242. package/dist/session/ws.d.ts.map +1 -1
  243. package/dist/session/ws.js +20 -8
  244. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  245. package/dist/shell/npm-bin-entrypoints.js +30 -5
  246. package/dist/vfs/facet-resident-limits.d.ts +33 -0
  247. package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
  248. package/dist/vfs/facet-resident-limits.js +33 -0
  249. package/dist/vfs/facet-resident-store.d.ts +2 -10
  250. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  251. package/dist/vfs/facet-resident-store.js +1594 -219
  252. package/dist/workspace-host.d.ts +3 -1
  253. package/dist/workspace-host.d.ts.map +1 -1
  254. package/dist/workspace-host.js +2 -0
  255. package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
  256. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  257. package/dist/wrangler/nimbus-wrangler.js +8 -22
  258. package/package.json +34 -7
  259. package/public/_assets/esbuild-0.24.2.js +2380 -0
  260. package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
  261. package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
  262. package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
  263. package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
  264. package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
  265. package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
  266. package/scripts/build-opencode-attach-entry.mjs +51 -1
  267. package/scripts/bundle-esbuild-wasm.mjs +55 -39
  268. package/scripts/bundle-facet-workers.mjs +159 -10
  269. package/scripts/bundle-git.mjs +88 -27
  270. package/scripts/bundle-node-shims.mjs +72 -46
  271. package/scripts/bundle-runtime.mjs +18 -421
  272. package/scripts/cf-git-patch.mjs +137 -0
  273. package/scripts/patch-install-deps.mjs +49 -96
  274. package/scripts/runtime-specs.mjs +435 -0
  275. package/vendor/git-http.generated.d.ts +82 -0
  276. package/vendor/git-upstream.generated.d.ts +4378 -0
  277. package/vendor/git.LICENSE +7 -0
  278. package/vendor/git.generated.d.mts +21 -0
  279. package/vendor/git.generated.mjs +103 -0
  280. package/dist/replica/suspension.d.ts +0 -36
  281. package/dist/replica/suspension.d.ts.map +0 -1
  282. package/dist/replica/suspension.js +0 -49
  283. package/dist/runtime/static-server.d.ts +0 -3
  284. package/dist/runtime/static-server.d.ts.map +0 -1
  285. package/dist/runtime/static-server.js +0 -133
  286. package/scripts/clean-dist.mjs +0 -7
@@ -24,14 +24,17 @@
24
24
  import { enc, StreamTextDecoders } from '@nimbus-sh/core/_shared/bytes.js';
25
25
  import { normalizeTerminalNewlines } from '@nimbus-sh/core/_shared/terminal.js';
26
26
  import { disposeRpcResource } from '@nimbus-sh/platform/rpc-dispose.js';
27
- import { getInnerDoClass } from '@nimbus-sh/fabric/inner-do-registry.js';
27
+ import { getInnerDoClass, noteInnerDoFacetOpened } from '@nimbus-sh/fabric/inner-do-registry.js';
28
28
  import { NpmCache } from '../npm/cache.js';
29
- import { EsbuildService } from '@nimbus-sh/core/runtime/esbuild-service.js';
29
+ import { supervisorEsbuildService } from '../facets/esbuild-transform.js';
30
30
  import { notifyTerminalEvent } from '../runtime/process-logs-api.js';
31
31
  import { IsolatePool } from '@nimbus-sh/fabric/isolate-pool.js';
32
32
  import { residentBootSpecSchema, } from '@nimbus-sh/fabric/process-fabric.js';
33
33
  import { processes, } from '@nimbus-sh/fabric/workerd-facet-host.js';
34
34
  import { supervisorEntrypoint } from '@nimbus-sh/fabric/composition.js';
35
+ import { residentFacetOf } from '@nimbus-sh/fabric/workerd-facet-host.js';
36
+ import { readHydrating } from '@nimbus-sh/core/workspace/supervisor-op.js';
37
+ import { isVfsError } from '@nimbus-sh/core/vfs/vfs-error.js';
35
38
  import { headerPairs, isolateToken, } from '@nimbus-sh/fabric/process-host.js';
36
39
  import { OpencodeStageSpecSchema } from '../facets/opencode-staging.js';
37
40
  import { recordFailure, getLastRpcFrame, getLastFacetId, } from '@nimbus-sh/platform/oom-discriminator.js';
@@ -174,7 +177,12 @@ export async function _rpcInnerDoFetch(self, req) {
174
177
  };
175
178
  }
176
179
  const facetName = 'innerDO-' + req.bindingName + '-' + req.id;
177
- const facet = self.ctx.facets.get(facetName, async () => ({
180
+ const ctx = self.ctx;
181
+ if (noteInnerDoFacetOpened(ctx, req.bindingName, facetName)) {
182
+ // Each build of the inner worker is a new class; get() with it on a facet still running an older one resets this object.
183
+ ctx.facets.abort(facetName, new Error('Nimbus: this inner Durable Object restarts on the current build'));
184
+ }
185
+ const facet = ctx.facets.get(facetName, async () => ({
178
186
  class: cls,
179
187
  id: req.id, // FacetStartupOptions.id — inner DO sees this as its ctx.id
180
188
  }));
@@ -260,12 +268,6 @@ export async function _rpcLstat(self, path, pid, cred) {
260
268
  export async function _rpcChmod(self, path, mode, pid, cred) {
261
269
  await self.supervisorOp({ op: 'chmod', args: [path, mode], pid, cred });
262
270
  }
263
- export async function _rpcAccess(self, path, mode, pid) {
264
- await self.supervisorBridge(pid).access(path, mode);
265
- }
266
- export async function _rpcChown(self, path, uid, gid, pid, options) {
267
- await self.supervisorBridge(pid).chown(path, uid, gid, options);
268
- }
269
271
  export async function _rpcSetUmask(self, mask, pid) {
270
272
  return self.processes.setUmask(processPid(pid), mask);
271
273
  }
@@ -282,13 +284,28 @@ export async function _rpcRename(self, from, to, pid, cred) {
282
284
  await self.supervisorOp({ op: 'rename', args: [from, to], pid, cred });
283
285
  }
284
286
  const FsRangeOffsetSchema = z.number().int().min(0).finite();
285
- const FsReadBatchArgsSchema = z.array(z.object({
287
+ /** A range of a file: what `fsReadRange` reads. */
288
+ const FsReadBatchRangeSchema = z.object({
286
289
  path: z.string().min(1),
287
290
  offset: FsRangeOffsetSchema,
288
291
  length: FsRangeOffsetSchema.max(FS_READ_BATCH_REQUEST_BYTES),
289
292
  expectedEpoch: z.string().optional(),
290
293
  expectedRevision: FsRangeOffsetSchema.optional(),
291
- })).min(1).max(FS_READ_BATCH_PATH_LIMIT);
294
+ });
295
+ /**
296
+ * A path's own metadata, not followed through a symlink: what `lstat`
297
+ * answers. Strict, so a request naming a range too is read as the range.
298
+ */
299
+ const FsReadBatchLstatSchema = z.object({
300
+ path: z.string().min(1),
301
+ lstat: z.literal(true),
302
+ }).strict();
303
+ const FsReadBatchArgsSchema = z.array(z.union([FsReadBatchLstatSchema, FsReadBatchRangeSchema]))
304
+ .min(1).max(FS_READ_BATCH_PATH_LIMIT);
305
+ /** The file bytes a batch request may return: its range's length; an lstat, none. */
306
+ export function fsReadBatchRequestBytes(request) {
307
+ return 'length' in request ? request.length : 0;
308
+ }
292
309
  const FsWriteRangeArgsSchema = z.object({
293
310
  path: z.string(),
294
311
  offset: FsRangeOffsetSchema,
@@ -313,6 +330,13 @@ const FsTruncateArgsSchema = z.object({
313
330
  const FsAcquireArgsSchema = z.object({
314
331
  epoch: z.string().max(64).nullable(),
315
332
  cursor: z.number().int().min(0),
333
+ options: z.object({
334
+ namespace: z.boolean().optional(),
335
+ push: z.object({
336
+ roots: z.array(z.string().max(4096)).max(64),
337
+ exclude: z.array(z.string().max(255)).max(64).optional(),
338
+ }).strict().optional(),
339
+ }).strict().optional(),
316
340
  });
317
341
  // Also facet-supplied, so also untrusted. `after` is a resume key from a
318
342
  // previous page and is bounded like any other path; `limit` is clamped rather
@@ -369,9 +393,97 @@ export async function _rpcWsClose(self, id, code, reason, pid) {
369
393
  * survive structured clone across the RPC boundary, so a cursor carried that
370
394
  * way would silently arrive as undefined.
371
395
  */
372
- export async function _rpcFsAcquire(self, epoch, cursor, pid) {
373
- const args = FsAcquireArgsSchema.parse({ epoch, cursor });
374
- return self.supervisorBridge(pid).acquire(args.epoch, args.cursor);
396
+ export async function _rpcFsAcquire(self, epoch, cursor, options, pid) {
397
+ const args = FsAcquireArgsSchema.parse({ epoch, cursor, options: options ?? undefined });
398
+ return self.supervisorBridge(pid).acquire(args.epoch, args.cursor, args.options);
399
+ }
400
+ const FsStorageGrantArgsSchema = z.object({
401
+ facet: z.string().min(1),
402
+ bytes: z.number().int().min(0),
403
+ databaseSize: z.number().min(0),
404
+ });
405
+ /**
406
+ * N18: a process's facet store asks for room to grow, reporting what its
407
+ * database measures. The ledger's row for the facet first takes the
408
+ * measurement where it is over the record (overshoot), then admits `bytes`
409
+ * more under the facet's name; refused, nothing is granted and the store
410
+ * keeps what it has (reading the rest through the session).
411
+ */
412
+ export async function _rpcFsStorageGrant(self, facet, bytes, databaseSize, pid) {
413
+ const args = FsStorageGrantArgsSchema.parse({ facet, bytes, databaseSize });
414
+ const owner = self.ctx !== undefined && pid !== undefined ? residentFacetOf(self.ctx, pid) : undefined;
415
+ if (owner !== undefined && owner !== args.facet) {
416
+ throw new Error(`EPERM: process ${pid} lives in facet ${owner}, not ${args.facet}`);
417
+ }
418
+ const ledger = self.sqliteFs?.ledger;
419
+ if (ledger === undefined)
420
+ return { granted: 0 };
421
+ const recorded = ledger.view().facets[args.facet] ?? 0;
422
+ if (args.databaseSize > recorded)
423
+ ledger.report(args.facet, args.databaseSize);
424
+ if (args.bytes === 0)
425
+ return { granted: 0 };
426
+ try {
427
+ ledger.fill(args.facet, args.bytes);
428
+ return { granted: args.bytes };
429
+ }
430
+ catch (error) {
431
+ if (isVfsError(error, 'ENOSPC'))
432
+ return { granted: 0 };
433
+ throw error;
434
+ }
435
+ }
436
+ /**
437
+ * The ACQUIRE a delivery carries, so the process it is delivered to applies
438
+ * it instead of asking.
439
+ *
440
+ * A stdin packet, a child's output or exit, a request routed to a port: the
441
+ * supervisor hands each of these to a process, and the process may not run
442
+ * the code they wake until it has applied everything written before them
443
+ * (protocol §3, §5.6). Asking costs a round trip per delivery, which an
444
+ * attached terminal pays on every keystroke. But the supervisor is already
445
+ * answering: `args` are what the process would pass to fsAcquire, and
446
+ * `answer` is exactly what fsAcquire answers for them, computed here, after
447
+ * the thing delivered was queued. Every write that preceded it is in the
448
+ * answer, and the delivery carries it, so it cannot be lost or reordered
449
+ * apart from it.
450
+ *
451
+ * One format with fsAcquire's own: the same arguments, checked by the same
452
+ * schema, answered by the same function. Undefined when there is no answer
453
+ * to carry — the process sent no arguments it can be answered for, or this
454
+ * one could not be computed — and the process then asks, as it always has,
455
+ * where a failure is counted and handled. It is never a reason to fail the
456
+ * delivery: that would lose a dequeued keystroke or a routed request.
457
+ */
458
+ export async function _acquireOnDelivery(self, args, pid) {
459
+ const parsed = FsAcquireArgsSchema.safeParse(args);
460
+ if (!parsed.success)
461
+ return undefined;
462
+ const caller = pid !== undefined && pid > 0 ? pid : undefined;
463
+ try {
464
+ return {
465
+ args: parsed.data,
466
+ answer: await _rpcFsAcquire(self, parsed.data.epoch, parsed.data.cursor, parsed.data.options, caller),
467
+ };
468
+ }
469
+ catch {
470
+ return undefined;
471
+ }
472
+ }
473
+ /**
474
+ * The ACQUIRE a request routed to `pid`'s port carries. The supervisor, not
475
+ * the process, starts a request, so it holds no cursor of the process's to
476
+ * answer from, and answers from its own: "nothing since now". The process can
477
+ * use that only when it is already there, which is protocol §9.2's
478
+ * one-integer piggyback — true for any request no write preceded since the
479
+ * process last caught up — and otherwise asks.
480
+ */
481
+ export function _acquireForRoutedRequest(self, pid) {
482
+ self.ensureSqliteFs();
483
+ const vfs = self.sqliteFs;
484
+ if (!vfs)
485
+ return Promise.resolve(undefined);
486
+ return _acquireOnDelivery(self, { epoch: vfs.epoch, cursor: vfs.revision() }, pid);
375
487
  }
376
488
  /**
377
489
  * Enumerate the session filesystem for a process, one bounded page at a time.
@@ -388,10 +500,11 @@ export async function _rpcFsReadRange(self, path, offset, length, pid, cred) {
388
500
  return self.supervisorOp({ op: 'fsReadRange', args: [path, offset, length], pid, cred });
389
501
  }
390
502
  /**
391
- * Read many ranges in ONE round trip.
503
+ * Read many ranges, and lstat many paths, in ONE round trip.
392
504
  *
393
- * Every entry is the same read `_rpcFsReadRange` performs, through the same
394
- * process credential and the same live bridge, in request order. A batch is
505
+ * Every entry is the same read `_rpcFsReadRange` performs, or the same stat
506
+ * the `lstat` op performs, through the same process credential and the same
507
+ * live bridge, in request order. A batch is
395
508
  * therefore exactly as authoritative as the individual reads it replaces —
396
509
  * it takes no snapshot and consults nothing the single-read path would not.
397
510
  * What it saves is round trips, which is the whole cost of a read.
@@ -407,7 +520,7 @@ export async function _rpcFsReadRange(self, path, offset, length, pid, cred) {
407
520
  */
408
521
  export async function _rpcFsReadBatch(self, requests, pid) {
409
522
  const args = FsReadBatchArgsSchema.parse(requests);
410
- const requestedBytes = args.reduce((total, request) => total + request.length, 0);
523
+ const requestedBytes = args.reduce((total, request) => total + fsReadBatchRequestBytes(request), 0);
411
524
  if (requestedBytes > FS_READ_BATCH_REQUEST_BYTES) {
412
525
  throw new RangeError(`filesystem read batch requests ${requestedBytes} bytes across ${args.length} ranges, `
413
526
  + `over the ${FS_READ_BATCH_REQUEST_BYTES}-byte limit`);
@@ -418,6 +531,8 @@ export async function _rpcFsReadBatch(self, requests, pid) {
418
531
  const fs = self.supervisorBridge(pid);
419
532
  let residentBytes = 0;
420
533
  for (const request of args) {
534
+ if (!('length' in request))
535
+ continue;
421
536
  try {
422
537
  residentBytes += await rangeReadBytes(fs, request.path, request.offset, request.length);
423
538
  }
@@ -427,9 +542,17 @@ export async function _rpcFsReadBatch(self, requests, pid) {
427
542
  const entries = [];
428
543
  for (const request of args) {
429
544
  try {
430
- entries.push({ bytes: await fs.readRange(request.path, request.offset, request.length, {
545
+ // The lstat op's own call (supervisor-op.ts): the same answer,
546
+ // `null` for a path that is not there, carried in this trip.
547
+ if (!('length' in request)) {
548
+ entries.push({ stat: (await fs.stat(request.path, { followSymlinks: false })) ?? null });
549
+ continue;
550
+ }
551
+ // N17: bytes still being imported are waited for, not failed.
552
+ const hydrated = (path) => (typeof self.getFilesystemAuthority === 'function' ? self.getFilesystemAuthority().hydrated(path) : Promise.resolve());
553
+ entries.push({ bytes: await readHydrating(hydrated, async () => fs.readRange(request.path, request.offset, request.length, {
431
554
  expectedEpoch: request.expectedEpoch, expectedRevision: request.expectedRevision,
432
- }) });
555
+ })) });
433
556
  }
434
557
  catch (error) {
435
558
  entries.push({ error: readBatchEntryError(error) });
@@ -489,9 +612,6 @@ export async function _rpcHmrRelay(self, clientId, msg) {
489
612
  return;
490
613
  self.cirrusReal.hmr.relayToBrowser(clientId, msg);
491
614
  }
492
- export async function _rpcUnlink(self, path, pid) {
493
- await self.supervisorOp({ op: 'unlink', args: [path], pid });
494
- }
495
615
  /**
496
616
  * Bulk-write files and directories via one transactionSync().
497
617
  * Called from facets that accumulate writes locally (git clone/fetch/pull,
@@ -582,7 +702,7 @@ export async function _rpcWriteBatchStream(self, stream, mutationOwner, pid) {
582
702
  * resolver-facet to flush a wave of resolved packages back to the
583
703
  * supervisor without per-entry round-trips.
584
704
  *
585
- * Payload is the array of RegistryCacheEntry shapes from src/npm-cache.ts.
705
+ * Payload is the array of RegistryCacheEntry shapes from src/npm/cache.ts.
586
706
  * Returns { written, failed } so the facet can surface partial-write
587
707
  * warnings to the install log.
588
708
  */
@@ -683,7 +803,11 @@ function shouldMirrorProcessOutputToShell(self, pid) {
683
803
  // the prompt).
684
804
  if (!entry)
685
805
  return false;
686
- return entry.attachedTty !== true;
806
+ // An exited process's straggling writes (a timer still firing in its facet)
807
+ // would land after the shell's prompt.
808
+ if (entry.state !== 'running')
809
+ return false;
810
+ return entry.attachedTty !== true && entry.foreground !== true;
687
811
  }
688
812
  /**
689
813
  * Called by facets from their `finally` block after I/O has drained.
@@ -693,7 +817,7 @@ function shouldMirrorProcessOutputToShell(self, pid) {
693
817
  *
694
818
  * Idempotent — double-call is a no-op (ProcessLogStore.markExit guards).
695
819
  */
696
- export async function _rpcReportExit(self, pid, code, tail) {
820
+ export async function _rpcReportExit(self, pid, code, tail, residencyMisses, profileUnread) {
697
821
  if (pid <= 0)
698
822
  return; // Ignore the pid-0 sentinel.
699
823
  // Prior-generation straggler unwinding after an instance reset: this
@@ -729,8 +853,10 @@ export async function _rpcReportExit(self, pid, code, tail) {
729
853
  if (self.processes.getExit(pid))
730
854
  return;
731
855
  self.processes.markExit(pid, code);
856
+ // The reads this session served the process, taken whatever the manager does with them.
857
+ const served = self.servedReads?.take(pid) ?? new Set();
732
858
  try {
733
- self.facetManager?.noteProcessReportedExit?.(pid, code);
859
+ self.facetManager?.noteProcessReportedExit?.(pid, code, residencyMisses, { served, profileUnread: profileUnread ?? null });
734
860
  }
735
861
  catch {
736
862
  try {
@@ -967,7 +1093,7 @@ export async function _rpcTransform(self, code, loader) {
967
1093
  self.ensureSqliteFs();
968
1094
  if (!self.sqliteFs)
969
1095
  throw new Error('Session VFS is not initialized');
970
- self.esbuildService = new EsbuildService(self.sqliteFs.as(CRED_KERNEL));
1096
+ self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
971
1097
  }
972
1098
  try {
973
1099
  const result = await self.esbuildService.transform(code, {
@@ -1022,7 +1148,17 @@ export async function _rpcCpStdinEnd(self, childPid) {
1022
1148
  const fpm = self._ensureFacetProcessManager();
1023
1149
  fpm.stdinEnd(childPid);
1024
1150
  }
1025
- export async function _rpcCpReadStdin(self, childPid, waitMs) {
1151
+ /**
1152
+ * `reply`, carrying the ACQUIRE for the caller (`_acquireOnDelivery`) when it
1153
+ * delivers anything. An empty poll wakes no code, so it is answered bare.
1154
+ */
1155
+ async function withDeliveredAcquire(self, reply, delivers, acquire, pid) {
1156
+ if (!delivers)
1157
+ return reply;
1158
+ const acquired = await _acquireOnDelivery(self, acquire, pid);
1159
+ return acquired ? { ...reply, acquired } : reply;
1160
+ }
1161
+ export async function _rpcCpReadStdin(self, childPid, waitMs, acquire, pid) {
1026
1162
  // Prior-generation straggler: its ProcessInputStore died with the old
1027
1163
  // instance. Deliver a kill so the facet's stdin pump unwinds immediately
1028
1164
  // with explicit semantics (__ProcessExit(137) → reportExit → the honest
@@ -1030,18 +1166,25 @@ export async function _rpcCpReadStdin(self, childPid, waitMs) {
1030
1166
  if (isPriorGenerationPid(self, childPid)) {
1031
1167
  return { signal: 'SIGKILL', ended: true };
1032
1168
  }
1169
+ let packet;
1033
1170
  if (self.processes.hasInput(childPid)) {
1034
1171
  // The interactive input store holds text packets; the child's stdin
1035
1172
  // pump takes bytes, so this text producer encodes at its edge.
1036
- const packet = await self.processes.readInput(childPid, waitMs);
1037
- return { ...packet, data: enc.encode(packet.data) };
1173
+ const input = await self.processes.readInput(childPid, waitMs);
1174
+ packet = { ...input, data: enc.encode(input.data) };
1038
1175
  }
1039
- const fpm = self._ensureFacetProcessManager();
1040
- return fpm.cpReadStdin(childPid, waitMs);
1176
+ else {
1177
+ const fpm = self._ensureFacetProcessManager();
1178
+ packet = await fpm.cpReadStdin(childPid, waitMs);
1179
+ }
1180
+ const delivers = packet.ended || packet.signal !== undefined || packet.resize !== undefined
1181
+ || packet.data.byteLength > 0;
1182
+ return withDeliveredAcquire(self, packet, delivers, acquire, pid);
1041
1183
  }
1042
- export async function _rpcCpReadOutput(self, childPid, fd, sinceSeq, waitMs) {
1184
+ export async function _rpcCpReadOutput(self, childPid, fd, sinceSeq, waitMs, acquire, pid) {
1043
1185
  const fpm = self._ensureFacetProcessManager();
1044
- return fpm.readOutput(childPid, fd, sinceSeq, waitMs);
1186
+ const output = await fpm.readOutput(childPid, fd, sinceSeq, waitMs);
1187
+ return withDeliveredAcquire(self, output, output.chunks.length > 0 || output.closed, acquire, pid);
1045
1188
  }
1046
1189
  export async function _rpcCpDrainOutput(self, childPid) {
1047
1190
  const fpm = self._ensureFacetProcessManager();
@@ -1051,9 +1194,10 @@ export async function _rpcCpKill(self, childPid, signal) {
1051
1194
  const fpm = self._ensureFacetProcessManager();
1052
1195
  return fpm.kill(childPid, signal);
1053
1196
  }
1054
- export async function _rpcCpWait(self, childPid, waitMs) {
1197
+ export async function _rpcCpWait(self, childPid, waitMs, acquire, pid) {
1055
1198
  const fpm = self._ensureFacetProcessManager();
1056
- return fpm.wait(childPid, waitMs);
1199
+ const status = await fpm.wait(childPid, waitMs);
1200
+ return withDeliveredAcquire(self, status, status.done, acquire, pid);
1057
1201
  }
1058
1202
  /**
1059
1203
  * child-process isolation gap #1: dispatch a single cp.spawn request inline using the
@@ -1189,6 +1333,7 @@ export async function _rpcFanoutExecute(self, fnSource, args, poolOpts = {}) {
1189
1333
  // back to ctx.id.toString() — the legacy behavior, correct for
1190
1334
  // single-DO callers.
1191
1335
  supervisorDoIdOverride: poolOpts.coordinatorDoId,
1336
+ supervisorRoute: poolOpts.coordinatorRoute,
1192
1337
  supervisorPid: poolOpts.supervisorPid,
1193
1338
  });
1194
1339
  try {
@@ -1224,10 +1369,18 @@ const ResidentBootSpecSchema = residentBootSpecSchema(OpencodeStageSpecSchema);
1224
1369
  const HostProcessOptsSchema = z.object({
1225
1370
  /** Full doId of the coordinator session (SUPERVISOR routing target). */
1226
1371
  coordinatorDoId: z.string().min(1),
1372
+ /** The coordinator's route, minted into the process's SUPERVISOR binding. */
1373
+ route: z.object({
1374
+ supervisorEntrypoint: z.string().min(1),
1375
+ hostNamespace: z.string().min(1),
1376
+ hostDispatchMethod: z.string().min(1),
1377
+ }).optional(),
1227
1378
  /** Supervisor-assigned pid of the process entry on the coordinator. */
1228
1379
  pid: z.number().int().positive(),
1229
1380
  /** Trusted identity of this concrete resident-host incarnation. */
1230
1381
  writerId: z.string().uuid(),
1382
+ /** The coordinator instance's delivery incarnation, for the process's SUPERVISOR binding. */
1383
+ hostIncarnation: z.string().uuid().optional(),
1231
1384
  /** Keyed dynamic-worker identity on THIS peer's loader. */
1232
1385
  workerKey: z.string().min(1),
1233
1386
  /** Unforgeable capability for the fetch-semantic WebSocket hop. */
@@ -1264,9 +1417,9 @@ const HOSTED_RECORD_WAIT_MS = 30_000;
1264
1417
  */
1265
1418
  const RESIDENT_READ_RANGE_BYTES = 4 * 1024 * 1024;
1266
1419
  function peerDiskReader(supervisor) {
1267
- const supervisorRpc = supervisorEntrypoint();
1420
+ const supervisorRpc = supervisorEntrypoint(undefined, supervisor.route?.supervisorEntrypoint);
1268
1421
  if (!supervisorRpc) {
1269
- throw new Error('Nimbus: ctx.exports.SupervisorRPC unavailable');
1422
+ throw new Error(`Nimbus: ctx.exports.${supervisor.route?.supervisorEntrypoint ?? 'SupervisorRPC'} unavailable`);
1270
1423
  }
1271
1424
  const fs = supervisorRpc({ props: supervisor });
1272
1425
  return { readFile: (path) => readSupervisorFile(fs, path) };
@@ -1366,6 +1519,8 @@ export async function _rpcHostProcess(self, boot, opts) {
1366
1519
  doId: hostOpts.coordinatorDoId,
1367
1520
  pid: hostOpts.pid,
1368
1521
  writerId: hostOpts.writerId,
1522
+ route: hostOpts.route,
1523
+ ...(hostOpts.hostIncarnation === undefined ? {} : { hostIncarnation: hostOpts.hostIncarnation }),
1369
1524
  };
1370
1525
  let cancel = () => { };
1371
1526
  const cancelled = new Promise((resolve) => { cancel = resolve; });
@@ -16,7 +16,7 @@
16
16
  * such session was unrecoverable after eviction.
17
17
  */
18
18
  import { CRED_KERNEL } from '@nimbus-sh/core/runtime/os-contracts.js';
19
- import { EsbuildService } from '@nimbus-sh/core/runtime/esbuild-service.js';
19
+ import { supervisorEsbuildService } from '../facets/esbuild-transform.js';
20
20
  import { rewriteCirrusViteConfigBundle } from '@nimbus-sh/core/runtime/cirrus-vite-config-rewriter.js';
21
21
  import { CirrusReal } from '../facets/cirrus-real.js';
22
22
  import { makeLongRunningPortStub } from '@nimbus-sh/core/runtime/long-running-handle.js';
@@ -53,7 +53,7 @@ export async function startRealVite(self, opts) {
53
53
  if (cfgPath) {
54
54
  try {
55
55
  if (!self.esbuildService)
56
- self.esbuildService = new EsbuildService(kernelFs);
56
+ self.esbuildService = supervisorEsbuildService(self.ctx, self.env, self.getFilesystemAuthority().namespaceFs(CRED_KERNEL));
57
57
  const bundleResult = await self.esbuildService.build([cfgPath], {
58
58
  bundle: true,
59
59
  format: 'esm',
@@ -8,7 +8,7 @@
8
8
  * isolate memory: the LIFO Shell instance owned cwd + env vars; the
9
9
  * LIFO Kernel owned mount points; the WebSocketTerminal had no
10
10
  * persistence at all. A wsClose / wsError nulled all three
11
- * (src/nimbus-session-ws.ts:165-167, :221-223), and the next /ws
11
+ * (src/session/ws.ts), and the next /ws
12
12
  * upgrade rebuilt them from defaults. Result: cwd reset to ~,
13
13
  * env vars lost, scrollback gone, MOTD reprinted — the user-
14
14
  * visible Bug C symptom.
@@ -27,7 +27,6 @@
27
27
  * — generic key/value bag for primitives. Today stores 'cwd'
28
28
  * and 'env' (the env is JSON-serialised). One row per key.
29
29
  *
30
- * nimbus_kernel_mounts (mount_point TEXT PRIMARY KEY)
31
30
  * — explicit mount-point list (B'.2). Empty until B'.2 lands.
32
31
  *
33
32
  * nimbus_terminal_scrollback (seq INTEGER PRIMARY KEY, ts INTEGER, data TEXT)
@@ -158,21 +157,6 @@ export declare function clearSessionState(ctx: any): void;
158
157
  * recorder to populate snapshotKeysRehydrated. Cheap; bounded by
159
158
  * the small key set above. */
160
159
  export declare function countSessionStateKeys(ctx: any): number;
161
- /**
162
- * Load the persisted mount-point list. Returns a plain string[] of
163
- * mount point names (without leading slash — same shape as
164
- * DEFAULT_MOUNT_POINTS). Empty array when no rows exist.
165
- */
166
- export declare function loadKernelMounts(ctx: any): string[];
167
- /**
168
- * Persist a mount-point list. Idempotent — replaces the entire
169
- * nimbus_kernel_mounts contents in a single transaction. Caller
170
- * provides the full desired set; we don't merge with existing rows.
171
- *
172
- * `mounts` should be plain names without leading slash
173
- * ('bin', 'etc', ...) — same shape DEFAULT_MOUNT_POINTS uses.
174
- */
175
- export declare function persistKernelMounts(ctx: any, mounts: string[]): void;
176
160
  /**
177
161
  * Append one coalesced output frame. Inserts a row, then evicts the
178
162
  * oldest rows until total bytes ≤ SCROLLBACK_MAX_BYTES.
@@ -1 +1 @@
1
- {"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/session/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH;;;;;;;;iDAQiD;AACjD,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;qEAyBqE;AACrE,eAAO,MAAM,oBAAoB,QAAc,CAAC;AAChD;;;;;;aAMa;AACb,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAErD;mCACmC;AACnC,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,YAAY,QAAQ,CAAC;AAClC,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;iDAE6C;IAC7C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAiCvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CAqC3D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;CAAE,GAChE,IAAI,CA6BN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQ5D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAOhD;AAED;;+BAE+B;AAC/B,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAQtD;AAaD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,EAAE,CAWnD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAcpE;AAwBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CA6E3E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAW/C;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;CAC/C,CAaA"}
1
+ {"version":3,"file":"state-store.d.ts","sourceRoot":"","sources":["../../src/session/state-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH;;;;;;;;iDAQiD;AACjD,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;qEAyBqE;AACrE,eAAO,MAAM,oBAAoB,QAAc,CAAC;AAChD;;;;;;aAMa;AACb,eAAO,MAAM,0BAA0B,QAAa,CAAC;AAErD;mCACmC;AACnC,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,YAAY,QAAQ,CAAC;AAClC,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,2EAA2E;AAC3E,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;iDAE6C;IAC7C,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CA+BvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,kBAAkB,CAqC3D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;CAAE,GAChE,IAAI,CA6BN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQ5D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAMhD;AAED;;+BAE+B;AAC/B,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAQtD;AAwBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CA6E3E;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAW/C;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;CAC/C,CAaA"}
@@ -8,7 +8,7 @@
8
8
  * isolate memory: the LIFO Shell instance owned cwd + env vars; the
9
9
  * LIFO Kernel owned mount points; the WebSocketTerminal had no
10
10
  * persistence at all. A wsClose / wsError nulled all three
11
- * (src/nimbus-session-ws.ts:165-167, :221-223), and the next /ws
11
+ * (src/session/ws.ts), and the next /ws
12
12
  * upgrade rebuilt them from defaults. Result: cwd reset to ~,
13
13
  * env vars lost, scrollback gone, MOTD reprinted — the user-
14
14
  * visible Bug C symptom.
@@ -27,7 +27,6 @@
27
27
  * — generic key/value bag for primitives. Today stores 'cwd'
28
28
  * and 'env' (the env is JSON-serialised). One row per key.
29
29
  *
30
- * nimbus_kernel_mounts (mount_point TEXT PRIMARY KEY)
31
30
  * — explicit mount-point list (B'.2). Empty until B'.2 lands.
32
31
  *
33
32
  * nimbus_terminal_scrollback (seq INTEGER PRIMARY KEY, ts INTEGER, data TEXT)
@@ -102,11 +101,11 @@ export function ensureSessionStateSchema(ctx) {
102
101
  const sql = ctx?.storage?.sql;
103
102
  if (!sql)
104
103
  return;
104
+ // The kernel's mount list, retired with the kernel filesystem.
105
+ sql.exec('DROP TABLE IF EXISTS nimbus_kernel_mounts');
105
106
  sql.exec('CREATE TABLE IF NOT EXISTS nimbus_session_kv (' +
106
107
  'k TEXT PRIMARY KEY, ' +
107
108
  'v TEXT NOT NULL)');
108
- sql.exec('CREATE TABLE IF NOT EXISTS nimbus_kernel_mounts (' +
109
- 'mount_point TEXT PRIMARY KEY)');
110
109
  sql.exec('CREATE TABLE IF NOT EXISTS nimbus_terminal_scrollback (' +
111
110
  'seq INTEGER PRIMARY KEY AUTOINCREMENT, ' +
112
111
  'ts INTEGER NOT NULL, ' +
@@ -243,7 +242,6 @@ export function clearSessionState(ctx) {
243
242
  return;
244
243
  ensureSessionStateSchema(ctx);
245
244
  sql.exec('DELETE FROM nimbus_session_kv');
246
- sql.exec('DELETE FROM nimbus_kernel_mounts');
247
245
  sql.exec('DELETE FROM nimbus_terminal_scrollback');
248
246
  }
249
247
  /** Count rows in nimbus_session_kv — used by the recovery_event
@@ -259,54 +257,6 @@ export function countSessionStateKeys(ctx) {
259
257
  }
260
258
  return 0;
261
259
  }
262
- // ── Kernel mount tree [B'.2] ───────────────────────────────────────────
263
- //
264
- // The kernel mount list lives in nimbus_kernel_mounts. Today the list
265
- // is exactly DEFAULT_MOUNT_POINTS (a static constant in src/constants.ts),
266
- // so persistence is functionally redundant — every initSession would
267
- // rebuild the same list from the constant. The architectural reason to
268
- // route mount-list reads through SQL anyway is to give a future
269
- // custom-mount feature a stable storage surface: when `mount /r2-cache`
270
- // is added later, it just inserts a row, and the rehydrate path picks
271
- // it up without any further refactor.
272
- /**
273
- * Load the persisted mount-point list. Returns a plain string[] of
274
- * mount point names (without leading slash — same shape as
275
- * DEFAULT_MOUNT_POINTS). Empty array when no rows exist.
276
- */
277
- export function loadKernelMounts(ctx) {
278
- const sql = ctx?.storage?.sql;
279
- if (!sql)
280
- return [];
281
- ensureSessionStateSchema(ctx);
282
- const out = [];
283
- for (const row of sql.exec('SELECT mount_point FROM nimbus_kernel_mounts ORDER BY mount_point ASC')) {
284
- out.push(String(row.mount_point));
285
- }
286
- return out;
287
- }
288
- /**
289
- * Persist a mount-point list. Idempotent — replaces the entire
290
- * nimbus_kernel_mounts contents in a single transaction. Caller
291
- * provides the full desired set; we don't merge with existing rows.
292
- *
293
- * `mounts` should be plain names without leading slash
294
- * ('bin', 'etc', ...) — same shape DEFAULT_MOUNT_POINTS uses.
295
- */
296
- export function persistKernelMounts(ctx, mounts) {
297
- const sql = ctx?.storage?.sql;
298
- if (!sql)
299
- return;
300
- ensureSessionStateSchema(ctx);
301
- // Replace-all semantics: clear, then insert. The whole table is
302
- // bounded by O(10) rows so a full rewrite per persist is cheap.
303
- sql.exec('DELETE FROM nimbus_kernel_mounts');
304
- for (const mp of mounts) {
305
- if (typeof mp !== 'string' || mp.length === 0)
306
- continue;
307
- sql.exec('INSERT OR REPLACE INTO nimbus_kernel_mounts (mount_point) VALUES (?)', mp);
308
- }
309
- }
310
260
  // ── Terminal scrollback [B'.3] ─────────────────────────────────────────
311
261
  //
312
262
  // Every coalesced WS `output` frame (post-flush) is appended as one
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import { type SupervisorOpBridgeStore, type SupervisorOpEnvelope, type SupervisorOpHost } from '@nimbus-sh/core/workspace/supervisor-op.js';
19
19
  import type { RuntimeFsBridge, NimbusFilesystemAuthority } from '@nimbus-sh/core/runtime/os-contracts.js';
20
+ import type { SupervisorDeliveries } from '@nimbus-sh/core/workspace/supervisor-delivery.js';
20
21
  import type { SqliteVFS } from '@nimbus-sh/core/vfs/sqlite-vfs.js';
21
22
  import type { SessionProcessSupervisor } from '@nimbus-sh/core/runtime/session-process-supervisor.js';
22
23
  /**
@@ -33,6 +34,12 @@ export interface SessionSupervisorHost {
33
34
  filesystem: NimbusFilesystemAuthority;
34
35
  } | null;
35
36
  getFilesystemAuthority?(): NimbusFilesystemAuthority;
37
+ /**
38
+ * This instance's receipts for mutations its processes deliver exactly
39
+ * once, opened with `openSupervisorDeliveries(ctx)` before anything is
40
+ * spawned. Absent, the session serves no delivered mutation.
41
+ */
42
+ readonly supervisorDeliveries?: SupervisorDeliveries;
36
43
  _rpcStdout(pid: number, data: Uint8Array): Promise<void>;
37
44
  _rpcStderr(pid: number, data: Uint8Array): Promise<void>;
38
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"supervisor-op.d.ts","sourceRoot":"","sources":["../../src/session/supervisor-op.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAEzB,KAAK,gBAAgB,EAGtB,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AAC1G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AAGtG;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,cAAc,IAAI,IAAI,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,wBAAwB,CAAC;IAC7C,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,UAAU,EAAE,yBAAyB,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7E,sBAAsB,CAAC,IAAI,yBAAyB,CAAC;IACrD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,eAAe,CAAC;IACnD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAQD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,qBAAqB,EAC3B,KAAK,CAAC,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,gBAAgB,GACzB,oBAAoB,CA8CtB"}
1
+ {"version":3,"file":"supervisor-op.d.ts","sourceRoot":"","sources":["../../src/session/supervisor-op.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAEzB,KAAK,gBAAgB,EAGtB,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AAC1G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kDAAkD,CAAC;AAC7F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AAGtG;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,cAAc,IAAI,IAAI,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,wBAAwB,CAAC;IAC7C,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,UAAU,EAAE,yBAAyB,CAAA;KAAE,GAAG,IAAI,CAAC;IAC7E,sBAAsB,CAAC,IAAI,yBAAyB,CAAC;IACrD;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IACrD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,eAAe,CAAC;IACnD,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAQD,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,qBAAqB,EAC3B,KAAK,CAAC,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,gBAAgB,GACzB,oBAAoB,CAmDtB"}
@@ -70,6 +70,11 @@ export function buildSessionSupervisorOps(host, store, methods) {
70
70
  // Every native read holds a lease for the payload it can answer with.
71
71
  readLease: withReadAllocation,
72
72
  extend,
73
+ deliveries: host.supervisorDeliveries,
73
74
  });
74
- return { dispatch, bridge: store.bridge, forget: store.forget, dispose: store.dispose };
75
+ const forget = (pid) => {
76
+ host.supervisorDeliveries?.forget(pid);
77
+ return store.forget(pid);
78
+ };
79
+ return { dispatch, bridge: store.bridge, forget, dispose: store.dispose };
75
80
  }