@nimbus-sh/worker 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +2 -2
  2. package/dist/cirrus-npm-cjs.generated.d.ts +1 -1
  3. package/dist/cirrus-npm-cjs.generated.js +1 -1
  4. package/dist/facets/cirrus-real.d.ts.map +1 -1
  5. package/dist/facets/cirrus-real.js +6 -5
  6. package/dist/facets/compose.d.ts +148 -0
  7. package/dist/facets/compose.d.ts.map +1 -0
  8. package/dist/facets/compose.js +146 -0
  9. package/dist/facets/durable-images.d.ts +9 -5
  10. package/dist/facets/durable-images.d.ts.map +1 -1
  11. package/dist/facets/durable-images.js +17 -7
  12. package/dist/facets/esbuild-bundle-pool.d.ts +49 -0
  13. package/dist/facets/esbuild-bundle-pool.d.ts.map +1 -0
  14. package/dist/facets/esbuild-bundle-pool.js +122 -0
  15. package/dist/facets/exec-telemetry.d.ts +8 -0
  16. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  17. package/dist/facets/manager.d.ts +240 -109
  18. package/dist/facets/manager.d.ts.map +1 -1
  19. package/dist/facets/manager.js +661 -337
  20. package/dist/facets/process.d.ts +20 -16
  21. package/dist/facets/process.d.ts.map +1 -1
  22. package/dist/facets/process.js +59 -28
  23. package/dist/facets/real-vite-fs-shim.js +2 -2
  24. package/dist/facets/vite-dev-server.d.ts +25 -47
  25. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  26. package/dist/facets/vite-dev-server.js +185 -219
  27. package/dist/facets/wasm-image-digest.d.ts +25 -0
  28. package/dist/facets/wasm-image-digest.d.ts.map +1 -0
  29. package/dist/facets/wasm-image-digest.js +25 -0
  30. package/dist/facets/wasm-swap-registry.d.ts +51 -92
  31. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  32. package/dist/facets/wasm-swap-registry.js +68 -227
  33. package/dist/git/network-facet.d.ts.map +1 -1
  34. package/dist/git/network-facet.js +6 -5
  35. package/dist/loaders/child-process/spawn-pool.d.ts +3 -2
  36. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  37. package/dist/loaders/child-process/spawn-pool.js +3 -2
  38. package/dist/loaders/generated-workers.d.ts +2 -2
  39. package/dist/loaders/generated-workers.d.ts.map +1 -1
  40. package/dist/loaders/generated-workers.js +3 -3
  41. package/dist/loaders/npm-resolve-preamble.d.ts +3 -6
  42. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  43. package/dist/loaders/npm-resolve-preamble.js +34 -108
  44. package/dist/node-shims-artifact.generated.js +3 -3
  45. package/dist/npm/install-batch-facet.d.ts +3 -2
  46. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  47. package/dist/npm/install-batch-facet.js +45 -15
  48. package/dist/npm/installer.d.ts +22 -17
  49. package/dist/npm/installer.d.ts.map +1 -1
  50. package/dist/npm/installer.js +209 -193
  51. package/dist/npm/pre-bundle-facet.d.ts +1 -1
  52. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  53. package/dist/npm/pre-bundle-facet.js +1 -1
  54. package/dist/npm/resolve-facet.d.ts +6 -0
  55. package/dist/npm/resolve-facet.d.ts.map +1 -1
  56. package/dist/npm/resolve-one-facet.d.ts +21 -20
  57. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  58. package/dist/npm/resolve-one-facet.js +85 -84
  59. package/dist/npm/semver.d.ts +59 -0
  60. package/dist/npm/semver.d.ts.map +1 -0
  61. package/dist/npm/semver.js +226 -0
  62. package/dist/router/remote-api.js +31 -1
  63. package/dist/runtime/html-entrypoint.d.ts +7 -0
  64. package/dist/runtime/html-entrypoint.d.ts.map +1 -1
  65. package/dist/runtime/html-entrypoint.js +18 -2
  66. package/dist/runtime/node-runner.d.ts +3 -0
  67. package/dist/runtime/node-runner.d.ts.map +1 -1
  68. package/dist/runtime/node-runner.js +7 -0
  69. package/dist/runtime/node-shims.d.ts.map +1 -1
  70. package/dist/runtime/node-shims.js +305 -29
  71. package/dist/runtime/opencode-facet-runner.js +2 -2
  72. package/dist/session/helpers.d.ts +38 -0
  73. package/dist/session/helpers.d.ts.map +1 -1
  74. package/dist/session/helpers.js +76 -0
  75. package/dist/session/init-phases.d.ts +1 -1
  76. package/dist/session/init-phases.d.ts.map +1 -1
  77. package/dist/session/init-phases.js +2 -12
  78. package/dist/session/init.d.ts +15 -1
  79. package/dist/session/init.d.ts.map +1 -1
  80. package/dist/session/init.js +82 -603
  81. package/dist/session/nimbus-session.d.ts +56 -22
  82. package/dist/session/nimbus-session.d.ts.map +1 -1
  83. package/dist/session/nimbus-session.js +130 -101
  84. package/dist/session/npm-install-port.d.ts +16 -0
  85. package/dist/session/npm-install-port.d.ts.map +1 -0
  86. package/dist/session/npm-install-port.js +37 -0
  87. package/dist/session/port-capability.d.ts +44 -0
  88. package/dist/session/port-capability.d.ts.map +1 -1
  89. package/dist/session/port-capability.js +110 -0
  90. package/dist/session/programmatic.d.ts +31 -5
  91. package/dist/session/programmatic.d.ts.map +1 -1
  92. package/dist/session/programmatic.js +94 -68
  93. package/dist/session/routes.d.ts +30 -17
  94. package/dist/session/routes.d.ts.map +1 -1
  95. package/dist/session/routes.js +42 -131
  96. package/dist/session/rpc.d.ts +15 -15
  97. package/dist/session/rpc.d.ts.map +1 -1
  98. package/dist/session/rpc.js +97 -47
  99. package/dist/session/serving-port.d.ts +27 -0
  100. package/dist/session/serving-port.d.ts.map +1 -0
  101. package/dist/session/serving-port.js +27 -0
  102. package/dist/session/start-real-vite.d.ts +12 -0
  103. package/dist/session/start-real-vite.d.ts.map +1 -1
  104. package/dist/session/start-real-vite.js +4 -4
  105. package/dist/session/supervisor-op.d.ts +2 -2
  106. package/dist/session/supervisor-op.d.ts.map +1 -1
  107. package/dist/session/supervisor-op.js +13 -7
  108. package/dist/session/supervisor-rpc.d.ts +7 -7
  109. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  110. package/dist/session/supervisor-rpc.js +4 -0
  111. package/dist/session/vite-command.d.ts +18 -0
  112. package/dist/session/vite-command.d.ts.map +1 -0
  113. package/dist/session/vite-command.js +609 -0
  114. package/dist/session/ws.d.ts +61 -0
  115. package/dist/session/ws.d.ts.map +1 -1
  116. package/dist/session/ws.js +122 -12
  117. package/dist/shell/npm-bin-entrypoints.d.ts +0 -35
  118. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  119. package/dist/shell/npm-bin-entrypoints.js +12 -85
  120. package/package.json +24 -4
  121. package/public/_assets/runtime/{node-shims-9e1380d9ee430fcc.js → node-shims-8f8c64edd2a1f0f5.js} +305 -29
  122. package/public/index.html +1 -1
  123. package/scripts/bundle-facet-workers.mjs +1 -1
  124. package/scripts/bundle-npm-cjs.mjs +2 -2
  125. package/dist/facets/on-demand-bundle-gate.d.ts +0 -65
  126. package/dist/facets/on-demand-bundle-gate.d.ts.map +0 -1
  127. package/dist/facets/on-demand-bundle-gate.js +0 -125
  128. package/dist/npm/install-args.d.ts +0 -21
  129. package/dist/npm/install-args.d.ts.map +0 -1
  130. package/dist/npm/install-args.js +0 -70
  131. package/dist/npm/npm-log.d.ts +0 -31
  132. package/dist/npm/npm-log.d.ts.map +0 -1
  133. package/dist/npm/npm-log.js +0 -51
