@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.
Files changed (184) 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 +677 -342
  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/real-vite-hmr.d.ts +3 -1
  25. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  26. package/dist/facets/real-vite-hmr.js +18 -8
  27. package/dist/facets/vite-dev-server.d.ts +25 -47
  28. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  29. package/dist/facets/vite-dev-server.js +185 -219
  30. package/dist/facets/wasm-image-digest.d.ts +25 -0
  31. package/dist/facets/wasm-image-digest.d.ts.map +1 -0
  32. package/dist/facets/wasm-image-digest.js +25 -0
  33. package/dist/facets/wasm-swap-registry.d.ts +51 -92
  34. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  35. package/dist/facets/wasm-swap-registry.js +68 -227
  36. package/dist/facets/ws-terminal.d.ts +9 -31
  37. package/dist/facets/ws-terminal.d.ts.map +1 -1
  38. package/dist/facets/ws-terminal.js +58 -51
  39. package/dist/git/network-facet.d.ts.map +1 -1
  40. package/dist/git/network-facet.js +6 -5
  41. package/dist/hosted/commands.d.ts +12 -0
  42. package/dist/hosted/commands.d.ts.map +1 -0
  43. package/dist/hosted/commands.js +1658 -0
  44. package/dist/hosted/runtime.d.ts +114 -0
  45. package/dist/hosted/runtime.d.ts.map +1 -0
  46. package/dist/hosted/runtime.js +288 -0
  47. package/dist/hosted/services.d.ts +40 -0
  48. package/dist/hosted/services.d.ts.map +1 -0
  49. package/dist/hosted/services.js +512 -0
  50. package/dist/loaders/child-process/spawn-pool.d.ts +3 -2
  51. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  52. package/dist/loaders/child-process/spawn-pool.js +3 -2
  53. package/dist/loaders/generated-workers.d.ts +2 -2
  54. package/dist/loaders/generated-workers.d.ts.map +1 -1
  55. package/dist/loaders/generated-workers.js +3 -3
  56. package/dist/loaders/npm-resolve-preamble.d.ts +3 -6
  57. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  58. package/dist/loaders/npm-resolve-preamble.js +34 -108
  59. package/dist/node-shims-artifact.generated.js +3 -3
  60. package/dist/npm/install-batch-facet.d.ts +3 -2
  61. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  62. package/dist/npm/install-batch-facet.js +45 -15
  63. package/dist/npm/installer.d.ts +22 -17
  64. package/dist/npm/installer.d.ts.map +1 -1
  65. package/dist/npm/installer.js +209 -193
  66. package/dist/npm/pre-bundle-facet.d.ts +1 -1
  67. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  68. package/dist/npm/pre-bundle-facet.js +1 -1
  69. package/dist/npm/resolve-facet.d.ts +6 -0
  70. package/dist/npm/resolve-facet.d.ts.map +1 -1
  71. package/dist/npm/resolve-one-facet.d.ts +21 -20
  72. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  73. package/dist/npm/resolve-one-facet.js +85 -84
  74. package/dist/npm/semver.d.ts +59 -0
  75. package/dist/npm/semver.d.ts.map +1 -0
  76. package/dist/npm/semver.js +226 -0
  77. package/dist/router/remote-api.js +31 -1
  78. package/dist/runtime/bash-repl.d.ts +1 -1
  79. package/dist/runtime/bash-repl.d.ts.map +1 -1
  80. package/dist/runtime/bash-repl.js +38 -4
  81. package/dist/runtime/bun-runner.js +1 -1
  82. package/dist/runtime/html-entrypoint.d.ts +7 -0
  83. package/dist/runtime/html-entrypoint.d.ts.map +1 -1
  84. package/dist/runtime/html-entrypoint.js +18 -2
  85. package/dist/runtime/node-runner.d.ts +4 -1
  86. package/dist/runtime/node-runner.d.ts.map +1 -1
  87. package/dist/runtime/node-runner.js +9 -2
  88. package/dist/runtime/node-shims.d.ts.map +1 -1
  89. package/dist/runtime/node-shims.js +305 -29
  90. package/dist/runtime/opencode-facet-runner.js +16 -16
  91. package/dist/runtime/package-manager.d.ts +35 -122
  92. package/dist/runtime/package-manager.d.ts.map +1 -1
  93. package/dist/runtime/package-manager.js +61 -596
  94. package/dist/runtime/process-logs-api.d.ts +1 -1
  95. package/dist/runtime/process-logs-api.d.ts.map +1 -1
  96. package/dist/runtime/process-logs-api.js +1 -1
  97. package/dist/runtime/python-repl.d.ts +2 -1
  98. package/dist/runtime/python-repl.d.ts.map +1 -1
  99. package/dist/runtime/python-repl.js +82 -59
  100. package/dist/runtime/repl-session.d.ts +9 -47
  101. package/dist/runtime/repl-session.d.ts.map +1 -1
  102. package/dist/runtime/repl-session.js +105 -105
  103. package/dist/runtime/runtime-catalog.d.ts +13 -0
  104. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  105. package/dist/runtime/runtime-catalog.js +88 -0
  106. package/dist/session/agent.d.ts +1 -21
  107. package/dist/session/agent.d.ts.map +1 -1
  108. package/dist/session/ai.d.ts +5 -1
  109. package/dist/session/ai.d.ts.map +1 -1
  110. package/dist/session/ai.js +7 -0
  111. package/dist/session/helpers.d.ts +38 -0
  112. package/dist/session/helpers.d.ts.map +1 -1
  113. package/dist/session/helpers.js +76 -0
  114. package/dist/session/hibernation.d.ts +2 -1
  115. package/dist/session/hibernation.d.ts.map +1 -1
  116. package/dist/session/hibernation.js +7 -4
  117. package/dist/session/init-phases.d.ts +1 -1
  118. package/dist/session/init-phases.d.ts.map +1 -1
  119. package/dist/session/init-phases.js +2 -12
  120. package/dist/session/init.d.ts +15 -36
  121. package/dist/session/init.d.ts.map +1 -1
  122. package/dist/session/init.js +50 -2327
  123. package/dist/session/loopback.d.ts +2 -29
  124. package/dist/session/loopback.d.ts.map +1 -1
  125. package/dist/session/loopback.js +3 -27
  126. package/dist/session/nimbus-session.d.ts +77 -34
  127. package/dist/session/nimbus-session.d.ts.map +1 -1
  128. package/dist/session/nimbus-session.js +126 -514
  129. package/dist/session/npm-install-port.d.ts +18 -0
  130. package/dist/session/npm-install-port.d.ts.map +1 -0
  131. package/dist/session/npm-install-port.js +37 -0
  132. package/dist/session/port-capability.d.ts +44 -0
  133. package/dist/session/port-capability.d.ts.map +1 -1
  134. package/dist/session/port-capability.js +110 -0
  135. package/dist/session/programmatic.d.ts +36 -43
  136. package/dist/session/programmatic.d.ts.map +1 -1
  137. package/dist/session/programmatic.js +109 -115
  138. package/dist/session/routes.d.ts +30 -17
  139. package/dist/session/routes.d.ts.map +1 -1
  140. package/dist/session/routes.js +42 -131
  141. package/dist/session/rpc.d.ts +15 -15
  142. package/dist/session/rpc.d.ts.map +1 -1
  143. package/dist/session/rpc.js +98 -49
  144. package/dist/session/serving-port.d.ts +27 -0
  145. package/dist/session/serving-port.d.ts.map +1 -0
  146. package/dist/session/serving-port.js +27 -0
  147. package/dist/session/start-real-vite.d.ts +12 -0
  148. package/dist/session/start-real-vite.d.ts.map +1 -1
  149. package/dist/session/start-real-vite.js +4 -4
  150. package/dist/session/supervisor-op.d.ts +4 -4
  151. package/dist/session/supervisor-op.d.ts.map +1 -1
  152. package/dist/session/supervisor-op.js +24 -10
  153. package/dist/session/supervisor-rpc.d.ts +7 -7
  154. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  155. package/dist/session/supervisor-rpc.js +4 -0
  156. package/dist/session/vite-command.d.ts +18 -0
  157. package/dist/session/vite-command.d.ts.map +1 -0
  158. package/dist/session/vite-command.js +609 -0
  159. package/dist/session/ws.d.ts +61 -0
  160. package/dist/session/ws.d.ts.map +1 -1
  161. package/dist/session/ws.js +122 -12
  162. package/dist/shell/npm-bin-entrypoints.d.ts +0 -35
  163. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  164. package/dist/shell/npm-bin-entrypoints.js +12 -85
  165. package/dist/workspace-host.d.ts +6 -0
  166. package/dist/workspace-host.d.ts.map +1 -0
  167. package/dist/workspace-host.js +5 -0
  168. package/dist/workspace.d.ts +2 -0
  169. package/dist/workspace.d.ts.map +1 -0
  170. package/dist/workspace.js +1 -0
  171. package/package.json +34 -9
  172. package/public/_assets/runtime/{node-shims-9e1380d9ee430fcc.js → node-shims-8f8c64edd2a1f0f5.js} +305 -29
  173. package/public/index.html +1 -1
  174. package/scripts/bundle-facet-workers.mjs +1 -1
  175. package/scripts/bundle-npm-cjs.mjs +2 -2
  176. package/dist/facets/on-demand-bundle-gate.d.ts +0 -65
  177. package/dist/facets/on-demand-bundle-gate.d.ts.map +0 -1
  178. package/dist/facets/on-demand-bundle-gate.js +0 -125
  179. package/dist/npm/install-args.d.ts +0 -21
  180. package/dist/npm/install-args.d.ts.map +0 -1
  181. package/dist/npm/install-args.js +0 -70
  182. package/dist/npm/npm-log.d.ts +0 -31
  183. package/dist/npm/npm-log.d.ts.map +0 -1
  184. package/dist/npm/npm-log.js +0 -51
