@nimbus-sh/worker 0.6.0 → 0.8.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/README.md +2 -2
- package/dist/cirrus-npm-cjs.generated.d.ts +1 -1
- package/dist/cirrus-npm-cjs.generated.js +1 -1
- package/dist/facets/cirrus-real.d.ts.map +1 -1
- package/dist/facets/cirrus-real.js +6 -5
- package/dist/facets/compose.d.ts +148 -0
- package/dist/facets/compose.d.ts.map +1 -0
- package/dist/facets/compose.js +146 -0
- package/dist/facets/durable-images.d.ts +9 -5
- package/dist/facets/durable-images.d.ts.map +1 -1
- package/dist/facets/durable-images.js +17 -7
- package/dist/facets/esbuild-bundle-pool.d.ts +49 -0
- package/dist/facets/esbuild-bundle-pool.d.ts.map +1 -0
- package/dist/facets/esbuild-bundle-pool.js +122 -0
- package/dist/facets/exec-telemetry.d.ts +8 -0
- package/dist/facets/exec-telemetry.d.ts.map +1 -1
- package/dist/facets/manager.d.ts +240 -109
- package/dist/facets/manager.d.ts.map +1 -1
- package/dist/facets/manager.js +677 -342
- package/dist/facets/process.d.ts +20 -16
- package/dist/facets/process.d.ts.map +1 -1
- package/dist/facets/process.js +59 -28
- package/dist/facets/real-vite-fs-shim.js +2 -2
- package/dist/facets/real-vite-hmr.d.ts +3 -1
- package/dist/facets/real-vite-hmr.d.ts.map +1 -1
- package/dist/facets/real-vite-hmr.js +18 -8
- package/dist/facets/vite-dev-server.d.ts +25 -47
- package/dist/facets/vite-dev-server.d.ts.map +1 -1
- package/dist/facets/vite-dev-server.js +185 -219
- package/dist/facets/wasm-image-digest.d.ts +25 -0
- package/dist/facets/wasm-image-digest.d.ts.map +1 -0
- package/dist/facets/wasm-image-digest.js +25 -0
- package/dist/facets/wasm-swap-registry.d.ts +51 -92
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
- package/dist/facets/wasm-swap-registry.js +68 -227
- package/dist/facets/ws-terminal.d.ts +9 -31
- package/dist/facets/ws-terminal.d.ts.map +1 -1
- package/dist/facets/ws-terminal.js +58 -51
- package/dist/git/network-facet.d.ts.map +1 -1
- package/dist/git/network-facet.js +6 -5
- package/dist/hosted/commands.d.ts +12 -0
- package/dist/hosted/commands.d.ts.map +1 -0
- package/dist/hosted/commands.js +1658 -0
- package/dist/hosted/runtime.d.ts +114 -0
- package/dist/hosted/runtime.d.ts.map +1 -0
- package/dist/hosted/runtime.js +288 -0
- package/dist/hosted/services.d.ts +40 -0
- package/dist/hosted/services.d.ts.map +1 -0
- package/dist/hosted/services.js +512 -0
- package/dist/loaders/child-process/spawn-pool.d.ts +3 -2
- package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
- package/dist/loaders/child-process/spawn-pool.js +3 -2
- package/dist/loaders/generated-workers.d.ts +2 -2
- package/dist/loaders/generated-workers.d.ts.map +1 -1
- package/dist/loaders/generated-workers.js +3 -3
- package/dist/loaders/npm-resolve-preamble.d.ts +3 -6
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
- package/dist/loaders/npm-resolve-preamble.js +34 -108
- package/dist/node-shims-artifact.generated.js +3 -3
- package/dist/npm/install-batch-facet.d.ts +3 -2
- package/dist/npm/install-batch-facet.d.ts.map +1 -1
- package/dist/npm/install-batch-facet.js +45 -15
- package/dist/npm/installer.d.ts +22 -17
- package/dist/npm/installer.d.ts.map +1 -1
- package/dist/npm/installer.js +209 -193
- package/dist/npm/pre-bundle-facet.d.ts +1 -1
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
- package/dist/npm/pre-bundle-facet.js +1 -1
- package/dist/npm/resolve-facet.d.ts +6 -0
- package/dist/npm/resolve-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.d.ts +21 -20
- package/dist/npm/resolve-one-facet.d.ts.map +1 -1
- package/dist/npm/resolve-one-facet.js +85 -84
- package/dist/npm/semver.d.ts +59 -0
- package/dist/npm/semver.d.ts.map +1 -0
- package/dist/npm/semver.js +226 -0
- package/dist/router/remote-api.js +31 -1
- package/dist/runtime/bash-repl.d.ts +1 -1
- package/dist/runtime/bash-repl.d.ts.map +1 -1
- package/dist/runtime/bash-repl.js +38 -4
- package/dist/runtime/bun-runner.js +1 -1
- package/dist/runtime/html-entrypoint.d.ts +7 -0
- package/dist/runtime/html-entrypoint.d.ts.map +1 -1
- package/dist/runtime/html-entrypoint.js +18 -2
- package/dist/runtime/node-runner.d.ts +4 -1
- package/dist/runtime/node-runner.d.ts.map +1 -1
- package/dist/runtime/node-runner.js +9 -2
- package/dist/runtime/node-shims.d.ts.map +1 -1
- package/dist/runtime/node-shims.js +305 -29
- package/dist/runtime/opencode-facet-runner.js +16 -16
- package/dist/runtime/package-manager.d.ts +35 -122
- package/dist/runtime/package-manager.d.ts.map +1 -1
- package/dist/runtime/package-manager.js +61 -596
- package/dist/runtime/process-logs-api.d.ts +1 -1
- package/dist/runtime/process-logs-api.d.ts.map +1 -1
- package/dist/runtime/process-logs-api.js +1 -1
- package/dist/runtime/python-repl.d.ts +2 -1
- package/dist/runtime/python-repl.d.ts.map +1 -1
- package/dist/runtime/python-repl.js +82 -59
- package/dist/runtime/repl-session.d.ts +9 -47
- package/dist/runtime/repl-session.d.ts.map +1 -1
- package/dist/runtime/repl-session.js +105 -105
- package/dist/runtime/runtime-catalog.d.ts +13 -0
- package/dist/runtime/runtime-catalog.d.ts.map +1 -1
- package/dist/runtime/runtime-catalog.js +88 -0
- package/dist/session/agent.d.ts +1 -21
- package/dist/session/agent.d.ts.map +1 -1
- package/dist/session/ai.d.ts +5 -1
- package/dist/session/ai.d.ts.map +1 -1
- package/dist/session/ai.js +7 -0
- package/dist/session/helpers.d.ts +38 -0
- package/dist/session/helpers.d.ts.map +1 -1
- package/dist/session/helpers.js +76 -0
- package/dist/session/hibernation.d.ts +2 -1
- package/dist/session/hibernation.d.ts.map +1 -1
- package/dist/session/hibernation.js +7 -4
- package/dist/session/init-phases.d.ts +1 -1
- package/dist/session/init-phases.d.ts.map +1 -1
- package/dist/session/init-phases.js +2 -12
- package/dist/session/init.d.ts +15 -36
- package/dist/session/init.d.ts.map +1 -1
- package/dist/session/init.js +50 -2327
- package/dist/session/loopback.d.ts +2 -29
- package/dist/session/loopback.d.ts.map +1 -1
- package/dist/session/loopback.js +3 -27
- package/dist/session/nimbus-session.d.ts +77 -34
- package/dist/session/nimbus-session.d.ts.map +1 -1
- package/dist/session/nimbus-session.js +126 -514
- package/dist/session/npm-install-port.d.ts +18 -0
- package/dist/session/npm-install-port.d.ts.map +1 -0
- package/dist/session/npm-install-port.js +37 -0
- package/dist/session/port-capability.d.ts +44 -0
- package/dist/session/port-capability.d.ts.map +1 -1
- package/dist/session/port-capability.js +110 -0
- package/dist/session/programmatic.d.ts +36 -43
- package/dist/session/programmatic.d.ts.map +1 -1
- package/dist/session/programmatic.js +109 -115
- package/dist/session/routes.d.ts +30 -17
- package/dist/session/routes.d.ts.map +1 -1
- package/dist/session/routes.js +42 -131
- package/dist/session/rpc.d.ts +15 -15
- package/dist/session/rpc.d.ts.map +1 -1
- package/dist/session/rpc.js +98 -49
- package/dist/session/serving-port.d.ts +27 -0
- package/dist/session/serving-port.d.ts.map +1 -0
- package/dist/session/serving-port.js +27 -0
- package/dist/session/start-real-vite.d.ts +12 -0
- package/dist/session/start-real-vite.d.ts.map +1 -1
- package/dist/session/start-real-vite.js +4 -4
- package/dist/session/supervisor-op.d.ts +4 -4
- package/dist/session/supervisor-op.d.ts.map +1 -1
- package/dist/session/supervisor-op.js +24 -10
- package/dist/session/supervisor-rpc.d.ts +7 -7
- package/dist/session/supervisor-rpc.d.ts.map +1 -1
- package/dist/session/supervisor-rpc.js +4 -0
- package/dist/session/vite-command.d.ts +18 -0
- package/dist/session/vite-command.d.ts.map +1 -0
- package/dist/session/vite-command.js +609 -0
- package/dist/session/ws.d.ts +61 -0
- package/dist/session/ws.d.ts.map +1 -1
- package/dist/session/ws.js +122 -12
- package/dist/shell/npm-bin-entrypoints.d.ts +0 -35
- package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
- package/dist/shell/npm-bin-entrypoints.js +12 -85
- package/dist/workspace-host.d.ts +6 -0
- package/dist/workspace-host.d.ts.map +1 -0
- package/dist/workspace-host.js +5 -0
- package/dist/workspace.d.ts +2 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +1 -0
- package/package.json +34 -9
- package/public/_assets/runtime/{node-shims-9e1380d9ee430fcc.js → node-shims-8f8c64edd2a1f0f5.js} +305 -29
- package/public/index.html +1 -1
- package/scripts/bundle-facet-workers.mjs +1 -1
- package/scripts/bundle-npm-cjs.mjs +2 -2
- package/dist/facets/on-demand-bundle-gate.d.ts +0 -65
- package/dist/facets/on-demand-bundle-gate.d.ts.map +0 -1
- package/dist/facets/on-demand-bundle-gate.js +0 -125
- package/dist/npm/install-args.d.ts +0 -21
- package/dist/npm/install-args.d.ts.map +0 -1
- package/dist/npm/install-args.js +0 -70
- package/dist/npm/npm-log.d.ts +0 -31
- package/dist/npm/npm-log.d.ts.map +0 -1
- package/dist/npm/npm-log.js +0 -51
package/dist/session/ws.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ import type { SessionProcessSupervisor } from '@nimbus-sh/core/runtime/session-p
|
|
|
37
37
|
import type { SqliteVFS } from '@nimbus-sh/core/vfs/sqlite-vfs.js';
|
|
38
38
|
import type { CirrusReal } from '../facets/cirrus-real.js';
|
|
39
39
|
import type { WebSocketTerminal } from '../facets/ws-terminal.js';
|
|
40
|
+
import type { InitSessionOptions } from './init.js';
|
|
40
41
|
import type { Kernel, Shell } from '@nimbus-sh/core/substrate/lifo/index.js';
|
|
41
42
|
/**
|
|
42
43
|
* Minimal host shape for WS lifecycle. Per plan §IX.1 b': fields here
|
|
@@ -67,9 +68,69 @@ export interface WsHost {
|
|
|
67
68
|
_w5LastPersistRingSize: number;
|
|
68
69
|
/** [B'.4] live phase indicator — see nimbus-session-internal.d.ts */
|
|
69
70
|
_b4Phase: import('@nimbus-sh/platform/oom-discriminator.js').SessionState | null;
|
|
71
|
+
/** The session rebuild a woken instance has in flight; see bindShellSocket. */
|
|
72
|
+
_wakeRebuild: Promise<void> | null;
|
|
73
|
+
initSession(ws: WebSocket, options?: InitSessionOptions): Promise<void>;
|
|
70
74
|
_w5PersistRing(): Promise<void> | null;
|
|
71
75
|
_w9FlushOnClose(): void;
|
|
72
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Give the shell socket a frame arrived on a live session to land in.
|
|
79
|
+
*
|
|
80
|
+
* The runtime evicts a quiet object from memory while its accepted sockets
|
|
81
|
+
* stay open (the WebSocket Hibernation API), and the next frame from the
|
|
82
|
+
* peer wakes a fresh instance whose `shell`, `terminal` and `kernel` are
|
|
83
|
+
* null: the socket outlived the sleep, the session in memory did not.
|
|
84
|
+
* Measured 2026-09-14 on a deployed Worker: eight quiet seconds and the
|
|
85
|
+
* object is still there, ten and it is gone; the frame that wakes it is
|
|
86
|
+
* delivered and handled without error, and the peer gets nothing back —
|
|
87
|
+
* no output, no close, no error — because the terminal lookup that follows
|
|
88
|
+
* found nothing to hand it to. Only a new /ws upgrade rebuilt the session,
|
|
89
|
+
* and a peer whose socket still reads OPEN has no reason to make one. A
|
|
90
|
+
* browser tab hides this by probing every few seconds; a driver that
|
|
91
|
+
* simply waits between commands does not.
|
|
92
|
+
*
|
|
93
|
+
* So the rebuild runs here, on the socket that spoke, before the frame is
|
|
94
|
+
* handled: the cold path the upgrade takes after an eviction (cwd, env,
|
|
95
|
+
* mounts back from SQLite) minus the scrollback replay the peer already has
|
|
96
|
+
* on screen. Frames that land while the build runs await the same build —
|
|
97
|
+
* the input gate does not serialise handlers across a non-storage await, so
|
|
98
|
+
* without the shared promise two quick keystrokes would build two shells.
|
|
99
|
+
*
|
|
100
|
+
* A session that exists but answers to another socket — one an SDK call
|
|
101
|
+
* built on its headless terminal after the same wake — is handed to this
|
|
102
|
+
* socket the way the warm rejoin hands it to a new upgrade. The upgrade
|
|
103
|
+
* refuses a second shell socket while one still has a peer, so the socket
|
|
104
|
+
* that speaks is the one the peer is on.
|
|
105
|
+
*
|
|
106
|
+
* A build that fails closes the socket with a reason and answers false, so
|
|
107
|
+
* the caller drops the frame. The peer must learn that its shell is gone;
|
|
108
|
+
* the silence this replaces is the whole defect.
|
|
109
|
+
*
|
|
110
|
+
* A socket this side has already closed gets no session either: destroy
|
|
111
|
+
* closes every accepted socket and nulls the terminal before it wipes
|
|
112
|
+
* storage, and a frame still in flight on one of them must not rebuild
|
|
113
|
+
* the session it is tearing down.
|
|
114
|
+
*/
|
|
115
|
+
export declare function bindShellSocket(self: WsHost, ws: WebSocket): Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* What every output frame of the shell terminal feeds besides the socket:
|
|
118
|
+
* the persisted scrollback, and the shell-state snapshot.
|
|
119
|
+
*
|
|
120
|
+
* The snapshot runs here and not only after each inbound frame because
|
|
121
|
+
* commands run asynchronously: the `cd` a line asked for takes effect
|
|
122
|
+
* after the inbound handler has already snapshotted, and the next frame —
|
|
123
|
+
* which used to catch the row up — never arrives when the object
|
|
124
|
+
* hibernates first. Measured 2026-09-14: `cd /tmp && echo one`, ten quiet
|
|
125
|
+
* seconds, and the woken shell answered `pwd` from /home/user. The prompt
|
|
126
|
+
* that ends every command is an output frame, so by the time it has
|
|
127
|
+
* flushed, the state it reflects is what the row records.
|
|
128
|
+
*
|
|
129
|
+
* Every socket a shell terminal is built on or handed to goes through
|
|
130
|
+
* this — initSession, the warm rejoin, and the wake rebuild — so the
|
|
131
|
+
* three cannot drift.
|
|
132
|
+
*/
|
|
133
|
+
export declare function shellTerminalTee(self: WsHost): (frame: string) => void;
|
|
73
134
|
/**
|
|
74
135
|
* Classify a closing/erroring WebSocket by its serialized attachment.
|
|
75
136
|
* Shell sockets carry `{kind:'shell'}` (set at the /ws upgrade site);
|
package/dist/session/ws.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/session/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/session/ws.ts"],"names":[],"mappings":"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"}
|
package/dist/session/ws.js
CHANGED
|
@@ -33,30 +33,97 @@
|
|
|
33
33
|
* touches ctx.waitUntil; uses `(host.ctx as any)` cast).
|
|
34
34
|
*/
|
|
35
35
|
import { dec } from '@nimbus-sh/core/_shared/bytes.js';
|
|
36
|
+
import { errorText } from '@nimbus-sh/core/_shared/error-text.js';
|
|
36
37
|
import { recordFailure, getLastRpcFrame, getLastFacetId, recordRecoveryEvent } from '@nimbus-sh/platform/oom-discriminator.js';
|
|
37
38
|
import { generation } from '@nimbus-sh/fabric/generation.js';
|
|
38
|
-
import { persistShellState } from './state-store.js';
|
|
39
|
+
import { appendScrollback, persistShellState } from './state-store.js';
|
|
39
40
|
import { handleFsWatchSubscribe, handleFsWatchUnsubscribe, cleanupFsWatchOnClose, } from './fs-watch.js';
|
|
40
41
|
import { parseProcessLogClientFrame } from '@nimbus-sh/core/runtime/process-io-protocol.js';
|
|
41
42
|
import { applyProcessClientFrame } from '@nimbus-sh/core/runtime/process-input-routing.js';
|
|
42
43
|
import { z } from 'zod/v4';
|
|
43
44
|
import { clearShellSocketStamp, noteShellSocketActivity } from './shell-socket.js';
|
|
44
45
|
import { PRIOR_GENERATION_EXIT_REASON } from './rpc.js';
|
|
46
|
+
/**
|
|
47
|
+
* Give the shell socket a frame arrived on a live session to land in.
|
|
48
|
+
*
|
|
49
|
+
* The runtime evicts a quiet object from memory while its accepted sockets
|
|
50
|
+
* stay open (the WebSocket Hibernation API), and the next frame from the
|
|
51
|
+
* peer wakes a fresh instance whose `shell`, `terminal` and `kernel` are
|
|
52
|
+
* null: the socket outlived the sleep, the session in memory did not.
|
|
53
|
+
* Measured 2026-09-14 on a deployed Worker: eight quiet seconds and the
|
|
54
|
+
* object is still there, ten and it is gone; the frame that wakes it is
|
|
55
|
+
* delivered and handled without error, and the peer gets nothing back —
|
|
56
|
+
* no output, no close, no error — because the terminal lookup that follows
|
|
57
|
+
* found nothing to hand it to. Only a new /ws upgrade rebuilt the session,
|
|
58
|
+
* and a peer whose socket still reads OPEN has no reason to make one. A
|
|
59
|
+
* browser tab hides this by probing every few seconds; a driver that
|
|
60
|
+
* simply waits between commands does not.
|
|
61
|
+
*
|
|
62
|
+
* So the rebuild runs here, on the socket that spoke, before the frame is
|
|
63
|
+
* handled: the cold path the upgrade takes after an eviction (cwd, env,
|
|
64
|
+
* mounts back from SQLite) minus the scrollback replay the peer already has
|
|
65
|
+
* on screen. Frames that land while the build runs await the same build —
|
|
66
|
+
* the input gate does not serialise handlers across a non-storage await, so
|
|
67
|
+
* without the shared promise two quick keystrokes would build two shells.
|
|
68
|
+
*
|
|
69
|
+
* A session that exists but answers to another socket — one an SDK call
|
|
70
|
+
* built on its headless terminal after the same wake — is handed to this
|
|
71
|
+
* socket the way the warm rejoin hands it to a new upgrade. The upgrade
|
|
72
|
+
* refuses a second shell socket while one still has a peer, so the socket
|
|
73
|
+
* that speaks is the one the peer is on.
|
|
74
|
+
*
|
|
75
|
+
* A build that fails closes the socket with a reason and answers false, so
|
|
76
|
+
* the caller drops the frame. The peer must learn that its shell is gone;
|
|
77
|
+
* the silence this replaces is the whole defect.
|
|
78
|
+
*
|
|
79
|
+
* A socket this side has already closed gets no session either: destroy
|
|
80
|
+
* closes every accepted socket and nulls the terminal before it wipes
|
|
81
|
+
* storage, and a frame still in flight on one of them must not rebuild
|
|
82
|
+
* the session it is tearing down.
|
|
83
|
+
*/
|
|
84
|
+
export async function bindShellSocket(self, ws) {
|
|
85
|
+
if (ws.readyState !== WS_READY_STATE_OPEN)
|
|
86
|
+
return false;
|
|
87
|
+
if (self.shell == null || self.terminal == null || self.kernel == null) {
|
|
88
|
+
if (!self._wakeRebuild) {
|
|
89
|
+
self._wakeRebuild = self.initSession(ws, { resume: 'wake' })
|
|
90
|
+
.finally(() => { self._wakeRebuild = null; });
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
await self._wakeRebuild;
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
const message = errorText(e);
|
|
97
|
+
console.error('[nimbus] session rebuild on wake failed:', message);
|
|
98
|
+
// A close reason is capped at 123 bytes by the protocol.
|
|
99
|
+
try {
|
|
100
|
+
ws.close(1011, `session rebuild after wake failed: ${message}`.slice(0, 123));
|
|
101
|
+
}
|
|
102
|
+
catch { /* closing */ }
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
if (self.terminal.ws !== ws)
|
|
108
|
+
self.terminal.attach(ws, shellTerminalTee(self));
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
/** The shell state each instance last wrote, so an unchanged state costs no SQL. */
|
|
112
|
+
const lastShellSnapshot = new WeakMap();
|
|
45
113
|
/**
|
|
46
114
|
* Snapshot the live Shell state and write it through to DO SQLite
|
|
47
115
|
* [Phase 3 B'.1].
|
|
48
116
|
*
|
|
49
|
-
* Called
|
|
50
|
-
* once more in the wsClose / wsError
|
|
51
|
-
* safety net before the in-memory Shell is
|
|
117
|
+
* Called after every inbound frame, from every output flush of the shell
|
|
118
|
+
* terminal (see shellTerminalTee), and once more in the wsClose / wsError
|
|
119
|
+
* shell-kind branch as a final safety net before the in-memory Shell is
|
|
120
|
+
* torn down.
|
|
52
121
|
*
|
|
53
122
|
* Read-only and synchronous (DO storage SQL is sync inside a request
|
|
54
|
-
* context). Cheap: one read of `shell.getCwd()` + `shell.getEnv()
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* pointer-equality on cwd plus env reference, since Shell.getEnv()
|
|
59
|
-
* returns a live Record and `cd` mutates `this.cwd` in place.
|
|
123
|
+
* context). Cheap: one read of `shell.getCwd()` + `shell.getEnv()` and a
|
|
124
|
+
* JSON.stringify of env; the INSERT-OR-REPLACE into nimbus_session_kv
|
|
125
|
+
* only runs when either differs from what this instance last wrote, so
|
|
126
|
+
* the per-flush call during a chatty command costs a string compare.
|
|
60
127
|
*
|
|
61
128
|
* Failure model: persistShellState throws ONLY on env-too-large
|
|
62
129
|
* (the SESSION_ENV_MAX_BYTES gate). We surface that via console.warn
|
|
@@ -88,13 +155,49 @@ function snapshotShellState(self) {
|
|
|
88
155
|
catch { /* best-effort */ }
|
|
89
156
|
if (!cwd && !env)
|
|
90
157
|
return;
|
|
158
|
+
const envJson = env ? JSON.stringify(env) : null;
|
|
159
|
+
const last = lastShellSnapshot.get(self);
|
|
160
|
+
if (last && last.cwd === cwd && last.envJson === envJson)
|
|
161
|
+
return;
|
|
91
162
|
try {
|
|
92
163
|
persistShellState(ctx, { cwd, env });
|
|
164
|
+
lastShellSnapshot.set(self, { cwd, envJson });
|
|
93
165
|
}
|
|
94
166
|
catch (e) {
|
|
95
167
|
console.warn('[nimbus/B\'.1] persistShellState failed:', e?.message || e);
|
|
96
168
|
}
|
|
97
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* What every output frame of the shell terminal feeds besides the socket:
|
|
172
|
+
* the persisted scrollback, and the shell-state snapshot.
|
|
173
|
+
*
|
|
174
|
+
* The snapshot runs here and not only after each inbound frame because
|
|
175
|
+
* commands run asynchronously: the `cd` a line asked for takes effect
|
|
176
|
+
* after the inbound handler has already snapshotted, and the next frame —
|
|
177
|
+
* which used to catch the row up — never arrives when the object
|
|
178
|
+
* hibernates first. Measured 2026-09-14: `cd /tmp && echo one`, ten quiet
|
|
179
|
+
* seconds, and the woken shell answered `pwd` from /home/user. The prompt
|
|
180
|
+
* that ends every command is an output frame, so by the time it has
|
|
181
|
+
* flushed, the state it reflects is what the row records.
|
|
182
|
+
*
|
|
183
|
+
* Every socket a shell terminal is built on or handed to goes through
|
|
184
|
+
* this — initSession, the warm rejoin, and the wake rebuild — so the
|
|
185
|
+
* three cannot drift.
|
|
186
|
+
*/
|
|
187
|
+
export function shellTerminalTee(self) {
|
|
188
|
+
// `ctx` is `protected` on the DO base class and so cannot sit on the
|
|
189
|
+
// host interface (DEFECT-D1); scrollback is the one thing here needing it.
|
|
190
|
+
const ctx = 'ctx' in self ? self.ctx : undefined;
|
|
191
|
+
return (frame) => {
|
|
192
|
+
try {
|
|
193
|
+
appendScrollback(ctx, frame, Date.now());
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
console.warn("[B'.3] appendScrollback failed:", errorText(e));
|
|
197
|
+
}
|
|
198
|
+
snapshotShellState(self);
|
|
199
|
+
};
|
|
200
|
+
}
|
|
98
201
|
const WsAttachmentSchema = z.object({
|
|
99
202
|
kind: z.string(),
|
|
100
203
|
clientId: z.string().optional(),
|
|
@@ -112,6 +215,8 @@ const FsWatchClientFrameSchema = z.discriminatedUnion('type', [
|
|
|
112
215
|
subId: z.string().optional(),
|
|
113
216
|
}).passthrough(),
|
|
114
217
|
]);
|
|
218
|
+
/** `WebSocket.readyState` for an open socket; the constant name differs between workerd and Node. */
|
|
219
|
+
const WS_READY_STATE_OPEN = 1;
|
|
115
220
|
const TerminalMessageSchema = z.object({
|
|
116
221
|
type: z.string(),
|
|
117
222
|
data: z.string().optional(),
|
|
@@ -156,8 +261,13 @@ export async function wsMessage(self, ws, message) {
|
|
|
156
261
|
// The stamp goes in the attachment because isolate memory does not
|
|
157
262
|
// survive hibernation and the /ws upgrade has to read it afterwards.
|
|
158
263
|
// Rate-limited inside; see src/session/shell-socket.ts.
|
|
159
|
-
if (attach?.kind === 'shell')
|
|
264
|
+
if (attach?.kind === 'shell') {
|
|
160
265
|
noteShellSocketActivity(ws);
|
|
266
|
+
// Before the frame is parsed: a woken instance has no session to
|
|
267
|
+
// hand ANY shell-socket frame to, the liveness probe included.
|
|
268
|
+
if (!(await bindShellSocket(self, ws)))
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
161
271
|
const data = typeof message === 'string' ? message : dec.decode(message);
|
|
162
272
|
const value = JSON.parse(data);
|
|
163
273
|
// file-tree-watch (2026-05-15): handle fs-watch-* on this WS BEFORE
|
|
@@ -212,7 +322,7 @@ export async function wsMessage(self, ws, message) {
|
|
|
212
322
|
// Persist Shell state to DO SQLite after the terminal has handled
|
|
213
323
|
// the user's keystroke. The Shell builtin `cd` mutates this.cwd
|
|
214
324
|
// synchronously inside executeLine, so by the time we reach this
|
|
215
|
-
// line a `cd app\r` has already taken effect and we capture the
|
|
325
|
+
// line a `cd example-app\r` has already taken effect and we capture the
|
|
216
326
|
// new cwd. Cheap when nothing has changed; SESSION_ENV_MAX_BYTES
|
|
217
327
|
// is the only failure mode and is logged, not thrown.
|
|
218
328
|
snapshotShellState(self);
|
|
@@ -4,41 +4,6 @@ import type { FacetManager } from '../facets/manager.js';
|
|
|
4
4
|
type Output = {
|
|
5
5
|
write(data: string): void;
|
|
6
6
|
};
|
|
7
|
-
/**
|
|
8
|
-
* How long a bin invocation may take before the shell stops waiting for it.
|
|
9
|
-
*
|
|
10
|
-
* The program itself is already bounded: FACET_TIMEOUT_MS kills a one-shot
|
|
11
|
-
* facet and the session reports exit 124 with a reason. Nothing bounds the
|
|
12
|
-
* supervisor-side work AROUND that run — the prefetch-bundle walk, the ESM
|
|
13
|
-
* transform, staging a bundled artifact, the loader hop — and nothing bounds
|
|
14
|
-
* the staged-artifact dispatch at all. A dispatch that never settles leaves
|
|
15
|
-
* `running` stuck true on this connection's shell: every later keystroke is
|
|
16
|
-
* swallowed, no prompt returns, and nothing says why. A terminal that goes
|
|
17
|
-
* silent forever is worse than a command that fails.
|
|
18
|
-
*
|
|
19
|
-
* So the invocation gets the program's lifetime twice over: the program keeps
|
|
20
|
-
* its full FACET_TIMEOUT_MS and the supervisor-side work gets the same again.
|
|
21
|
-
* Derived rather than chosen, so it cannot drift from the bound it exists to
|
|
22
|
-
* sit outside. Measured against a deployed Worker, the heaviest bins we run
|
|
23
|
-
* sit far inside it: `pi --version` (a 17.4 MiB module map, the largest
|
|
24
|
-
* observed) returns in 16s, and every staged-opencode one-shot in 2-4s.
|
|
25
|
-
*/
|
|
26
|
-
export declare const BIN_DISPATCH_TIMEOUT_MS: number;
|
|
27
|
-
export type BinDispatchOutcome<T> = {
|
|
28
|
-
expired: false;
|
|
29
|
-
value: T;
|
|
30
|
-
} | {
|
|
31
|
-
expired: true;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Await a bin dispatch under a bound. Reports expiry instead of hanging.
|
|
35
|
-
*
|
|
36
|
-
* The abandoned work keeps running — there is nothing to cancel it with, and a
|
|
37
|
-
* facet that eventually finishes still lands its own exit and its write-back.
|
|
38
|
-
* It just no longer holds the shell open, and it can never surface as an
|
|
39
|
-
* unhandled rejection once we have stopped listening.
|
|
40
|
-
*/
|
|
41
|
-
export declare function awaitBinDispatch<T>(work: Promise<T>, budgetMs: number): Promise<BinDispatchOutcome<T>>;
|
|
42
7
|
type RegistryLike = {
|
|
43
8
|
resolve(name: string): Promise<unknown> | unknown;
|
|
44
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"npm-bin-entrypoints.d.ts","sourceRoot":"","sources":["../../src/shell/npm-bin-entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,sBAAsB,CAAC;AAWnF,KAAK,MAAM,GAAG;IAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"npm-bin-entrypoints.d.ts","sourceRoot":"","sources":["../../src/shell/npm-bin-entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AACtG,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,sBAAsB,CAAC;AAWnF,KAAK,MAAM,GAAG;IAAE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAiB5C,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CACnD,CAAC;AAEF,KAAK,kBAAkB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC;AAezD,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE;IACJ,GAAG,EAAE,eAAe,CAAC;IACrB,MAAM,IAAI,MAAM,CAAC;IACjB,SAAS,EAAE,wBAAwB,CAAC;IACpC,eAAe,IAAI,YAAY,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxJ,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC9D,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7F,GACA,IAAI,CAqHN;AAqFD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAEnF,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EAAE,GACb,yBAAyB,CAS3B;AA+FD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAS/E"}
|
|
@@ -2,67 +2,8 @@ import { resolveNpmBin, resolveNpmBinFromPath, isStagedArtifactTarget, stagedArt
|
|
|
2
2
|
import { bundleProfileForNpmBin } from '@nimbus-sh/core/runtime/bundle-profile.js';
|
|
3
3
|
import { OPENCODE_TREE_SITTER_DIAG_ARG } from '../runtime/opencode-facet-runner.js';
|
|
4
4
|
import { normalizeVfsPath } from '@nimbus-sh/core/vfs/path.js';
|
|
5
|
-
import { DEFAULT_PATH
|
|
5
|
+
import { DEFAULT_PATH } from '@nimbus-sh/core/constants.js';
|
|
6
6
|
import { z } from 'zod/v4';
|
|
7
|
-
/**
|
|
8
|
-
* How long a bin invocation may take before the shell stops waiting for it.
|
|
9
|
-
*
|
|
10
|
-
* The program itself is already bounded: FACET_TIMEOUT_MS kills a one-shot
|
|
11
|
-
* facet and the session reports exit 124 with a reason. Nothing bounds the
|
|
12
|
-
* supervisor-side work AROUND that run — the prefetch-bundle walk, the ESM
|
|
13
|
-
* transform, staging a bundled artifact, the loader hop — and nothing bounds
|
|
14
|
-
* the staged-artifact dispatch at all. A dispatch that never settles leaves
|
|
15
|
-
* `running` stuck true on this connection's shell: every later keystroke is
|
|
16
|
-
* swallowed, no prompt returns, and nothing says why. A terminal that goes
|
|
17
|
-
* silent forever is worse than a command that fails.
|
|
18
|
-
*
|
|
19
|
-
* So the invocation gets the program's lifetime twice over: the program keeps
|
|
20
|
-
* its full FACET_TIMEOUT_MS and the supervisor-side work gets the same again.
|
|
21
|
-
* Derived rather than chosen, so it cannot drift from the bound it exists to
|
|
22
|
-
* sit outside. Measured against a deployed Worker, the heaviest bins we run
|
|
23
|
-
* sit far inside it: `pi --version` (a 17.4 MiB module map, the largest
|
|
24
|
-
* observed) returns in 16s, and every staged-opencode one-shot in 2-4s.
|
|
25
|
-
*/
|
|
26
|
-
export const BIN_DISPATCH_TIMEOUT_MS = 2 * FACET_TIMEOUT_MS;
|
|
27
|
-
const DISPATCH_EXPIRED = Symbol('nimbus.bin-dispatch-expired');
|
|
28
|
-
/**
|
|
29
|
-
* Await a bin dispatch under a bound. Reports expiry instead of hanging.
|
|
30
|
-
*
|
|
31
|
-
* The abandoned work keeps running — there is nothing to cancel it with, and a
|
|
32
|
-
* facet that eventually finishes still lands its own exit and its write-back.
|
|
33
|
-
* It just no longer holds the shell open, and it can never surface as an
|
|
34
|
-
* unhandled rejection once we have stopped listening.
|
|
35
|
-
*/
|
|
36
|
-
export async function awaitBinDispatch(work, budgetMs) {
|
|
37
|
-
let timer;
|
|
38
|
-
const deadline = new Promise((_resolve, reject) => {
|
|
39
|
-
timer = setTimeout(() => reject(DISPATCH_EXPIRED), budgetMs);
|
|
40
|
-
});
|
|
41
|
-
try {
|
|
42
|
-
return { expired: false, value: await Promise.race([work, deadline]) };
|
|
43
|
-
}
|
|
44
|
-
catch (e) {
|
|
45
|
-
if (e !== DISPATCH_EXPIRED)
|
|
46
|
-
throw e;
|
|
47
|
-
work.catch(() => { });
|
|
48
|
-
return { expired: true };
|
|
49
|
-
}
|
|
50
|
-
finally {
|
|
51
|
-
if (timer !== undefined)
|
|
52
|
-
clearTimeout(timer);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* The reason a bin invocation is being abandoned. Names the limit and both
|
|
57
|
-
* numbers it is derived from so the text cannot drift from the code, and says
|
|
58
|
-
* where anything the program still produces will go.
|
|
59
|
-
*/
|
|
60
|
-
function dispatchExpiredReason(shellLine, pid) {
|
|
61
|
-
return `${shellLine}: did not come back after ${BIN_DISPATCH_TIMEOUT_MS / 1000}s — the ` +
|
|
62
|
-
`${FACET_TIMEOUT_MS / 1000}s a program is given to run, and the same again for the work ` +
|
|
63
|
-
'around it. The shell is no longer waiting on it' +
|
|
64
|
-
(pid === null ? '.' : `; anything it still produces goes to the log for pid ${pid}.`);
|
|
65
|
-
}
|
|
66
7
|
const NpmBinPackageMetadataSchema = z.object({
|
|
67
8
|
name: z.string().optional(),
|
|
68
9
|
keywords: z.array(z.string()).optional(),
|
|
@@ -135,18 +76,14 @@ export function installNpmBinFallbackResolver(registry, deps) {
|
|
|
135
76
|
const label = longRunning ? 'started (long-running)' : 'started';
|
|
136
77
|
deps.terminal?.write(`\x1b[2m[bin ${label}: pid=${pid} cmd="${shellLine}"]\x1b[0m\r\n`);
|
|
137
78
|
deps.notifyTerminalEvent({ type: 'spawn', pid, command: shellLine, longRunning, attachedTty });
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
// still takes everything — that is where the rest of the run shows up.
|
|
141
|
-
let abandoned = false;
|
|
79
|
+
// Output goes to the pid's log ring and the caller's streams; nothing
|
|
80
|
+
// abandons this invocation — it runs until the program exits.
|
|
142
81
|
const writeThrough = (stream, target) => (data) => {
|
|
143
82
|
const text = String(data);
|
|
144
83
|
try {
|
|
145
84
|
deps.processes.appendOutput(pid, stream, text);
|
|
146
85
|
}
|
|
147
86
|
catch { }
|
|
148
|
-
if (abandoned)
|
|
149
|
-
return;
|
|
150
87
|
try {
|
|
151
88
|
target.write(text);
|
|
152
89
|
}
|
|
@@ -154,7 +91,10 @@ export function installNpmBinFallbackResolver(registry, deps) {
|
|
|
154
91
|
};
|
|
155
92
|
let exitCode = 1;
|
|
156
93
|
try {
|
|
157
|
-
|
|
94
|
+
// A user-invoked bin is a foreground program: the shell waits for its
|
|
95
|
+
// real exit — no dispatch timeout. Ctrl-C ends it through the
|
|
96
|
+
// terminator the exec path registers on the pid.
|
|
97
|
+
exitCode = await runRuntime({
|
|
158
98
|
...ctx,
|
|
159
99
|
args: ['/' + bin.targetPath, ...argv],
|
|
160
100
|
stdout: { write: writeThrough('stdout', ctx.stdout) },
|
|
@@ -167,15 +107,7 @@ export function installNpmBinFallbackResolver(registry, deps) {
|
|
|
167
107
|
attachedTty,
|
|
168
108
|
},
|
|
169
109
|
__nimbusBundleProfile: bundleProfile,
|
|
170
|
-
})
|
|
171
|
-
if (dispatched.expired) {
|
|
172
|
-
writeThrough('stderr', ctx.stderr)(`${dispatchExpiredReason(shellLine, pid)}\n`);
|
|
173
|
-
abandoned = true;
|
|
174
|
-
exitCode = 124;
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
exitCode = dispatched.value;
|
|
178
|
-
}
|
|
110
|
+
});
|
|
179
111
|
}
|
|
180
112
|
catch (e) {
|
|
181
113
|
writeThrough('stderr', ctx.stderr)(`bin error: ${formatError(e)}\n`);
|
|
@@ -212,21 +144,16 @@ async function runStagedArtifact(deps, name, artifact, argv, cwd, ctx, dispositi
|
|
|
212
144
|
// Piped stdin is not yet wired for staged artifacts; the interactive TUI reads
|
|
213
145
|
// keystrokes from the live ProcessInputStore via the attached-TTY stdin pump.
|
|
214
146
|
const base = { argv, env: ctx.env ?? {}, cwd, command: shellLine };
|
|
215
|
-
let
|
|
147
|
+
let result;
|
|
216
148
|
try {
|
|
217
|
-
|
|
149
|
+
// Same contract as the node-bin path: a user-invoked program runs to
|
|
150
|
+
// its own exit; the shell does not bound the wait.
|
|
151
|
+
result = await stagedArtifactWork(fm, artifact, base, disposition);
|
|
218
152
|
}
|
|
219
153
|
catch (e) {
|
|
220
154
|
ctx.stderr.write(`${name}: ${formatError(e)}\n`);
|
|
221
155
|
return 1;
|
|
222
156
|
}
|
|
223
|
-
// A staged artifact owns its own process-table entry and only tells us the
|
|
224
|
-
// pid on the way out, so an abandoned dispatch has no pid to point at.
|
|
225
|
-
if (dispatched.expired) {
|
|
226
|
-
ctx.stderr.write(`${dispatchExpiredReason(shellLine, null)}\n`);
|
|
227
|
-
return 124;
|
|
228
|
-
}
|
|
229
|
-
const result = dispatched.value;
|
|
230
157
|
// Resident dispositions (dual / server / attached): the facet(s) are now
|
|
231
158
|
// resident, streaming live and reporting their own exit through the
|
|
232
159
|
// supervisor. Surface the long-running spawn and hand off — the same
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { composeFacetManager, type FacetManagerDeps, type ComposedFacetManager } from './facets/compose.js';
|
|
2
|
+
export { composeHostedRuntime, type HostedRuntime, type HostedRuntimeOptions, type HostedRuntimeLifecycle, type HostedRuntimeTask, type RuntimeFiles } from './hosted/runtime.js';
|
|
3
|
+
export { runtimeCatalogSource } from './runtime/runtime-catalog.js';
|
|
4
|
+
export { SupervisorRPC } from './session/supervisor-rpc.js';
|
|
5
|
+
export { NimbusAssetsRPC, NimbusLoaderRPC, NimbusLoadedWorker, NimbusLoadedEntrypoint, NimbusDurableObjectNamespace, NimbusDOStub } from '@nimbus-sh/fabric/bindings.js';
|
|
6
|
+
//# sourceMappingURL=workspace-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-host.d.ts","sourceRoot":"","sources":["../src/workspace-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC5G,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAClL,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { composeFacetManager } from './facets/compose.js';
|
|
2
|
+
export { composeHostedRuntime } from './hosted/runtime.js';
|
|
3
|
+
export { runtimeCatalogSource } from './runtime/runtime-catalog.js';
|
|
4
|
+
export { SupervisorRPC } from './session/supervisor-rpc.js';
|
|
5
|
+
export { NimbusAssetsRPC, NimbusLoaderRPC, NimbusLoadedWorker, NimbusLoadedEntrypoint, NimbusDurableObjectNamespace, NimbusDOStub } from '@nimbus-sh/fabric/bindings.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NimbusWorkspace } from '@nimbus-sh/core/workspace';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nimbus-sh/worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Nimbus runtime package for Cloudflare Workers, re-exported publicly through @nimbus-sh/sdk/worker.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"import": "./dist/index.js"
|
|
30
30
|
},
|
|
31
31
|
"./workspace": {
|
|
32
|
-
"workspace": "./src/workspace
|
|
33
|
-
"types": "./dist/workspace
|
|
34
|
-
"import": "./dist/workspace
|
|
32
|
+
"workspace": "./src/workspace.ts",
|
|
33
|
+
"types": "./dist/workspace.d.ts",
|
|
34
|
+
"import": "./dist/workspace.js"
|
|
35
35
|
},
|
|
36
36
|
"./router": {
|
|
37
37
|
"workspace": "./src/router/index.ts",
|
|
@@ -53,6 +53,31 @@
|
|
|
53
53
|
"types": "./dist/_shared/preview-host.d.ts",
|
|
54
54
|
"import": "./dist/_shared/preview-host.js"
|
|
55
55
|
},
|
|
56
|
+
"./workspace-host": {
|
|
57
|
+
"workspace": "./src/workspace-host.ts",
|
|
58
|
+
"types": "./dist/workspace-host.d.ts",
|
|
59
|
+
"import": "./dist/workspace-host.js"
|
|
60
|
+
},
|
|
61
|
+
"./facet-host": {
|
|
62
|
+
"workspace": "./src/runtime/facet-loader-host.ts",
|
|
63
|
+
"types": "./dist/runtime/facet-loader-host.d.ts",
|
|
64
|
+
"import": "./dist/runtime/facet-loader-host.js"
|
|
65
|
+
},
|
|
66
|
+
"./port-capability": {
|
|
67
|
+
"workspace": "./src/session/port-capability.ts",
|
|
68
|
+
"types": "./dist/session/port-capability.d.ts",
|
|
69
|
+
"import": "./dist/session/port-capability.js"
|
|
70
|
+
},
|
|
71
|
+
"./durable-slots": {
|
|
72
|
+
"workspace": "./src/facets/durable-slots.ts",
|
|
73
|
+
"types": "./dist/facets/durable-slots.d.ts",
|
|
74
|
+
"import": "./dist/facets/durable-slots.js"
|
|
75
|
+
},
|
|
76
|
+
"./git": {
|
|
77
|
+
"workspace": "./src/git/commands.ts",
|
|
78
|
+
"types": "./dist/git/commands.d.ts",
|
|
79
|
+
"import": "./dist/git/commands.js"
|
|
80
|
+
},
|
|
56
81
|
"./runtime-sync-helper": "./scripts/bundle-runtime.mjs",
|
|
57
82
|
"./public/*": "./public/*",
|
|
58
83
|
"./package.json": "./package.json"
|
|
@@ -78,15 +103,15 @@
|
|
|
78
103
|
"bundle:agent-chat": "node scripts/bundle-agent-chat.mjs",
|
|
79
104
|
"bundle": "bun run bundle:git && bun run bundle:facets && bun run bundle:esbuild && bun run bundle:sqlite && bun run bundle:shims && bun run bundle:tailwind && bun run bundle:opencode && bun run bundle:agent-chat",
|
|
80
105
|
"clean:dist": "node scripts/clean-dist.mjs",
|
|
81
|
-
"build": "
|
|
82
|
-
"prepack": "
|
|
106
|
+
"build": "bun run clean:dist && tsc -p tsconfig.json --noCheck --noEmit false --declaration true --declarationMap true --outDir dist --rootDir src",
|
|
107
|
+
"prepack": "bun run build",
|
|
83
108
|
"typecheck": "tsc --noEmit && tsc -p frontend --noEmit"
|
|
84
109
|
},
|
|
85
110
|
"dependencies": {
|
|
86
111
|
"@ai-sdk/openai-compatible": "^2.0.41",
|
|
87
|
-
"@nimbus-sh/core": "^0.
|
|
88
|
-
"@nimbus-sh/fabric": "^0.
|
|
89
|
-
"@nimbus-sh/platform": "^0.
|
|
112
|
+
"@nimbus-sh/core": "^0.10.0",
|
|
113
|
+
"@nimbus-sh/fabric": "^0.6.0",
|
|
114
|
+
"@nimbus-sh/platform": "^0.4.0",
|
|
90
115
|
"@renovatebot/pep440": "^5.0.0",
|
|
91
116
|
"ai": "^6.0.182",
|
|
92
117
|
"clean-git-ref": "^2.0.1",
|