@@ -57,6 +57,14 @@ export interface ExecTelemetryRecord {
57
57
  fsRpcReads: number;
58
58
  /** Whether the prefetch bundle was served from cache (no VFS walk). */
59
59
  cacheHit: boolean;
60
+ /**
61
+ * Durable Object turns the bundle build was paged across — the alarm
62
+ * round trips `TurnBudget` took before the process could start. 0 when the
63
+ * whole build fit in the turn that asked for it, which is every cache hit
64
+ * and every small tree; the count is what says a large tree cost turns
65
+ * rather than a held thread.
66
+ */
67
+ turns: number;
60
68
  /** Exit code, for cross-referencing telemetry against failures. */
61
69
  exitCode: number;
62
70
  /** Wall-clock at record time (supervisor side). */
@@ -1 +1 @@
1
- {"version":3,"file":"exec-telemetry.d.ts","sourceRoot":"","sources":["../../src/facets/exec-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd;0EACsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB;;gEAE4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,mBAAmB,EACnB,QAAQ,GAAG,OAAO,GAAG,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,CAC1F,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAIlE;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,mBAAmB,EAAE,CAEzD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
1
+ {"version":3,"file":"exec-telemetry.d.ts","sourceRoot":"","sources":["../../src/facets/exec-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IAClC,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd;0EACsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;;;OASG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB;;gEAE4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,mBAAmB,EACnB,QAAQ,GAAG,OAAO,GAAG,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,CAC1F,CAAC;AAKF;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAIlE;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,IAAI,mBAAmB,EAAE,CAEzD;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
@@ -25,6 +25,7 @@ import { EsbuildService, type TransformResult } from '@nimbus-sh/core/runtime/es
25
25
  import { type ProcessHostFactory, type ResidentCodeSpec } from '@nimbus-sh/fabric/process-fabric.js';
26
26
  import { type OpencodeRunnerOptions } from '../runtime/opencode-facet-runner.js';
27
27
  import { type FacetBundleProfile } from '@nimbus-sh/core/runtime/bundle-profile.js';
28
+ import { type WasmImageRecord } from './wasm-image-digest.js';
28
29
  type EsbuildTransformOptions = NonNullable<Parameters<EsbuildService['transform']>[1]>;
29
30
  type LargeEsmTransform = (code: string, options: EsbuildTransformOptions) => Promise<TransformResult>;
30
31
  /** Result returned from a facet execution */
@@ -75,34 +76,6 @@ export interface StagedArtifactExecResult extends FacetExecResult {
75
76
  /** For the resident server path: the loopback port the facet is bound to. */
76
77
  port?: number;
77
78
  }
78
- /**
79
- * Reserve held back from a one-shot facet's lifetime so a program that runs
80
- * out of time is still alive to say so.
81
- *
82
- * A one-shot exec is ALREADY bounded: `_execWithTimeout` kills it at
83
- * FACET_TIMEOUT_MS with exit 124 and "[process killed: timeout after 30s]".
84
- * The entry drain must therefore not be a second, tighter, independent
85
- * timeout. Measured against a deployed Worker, floating async work of 5s /
86
- * 15s / 25s completes and 40s is killed by that outer bound at exactly 30s —
87
- * so the fixed 8s budget this used to carry was abandoning programs 22
88
- * seconds before anything actually required it.
89
- *
90
- * The drain therefore runs to the outer bound MINUS this reserve, which is
91
- * what buys the facet time to flush and report the honest "still in flight"
92
- * reason instead of the supervisor's generic kill. The reserve has to cover
93
- * the longest tail a facet can have after the drain: settling pending RPC,
94
- * writing back __vfsWrites (bounded by MAX_RPC_SAFE_PAYLOAD_BYTES; a 20 MiB
95
- * write-back measures ~1.5s), draining children, then reportExit.
96
- */
97
- export declare const ONE_SHOT_EXIT_RESERVE_MS = 3000;
98
- /**
99
- * Budget used when the supervisor did not stamp an absolute deadline on the
100
- * payload. The deadline is the real bound — see `entryDeadlineAt` — because
101
- * it is measured from the supervisor's own timer rather than restarted when
102
- * the drain begins, so a slow module init cannot push the drain past the kill
103
- * and lose the honest message.
104
- */
105
- export declare const ONE_SHOT_ENTRY_DEADLINE_MS: number;
106
79
  /**
107
80
  * How long a RESIDENT facet settles its startup before answering its boot
108
81
  * call. It keeps running afterwards, so this is not a lifetime decision: the
@@ -118,8 +91,11 @@ export declare const RESIDENT_BOOT_SETTLE_MS = 1000;
118
91
  * servers, requests in flight. A promise is not a handle: a program whose
119
92
  * last act leaves `new Promise(() => {})` unsettled prints its output and
120
93
  * exits 0. Counting unsettled promises as work was a real divergence from
121
- * that — such a program burned the whole facet lifetime and was then
122
- * reported as having not finished.
94
+ * that — such a program's drain used to end early and it was
95
+ * reported as having not finished. A user-invoked program runs this loop
96
+ * with NO deadline — Node itself has no wall-clock kill; the only endings
97
+ * are the program's exit and a signal. Callers that still pass a finite
98
+ * deadline (the resident boot settle) arm the expiry timer.
123
99
  *
124
100
  * Three kinds of handle, each owned by the shim that creates them:
125
101
  *
@@ -132,19 +108,12 @@ export declare const RESIDENT_BOOT_SETTLE_MS = 1000;
132
108
  * - listening SERVERS (`__portRegistry`), open until the program closes
133
109
  * them.
134
110
  *
135
- * The bound is a REAL wall-clock deadline, armed as a timer rather than
136
- * compared against `Date.now()`: a `setTimeout(0)` turn in workerd costs
137
- * ~5µs, so the pass budget this loop used to carry (50k) expired after
138
- * ~150ms and silently overrode every longer deadline the callers declared —
139
- * anything slower than that, including an ordinary network fetch, was
140
- * abandoned mid-flight and reported as a clean exit.
141
- *
142
111
  * The loop subscribes to the exit promise ONCE — a per-pass
143
112
  * `exitPromise.then()` allocates a promise every iteration — and yields
144
113
  * through the raw setTimeout so its own ticks don't inflate the timer count
145
114
  * it watches.
146
115
  */
147
- export declare const ENTRYPOINT_EVENT_LOOP = "\nfunction __nimbusHandleCount(__name) {\n const __value = globalThis[__name];\n return typeof __value === \"number\" ? __value : 0;\n}\n\n// Work an entrypoint's STARTUP has to settle before it can be called booted.\nfunction __nimbusPendingStartupWork() {\n return __nimbusHandleCount(\"__nimbusPendingTimers\") + __nimbusHandleCount(\"__nimbusPendingOps\");\n}\n\n// The above, plus the handles a program holds open on purpose. A bound port\n// keeps a Node process alive, and it keeps a one-shot facet alive too.\nfunction __nimbusLiveHandles() {\n const __servers = globalThis.__portRegistry;\n const __bound = __servers && typeof __servers.size === \"number\" ? __servers.size : 0;\n return __nimbusPendingStartupWork() + __bound;\n}\n\nasync function __nimbusRunEventLoop(__countHandles, __exitPromise, __deadlineMs, __minPasses) {\n let __exited = false;\n if (__exitPromise && typeof __exitPromise.then === \"function\") {\n __exitPromise.then(() => { __exited = true; }, () => { __exited = true; });\n }\n const __rawSetTimeout = (typeof globalThis.__nimbusRawSetTimeout === \"function\")\n ? globalThis.__nimbusRawSetTimeout\n : globalThis.setTimeout;\n const __rawClearTimeout = (typeof globalThis.__nimbusRawClearTimeout === \"function\")\n ? globalThis.__nimbusRawClearTimeout\n : globalThis.clearTimeout;\n let __expired = false;\n const __deadline = __rawSetTimeout(() => { __expired = true; }, __deadlineMs);\n let __pass = 0;\n while (!__exited && !__expired && (__pass < __minPasses || __countHandles() > 0)) {\n // The warm-up passes give a settling microtask chain its turns and cost\n // ~5\u00B5s each; past them the loop is waiting on wall-clock work, where\n // spinning at 0ms would burn the isolate's CPU for the whole deadline.\n await new Promise((resolve) => __rawSetTimeout(resolve, __pass < __minPasses ? 0 : 1));\n __pass++;\n }\n try { __rawClearTimeout(__deadline); } catch {}\n // `pending` is what the caller reports when it gives up: a one-shot program\n // still holding a handle did NOT finish, and exiting 0 would claim it did.\n return { passes: __pass, pending: __exited ? 0 : __countHandles() };\n}\n\n// An ESM entry's own evaluation promise (top-level await) is the one promise\n// that IS a handle \u2014 the module has not finished loading until it settles.\n// Answers true when process.exit won the race instead.\nasync function __nimbusAwaitEntryEvaluation(__entryResult) {\n if (!__entryResult || typeof __entryResult.then !== \"function\") return false;\n const __exit = {};\n const __raced = await Promise.race([\n __entryResult.then(() => null),\n __nimbusProcessExitPromise.then(() => __exit, () => __exit),\n ]);\n return __raced === __exit;\n}\n\n// A one-shot facet's lifetime IS the loop: it runs the program until Node\n// would exit, or until the lifetime budget runs out.\nasync function __nimbusRunEntrypointToExit(__entryResult, __deadlineMs) {\n if (await __nimbusAwaitEntryEvaluation(__entryResult)) return { passes: 0, pending: 0 };\n return await __nimbusRunEventLoop(__nimbusLiveHandles, __nimbusProcessExitPromise, __deadlineMs, 4);\n}\n\n// A resident facet keeps running after the call that boots it returns, so it\n// settles startup and nothing more. The handles it holds open deliberately \u2014\n// its listening port \u2014 are the point of it, not a reason to make the shell's\n// prompt wait.\nasync function __nimbusSettleEntrypointStartup(__entryResult, __deadlineMs) {\n if (await __nimbusAwaitEntryEvaluation(__entryResult)) return { passes: 0, pending: 0 };\n return await __nimbusRunEventLoop(\n __nimbusPendingStartupWork, __nimbusProcessExitPromise, __deadlineMs, 4,\n );\n}\n";
116
+ export declare const ENTRYPOINT_EVENT_LOOP = "\nfunction __nimbusHandleCount(__name) {\n const __value = globalThis[__name];\n return typeof __value === \"number\" ? __value : 0;\n}\n\n// Work an entrypoint's STARTUP has to settle before it can be called booted.\nfunction __nimbusPendingStartupWork() {\n return __nimbusHandleCount(\"__nimbusPendingTimers\") + __nimbusHandleCount(\"__nimbusPendingOps\");\n}\n\n// The above, plus the handles a program holds open on purpose. A bound port\n// keeps a Node process alive, and it keeps a one-shot facet alive too.\nfunction __nimbusLiveHandles() {\n const __servers = globalThis.__portRegistry;\n const __bound = __servers && typeof __servers.size === \"number\" ? __servers.size : 0;\n return __nimbusPendingStartupWork() + __bound;\n}\n\nasync function __nimbusRunEventLoop(__countHandles, __exitPromise, __deadlineMs, __minPasses) {\n let __exited = false;\n if (__exitPromise && typeof __exitPromise.then === \"function\") {\n __exitPromise.then(() => { __exited = true; }, () => { __exited = true; });\n }\n const __rawSetTimeout = (typeof globalThis.__nimbusRawSetTimeout === \"function\")\n ? globalThis.__nimbusRawSetTimeout\n : globalThis.setTimeout;\n const __rawClearTimeout = (typeof globalThis.__nimbusRawClearTimeout === \"function\")\n ? globalThis.__nimbusRawClearTimeout\n : globalThis.clearTimeout;\n let __expired = false;\n let __pass = 0;\n // A user-invoked program runs until it exits or is killed \u2014 there is no\n // wall-clock deadline, so no expiry timer is armed at all. (Callers that\n // still pass a finite deadline get the timer for compatibility.)\n const __deadline = Number.isFinite(__deadlineMs)\n ? __rawSetTimeout(() => { __expired = true; }, __deadlineMs)\n : null;\n while (!__exited && !__expired && (__pass < __minPasses || __countHandles() > 0)) {\n // The warm-up passes give a settling microtask chain its turns and cost\n // ~5\u00B5s each; past them the loop is waiting on wall-clock work, where\n // spinning at 0ms would burn the isolate's CPU indefinitely.\n await new Promise((resolve) => __rawSetTimeout(resolve, __pass < __minPasses ? 0 : 1));\n __pass++;\n }\n if (__deadline !== null) { try { __rawClearTimeout(__deadline); } catch {} }\n // `pending` is what the caller reports when it gives up: a one-shot program\n // still holding a handle did NOT finish, and exiting 0 would claim it did.\n return { passes: __pass, pending: __exited ? 0 : __countHandles() };\n}\n\n// An ESM entry's own evaluation promise (top-level await) is the one promise\n// that IS a handle \u2014 the module has not finished loading until it settles.\n// Answers true when process.exit won the race instead.\nasync function __nimbusAwaitEntryEvaluation(__entryResult) {\n if (!__entryResult || typeof __entryResult.then !== \"function\") return false;\n const __exit = {};\n const __raced = await Promise.race([\n __entryResult.then(() => null),\n __nimbusProcessExitPromise.then(() => __exit, () => __exit),\n ]);\n return __raced === __exit;\n}\n\n// A one-shot facet's lifetime IS the loop: it runs the program until Node\n// would exit, or until the lifetime budget runs out.\nasync function __nimbusRunEntrypointToExit(__entryResult, __deadlineMs) {\n if (await __nimbusAwaitEntryEvaluation(__entryResult)) return { passes: 0, pending: 0 };\n return await __nimbusRunEventLoop(__nimbusLiveHandles, __nimbusProcessExitPromise, __deadlineMs, 4);\n}\n\n// A resident facet keeps running after the call that boots it returns, so it\n// settles startup and nothing more. The handles it holds open deliberately \u2014\n// its listening port \u2014 are the point of it, not a reason to make the shell's\n// prompt wait.\nasync function __nimbusSettleEntrypointStartup(__entryResult, __deadlineMs) {\n if (await __nimbusAwaitEntryEvaluation(__entryResult)) return { passes: 0, pending: 0 };\n return await __nimbusRunEventLoop(\n __nimbusPendingStartupWork, __nimbusProcessExitPromise, __deadlineMs, 4,\n );\n}\n";
148
117
  /**
149
118
  * A generated facet's module map: its main module plus whatever side modules
150
119
  * the VFS bundle had to be partitioned across.
@@ -156,14 +125,32 @@ interface GeneratedNodeFacetCode {
156
125
  /**
157
126
  * Generate one-shot runtime code with a plain fetch handler.
158
127
  */
159
- export declare function generateEntrypointCode(userCode: string, vfsState: FacetVfsState, usesSqlite: boolean, shims: string): Promise<GeneratedNodeFacetCode>;
128
+ export declare function generateEntrypointCode(userCode: string, vfsState: FacetVfsState, usesSqlite: boolean, shims: string, wasmImports?: readonly FacetWasmImport[]): Promise<GeneratedNodeFacetCode>;
129
+ /** One wasm image the generated main module imports from the module map. */
130
+ export interface FacetWasmImport {
131
+ /** The module-map name the boot spec carries the image under. */
132
+ moduleName: string;
133
+ /** The absolute VFS path the program reads the same bytes from. */
134
+ vfsPath: string;
135
+ /**
136
+ * A content key for the same bytes, for an image the program never reads
137
+ * from the filesystem — one inlined in a package's own source as base64.
138
+ * The seam recognises the bytes instead of the path.
139
+ */
140
+ digest?: string;
141
+ }
142
+ /** The module-map name a precompiled wasm image travels under. */
143
+ export declare function facetWasmModuleName(index: number): string;
160
144
  /**
161
- * Generate a long-running Node entrypoint.
162
- *
163
- * Same core shim/VFS machinery as foreground node execution, but the
164
- * compiled user entry is booted once and the exported entrypoint keeps
165
- * serving HTTP requests from the shimmed http.Server registry.
145
+ * The wasm imports one launch stages: the images its options name, then
146
+ * every image the closure walk recorded (FacetVfsState.wasmImages) that the
147
+ * options did not already name by path. One member per path; the closure's
148
+ * record supplies the digest an option without one lacks.
166
149
  */
150
+ export declare function facetWasmImports(named: readonly {
151
+ vfsPath: string;
152
+ digest: string | undefined;
153
+ }[], closure: readonly WasmImageRecord[]): FacetWasmImport[];
167
154
  export declare function generateLongRunningNodeCode(userCode: string, vfsState: FacetVfsState, opts: {
168
155
  argv?: string[];
169
156
  env?: Record<string, string>;
@@ -173,6 +160,8 @@ export declare function generateLongRunningNodeCode(userCode: string, vfsState:
173
160
  stdin?: string;
174
161
  attachedTty?: boolean;
175
162
  cred: ProcessEntry['cred'];
163
+ /** Wasm images the generated main module imports and parks in the seam. */
164
+ wasmImports?: readonly FacetWasmImport[];
176
165
  }, usesSqlite: boolean, shims: string, pacer?: TurnBudget): Promise<GeneratedNodeFacetCode>;
177
166
  /**
178
167
  * Result of preparing facet VFS state.
@@ -238,6 +227,11 @@ interface FacetVfsState {
238
227
  serializedMetadata?: string;
239
228
  /** Move the bundle out of the main module when combined state exceeds its ceiling. */
240
229
  bundleSideModulesRequired?: boolean;
230
+ /**
231
+ * The wasm images the closure holds, by path and content digest — see
232
+ * `collectClosureWasmImages`. A launch stages each as a wasm map entry.
233
+ */
234
+ wasmImages?: readonly WasmImageRecord[];
241
235
  /**
242
236
  * Memoized `bundleUsesNodeSqlite(entryCode, bundle)`. Answered while the raw
243
237
  * cells are still in hand so `releaseSerializedSources` can drop them — it is
@@ -263,38 +257,37 @@ interface FacetVfsState {
263
257
  * `bundleSource`, `serializedManifest` and `serializedMetadata` are total
264
258
  * encodings of `bundle`, `manifest` and `metadata` — no caller can distinguish
265
259
  * a state carrying both from one carrying only the serialized halves, because
266
- * `generateEntrypointCode` reads the serialized halves and nothing else does.
260
+ * both facet generators read the serialized halves and nothing else does.
267
261
  * Holding both doubles the cost of a cached entry for its whole lifetime, and
268
262
  * that lifetime spans execs.
269
263
  *
270
- * Only for states on the one-shot cached path, and applied there whether or
271
- * not the entry turns out small enough to retain: the invocation being served
272
- * reads the serialized forms too. `spawnNode` and `_stageOpencodeFacet` build
273
- * their own uncached states and genuinely re-read the raw cells
274
- * (`_serializeBundleForFacet`, `assertStagedBundleFitsRpcPayload`); neither
275
- * goes through here.
264
+ * Applied by `_buildProcessBundle` to every state it builds, whether or not
265
+ * the entry turns out small enough to retain: the launch being served reads
266
+ * the serialized forms too. `_stageOpencodeFacet` builds its own uncached
267
+ * state and genuinely re-reads the raw cells
268
+ * (`assertStagedBundleFitsRpcPayload`); it does not go through here.
276
269
  */
277
270
  export declare function releaseSerializedSources(vfsState: FacetVfsState): void;
278
271
  /**
279
- * Drop everything a resident launch has finished reading, in place.
272
+ * Drop the serialized forms once a module map has been generated from them.
280
273
  *
281
- * The one-shot path releases its map at LOADER.load; this is the same policy
282
- * for the path `spawnNode` takes, which is the path every attached-TTY npm bin
283
- * takes — how a real agentic CLI starts. The generated source is a total
284
- * encoding of the cells, the manifest and the metadata, and the only thing the
285
- * rest of a launch reads off the state is `cursor`. Everything else is a second
286
- * copy of the largest thing this DO builds — 22.9 MB for pi — held for exactly
287
- * as long as the facet takes to boot on it.
274
+ * The generated source is a total encoding of all three: every byte of the
275
+ * bundle expression, the manifest and the metadata is inside it. Holding them
276
+ * afterwards keeps a second copy of the largest thing this DO builds alive for
277
+ * as long as the facet runs — for pi, 22.7 MB across the ~20 s window in which
278
+ * the isolate was being reset. For the one-shot path that window is the run;
279
+ * for a resident launch — the path every attached-TTY npm bin takes, how a
280
+ * real agentic CLI starts — it is the boot, and holding the copy across it
281
+ * reset the session isolate with exceededMemory, which tears the terminal
282
+ * WebSocket down with no exit frame: the dead screen reading "[process
283
+ * terminal closed]".
288
284
  *
289
- * Holding it reset the session isolate with exceededMemory, and an isolate
290
- * reset tears the terminal WebSocket down with no exit frame: the dead screen
291
- * reading "[process terminal closed]".
292
- *
293
- * An emptied state can still generate a map — it would just generate one with
294
- * no program in it — so this marks the state instead of trusting callers to
295
- * stop.
285
+ * Only for a state the prefetch cache refused. A retained entry's serialized
286
+ * forms ARE the entry, and a later launch is served from them. An emptied
287
+ * state could still generate a map — one with no program in it — so this
288
+ * marks the state instead of trusting callers to stop.
296
289
  */
297
- export declare function releaseResidentLaunchSources(vfsState: FacetVfsState): void;
290
+ export declare function releaseGeneratedSources(vfsState: FacetVfsState): void;
298
291
  interface FacetVfsBundleSource {
299
292
  expression: string;
300
293
  imports: string;
@@ -351,13 +344,35 @@ export declare function assertStagedBundleFitsRpcPayload(serialized: string, bun
351
344
  * computed-path requires). Bounded to package.json + 1 main-entry file
352
345
  * per package — sub-agent §Q3 quantified the worst-case cumulative
353
346
  * budget impact (~322 KiB for fastify, ~1.7 MiB for ts-jest).
347
+ *
348
+ * `requiredPaths` is the static require closure. A package the closure
349
+ * already reached — but reached only through a SUBPATH — has its main entry
350
+ * skipped; see `mainIsSpeculative`.
354
351
  */
355
352
  export declare function greedyAddMainEntries(vfs: CredentialedVfs, cwd: string, bundle: Record<string, string | Uint8Array>, budgetState: {
356
353
  totalBytes: number;
357
354
  fileCount: number;
358
- }): {
355
+ }, requiredPaths?: ReadonlySet<string>): {
359
356
  added: number;
360
357
  };
358
+ /**
359
+ * The packages a computed `require(name)` inside the program can plausibly
360
+ * name: the project root's own runtime `dependencies`, plus every package
361
+ * ONE `dependencies` hop from a package that already owns a file in the
362
+ * static closure. Never devDependencies, never a second hop.
363
+ *
364
+ * Unbounded, the greedy oversample read every installed package's main:
365
+ * for `node -e "import('got')"` in got's repo — a one-file static closure —
366
+ * that was 1,526 files / 10.9 MB from 706 packages, which every later pass
367
+ * re-scanned and esbuild-wasm transformed, and the exec path's 20 s bundle
368
+ * deadline fired on a program that reads none of it. A bound that followed
369
+ * dependency edges from the project's devDependencies reached all 772 of
370
+ * them (measured), because a library repo's dev toolchain reaches the whole
371
+ * tree. Computed requires almost always target a declared runtime
372
+ * dependency of the package doing the requiring, so the bound is one hop
373
+ * over `dependencies` only. Directories, sorted for a stable bundle.
374
+ */
375
+ export declare function speculativePackageDirs(vfs: CredentialedVfs, cwdStripped: string, bundle: Record<string, string | Uint8Array>): string[];
361
376
  /**
362
377
  * X.5-Z3: scan every JS source already in `bundle` for static
363
378
  * `fs.readFileSync(path.resolve(__dirname, "<rel>"))` shapes and pull
@@ -489,7 +504,21 @@ export declare function addBinTargetSiblings(vfs: CredentialedVfs, scriptPath: s
489
504
  fileCount: number;
490
505
  }, bundleProfile: FacetBundleProfile): {
491
506
  added: number;
507
+ wasmPaths: string[];
492
508
  };
509
+ /**
510
+ * The wasm images a program's closure holds, by path and content digest.
511
+ *
512
+ * Two sources, one record: a `.wasm` cell the walk already staged (digested
513
+ * from the cell, no second read), and a `.wasm` file the bin-package pass
514
+ * saw but did not stage because it is over the bundle's per-file cap —
515
+ * esbuild-wasm's 11.9 MiB image is the motivating one. A launch stages each
516
+ * as a module-map member the loader compiles, registered under both keys,
517
+ * so the program's own `new WebAssembly.Module(bytes)` is answered from the
518
+ * map whether it read the bytes by path or carried them inline. A file that
519
+ * cannot be read is left out; the seam's refusal names the module later.
520
+ */
521
+ export declare function collectClosureWasmImages(vfs: Pick<CredentialedVfs, 'readFile'>, bundle: Record<string, string | Uint8Array | FacetVfsDenial>, unstagedPaths: readonly string[]): WasmImageRecord[];
493
522
  /**
494
523
  * Stage the paths an earlier run of the same entry read synchronously and did
495
524
  * not have.
@@ -577,7 +606,7 @@ export declare const BUNDLE_PRECOMPILE_LOOP: string;
577
606
  * behaviour for code paths that don't have esbuild handy).
578
607
  *
579
608
  */
580
- export declare function buildPrefetchBundle(vfs: CredentialedVfs, scriptPath: string | undefined, cwd: string, entryCode: string, esbuild?: EsbuildService, bundleProfile?: FacetBundleProfile, observedReads?: ReadonlySet<string>, pacer?: TurnBudget, isolatedTransform?: LargeEsmTransform): Promise<FacetVfsState>;
609
+ export declare function buildPrefetchBundle(vfs: CredentialedVfs, scriptPath: string | undefined, cwd: string, entryCode: string, esbuild?: EsbuildService, bundleProfile?: FacetBundleProfile, observedReads?: ReadonlySet<string>, pacer?: TurnBudget, isolatedTransform?: LargeEsmTransform, maxBundleBytes?: number): Promise<FacetVfsState>;
581
610
  /**
582
611
  * Optional hooks wired in by NimbusSession. Kept as callbacks so
583
612
  * FacetManager stays unaware of the session / log-store types.
@@ -646,6 +675,20 @@ export interface LongRunningWorkerSpawnOptions {
646
675
  * 34.3 MiB, past what any single RPC value may carry.
647
676
  */
648
677
  vfsWasmModules?: Record<string, string>;
678
+ /**
679
+ * Module name → VFS path of a content-addressed module SOURCE, read as
680
+ * UTF-8 when the facet loads — the same by-path posture as
681
+ * `vfsWasmModules`, through the same kernel image reader, for module text
682
+ * an embedder keeps in its own content store rather than carrying by value.
683
+ * Each path must name its own digest (`…/<sha256>.js`, see fabric's
684
+ * `facetImagePath`); the loader verifies it on read.
685
+ */
686
+ vfsTextModules?: Record<string, string>;
687
+ /**
688
+ * The module the isolate boots from; `workerCode` is placed under this name
689
+ * in the module map. Default `'worker.js'`.
690
+ */
691
+ mainModule?: string;
649
692
  compatibilityFlags?: string[];
650
693
  compatibilityDate?: string;
651
694
  env?: ResidentCodeSpec['env'];
@@ -665,6 +708,29 @@ export interface LongRunningWorkerSpawnOptions {
665
708
  };
666
709
  };
667
710
  }
711
+ /** The main module name a worker launch boots from unless told otherwise. */
712
+ export declare const DEFAULT_WORKER_MAIN_MODULE = "worker.js";
713
+ /**
714
+ * The narrow handle `spawnWorker` returns beside the pid: the process's own
715
+ * inbound surface, bound to the resident handle's route target, for an
716
+ * embedder that invokes the worker directly rather than through a registered
717
+ * port. It carries NO release — `kill(pid)` remains the one lifecycle owner,
718
+ * and this handle is dead once that pid is; nothing here can end, restart or
719
+ * detach the process.
720
+ */
721
+ export interface WorkerFacet {
722
+ /** Inbound HTTP, on the facet's `handleHttpRequest`. */
723
+ fetch(request: Request): Promise<Response>;
724
+ /** Inbound WebSocket upgrade, on the facet's `handleWebSocketRequest`. */
725
+ connect(request: Request): Promise<Response>;
726
+ }
727
+ /** What `spawnWorker` answers with. */
728
+ export interface SpawnedWorker {
729
+ pid: number;
730
+ /** The runner's startProcess payload. */
731
+ boot: unknown;
732
+ facet: WorkerFacet;
733
+ }
668
734
  /** What `spawnNode` needs to build and boot one resident Node process. */
669
735
  export interface ResidentSpawnOptions {
670
736
  argv?: string[];
@@ -682,6 +748,18 @@ export interface ResidentSpawnOptions {
682
748
  /** The launch inputs a re-drive rebuilds a worker from: content digests and
683
749
  * transport, never env or credentials — the embedder resolves those. */
684
750
  export interface WorkerRecipe {
751
+ /**
752
+ * Set only for an interpreter resident the SESSION launched itself — a
753
+ * `python`/`ruby` socket server whose image is the runtime the session
754
+ * installed. It is the runtime and argv of that interpreter, never a
755
+ * boolean, and it is what routes the recipe's re-drive to the session's own
756
+ * image-store fallback (`resolveWorkerLaunchFallback`) rather than the
757
+ * embedder's `resolveWorkerLaunch`: the session owns that image and its
758
+ * bookkeeping, and no embedder was asked about the launch. A worker recipe
759
+ * WITHOUT it — every embedder-driven `spawnWorker` — re-drives through the
760
+ * embedder's resolver, with the fallback consulted only when no embedder
761
+ * hook is composed.
762
+ */
685
763
  resident?: LongRunningWorkerSpawnOptions['resident'];
686
764
  kind: 'worker';
687
765
  /** The durable application this process belongs to, keyed by the embedder. */
@@ -696,6 +774,12 @@ export interface WorkerRecipe {
696
774
  compatibilityDate: string;
697
775
  compatibilityFlags: string[];
698
776
  startArgs?: unknown;
777
+ /**
778
+ * The main module the launch booted from, when it was not the default —
779
+ * so a re-drive whose resolver answers modules alone still boots the same
780
+ * one. Rows written before the field existed booted `worker.js`.
781
+ */
782
+ mainModule?: string;
699
783
  }
700
784
  export type ResidentRestartPolicy = 'never' | 'on-failure';
701
785
  /** The env var a launch reads its restart policy from — set by startProcess({ restart }) and `nimbus start --restart`. */
@@ -725,10 +809,17 @@ export interface ResolvedWorkerLaunch {
725
809
  /** Null is the absent answer — the same JSON the image blob carries. */
726
810
  env: ResidentCodeSpec['env'] | null;
727
811
  globalOutbound: ResidentCodeSpec['globalOutbound'];
728
- /** Module name → source text, including the `worker.js` main module. */
812
+ /** Module name → source text, including the main module under its name. */
729
813
  modules: Record<string, string>;
730
814
  /** Module name → VFS path of a wasm image, restored with the launch. */
731
815
  vfsWasmModules?: Record<string, string>;
816
+ /** Module name → VFS path of a content-addressed module source, restored with the launch. */
817
+ vfsTextModules?: Record<string, string>;
818
+ /**
819
+ * The name in `modules` the launch boots from. Absent, the recipe's own
820
+ * `mainModule` decides, then `'worker.js'`.
821
+ */
822
+ mainModule?: string;
732
823
  }
733
824
  export declare class FacetManager {
734
825
  private ctx;
@@ -772,7 +863,6 @@ export declare class FacetManager {
772
863
  * journal recovery rides the first pump.
773
864
  */
774
865
  private readonly launchPump;
775
- private timedOutProcessIds;
776
866
  private _pairedServeFacet;
777
867
  /**
778
868
  * W3.5 Fix B: lazily-created EsbuildService for the ESM→CJS pre-pass
@@ -880,39 +970,56 @@ export declare class FacetManager {
880
970
  */
881
971
  setEsbuildService(esbuild: EsbuildService): void;
882
972
  /**
883
- * buildPrefetchBundle wrapped in a global-revision-keyed cache. On a hit
884
- * (same key AND the VFS hasn't been mutated since) it returns the memoized
885
- * bundle + pre-built facet source, skipping the full VFS walk + esbuild
886
- * pass + source construction. See `prefetchBundleCache` for the
887
- * correctness argument behind the conservative global-revision watermark.
888
- *
889
- * The bundle source and manifest are computed once on the miss path and
890
- * stored so subsequent hits skip rebuilding them too.
973
+ * The pacer every launch is built under: the session's alarm-driven turn
974
+ * pump, the deployment's chunk bound, and the one check a suspended launch
975
+ * makes when it resumes — that the process it is building for still exists.
891
976
  */
977
+ private _launchPacer;
892
978
  /**
893
- * Bound the prefetch build, so a cache miss cannot be a silent hang.
979
+ * Assemble the filesystem bundle a process boots on, across as many
980
+ * Durable Object turns as it takes.
894
981
  *
895
- * The build was awaited entirely OUTSIDE `_execWithTimeout`, which wraps
896
- * only `_execViaLoader`. So every timeout in the system — the 30 s facet
897
- * bound, the 60 s bin-dispatch bound — sat downstream of a step that could
898
- * take arbitrarily long, and a heavy build wedged the Durable Object with
899
- * nothing able to report it. Observed as a terminal that goes quiet and
900
- * never returns, with no exit record for the process.
982
+ * The one builder for every Node process this manager starts. A one-shot
983
+ * exec and a resident launch used to own two copies of this: exec's was
984
+ * memoized behind the prefetch cache and raced a wall-clock deadline in a
985
+ * single turn; the resident's was paged with a TurnBudget and never cached.
986
+ * Two paths, one job — and a tree large enough to page on one path hit the
987
+ * deadline on the other, failing every `node -e` in it with "assembling the
988
+ * filesystem bundle … exceeded". What the two callers genuinely differ in is
989
+ * the entry, the working directory and the process they build for; that is
990
+ * all they supply. Everything else — the revision-keyed cache and its stale
991
+ * eviction, the residency profile a previous miss learned, the reachable-set
992
+ * walk and its enrichment passes, the ESM→CJS transform, the manifest and
993
+ * metadata, the module-map serialization with its side-module split, the
994
+ * `node:sqlite` answer, and the release of the raw cells once they are
995
+ * serialized — happens here, once, and yields the turn whenever a chunk's
996
+ * worth of it has been done.
901
997
  *
902
- * WHAT THIS CAN AND CANNOT CATCH, stated plainly because the difference
903
- * decides whether a given hang is fixed by it. The build is asynchronous —
904
- * it awaits the VFS walk and the esbuild ESM→CJS pass — so a stall at any
905
- * of those points is caught and reported here. A stall inside ONE
906
- * synchronous stretch is not: a JS stack that never yields cannot be raced
907
- * by anything in the same isolate, so serializing a multi-megabyte bundle
908
- * in a single pass still wedges, and the deadline fires only once the stack
909
- * finally unwinds. That class needs the work bounded at its INPUT rather
910
- * than timed at its edge, which is a separate change; this one converts
911
- * every interruptible stall from a silent wedge into a loud failure, and
912
- * makes the remaining class the only one left to explain.
913
- */
914
- private _withBundleBuildDeadline;
915
- private _buildPrefetchBundleCached;
998
+ * There is no deadline. A launch that spans turns costs turns, not a held
999
+ * thread, so a large tree is not a defect to be reported at N seconds; the
1000
+ * pacer's `stillWanted` check is what ends a build nothing will use — a
1001
+ * process killed while its build was suspended throws from the next resume,
1002
+ * and the caller reports that as it reports any other launch failure.
1003
+ *
1004
+ * The returned state carries its serialized forms (`bundleSource`,
1005
+ * `serializedManifest`, `serializedMetadata`) and has already released the
1006
+ * raw ones: `generateEntrypointCode` and `generateLongRunningNodeCode` read
1007
+ * the serialized forms and nothing else. A state the cache retained belongs
1008
+ * to the cache — a caller must not release its serialized forms either
1009
+ * (`cacheRetained` says which); one the cache refused belongs to the caller
1010
+ * alone, and `releaseGeneratedSources` drops it once a map is generated.
1011
+ *
1012
+ * A session without a filesystem gets an empty state: there is nothing to
1013
+ * stage and nothing to yield for.
1014
+ */
1015
+ /**
1016
+ * The closure's wasm images as module-map members for a one-shot facet,
1017
+ * read by path under the process's own credential. An image that cannot
1018
+ * be read is left out; the program's compile then meets the seam's own
1019
+ * refusal, which names the module.
1020
+ */
1021
+ private _wasmModulesByValue;
1022
+ private _buildProcessBundle;
916
1023
  /**
917
1024
  * Admit an entry and evict, oldest first, until the LRU is inside BOTH its
918
1025
  * entry count and its byte bound.
@@ -989,6 +1096,8 @@ export declare class FacetManager {
989
1096
  /** Return stdout/stderr in the result while keeping supervisor RPC
990
1097
  * available for VFS and child_process operations. */
991
1098
  captureOutput?: boolean;
1099
+ /** Shell abort (Ctrl+C): aborting this aborts the in-flight run. */
1100
+ signal?: AbortSignal;
992
1101
  }): Promise<FacetExecResult>;
993
1102
  /**
994
1103
  * W5 Lever 5: push a DiagFailure into the OOM ring for every facet
@@ -1141,8 +1250,6 @@ export declare class FacetManager {
1141
1250
  private _failLaunch;
1142
1251
  /** Flush files written by the script back to the supervisor's VFS. */
1143
1252
  private _flushVfsWrites;
1144
- /** Execution timeout. */
1145
- private _execWithTimeout;
1146
1253
  /**
1147
1254
  * Re-drive a journalled launch after an instance reset. What the journal
1148
1255
  * row carries is the recipe and nothing else: env and credentials are never
@@ -1183,10 +1290,21 @@ export declare class FacetManager {
1183
1290
  private _runResidentLaunch;
1184
1291
  private _residentLaunchBody;
1185
1292
  /**
1186
- * Spawn a long-running dynamic Worker, boot it, and return its boot payload.
1293
+ * The exit code of a launched process that has already ended, or null
1294
+ * while it runs. What a caller that started a resident reads to tell a
1295
+ * server that is up from a program that finished during its boot.
1296
+ */
1297
+ processExitCode(pid: number): number | null;
1298
+ /**
1299
+ * Spawn a long-running dynamic Worker, boot it, and return its boot payload
1300
+ * beside the pid and the process's own inbound facet.
1187
1301
  *
1188
1302
  * The shared primitive for any runtime that serves over
1189
- * handleHttpRequest(Request) — the python and ruby socket servers today.
1303
+ * handleHttpRequest(Request) — the python and ruby socket servers today —
1304
+ * and for an embedder's own Worker-class program: `workerCode` boots as
1305
+ * `opts.mainModule` (default `worker.js`), `opts.modules` ride inline,
1306
+ * `opts.vfsTextModules` and `opts.vfsWasmModules` are read by path when the
1307
+ * facet loads.
1190
1308
  *
1191
1309
  * The interpreter image it carries is the memory that should not sit in the
1192
1310
  * session's own isolate — ruby's interpreter+stdlib alone is 34.3 MiB — and
@@ -1194,11 +1312,13 @@ export declare class FacetManager {
1194
1312
  * no readiness coupling back into the session: the runner answers
1195
1313
  * startProcess with its boot payload and the caller waits on that one
1196
1314
  * promise, so nothing polls the port to decide the process is up.
1315
+ *
1316
+ * The returned `facet` is bound to the resident handle's route target — the
1317
+ * same target a registered port routes to — so a port-less process can be
1318
+ * invoked directly. It has no release: `kill(pid)` is the one lifecycle
1319
+ * owner, and the facet is dead once the pid is.
1197
1320
  */
1198
- spawnWorker(workerCode: string, command: string, cwd: string, opts?: LongRunningWorkerSpawnOptions): Promise<{
1199
- pid: number;
1200
- boot: unknown;
1201
- }>;
1321
+ spawnWorker(workerCode: string, command: string, cwd: string, opts?: LongRunningWorkerSpawnOptions): Promise<SpawnedWorker>;
1202
1322
  /** `attempt` is the journal's re-drive budget, as `_spawnResident` carries it. */
1203
1323
  private _spawnWorker;
1204
1324
  /**
@@ -1225,7 +1345,18 @@ export declare class FacetManager {
1225
1345
  * the mismatch, so `apps.list` reports it as failed and the user is told.
1226
1346
  */
1227
1347
  private _registerResidentPort;
1228
- /** What a pid's journal row says about who it is; null for a pid without one. */
1348
+ /**
1349
+ * Who a pid is. One resolver, in precedence order: the ephemeral-duplicate
1350
+ * mark, the journal row (the owner a launch this manager made was stamped
1351
+ * with — derived from the launch's own cwd+argv, or adopted from an
1352
+ * explicit reservation), and finally the process table. The table knows
1353
+ * cwd and argv for every pid, so a serving process nothing journalled — the
1354
+ * in-process Vite dev server, real-vite, a staged artifact, any wrapper pid
1355
+ * a builtin adopted — has the same derived identity shape as a resident
1356
+ * and answers to the same app verbs. It just cannot be re-driven after a
1357
+ * reset: only a journal row carries a recipe. Null only for a pid that is
1358
+ * neither journalled nor running.
1359
+ */
1229
1360
  residentIdentity(pid: number): Promise<ResidentIdentity | null>;
1230
1361
  /**
1231
1362
  * Every stamped identity — the reservations, and the journal rows that