@@ -1 +1 @@
1
- {"version":3,"file":"process-logs-api.d.ts","sourceRoot":"","sources":["../../src/runtime/process-logs-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AAEtG;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,wBAAwB,CAAC;IACpC;;;;OAIG;IACH,GAAG,EAAE;QACH,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;KACvD,CAAC;CACH;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,CAAC;CACf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,EAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAON;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,iBAAiB,GACtB,QAAQ,CA8EV;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,wBAAwB,EACnC,GAAG,EAAE;IAAE,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAAA;CAAE,GACjD,IAAI,CA8CN;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,wBAAwB,GAClC,QAAQ,CAsCV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7D"}
1
+ {"version":3,"file":"process-logs-api.d.ts","sourceRoot":"","sources":["../../src/runtime/process-logs-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uDAAuD,CAAC;AAEtG;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,wBAAwB,CAAC;IACpC;;;;OAIG;IACH,GAAG,EAAE;QACH,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;KACvD,CAAC;CACH;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,SAAS,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,GAAG,IAAI,EAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAON;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,iBAAiB,GACtB,QAAQ,CA8EV;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,SAAS,EAAE,wBAAwB,EACnC,GAAG,EAAE;IAAE,aAAa,CAAC,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAAA;CAAE,GACjD,IAAI,CA8CN;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,wBAAwB,GAClC,QAAQ,CAsCV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7D"}
@@ -30,7 +30,7 @@ export function notifyTerminalEvent(terminal, event) {
30
30
  if (!terminal)
31
31
  return;
32
32
  try {
33
- terminal.ws.send(JSON.stringify(event));
33
+ terminal.ws?.send(JSON.stringify(event));
34
34
  }
35
35
  catch {
36
36
  /* socket closed or congested — dropping is the right behavior here */
@@ -1,3 +1,4 @@
1
+ import type { Shell } from '@nimbus-sh/core/substrate/lifo/shell/Shell.js';
1
2
  /**
2
3
  * python-repl.ts — the interactive `python` prompt.
3
4
  *
@@ -40,7 +41,7 @@ export interface PythonReplDeps {
40
41
  * ReplSession lets it drain that queue on attach, which is the difference
41
42
  * between the pasted tail arriving and the prompt hanging.
42
43
  */
43
- shell?: unknown;
44
+ shell?: Pick<Shell, 'takeQueuedInput'>;
44
45
  /**
45
46
  * The invoking process's pid.
46
47
  *
@@ -1 +1 @@
1
- {"version":3,"file":"python-repl.d.ts","sourceRoot":"","sources":["../../src/runtime/python-repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAoBnF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA0QD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAIzE;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,CAAC,GAC1E,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"python-repl.d.ts","sourceRoot":"","sources":["../../src/runtime/python-repl.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+CAA+C,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAoBnF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IACvC;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAySD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAIzE;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,CAAC,GAC1E,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -1,24 +1,6 @@
1
- /**
2
- * python-repl.ts — the interactive `python` prompt.
3
- *
4
- * A long-lived facet holds one interpreter and each submitted line is run in
5
- * it, so definitions, imports and open files survive between prompts. That is
6
- * the whole reason the interpreter is built as a WASI reactor: a command
7
- * module's _start runs once.
8
- *
9
- * Incompleteness is decided by `codeop.compile_command`, which is what the real
10
- * Python REPL uses — it returns None for source that is syntactically fine so
11
- * far but unfinished (an open bracket, a `def` with no body yet), raises
12
- * SyntaxError for source that can never complete, and otherwise hands back a
13
- * code object. That distinction is not something to re-derive from error
14
- * strings; the previous Pyodide implementation asked PyodideConsole for it,
15
- * which is the same idea reached through a Pyodide-only object.
16
- *
17
- * Compiling in 'single' mode also gets the echo right for free: an expression
18
- * statement goes through sys.displayhook exactly as it does at a real prompt,
19
- * so `1 + 1` prints `2` and `x = 1` prints nothing, with no wrapper of ours
20
- * deciding what counts as a result.
21
- */
1
+ import { IsolatePool } from '@nimbus-sh/fabric/isolate-pool.js';
2
+ import { manifestVfs } from '@nimbus-sh/core/runtime/vfs-manifest.js';
3
+ import { z } from 'zod/v4';
22
4
  import { ReplSession } from './repl-session.js';
23
5
  import { sessionUsesSciVariant } from '@nimbus-sh/core/runtime/python-pip.js';
24
6
  import { buildCPythonPreamble } from '@nimbus-sh/core/runtime/cpython-runner.js';
@@ -35,6 +17,8 @@ const INCOMPLETE_MARKER = '__NIMBUS_PY_INCOMPLETE__';
35
17
  * ordinary output and never leaves.
36
18
  */
37
19
  const EXIT_MARKER = '__NIMBUS_PY_EXIT__';
20
+ const PythonFacetResult = z.object({ stdout: z.string(), stderr: z.string(), exitCode: z.number().int(), error: z.string().optional() });
21
+ const PythonFacetFailure = z.object({ __nimbusFacetError: z.string() });
38
22
  /** Where cpython-runner's catalog spec stages the interpreter. */
39
23
  const CPYTHON_WASM_REL = 'share/cpython/python.wasm';
40
24
  const CPYTHON_SCI_WASM_REL = 'share/cpython/python-sci.wasm';
@@ -102,13 +86,25 @@ class PythonReplAdapter {
102
86
  return ('Python 3.13.14 (CPython, wasm32-wasi, Nimbus runtime)\r\n' +
103
87
  'Type "exit()" or press Ctrl-D to exit.\r\n');
104
88
  }
105
- async push(source) {
89
+ push(source) {
90
+ const controller = new AbortController();
91
+ const done = this.evaluate(source, controller.signal);
92
+ const active = { controller, done };
93
+ this.active = active;
94
+ const clear = () => { if (this.active === active)
95
+ this.active = null; };
96
+ void done.then(clear, clear);
97
+ return done;
98
+ }
99
+ async evaluate(source, signal) {
106
100
  const trimmed = source.trim();
107
101
  if (trimmed === 'exit' || trimmed === 'quit') {
108
102
  return { kind: 'output', stdout: '', stderr: 'Use exit() or Ctrl-D to exit\n' };
109
103
  }
110
104
  try {
105
+ signal.throwIfAborted();
111
106
  await this.ensurePool();
107
+ signal.throwIfAborted();
112
108
  }
113
109
  catch (e) {
114
110
  const message = e instanceof Error ? e.message : String(e);
@@ -116,7 +112,7 @@ class PythonReplAdapter {
116
112
  }
117
113
  let result;
118
114
  try {
119
- result = await this.submit(buildReplDriver(source));
115
+ result = await this.submit(buildReplDriver(source), signal);
120
116
  }
121
117
  catch (e) {
122
118
  const message = e instanceof Error ? e.message : String(e);
@@ -149,13 +145,22 @@ class PythonReplAdapter {
149
145
  }
150
146
  return { kind: 'output', stdout: result.stdout, stderr: result.stderr };
151
147
  }
152
- async close() {
153
- if (this.pool) {
154
- try {
155
- this.pool.dispose?.();
156
- }
157
- catch { /* fail-soft: the session is ending anyway */ }
158
- this.pool = null;
148
+ close() { return this.interrupt(); }
149
+ resetPool() {
150
+ const pool = this.pool;
151
+ this.pool = null;
152
+ this.wasmBytes = null;
153
+ this.fsSnapshot = null;
154
+ pool?.dispose();
155
+ }
156
+ async interrupt() {
157
+ const active = this.active;
158
+ active?.controller.abort();
159
+ try {
160
+ await active?.done;
161
+ }
162
+ finally {
163
+ this.resetPool();
159
164
  }
160
165
  }
161
166
  async ensurePool() {
@@ -166,11 +171,7 @@ class PythonReplAdapter {
166
171
  // interpreter that does not have it. Dropping the pool rebuilds on the next
167
172
  // statement, which is the facet restart EXTENSIONS.md says this costs.
168
173
  if (this.pool && this.poolUsesSci !== wantsSci) {
169
- try {
170
- this.pool.dispose?.();
171
- }
172
- catch { /* fail-soft: it is being replaced */ }
173
- this.pool = null;
174
+ this.resetPool();
174
175
  }
175
176
  if (this.pool)
176
177
  return;
@@ -186,7 +187,6 @@ class PythonReplAdapter {
186
187
  throw new Error(`python313.zip missing at ${stdlibPath} (run 'nimbus install python')`);
187
188
  }
188
189
  this.wasmBytes = toArrayBuffer(vfs.readFile(wasmPath));
189
- const { manifestVfs } = await import('@nimbus-sh/core/runtime/vfs-manifest.js');
190
190
  // The install root is the Python prefix, so the manifest covers lib/ and
191
191
  // etc/ as they are — nothing is aliased into a path the supervisor could
192
192
  // not serve.
@@ -207,7 +207,6 @@ class PythonReplAdapter {
207
207
  snapshot.files[stdlibPath.replace(/^\/+/, '')] = btoa(bin);
208
208
  this.fsSnapshot = snapshot;
209
209
  this.pythonHome = `/${installRoot.replace(/^\/+/, '')}`;
210
- const { IsolatePool } = await import('@nimbus-sh/fabric/isolate-pool.js');
211
210
  const host = getFacetManagerLoaderHost(facetMgr);
212
211
  // A prompt where `open(path, "w")` silently does nothing is worse than one
213
212
  // that refuses to start, so the pid decides which pool this is. Written as
@@ -219,43 +218,65 @@ class PythonReplAdapter {
219
218
  // Distinct from cpython-runner's tag: a REPL facet holds a live
220
219
  // interpreter and must never be handed a one-shot invocation.
221
220
  tag: wantsSci ? 'python-repl:sci' : 'python-repl',
221
+ scope: crypto.randomUUID(),
222
222
  concurrency: 1,
223
223
  preamble: buildCPythonPreamble(),
224
224
  wasmModules: { 'python.wasm': this.wasmBytes },
225
225
  };
226
226
  const pid = this.deps.pid;
227
- this.pool = (typeof pid === 'number' && pid > 0
227
+ this.pool = typeof pid === 'number' && pid > 0
228
228
  ? new IsolatePool(host.env, host.ctx, { ...base, supervisorPid: pid })
229
229
  // The install-time warm-up has no invoking process. It boots the
230
230
  // interpreter and never touches a file, so it asks for no supervisor
231
231
  // rather than binding one it cannot authenticate to.
232
- : new IsolatePool(host.env, host.ctx, { ...base, omitSupervisor: true }));
232
+ : new IsolatePool(host.env, host.ctx, { ...base, omitSupervisor: true });
233
233
  }
234
- async submit(userCode) {
235
- const result = await this.pool.submit(pythonReplStepFacetFn, {
236
- userCode,
237
- pythonHome: this.pythonHome,
238
- pyArgv: ['python'],
239
- userEnv: { HOME: '/home/user', PYTHONUNBUFFERED: '1' },
240
- progName: 'python',
241
- cwd: '/home/user',
242
- fsSnapshot: this.fsSnapshot,
243
- }, { timeoutMs: 60_000 });
244
- return result;
234
+ active = null;
235
+ async submit(userCode, signal) {
236
+ const pool = this.pool;
237
+ if (!pool || !this.fsSnapshot)
238
+ throw new Error('Python REPL is not initialized');
239
+ const response = await pool.submitRequest(pythonReplStepRequestFn, new Request('https://facet.internal/python-repl-step', {
240
+ method: 'POST',
241
+ body: JSON.stringify({
242
+ userCode,
243
+ pythonHome: this.pythonHome,
244
+ pyArgv: ['python'],
245
+ userEnv: { HOME: '/home/user', PYTHONUNBUFFERED: '1' },
246
+ progName: 'python',
247
+ cwd: '/home/user',
248
+ fsSnapshot: this.fsSnapshot,
249
+ }),
250
+ signal,
251
+ }), { timeoutMs: 60_000 });
252
+ if (!response.ok) {
253
+ const failure = PythonFacetFailure.parse(await response.json());
254
+ throw new Error(failure.__nimbusFacetError);
255
+ }
256
+ return PythonFacetResult.parse(await response.json());
245
257
  }
246
258
  }
247
259
  /**
248
- * Facet-side. Serialized with fn.toString(), so it captures nothing and names
249
- * no import: __cpythonReplRun is put on globalThis by the preamble, and unlike
250
- * __cpythonRun it keeps its interpreter between calls.
260
+ * Facet-side, request-shaped: serialized with fn.toString() into the
261
+ * pool's fetch entrypoint, so it captures nothing and names no import —
262
+ * __cpythonReplRun is put on globalThis by the preamble, and unlike
263
+ * __cpythonRun it keeps its interpreter between calls. The request body
264
+ * is the step payload the adapter JSON-encodes; the response is the
265
+ * step result. Request transport because it is the pool's only
266
+ * cancellable dispatch: Ctrl-C aborts the request, workerd stops the
267
+ * interpreter at its suspension point.
251
268
  */
252
- async function pythonReplStepFacetFn(args, facetEnv) {
269
+ async function pythonReplStepRequestFn(request, facetEnv) {
270
+ const args = await request.json();
271
+ if (typeof args !== 'object' || args === null || !('userCode' in args) || typeof args.userCode !== 'string') {
272
+ throw new Error('Python REPL request must contain userCode');
273
+ }
253
274
  const run = Reflect.get(globalThis, '__cpythonReplRun');
254
275
  if (typeof run !== 'function') {
255
- return {
276
+ return Response.json({
256
277
  stdout: '', stderr: '', exitCode: 127,
257
278
  error: 'cpython preamble missing: __cpythonReplRun not in scope',
258
- };
279
+ });
259
280
  }
260
281
  const adopt = Reflect.get(globalThis, '__wasiAdoptSupervisor');
261
282
  const drain = Reflect.get(globalThis, '__wasiDrainPersist');
@@ -266,13 +287,15 @@ async function pythonReplStepFacetFn(args, facetEnv) {
266
287
  // filesystem it could read.
267
288
  if (supervisor)
268
289
  Reflect.set(globalThis, '__nimbusPySupervisor', supervisor);
269
- adopt?.(supervisor);
290
+ if (typeof adopt === 'function')
291
+ Reflect.apply(adopt, undefined, [supervisor ?? null]);
270
292
  try {
271
- return await run(args);
293
+ return Response.json(await run(args));
272
294
  }
273
295
  finally {
274
296
  // A line that wrote a file and then raised still wrote the file.
275
- await drain?.();
297
+ if (typeof drain === 'function')
298
+ await drain();
276
299
  }
277
300
  }
278
301
  export async function runPythonRepl(deps) {
@@ -12,6 +12,7 @@
12
12
  * interface declared below.
13
13
  */
14
14
  import type { WebSocketTerminal } from '../facets/ws-terminal.js';
15
+ import type { Shell } from '@nimbus-sh/core/substrate/lifo/shell/Shell.js';
15
16
  /**
16
17
  * Per-runtime adapter contract. The shell-side ReplSession orchestrates
17
18
  * input handling; the adapter wraps the actual runtime invocation.
@@ -30,6 +31,8 @@ export interface ReplAdapter {
30
31
  /** Called once on session close (exit() / Ctrl-D / shell teardown).
31
32
  * Should free any cached pool / isolate. Idempotent. */
32
33
  close(): Promise<void>;
34
+ /** Abort and settle the active push, resetting its interpreter before resolving. */
35
+ interrupt?(): void | Promise<void>;
33
36
  /** Primary prompt (typically '>>> '). */
34
37
  ps1: string;
35
38
  /** Continuation prompt (typically '... '). */
@@ -50,45 +53,10 @@ export type ReplPushResult = {
50
53
  kind: 'error';
51
54
  stderr: string;
52
55
  };
53
- /**
54
- * Manages an interactive REPL session: stdin buffering with minimal
55
- * readline UX (line-mode), output routing to the WS terminal, prompt
56
- * rendering, and adapter dispatch.
57
- *
58
- * The shell creates a ReplSession when a runtime's `startRepl` hook
59
- * fires; the session installs a `replCallback` on the WebSocketTerminal
60
- * (via attachRepl()) and runs until the adapter signals 'exit' or the
61
- * user presses Ctrl-D on an empty line.
62
- *
63
- * No setTimeout in the read loop — the session is driven entirely by
64
- * keystroke arrival on the WS, with awaits gating the adapter's push().
65
- */
66
56
  export declare class ReplSession {
67
57
  private adapter;
58
+ private detachRepl;
68
59
  private terminal;
69
- private detachReplCb;
70
- /**
71
- * REPL-R7-1 (2026-05-12): optional reference to the Nimbus shell.
72
- *
73
- * Required when the REPL is launched from a multi-line WS frame
74
- * (e.g. user pastes `python\nexit(7)`). The shell input handler
75
- * splits the frame on \r\n and pushes lines AFTER
76
- * the first into `shell.pasteQueue`, which is drained ONLY when
77
- * the shell becomes idle (after executeLine returns). While our
78
- * REPL is running, those pasteQueue lines sit there waiting and
79
- * the REPL itself receives no input → user sees a hung `>>> `
80
- * prompt that never responds.
81
- *
82
- * If `shell` is provided, ReplSession will, immediately after
83
- * attaching its replCallback, drain shell.pasteQueue and feed the
84
- * lines into the callback (suffixed with \r each — matches what
85
- * the WS frame originally would have looked like). This makes the
86
- * paste path work transparently for REPL launches.
87
- *
88
- * The shell reference is optional so existing adapters (bun, node,
89
- * ruby) that haven't been updated keep working with their
90
- * pre-fix behavior.
91
- */
92
60
  private shellRef;
93
61
  /** Current line buffer (chars typed since the last enter). */
94
62
  private lineBuf;
@@ -101,9 +69,11 @@ export declare class ReplSession {
101
69
  /** Per-session history ring (most recent first). Capped at 100. */
102
70
  private history;
103
71
  private historyIdx;
104
- /** Resolves when close() has been called and the session ended. */
105
72
  private closedResolve;
106
73
  private closedPromise;
74
+ private pendingInterrupt;
75
+ private activePush;
76
+ private ending;
107
77
  /** Exit code captured from adapter's last 'exit' return. */
108
78
  private exitCode;
109
79
  /**
@@ -124,23 +94,16 @@ export declare class ReplSession {
124
94
  */
125
95
  private inputQueue;
126
96
  private draining;
127
- constructor(adapter: ReplAdapter, terminal: WebSocketTerminal, shell?: any);
97
+ constructor(adapter: ReplAdapter, terminal: WebSocketTerminal, shell?: Pick<Shell, 'takeQueuedInput'>);
128
98
  /** Run the session: prints banner, installs the input hook, returns
129
99
  * a promise that resolves with the exit code when the session ends. */
130
100
  run(): Promise<number>;
131
- /**
132
- * REPL-A1b: drain the input queue serially. Pulls data off
133
- * inputQueue, runs handleInput, and reads any data that arrived
134
- * during the await. Exits when queue is empty. Only ONE drainInput
135
- * runs at a time (guarded by draining flag set in attachRepl
136
- * callback).
137
- */
138
101
  private drainInput;
139
102
  /** Process an input chunk. May contain multiple characters (paste
140
103
  * or rapid typing) — we iterate char-by-char to handle each
141
104
  * control byte individually. */
142
105
  private handleInput;
143
- /** Submit the current line buffer to the adapter. */
106
+ private interruptBusy;
144
107
  private submitLine;
145
108
  /** Map up-arrow → previous history entry. */
146
109
  private historyUp;
@@ -148,7 +111,6 @@ export declare class ReplSession {
148
111
  private historyDown;
149
112
  /** Erase the current displayed line and replace with `text`. */
150
113
  private replaceCurrentLine;
151
- /** Close the session: detach input hook, free adapter, resolve. */
152
114
  private endSession;
153
115
  }
154
116
  //# sourceMappingURL=repl-session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repl-session.d.ts","sourceRoot":"","sources":["../../src/runtime/repl-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;mCAC+B;IAC/B,MAAM,IAAI,MAAM,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5C;6DACyD;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,YAAY,CAA6B;IACjD;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,QAAQ,CAAa;IAE7B,8DAA8D;IAC9D,OAAO,CAAC,OAAO,CAAc;IAC7B,sDAAsD;IACtD,OAAO,CAAC,SAAS,CAAa;IAC9B,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAgB;IAChC,8EAA8E;IAC9E,OAAO,CAAC,IAAI,CAAkB;IAC9B,mEAAmE;IACnE,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAc;IAChC,mEAAmE;IACnE,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,aAAa,CAAgB;IACrC,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAa;IAC7B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,GAAG;IAU1E;4EACwE;IAClE,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;IAyD5B;;;;;;OAMG;YACW,UAAU;IASxB;;qCAEiC;YACnB,WAAW;IA6EzB,qDAAqD;YACvC,UAAU;IA8ExB,6CAA6C;IAC7C,OAAO,CAAC,SAAS;IAMjB,mDAAmD;IACnD,OAAO,CAAC,WAAW;IAUnB,gEAAgE;IAChE,OAAO,CAAC,kBAAkB;IAW1B,mEAAmE;YACrD,UAAU;CAYzB"}
1
+ {"version":3,"file":"repl-session.d.ts","sourceRoot":"","sources":["../../src/runtime/repl-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,+CAA+C,CAAC;AAI3E;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;mCAC+B;IAC/B,MAAM,IAAI,MAAM,CAAC;IACjB;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5C;6DACyD;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,oFAAoF;IACpF,SAAS,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAiBtC,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,QAAQ,CAA+C;IAE/D,8DAA8D;IAC9D,OAAO,CAAC,OAAO,CAAc;IAC7B,sDAAsD;IACtD,OAAO,CAAC,SAAS,CAAa;IAC9B,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAgB;IAChC,8EAA8E;IAC9E,OAAO,CAAC,IAAI,CAAkB;IAC9B,mEAAmE;IACnE,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,MAAM,CAA8B;IAE5C,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAa;IAC7B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAUrG;4EACwE;IAClE,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;YAuCd,UAAU;IAiBxB;;qCAEiC;YACnB,WAAW;IA0EzB,OAAO,CAAC,aAAa;YAiBP,UAAU;IA0FxB,6CAA6C;IAC7C,OAAO,CAAC,SAAS;IAMjB,mDAAmD;IACnD,OAAO,CAAC,WAAW;IAUnB,gEAAgE;IAChE,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;CAwBnB"}