@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.
- package/NOTICE.md +5 -0
- package/README.md +10 -0
- package/dist/_shared/session-router.d.ts +7 -0
- package/dist/_shared/session-router.d.ts.map +1 -1
- package/dist/_shared/session-router.js +7 -0
- package/dist/bindings/body.d.ts +6 -0
- package/dist/bindings/body.d.ts.map +1 -0
- package/dist/bindings/body.js +37 -0
- package/dist/bindings/kv.d.ts +0 -2
- package/dist/bindings/kv.d.ts.map +1 -1
- package/dist/bindings/kv.js +3 -42
- package/dist/bindings/r2.d.ts +0 -2
- package/dist/bindings/r2.d.ts.map +1 -1
- package/dist/bindings/r2.js +4 -44
- package/dist/esbuild-cli-artifact.generated.d.ts +18 -0
- package/dist/esbuild-cli-artifact.generated.d.ts.map +1 -0
- package/dist/esbuild-cli-artifact.generated.js +17 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +24 -24
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
- package/dist/esbuild-wasm-bundle.generated.js +24 -24
- package/dist/facets/cirrus-real.d.ts.map +1 -1
- package/dist/facets/cirrus-real.js +11 -6
- package/dist/facets/compose.d.ts +11 -7
- package/dist/facets/compose.d.ts.map +1 -1
- package/dist/facets/compose.js +8 -31
- package/dist/facets/data-plan.d.ts +79 -0
- package/dist/facets/data-plan.d.ts.map +1 -0
- package/dist/facets/data-plan.js +477 -0
- package/dist/facets/esbuild-bundle-pool.d.ts +1 -1
- package/dist/facets/esbuild-bundle-pool.js +3 -3
- package/dist/facets/esbuild-transform.d.ts +38 -8
- package/dist/facets/esbuild-transform.d.ts.map +1 -1
- package/dist/facets/esbuild-transform.js +219 -19
- package/dist/facets/exec-telemetry.d.ts +7 -3
- package/dist/facets/exec-telemetry.d.ts.map +1 -1
- package/dist/facets/manager.d.ts +198 -69
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +1276 -652
- package/dist/facets/opencode-staging.d.ts +0 -2
- package/dist/facets/opencode-staging.d.ts.map +1 -1
- package/dist/facets/opencode-staging.js +5 -11
- package/dist/facets/process.d.ts +4 -0
- package/dist/facets/process.d.ts.map +1 -1
- package/dist/facets/process.js +3 -0
- package/dist/facets/read-profile.d.ts +149 -0
- package/dist/facets/read-profile.d.ts.map +1 -0
- package/dist/facets/read-profile.js +483 -0
- package/dist/facets/real-vite-hmr.d.ts +2 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -1
- package/dist/facets/real-vite-hmr.js +3 -2
- package/dist/facets/resident-identity.d.ts +0 -1
- package/dist/facets/resident-identity.d.ts.map +1 -1
- package/dist/facets/resident-identity.js +0 -3
- package/dist/facets/wasm-swap-registry.d.ts +34 -25
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
- package/dist/facets/wasm-swap-registry.js +62 -56
- package/dist/facets/ws-terminal.d.ts +4 -4
- package/dist/facets/ws-terminal.d.ts.map +1 -1
- package/dist/facets/ws-terminal.js +4 -5
- package/dist/git/commands.d.ts +33 -10
- package/dist/git/commands.d.ts.map +1 -1
- package/dist/git/commands.js +1891 -197
- package/dist/git/network-facet.d.ts +12 -2
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +69 -18
- package/dist/git/unified-diff.d.ts +74 -0
- package/dist/git/unified-diff.d.ts.map +1 -0
- package/dist/git/unified-diff.js +676 -0
- package/dist/git-bundle.generated.d.ts +7 -11
- package/dist/git-bundle.generated.d.ts.map +1 -1
- package/dist/git-bundle.generated.js +7 -11
- package/dist/hosted/commands.d.ts.map +1 -1
- package/dist/hosted/commands.js +64 -245
- package/dist/hosted/runtime.d.ts +22 -15
- package/dist/hosted/runtime.d.ts.map +1 -1
- package/dist/hosted/runtime.js +72 -14
- package/dist/hosted/services.d.ts +8 -1
- package/dist/hosted/services.d.ts.map +1 -1
- package/dist/hosted/services.js +12 -13
- package/dist/hosted/session.d.ts +165 -0
- package/dist/hosted/session.d.ts.map +1 -0
- package/dist/hosted/session.js +132 -0
- package/dist/loaders/generated-workers.d.ts +6 -3
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +8 -5
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
- package/dist/loaders/npm-resolve-preamble.js +0 -27
- package/dist/loaders/pre-bundle-preamble.d.ts +6 -3
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -1
- package/dist/loaders/pre-bundle-preamble.js +13 -8
- package/dist/node-shims-artifact.generated.d.ts +13 -4
- package/dist/node-shims-artifact.generated.d.ts.map +1 -1
- package/dist/node-shims-artifact.generated.js +16 -7
- package/dist/npm/bin-links.d.ts +3 -1
- package/dist/npm/bin-links.d.ts.map +1 -1
- package/dist/npm/bin-links.js +32 -8
- package/dist/npm/cache.d.ts +11 -1
- package/dist/npm/cache.d.ts.map +1 -1
- package/dist/npm/cache.js +21 -7
- package/dist/npm/install-batch-facet.d.ts +4 -2
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +32 -18
- package/dist/npm/installer.d.ts +23 -3
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +330 -131
- package/dist/npm/npx-install.d.ts +3 -1
- package/dist/npm/npx-install.d.ts.map +1 -1
- package/dist/npm/npx-install.js +4 -1
- package/dist/npm/package-lock.d.ts +32 -0
- package/dist/npm/package-lock.d.ts.map +1 -0
- package/dist/npm/package-lock.js +65 -0
- package/dist/npm/placement.d.ts +16 -0
- package/dist/npm/placement.d.ts.map +1 -0
- package/dist/npm/placement.js +33 -0
- package/dist/npm/pre-bundle-facet.d.ts +1 -30
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
- package/dist/npm/pre-bundle-facet.js +3 -5
- package/dist/npm/r2-cache.d.ts +12 -6
- package/dist/npm/r2-cache.d.ts.map +1 -1
- package/dist/npm/r2-cache.js +34 -16
- package/dist/npm/resolve-one-facet.d.ts +3 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +15 -3
- package/dist/npm/resolver.d.ts +11 -13
- package/dist/npm/resolver.d.ts.map +1 -1
- package/dist/npm/resolver.js +12 -25
- package/dist/opencode-artifact.generated.js +2 -2
- package/dist/replica/routing.d.ts +2 -38
- package/dist/replica/routing.d.ts.map +1 -1
- package/dist/replica/routing.js +3 -55
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +15 -2
- package/dist/router/public-directory.d.ts +18 -0
- package/dist/router/public-directory.d.ts.map +1 -1
- package/dist/router/public-directory.js +1 -1
- package/dist/router/remote-api.d.ts +3 -1
- package/dist/router/remote-api.d.ts.map +1 -1
- package/dist/router/remote-api.js +42 -79
- package/dist/runtime/bash-repl.js +2 -2
- package/dist/runtime/bun-repl.d.ts.map +1 -1
- package/dist/runtime/bun-repl.js +2 -13
- package/dist/runtime/cpython-resident.d.ts.map +1 -1
- package/dist/runtime/cpython-resident.js +2 -10
- package/dist/runtime/esbuild-wasm-bytes.d.ts +37 -18
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/esbuild-wasm-bytes.js +66 -92
- package/dist/runtime/facet-loader-host.d.ts.map +1 -1
- package/dist/runtime/facet-loader-host.js +0 -7
- package/dist/runtime/git-bundle-artifact.d.ts +17 -0
- package/dist/runtime/git-bundle-artifact.d.ts.map +1 -0
- package/dist/runtime/git-bundle-artifact.js +25 -0
- package/dist/runtime/node-repl.d.ts.map +1 -1
- package/dist/runtime/node-repl.js +2 -13
- package/dist/runtime/node-shims-artifact.d.ts +22 -23
- package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
- package/dist/runtime/node-shims-artifact.js +48 -78
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +2358 -996
- package/dist/runtime/opencode-artifact.d.ts.map +1 -1
- package/dist/runtime/opencode-artifact.js +17 -53
- package/dist/runtime/opencode-facet-runner.d.ts +3 -6
- package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
- package/dist/runtime/opencode-facet-runner.js +45 -10
- package/dist/runtime/opentui-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/opentui-wasm-bytes.js +16 -49
- package/dist/runtime/package-manager.d.ts +0 -2
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +0 -3
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +4 -35
- package/dist/runtime/repl-session.d.ts +10 -0
- package/dist/runtime/repl-session.d.ts.map +1 -1
- package/dist/runtime/repl-session.js +7 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -1
- package/dist/runtime/ruby-repl.js +2 -2
- package/dist/runtime/ruby-resident.d.ts.map +1 -1
- package/dist/runtime/ruby-resident.js +41 -51
- package/dist/runtime/runtime-catalog.d.ts +10 -3
- package/dist/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/runtime/runtime-catalog.js +125 -15
- package/dist/runtime/sqlite-wasm-bytes.d.ts +4 -4
- package/dist/runtime/sqlite-wasm-bytes.d.ts.map +1 -1
- package/dist/runtime/sqlite-wasm-bytes.js +21 -57
- package/dist/runtime/staged-source.d.ts +67 -0
- package/dist/runtime/staged-source.d.ts.map +1 -0
- package/dist/runtime/staged-source.js +113 -0
- package/dist/runtime/wasi/preamble.d.ts +0 -22
- package/dist/runtime/wasi/preamble.d.ts.map +1 -1
- package/dist/runtime/wasi/preamble.js +98 -1425
- package/dist/runtime-catalog.generated.js +1 -1
- package/dist/session/agent.d.ts +14 -2
- package/dist/session/agent.d.ts.map +1 -1
- package/dist/session/agent.js +57 -19
- package/dist/session/ai.d.ts +0 -11
- package/dist/session/ai.d.ts.map +1 -1
- package/dist/session/ai.js +0 -4
- package/dist/session/fs-watch.d.ts +0 -11
- package/dist/session/fs-watch.d.ts.map +1 -1
- package/dist/session/fs-watch.js +0 -21
- package/dist/session/hibernation.d.ts +68 -2
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +95 -1
- package/dist/session/init-phases.d.ts +1 -2
- package/dist/session/init-phases.d.ts.map +1 -1
- package/dist/session/init-phases.js +1 -2
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +7 -20
- package/dist/session/keys.d.ts +0 -3
- package/dist/session/keys.d.ts.map +1 -1
- package/dist/session/keys.js +0 -3
- package/dist/session/legacy-reset.d.ts +11 -0
- package/dist/session/legacy-reset.d.ts.map +1 -0
- package/dist/session/legacy-reset.js +16 -0
- package/dist/session/nimbus-session.d.ts +50 -16
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +77 -71
- package/dist/session/npm-install-port.d.ts.map +1 -1
- package/dist/session/npm-install-port.js +2 -0
- package/dist/session/programmatic.d.ts +13 -18
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +53 -39
- package/dist/session/replica-routes.d.ts +2 -3
- package/dist/session/replica-routes.d.ts.map +1 -1
- package/dist/session/replica-routes.js +3 -10
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +11 -12
- package/dist/session/rpc.d.ts +108 -21
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +194 -39
- package/dist/session/start-real-vite.js +2 -2
- package/dist/session/state-store.d.ts +1 -17
- package/dist/session/state-store.d.ts.map +1 -1
- package/dist/session/state-store.js +3 -53
- package/dist/session/supervisor-op.d.ts +7 -0
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +6 -1
- package/dist/session/supervisor-rpc.d.ts +116 -19
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +194 -84
- package/dist/session/vite-command.d.ts.map +1 -1
- package/dist/session/vite-command.js +17 -14
- package/dist/session/ws.d.ts.map +1 -1
- package/dist/session/ws.js +20 -8
- package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
- package/dist/shell/npm-bin-entrypoints.js +30 -5
- package/dist/vfs/facet-resident-limits.d.ts +33 -0
- package/dist/vfs/facet-resident-limits.d.ts.map +1 -0
- package/dist/vfs/facet-resident-limits.js +33 -0
- package/dist/vfs/facet-resident-store.d.ts +2 -10
- package/dist/vfs/facet-resident-store.d.ts.map +1 -1
- package/dist/vfs/facet-resident-store.js +1594 -219
- package/dist/workspace-host.d.ts +3 -1
- package/dist/workspace-host.d.ts.map +1 -1
- package/dist/workspace-host.js +2 -0
- package/dist/wrangler/nimbus-wrangler.d.ts +0 -2
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
- package/dist/wrangler/nimbus-wrangler.js +8 -22
- package/package.json +34 -7
- package/public/_assets/esbuild-0.24.2.js +2380 -0
- package/public/_assets/opencode/1.16.2/index-attach.js +2 -2
- package/public/_assets/runtime/esbuild-cli-c4fda380d52befc1.js +6892 -0
- package/public/_assets/runtime/git-de3e60c9f3ff006a.js +103 -0
- package/public/_assets/runtime/{node-shims-acaa037e6d26ec0d.js → node-shims-06565b121555c194.js} +2879 -992
- package/public/_assets/runtime/resident-store-6ffb1939c53d982f.js +2264 -0
- package/public/_assets/runtime/vfs-write-ledger-e501e8fc793bc2c1.js +889 -0
- package/scripts/build-opencode-attach-entry.mjs +51 -1
- package/scripts/bundle-esbuild-wasm.mjs +55 -39
- package/scripts/bundle-facet-workers.mjs +159 -10
- package/scripts/bundle-git.mjs +88 -27
- package/scripts/bundle-node-shims.mjs +72 -46
- package/scripts/bundle-runtime.mjs +18 -421
- package/scripts/cf-git-patch.mjs +137 -0
- package/scripts/patch-install-deps.mjs +49 -96
- package/scripts/runtime-specs.mjs +435 -0
- package/vendor/git-http.generated.d.ts +82 -0
- package/vendor/git-upstream.generated.d.ts +4378 -0
- package/vendor/git.LICENSE +7 -0
- package/vendor/git.generated.d.mts +21 -0
- package/vendor/git.generated.mjs +103 -0
- package/dist/replica/suspension.d.ts +0 -36
- package/dist/replica/suspension.d.ts.map +0 -1
- package/dist/replica/suspension.js +0 -49
- package/dist/runtime/static-server.d.ts +0 -3
- package/dist/runtime/static-server.d.ts.map +0 -1
- package/dist/runtime/static-server.js +0 -133
- package/scripts/clean-dist.mjs +0 -7
package/dist/session/rpc.js
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
})
|
|
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,
|
|
394
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
1037
|
-
|
|
1173
|
+
const input = await self.processes.readInput(childPid, waitMs);
|
|
1174
|
+
packet = { ...input, data: enc.encode(input.data) };
|
|
1038
1175
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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 {
|
|
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 =
|
|
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/
|
|
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
|
|
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/
|
|
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,
|
|
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
|
-
|
|
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
|
}
|