@nimbus-sh/worker 0.1.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 +219 -0
- package/dist/_shared/bytes.d.ts +18 -0
- package/dist/_shared/bytes.d.ts.map +1 -0
- package/dist/_shared/bytes.js +17 -0
- package/dist/_shared/cache-stats.d.ts +146 -0
- package/dist/_shared/cache-stats.d.ts.map +1 -0
- package/dist/_shared/cache-stats.js +162 -0
- package/dist/_shared/exports-resolver.d.ts +76 -0
- package/dist/_shared/exports-resolver.d.ts.map +1 -0
- package/dist/_shared/exports-resolver.js +284 -0
- package/dist/_shared/install-phase.d.ts +47 -0
- package/dist/_shared/install-phase.d.ts.map +1 -0
- package/dist/_shared/install-phase.js +1 -0
- package/dist/_shared/real-node-imports.d.ts +38 -0
- package/dist/_shared/real-node-imports.d.ts.map +1 -0
- package/dist/_shared/real-node-imports.js +46 -0
- package/dist/_shared/retry.d.ts +93 -0
- package/dist/_shared/retry.d.ts.map +1 -0
- package/dist/_shared/retry.js +161 -0
- package/dist/_shared/session-id.d.ts +39 -0
- package/dist/_shared/session-id.d.ts.map +1 -0
- package/dist/_shared/session-id.js +127 -0
- package/dist/_shared/session-router.d.ts +104 -0
- package/dist/_shared/session-router.d.ts.map +1 -0
- package/dist/_shared/session-router.js +165 -0
- package/dist/_shared/w7-frame.d.ts +93 -0
- package/dist/_shared/w7-frame.d.ts.map +1 -0
- package/dist/_shared/w7-frame.js +402 -0
- package/dist/auth/index.d.ts +16 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +15 -0
- package/dist/auth/middleware.d.ts +85 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +150 -0
- package/dist/auth/token.d.ts +96 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +226 -0
- package/dist/auth/types.d.ts +141 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +114 -0
- package/dist/bindings/d1.d.ts +102 -0
- package/dist/bindings/d1.d.ts.map +1 -0
- package/dist/bindings/d1.js +549 -0
- package/dist/bindings/kv.d.ts +82 -0
- package/dist/bindings/kv.d.ts.map +1 -0
- package/dist/bindings/kv.js +290 -0
- package/dist/bindings/r2.d.ts +137 -0
- package/dist/bindings/r2.d.ts.map +1 -0
- package/dist/bindings/r2.js +379 -0
- package/dist/cirrus-npm-cjs.generated.d.ts +17 -0
- package/dist/cirrus-npm-cjs.generated.d.ts.map +1 -0
- package/dist/cirrus-npm-cjs.generated.js +41 -0
- package/dist/cirrus-plugin-react.generated.d.ts +34 -0
- package/dist/cirrus-plugin-react.generated.d.ts.map +1 -0
- package/dist/cirrus-plugin-react.generated.js +33 -0
- package/dist/constants.d.ts +34 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +116 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts +41 -0
- package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -0
- package/dist/esbuild-wasm-bundle.generated.js +40 -0
- package/dist/facets/cirrus-real.d.ts +147 -0
- package/dist/facets/cirrus-real.d.ts.map +1 -0
- package/dist/facets/cirrus-real.js +981 -0
- package/dist/facets/inner-do-registry.d.ts +41 -0
- package/dist/facets/inner-do-registry.d.ts.map +1 -0
- package/dist/facets/inner-do-registry.js +51 -0
- package/dist/facets/manager.d.ts +314 -0
- package/dist/facets/manager.d.ts.map +1 -0
- package/dist/facets/manager.js +2681 -0
- package/dist/facets/process.d.ts +318 -0
- package/dist/facets/process.d.ts.map +1 -0
- package/dist/facets/process.js +567 -0
- package/dist/facets/real-vite-fs-shim.d.ts +151 -0
- package/dist/facets/real-vite-fs-shim.d.ts.map +1 -0
- package/dist/facets/real-vite-fs-shim.js +1279 -0
- package/dist/facets/real-vite-hmr.d.ts +142 -0
- package/dist/facets/real-vite-hmr.d.ts.map +1 -0
- package/dist/facets/real-vite-hmr.js +476 -0
- package/dist/facets/vite-dev-server.d.ts +293 -0
- package/dist/facets/vite-dev-server.d.ts.map +1 -0
- package/dist/facets/vite-dev-server.js +2580 -0
- package/dist/facets/wasm-swap-registry.d.ts +261 -0
- package/dist/facets/wasm-swap-registry.d.ts.map +1 -0
- package/dist/facets/wasm-swap-registry.js +551 -0
- package/dist/facets/ws-terminal.d.ts +107 -0
- package/dist/facets/ws-terminal.d.ts.map +1 -0
- package/dist/facets/ws-terminal.js +207 -0
- package/dist/git/commands.d.ts +13 -0
- package/dist/git/commands.d.ts.map +1 -0
- package/dist/git/commands.js +633 -0
- package/dist/git/network-facet.d.ts +61 -0
- package/dist/git/network-facet.d.ts.map +1 -0
- package/dist/git/network-facet.js +700 -0
- package/dist/git-bundle.generated.d.ts +16 -0
- package/dist/git-bundle.generated.d.ts.map +1 -0
- package/dist/git-bundle.generated.js +15 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/loaders/child-process/spawn-facet.d.ts +90 -0
- package/dist/loaders/child-process/spawn-facet.d.ts.map +1 -0
- package/dist/loaders/child-process/spawn-facet.js +103 -0
- package/dist/loaders/child-process/spawn-pool.d.ts +110 -0
- package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -0
- package/dist/loaders/child-process/spawn-pool.js +161 -0
- package/dist/loaders/fanout-pool.d.ts +195 -0
- package/dist/loaders/fanout-pool.d.ts.map +1 -0
- package/dist/loaders/fanout-pool.js +326 -0
- package/dist/loaders/generated-workers.d.ts +26 -0
- package/dist/loaders/generated-workers.d.ts.map +1 -0
- package/dist/loaders/generated-workers.js +25 -0
- package/dist/loaders/index.d.ts +15 -0
- package/dist/loaders/index.d.ts.map +1 -0
- package/dist/loaders/index.js +13 -0
- package/dist/loaders/loader-pool.d.ts +273 -0
- package/dist/loaders/loader-pool.d.ts.map +1 -0
- package/dist/loaders/loader-pool.js +624 -0
- package/dist/loaders/npm-resolve-preamble.d.ts +34 -0
- package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -0
- package/dist/loaders/npm-resolve-preamble.js +237 -0
- package/dist/loaders/pre-bundle-preamble.d.ts +41 -0
- package/dist/loaders/pre-bundle-preamble.d.ts.map +1 -0
- package/dist/loaders/pre-bundle-preamble.js +114 -0
- package/dist/loaders/vendor/codegen.d.ts +24 -0
- package/dist/loaders/vendor/codegen.d.ts.map +1 -0
- package/dist/loaders/vendor/codegen.js +44 -0
- package/dist/loaders/vendor/errors.d.ts +24 -0
- package/dist/loaders/vendor/errors.d.ts.map +1 -0
- package/dist/loaders/vendor/errors.js +46 -0
- package/dist/loaders/vendor/index.d.ts +16 -0
- package/dist/loaders/vendor/index.d.ts.map +1 -0
- package/dist/loaders/vendor/index.js +11 -0
- package/dist/loaders/vendor/pool.d.ts +88 -0
- package/dist/loaders/vendor/pool.d.ts.map +1 -0
- package/dist/loaders/vendor/pool.js +353 -0
- package/dist/loaders/vendor/primitives.d.ts +11 -0
- package/dist/loaders/vendor/primitives.d.ts.map +1 -0
- package/dist/loaders/vendor/primitives.js +33 -0
- package/dist/loaders/vendor/serialize.d.ts +3 -0
- package/dist/loaders/vendor/serialize.d.ts.map +1 -0
- package/dist/loaders/vendor/serialize.js +25 -0
- package/dist/loaders/vendor/types.d.ts +60 -0
- package/dist/loaders/vendor/types.d.ts.map +1 -0
- package/dist/loaders/vendor/types.js +4 -0
- package/dist/npm/cache.d.ts +136 -0
- package/dist/npm/cache.d.ts.map +1 -0
- package/dist/npm/cache.js +429 -0
- package/dist/npm/install-batch-facet.d.ts +129 -0
- package/dist/npm/install-batch-facet.d.ts.map +1 -0
- package/dist/npm/install-batch-facet.js +598 -0
- package/dist/npm/install-facet.d.ts +29 -0
- package/dist/npm/install-facet.d.ts.map +1 -0
- package/dist/npm/install-facet.js +9 -0
- package/dist/npm/installer.d.ts +239 -0
- package/dist/npm/installer.d.ts.map +1 -0
- package/dist/npm/installer.js +2022 -0
- package/dist/npm/npx-install.d.ts +74 -0
- package/dist/npm/npx-install.d.ts.map +1 -0
- package/dist/npm/npx-install.js +302 -0
- package/dist/npm/pre-bundle-facet.d.ts +168 -0
- package/dist/npm/pre-bundle-facet.d.ts.map +1 -0
- package/dist/npm/pre-bundle-facet.js +653 -0
- package/dist/npm/r2-cache.d.ts +286 -0
- package/dist/npm/r2-cache.d.ts.map +1 -0
- package/dist/npm/r2-cache.js +506 -0
- package/dist/npm/resolve-facet.d.ts +202 -0
- package/dist/npm/resolve-facet.d.ts.map +1 -0
- package/dist/npm/resolve-facet.js +833 -0
- package/dist/npm/resolve-one-facet.d.ts +204 -0
- package/dist/npm/resolve-one-facet.d.ts.map +1 -0
- package/dist/npm/resolve-one-facet.js +437 -0
- package/dist/npm/resolver.d.ts +109 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/resolver.js +899 -0
- package/dist/npm/tarball-stream.d.ts +85 -0
- package/dist/npm/tarball-stream.d.ts.map +1 -0
- package/dist/npm/tarball-stream.js +205 -0
- package/dist/npm/tarball.d.ts +51 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/npm/tarball.js +185 -0
- package/dist/observability/diag-counters.d.ts +292 -0
- package/dist/observability/diag-counters.d.ts.map +1 -0
- package/dist/observability/diag-counters.js +302 -0
- package/dist/observability/heap-estimate.d.ts +166 -0
- package/dist/observability/heap-estimate.d.ts.map +1 -0
- package/dist/observability/heap-estimate.js +192 -0
- package/dist/observability/heavy-alloc-coord.d.ts +95 -0
- package/dist/observability/heavy-alloc-coord.d.ts.map +1 -0
- package/dist/observability/heavy-alloc-coord.js +149 -0
- package/dist/observability/oom-classify.d.ts +56 -0
- package/dist/observability/oom-classify.d.ts.map +1 -0
- package/dist/observability/oom-classify.js +118 -0
- package/dist/observability/oom-discriminator.d.ts +192 -0
- package/dist/observability/oom-discriminator.d.ts.map +1 -0
- package/dist/observability/oom-discriminator.js +233 -0
- package/dist/real-vite-bundle.generated.d.ts +46 -0
- package/dist/real-vite-bundle.generated.d.ts.map +1 -0
- package/dist/real-vite-bundle.generated.js +53 -0
- package/dist/replica/routing.d.ts +171 -0
- package/dist/replica/routing.d.ts.map +1 -0
- package/dist/replica/routing.js +288 -0
- package/dist/replica/suspension.d.ts +36 -0
- package/dist/replica/suspension.d.ts.map +1 -0
- package/dist/replica/suspension.js +49 -0
- package/dist/router/index.d.ts +156 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +220 -0
- package/dist/runtime/assets-loader.d.ts +71 -0
- package/dist/runtime/assets-loader.d.ts.map +1 -0
- package/dist/runtime/assets-loader.js +128 -0
- package/dist/runtime/barrel-detect.d.ts +46 -0
- package/dist/runtime/barrel-detect.d.ts.map +1 -0
- package/dist/runtime/barrel-detect.js +73 -0
- package/dist/runtime/barrel-synthesizer.d.ts +181 -0
- package/dist/runtime/barrel-synthesizer.d.ts.map +1 -0
- package/dist/runtime/barrel-synthesizer.js +541 -0
- package/dist/runtime/bun-repl.d.ts +46 -0
- package/dist/runtime/bun-repl.d.ts.map +1 -0
- package/dist/runtime/bun-repl.js +326 -0
- package/dist/runtime/bun-runner.d.ts +66 -0
- package/dist/runtime/bun-runner.d.ts.map +1 -0
- package/dist/runtime/bun-runner.js +219 -0
- package/dist/runtime/clang-runner.d.ts +38 -0
- package/dist/runtime/clang-runner.d.ts.map +1 -0
- package/dist/runtime/clang-runner.js +1033 -0
- package/dist/runtime/comment-strip.d.ts +37 -0
- package/dist/runtime/comment-strip.d.ts.map +1 -0
- package/dist/runtime/comment-strip.js +74 -0
- package/dist/runtime/esbuild-service.d.ts +201 -0
- package/dist/runtime/esbuild-service.d.ts.map +1 -0
- package/dist/runtime/esbuild-service.js +1444 -0
- package/dist/runtime/esbuild-wasm-bytes.d.ts +87 -0
- package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -0
- package/dist/runtime/esbuild-wasm-bytes.js +131 -0
- package/dist/runtime/framework-detect.d.ts +71 -0
- package/dist/runtime/framework-detect.d.ts.map +1 -0
- package/dist/runtime/framework-detect.js +178 -0
- package/dist/runtime/long-running-handle.d.ts +133 -0
- package/dist/runtime/long-running-handle.d.ts.map +1 -0
- package/dist/runtime/long-running-handle.js +192 -0
- package/dist/runtime/node-repl.d.ts +36 -0
- package/dist/runtime/node-repl.d.ts.map +1 -0
- package/dist/runtime/node-repl.js +293 -0
- package/dist/runtime/node-runner.d.ts +111 -0
- package/dist/runtime/node-runner.d.ts.map +1 -0
- package/dist/runtime/node-runner.js +194 -0
- package/dist/runtime/node-shims.d.ts +24 -0
- package/dist/runtime/node-shims.d.ts.map +1 -0
- package/dist/runtime/node-shims.js +3019 -0
- package/dist/runtime/package-manager.d.ts +118 -0
- package/dist/runtime/package-manager.d.ts.map +1 -0
- package/dist/runtime/package-manager.js +420 -0
- package/dist/runtime/port-registry.d.ts +80 -0
- package/dist/runtime/port-registry.d.ts.map +1 -0
- package/dist/runtime/port-registry.js +166 -0
- package/dist/runtime/process-logs-api.d.ts +102 -0
- package/dist/runtime/process-logs-api.d.ts.map +1 -0
- package/dist/runtime/process-logs-api.js +253 -0
- package/dist/runtime/process-logs.d.ts +311 -0
- package/dist/runtime/process-logs.d.ts.map +1 -0
- package/dist/runtime/process-logs.js +656 -0
- package/dist/runtime/process-table.d.ts +65 -0
- package/dist/runtime/process-table.d.ts.map +1 -0
- package/dist/runtime/process-table.js +107 -0
- package/dist/runtime/project-detect.d.ts +21 -0
- package/dist/runtime/project-detect.d.ts.map +1 -0
- package/dist/runtime/project-detect.js +46 -0
- package/dist/runtime/python-repl.d.ts +66 -0
- package/dist/runtime/python-repl.d.ts.map +1 -0
- package/dist/runtime/python-repl.js +563 -0
- package/dist/runtime/python-runner.d.ts +50 -0
- package/dist/runtime/python-runner.d.ts.map +1 -0
- package/dist/runtime/python-runner.js +870 -0
- package/dist/runtime/repl-session.d.ts +160 -0
- package/dist/runtime/repl-session.d.ts.map +1 -0
- package/dist/runtime/repl-session.js +393 -0
- package/dist/runtime/require-resolver.d.ts +52 -0
- package/dist/runtime/require-resolver.d.ts.map +1 -0
- package/dist/runtime/require-resolver.js +690 -0
- package/dist/runtime/router-basename.d.ts +36 -0
- package/dist/runtime/router-basename.d.ts.map +1 -0
- package/dist/runtime/router-basename.js +310 -0
- package/dist/runtime/ruby-repl.d.ts +43 -0
- package/dist/runtime/ruby-repl.d.ts.map +1 -0
- package/dist/runtime/ruby-repl.js +229 -0
- package/dist/runtime/ruby-runner.d.ts +62 -0
- package/dist/runtime/ruby-runner.d.ts.map +1 -0
- package/dist/runtime/ruby-runner.js +737 -0
- package/dist/runtime/runtime-catalog.d.ts +99 -0
- package/dist/runtime/runtime-catalog.d.ts.map +1 -0
- package/dist/runtime/runtime-catalog.js +183 -0
- package/dist/runtime/runtime-registry.d.ts +136 -0
- package/dist/runtime/runtime-registry.d.ts.map +1 -0
- package/dist/runtime/runtime-registry.js +318 -0
- package/dist/runtime/streams.d.ts +13 -0
- package/dist/runtime/streams.d.ts.map +1 -0
- package/dist/runtime/streams.js +402 -0
- package/dist/runtime/wasi-instance.d.ts +190 -0
- package/dist/runtime/wasi-instance.d.ts.map +1 -0
- package/dist/runtime/wasi-instance.js +2044 -0
- package/dist/runtime/wasm-runner.d.ts +117 -0
- package/dist/runtime/wasm-runner.d.ts.map +1 -0
- package/dist/runtime/wasm-runner.js +705 -0
- package/dist/session/bindings.d.ts +168 -0
- package/dist/session/bindings.d.ts.map +1 -0
- package/dist/session/bindings.js +524 -0
- package/dist/session/ctx-exports.d.ts +16 -0
- package/dist/session/ctx-exports.d.ts.map +1 -0
- package/dist/session/ctx-exports.js +22 -0
- package/dist/session/diag.d.ts +62 -0
- package/dist/session/diag.d.ts.map +1 -0
- package/dist/session/diag.js +118 -0
- package/dist/session/fs-watch.d.ts +132 -0
- package/dist/session/fs-watch.d.ts.map +1 -0
- package/dist/session/fs-watch.js +255 -0
- package/dist/session/helpers.d.ts +150 -0
- package/dist/session/helpers.d.ts.map +1 -0
- package/dist/session/helpers.js +472 -0
- package/dist/session/hibernation.d.ts +145 -0
- package/dist/session/hibernation.d.ts.map +1 -0
- package/dist/session/hibernation.js +385 -0
- package/dist/session/init-phases.d.ts +87 -0
- package/dist/session/init-phases.d.ts.map +1 -0
- package/dist/session/init-phases.js +137 -0
- package/dist/session/init.d.ts +46 -0
- package/dist/session/init.d.ts.map +1 -0
- package/dist/session/init.js +3579 -0
- package/dist/session/keys.d.ts +56 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +55 -0
- package/dist/session/nimbus-session.d.ts +434 -0
- package/dist/session/nimbus-session.d.ts.map +1 -0
- package/dist/session/nimbus-session.js +1084 -0
- package/dist/session/programmatic.d.ts +105 -0
- package/dist/session/programmatic.d.ts.map +1 -0
- package/dist/session/programmatic.js +326 -0
- package/dist/session/replica-routes.d.ts +68 -0
- package/dist/session/replica-routes.d.ts.map +1 -0
- package/dist/session/replica-routes.js +77 -0
- package/dist/session/routes.d.ts +29 -0
- package/dist/session/routes.d.ts.map +1 -0
- package/dist/session/routes.js +1331 -0
- package/dist/session/rpc.d.ts +323 -0
- package/dist/session/rpc.d.ts.map +1 -0
- package/dist/session/rpc.js +808 -0
- package/dist/session/state-store.d.ts +210 -0
- package/dist/session/state-store.d.ts.map +1 -0
- package/dist/session/state-store.js +459 -0
- package/dist/session/supervisor-rpc.d.ts +269 -0
- package/dist/session/supervisor-rpc.d.ts.map +1 -0
- package/dist/session/supervisor-rpc.js +437 -0
- package/dist/session/ws-hibernation-config.d.ts +64 -0
- package/dist/session/ws-hibernation-config.d.ts.map +1 -0
- package/dist/session/ws-hibernation-config.js +89 -0
- package/dist/session/ws.d.ts +95 -0
- package/dist/session/ws.d.ts.map +1 -0
- package/dist/session/ws.js +395 -0
- package/dist/shell/features.d.ts +410 -0
- package/dist/shell/features.d.ts.map +1 -0
- package/dist/shell/features.js +1885 -0
- package/dist/shell/unix-commands.d.ts +15 -0
- package/dist/shell/unix-commands.d.ts.map +1 -0
- package/dist/shell/unix-commands.js +3703 -0
- package/dist/stubs/lifo-ui.d.ts +10 -0
- package/dist/stubs/lifo-ui.d.ts.map +1 -0
- package/dist/stubs/lifo-ui.js +1 -0
- package/dist/tailwind-play.generated.d.ts +19 -0
- package/dist/tailwind-play.generated.d.ts.map +1 -0
- package/dist/tailwind-play.generated.js +18 -0
- package/dist/vfs/dev-provider.d.ts +64 -0
- package/dist/vfs/dev-provider.d.ts.map +1 -0
- package/dist/vfs/dev-provider.js +191 -0
- package/dist/vfs/events.d.ts +51 -0
- package/dist/vfs/events.d.ts.map +1 -0
- package/dist/vfs/events.js +127 -0
- package/dist/vfs/path.d.ts +30 -0
- package/dist/vfs/path.d.ts.map +1 -0
- package/dist/vfs/path.js +41 -0
- package/dist/vfs/seed-project.d.ts +62 -0
- package/dist/vfs/seed-project.d.ts.map +1 -0
- package/dist/vfs/seed-project.js +1045 -0
- package/dist/vfs/sqlite-vfs.d.ts +435 -0
- package/dist/vfs/sqlite-vfs.d.ts.map +1 -0
- package/dist/vfs/sqlite-vfs.js +1670 -0
- package/dist/vfs/symlink-registry.d.ts +64 -0
- package/dist/vfs/symlink-registry.d.ts.map +1 -0
- package/dist/vfs/symlink-registry.js +137 -0
- package/dist/wrangler/nimbus-wrangler.d.ts +157 -0
- package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -0
- package/dist/wrangler/nimbus-wrangler.js +931 -0
- package/package.json +77 -0
- package/public/_assets/cirrus-plugin-react.bundle.js +70740 -0
- package/public/_assets/esbuild-0.24.2.wasm +0 -0
- package/public/_assets/real-vite-bundle.js +101478 -0
- package/public/_assets/rollup.wasm +0 -0
- package/public/favicon.svg +8 -0
- package/public/index.html +565 -0
- package/public/s/index.html +2379 -0
- package/scripts/bundle-esbuild-wasm.mjs +244 -0
- package/scripts/bundle-facet-workers.mjs +137 -0
- package/scripts/bundle-git.mjs +118 -0
- package/scripts/bundle-npm-cjs.mjs +363 -0
- package/scripts/bundle-plugin-react.mjs +480 -0
- package/scripts/bundle-real-vite.mjs +959 -0
- package/scripts/bundle-runtime.mjs +600 -0
- package/scripts/bundle-tailwind-play.mjs +130 -0
- package/scripts/patch-lifo-ui.mjs +131 -0
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* python-repl.ts — Python REPL adapter (Pyodide 0.29.4).
|
|
3
|
+
*
|
|
4
|
+
* Implements ReplAdapter for the `python` shell command's no-args
|
|
5
|
+
* invocation. Reuses the existing Pyodide v2 preamble built by
|
|
6
|
+
* python-runner.ts's `buildPyodidePreamble`; this file only adds:
|
|
7
|
+
* 1. A REPL-step facet fn that pushes a line into a long-lived
|
|
8
|
+
* pyodide.console.PyodideConsole instance and returns the
|
|
9
|
+
* result.
|
|
10
|
+
* 2. Adapter wiring (banner, push, close, ps1/ps2 prompts).
|
|
11
|
+
*
|
|
12
|
+
* Design per /workspace/.seal-internal/2026-05-11-repl-plan/plan.md §5:
|
|
13
|
+
* - State persistence: same NimbusLoaderPool reference held across
|
|
14
|
+
* submits → same child-facet isolate → globalThis.__nimbusPyodideInstance
|
|
15
|
+
* persists.
|
|
16
|
+
* - Continuation prompts: PyodideConsole's runsource() returns an
|
|
17
|
+
* 'incomplete' status when input is mid-block (e.g. unclosed
|
|
18
|
+
* `def f():`); the adapter signals 'incomplete' back to ReplSession,
|
|
19
|
+
* which renders ps2 ('... ') and accumulates.
|
|
20
|
+
* - sys.exit() / exit() / quit(): captured via SystemExit on the
|
|
21
|
+
* pyodide.console.Console runtime; returned as ReplPushResult
|
|
22
|
+
* 'exit' with the captured code.
|
|
23
|
+
*
|
|
24
|
+
* NOT supported in v1 (deferred to W5+):
|
|
25
|
+
* - top-level await at the REPL prompt (Pyodide supports this via
|
|
26
|
+
* runPythonAsync; v1 uses runsource synchronously).
|
|
27
|
+
* - Tab-completion (PyodideConsole has rlcompleter; surface deferred).
|
|
28
|
+
* - SIGINT mid-statement (no interrupt-buffer plumbing yet).
|
|
29
|
+
*/
|
|
30
|
+
import { ReplSession } from './repl-session.js';
|
|
31
|
+
import { buildPyodidePreamble } from './python-runner.js';
|
|
32
|
+
/**
|
|
33
|
+
* Adapter that owns a NimbusLoaderPool for the lifetime of the REPL
|
|
34
|
+
* session. Each push(line) is a fresh pool.submit() into the cached
|
|
35
|
+
* facet slot — slot reuse means globalThis state (including the
|
|
36
|
+
* PyodideConsole instance bound to a persistent globals dict) survives
|
|
37
|
+
* across pushes.
|
|
38
|
+
*/
|
|
39
|
+
class PythonReplAdapter {
|
|
40
|
+
pool = null; // NimbusLoaderPool (typed loosely to avoid cyclic import)
|
|
41
|
+
initDone = false;
|
|
42
|
+
deps;
|
|
43
|
+
ps1 = '>>> ';
|
|
44
|
+
ps2 = '... ';
|
|
45
|
+
constructor(deps) {
|
|
46
|
+
this.deps = deps;
|
|
47
|
+
}
|
|
48
|
+
banner() {
|
|
49
|
+
return ('Python 3.13.2 (Pyodide 0.29.4) on Nimbus\r\n' +
|
|
50
|
+
'Type "exit()" or press Ctrl-D to exit.\r\n');
|
|
51
|
+
}
|
|
52
|
+
async push(source) {
|
|
53
|
+
try {
|
|
54
|
+
await this.ensurePool();
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
return { kind: 'error', stderr: `[python-repl] bootstrap failed: ${e?.message || e}\n` };
|
|
58
|
+
}
|
|
59
|
+
// First push initializes the PyodideConsole.
|
|
60
|
+
if (!this.initDone) {
|
|
61
|
+
try {
|
|
62
|
+
const initResult = await this.submitFacetFn({ mode: 'init' });
|
|
63
|
+
if (initResult.error) {
|
|
64
|
+
return { kind: 'error', stderr: `[python-repl] console init failed: ${initResult.error}\n` };
|
|
65
|
+
}
|
|
66
|
+
this.initDone = true;
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
return { kind: 'error', stderr: `[python-repl] init dispatch failed: ${e?.message || e}\n` };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let result;
|
|
73
|
+
try {
|
|
74
|
+
result = await this.submitFacetFn({ mode: 'push', source });
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
return { kind: 'error', stderr: `[python-repl] push dispatch failed: ${e?.message || e}\n` };
|
|
78
|
+
}
|
|
79
|
+
// Map facet result → adapter result.
|
|
80
|
+
if (result.exit) {
|
|
81
|
+
return {
|
|
82
|
+
kind: 'exit',
|
|
83
|
+
exitCode: result.exitCode || 0,
|
|
84
|
+
stdout: result.stdout,
|
|
85
|
+
stderr: result.stderr,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (result.incomplete) {
|
|
89
|
+
return { kind: 'incomplete' };
|
|
90
|
+
}
|
|
91
|
+
if (result.error) {
|
|
92
|
+
// The error is rendered via stderr in result.stderr; surface as
|
|
93
|
+
// 'output' so output framing is consistent.
|
|
94
|
+
return { kind: 'output', stdout: result.stdout || '', stderr: result.stderr || '' };
|
|
95
|
+
}
|
|
96
|
+
return { kind: 'output', stdout: result.stdout || '', stderr: result.stderr || '' };
|
|
97
|
+
}
|
|
98
|
+
async close() {
|
|
99
|
+
if (this.pool) {
|
|
100
|
+
// NimbusLoaderPool.dispose() is synchronous (see loader-pool.ts:865);
|
|
101
|
+
// the await wraps any throw without bothering the caller.
|
|
102
|
+
try {
|
|
103
|
+
this.pool.dispose?.();
|
|
104
|
+
}
|
|
105
|
+
catch { /* fail-soft */ }
|
|
106
|
+
this.pool = null;
|
|
107
|
+
}
|
|
108
|
+
this.initDone = false;
|
|
109
|
+
}
|
|
110
|
+
/** Build the pool once on the first push. Pulls VFS bytes for the
|
|
111
|
+
* Pyodide assets, builds the canonical preamble, creates the pool. */
|
|
112
|
+
async ensurePool() {
|
|
113
|
+
if (this.pool)
|
|
114
|
+
return;
|
|
115
|
+
const { vfs, installRoot, facetMgr } = this.deps;
|
|
116
|
+
const wasmPath = `${installRoot}/share/pyodide/pyodide.asm.wasm`;
|
|
117
|
+
const jsPath = `${installRoot}/share/pyodide/pyodide.asm.js`;
|
|
118
|
+
const stdlibPath = `${installRoot}/share/pyodide/python_stdlib.zip`;
|
|
119
|
+
if (!vfs.exists(wasmPath)) {
|
|
120
|
+
throw new Error(`pyodide.asm.wasm missing at ${wasmPath} (run 'nimbus install python')`);
|
|
121
|
+
}
|
|
122
|
+
if (!vfs.exists(jsPath)) {
|
|
123
|
+
throw new Error(`pyodide.asm.js missing at ${jsPath}`);
|
|
124
|
+
}
|
|
125
|
+
if (!vfs.exists(stdlibPath)) {
|
|
126
|
+
throw new Error(`python_stdlib.zip missing at ${stdlibPath}`);
|
|
127
|
+
}
|
|
128
|
+
const wasmBytes = vfs.readFile(wasmPath);
|
|
129
|
+
const jsBytes = vfs.readFile(jsPath);
|
|
130
|
+
const stdlibBytes = vfs.readFile(stdlibPath);
|
|
131
|
+
// Apply the same asm.js source-patches python-runner.ts:317-331 does.
|
|
132
|
+
let asmJsSrc = new TextDecoder('utf-8').decode(jsBytes);
|
|
133
|
+
const PATCH_NEEDLE = 'else throw new Error("Cannot determine runtime environment")';
|
|
134
|
+
const PATCH_REPLACE = '/* nimbus-patch: was: ' + PATCH_NEEDLE + ' */';
|
|
135
|
+
if (asmJsSrc.includes(PATCH_NEEDLE)) {
|
|
136
|
+
asmJsSrc = asmJsSrc.replace(PATCH_NEEDLE, PATCH_REPLACE);
|
|
137
|
+
}
|
|
138
|
+
const HEAD_NEEDLE = 'if(d.IN_BROWSER_MAIN_THREAD)';
|
|
139
|
+
const HEAD_REPLACE = 'if(true||d.IN_BROWSER_MAIN_THREAD)';
|
|
140
|
+
if (asmJsSrc.includes(HEAD_NEEDLE)) {
|
|
141
|
+
asmJsSrc = asmJsSrc.replace(HEAD_NEEDLE, HEAD_REPLACE);
|
|
142
|
+
}
|
|
143
|
+
// Encode stdlib bytes to base64 for splice into preamble.
|
|
144
|
+
const stdlibB64 = uint8ToBase64(stdlibBytes);
|
|
145
|
+
const preamble = buildPyodidePreamble(asmJsSrc, stdlibB64);
|
|
146
|
+
// Create the pool. Tag MUST differ from 'python-runner' so REPL
|
|
147
|
+
// sessions don't collide with one-shot dispatches in the loader
|
|
148
|
+
// slot cache (different fnHash + different tag = separate slot).
|
|
149
|
+
const { NimbusLoaderPool } = await import('../loaders/loader-pool.js');
|
|
150
|
+
const env = facetMgr.env;
|
|
151
|
+
const ctx = facetMgr.ctx;
|
|
152
|
+
this.pool = new NimbusLoaderPool(env, ctx, {
|
|
153
|
+
tag: 'python-repl',
|
|
154
|
+
concurrency: 1,
|
|
155
|
+
omitSupervisor: true,
|
|
156
|
+
preamble,
|
|
157
|
+
});
|
|
158
|
+
// Stash the wasm bytes for first submit's wasmModules.
|
|
159
|
+
this.__wasmBytesAB = toAB(wasmBytes);
|
|
160
|
+
}
|
|
161
|
+
async submitFacetFn(args) {
|
|
162
|
+
const wasmModules = { 'pyodide.asm.wasm': this.__wasmBytesAB };
|
|
163
|
+
return await this.pool.submit(replStepFacetFn, args, {
|
|
164
|
+
wasmModules,
|
|
165
|
+
timeoutMs: 60_000,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The facet-side function. Self-contained (no closure captures —
|
|
171
|
+
* serialized via fn.toString() across the LOADER boundary).
|
|
172
|
+
*
|
|
173
|
+
* Modes:
|
|
174
|
+
* - 'init': bootstrap Pyodide (via __pyodideRun's preamble), import
|
|
175
|
+
* pyodide.console.PyodideConsole, store on globalThis.__pyConsole.
|
|
176
|
+
* - 'push': push args.source into __pyConsole; check syntax_check;
|
|
177
|
+
* await the future if complete; capture stdout/stderr; map
|
|
178
|
+
* SystemExit → exit:true.
|
|
179
|
+
*/
|
|
180
|
+
function replStepFacetFn(args) {
|
|
181
|
+
// The preamble exposes globalThis.__pyodideRun (one-shot path) and
|
|
182
|
+
// populates __nimbusPyodideInstance once Pyodide is finalized. We
|
|
183
|
+
// first invoke __pyodideRun({userCode: ''}) for its side effect of
|
|
184
|
+
// running the bootstrap + finalizeBootstrap path, then take over.
|
|
185
|
+
const g = globalThis;
|
|
186
|
+
return (async function () {
|
|
187
|
+
// ── Init path ──
|
|
188
|
+
if (args.mode === 'init') {
|
|
189
|
+
// Bootstrap via the existing __pyodideRun helper. Passing an
|
|
190
|
+
// empty userCode runs the full bootstrap (gate release, await
|
|
191
|
+
// bootstrap promise, finalizeBootstrap, sys.argv setup) without
|
|
192
|
+
// running any user code. After bootstrap, __nimbusPyodideInstance
|
|
193
|
+
// is cached and we can call its runPython directly.
|
|
194
|
+
if (typeof g.__pyodideRun !== 'function') {
|
|
195
|
+
return {
|
|
196
|
+
stdout: '',
|
|
197
|
+
stderr: '',
|
|
198
|
+
error: '__pyodideRun missing in preamble',
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const r0 = await g.__pyodideRun({
|
|
202
|
+
userCode: '',
|
|
203
|
+
pyArgv: ['python'],
|
|
204
|
+
userEnv: { HOME: '/home/pyodide', PYTHONINSPECT: '1' },
|
|
205
|
+
progName: 'python',
|
|
206
|
+
});
|
|
207
|
+
if (r0.error) {
|
|
208
|
+
return { stdout: r0.stdout || '', stderr: r0.stderr || '', error: r0.error };
|
|
209
|
+
}
|
|
210
|
+
const pyodide = g.__nimbusPyodideInstance;
|
|
211
|
+
if (!pyodide) {
|
|
212
|
+
return { stdout: '', stderr: '', error: 'pyodide not finalized after init' };
|
|
213
|
+
}
|
|
214
|
+
// Create the PyodideConsole instance and stash it. We capture
|
|
215
|
+
// stdout/stderr by passing explicit callbacks that forward to
|
|
216
|
+
// the SAME __nimbusPyStdout / __nimbusPyStderr buffers the rest
|
|
217
|
+
// of the runtime uses. PyodideConsole(persistent_stream_redirection=
|
|
218
|
+
// False) means each push() temporarily redirects sys.stdout to
|
|
219
|
+
// its internal capture (via redirect_stdout); we supply explicit
|
|
220
|
+
// callbacks so output also reaches our JS-side buffers.
|
|
221
|
+
try {
|
|
222
|
+
// Expose JS-side push callbacks for Python's stdout/stderr
|
|
223
|
+
// forwarding. Setting them on globalThis lets the Python
|
|
224
|
+
// side reach them via the `js` module.
|
|
225
|
+
g.__nimbus_repl_stdout_cb = function (s) { g.__nimbusPyStdout.push(s); };
|
|
226
|
+
g.__nimbus_repl_stderr_cb = function (s) { g.__nimbusPyStderr.push(s); };
|
|
227
|
+
// REPL-A2 (master plan §1 + 2026-05-11 user-evidence): the
|
|
228
|
+
// PyodideConsole runsource() path swallows three things by
|
|
229
|
+
// default that real CPython's REPL surfaces:
|
|
230
|
+
// 1. Expression result (sys.displayhook → repr → stdout).
|
|
231
|
+
// 2. Runtime exceptions (traceback.format_exception → stderr).
|
|
232
|
+
// 3. SystemExit exit code (SystemExit.code → int, propagated).
|
|
233
|
+
// We re-implement them Python-side inside __nimbus_repl_push,
|
|
234
|
+
// which the JS host calls per submitted line. The function
|
|
235
|
+
// returns a 4-tuple-like dict {status, exit_code} via globals
|
|
236
|
+
// and pushes formatted text through stdout/stderr callbacks.
|
|
237
|
+
pyodide.runPython([
|
|
238
|
+
'import sys',
|
|
239
|
+
'import io',
|
|
240
|
+
'import traceback',
|
|
241
|
+
'import ast',
|
|
242
|
+
'import js',
|
|
243
|
+
'from pyodide.console import PyodideConsole',
|
|
244
|
+
// REPL-A2 (2026-05-11): PyodideConsole.runcode does
|
|
245
|
+
// `from pyodide_js import loadPackagesFromImports` and awaits
|
|
246
|
+
// it. In our env without the package registry initialised,
|
|
247
|
+
// the call raises "TypeError: Cannot read properties of undefined
|
|
248
|
+
// (reading has)" on the first 'import X' line.
|
|
249
|
+
//
|
|
250
|
+
// Override pyodide_js.loadPackagesFromImports with a no-op
|
|
251
|
+
// async function. pyodide_js is a JsProxy for the JS-side
|
|
252
|
+
// pyodide module; setattr on it writes the JS object property,
|
|
253
|
+
// and PyodideConsole's import at call-time picks up the stub.
|
|
254
|
+
'import pyodide_js as __nimbus_pyjs',
|
|
255
|
+
'async def __nimbus_noop_loadpkgs(source): return None',
|
|
256
|
+
'__nimbus_pyjs.loadPackagesFromImports = __nimbus_noop_loadpkgs',
|
|
257
|
+
// Top-level globals dict — shared across all push() calls so
|
|
258
|
+
// user-defined vars persist.
|
|
259
|
+
'__nimbus_repl_globals = {"__name__": "__main__", "__doc__": None}',
|
|
260
|
+
'__nimbus_repl_console = PyodideConsole(',
|
|
261
|
+
' __nimbus_repl_globals,',
|
|
262
|
+
// The Console will call these for every write during runsource.
|
|
263
|
+
' stdout_callback=lambda s: js.__nimbus_repl_stdout_cb(s),',
|
|
264
|
+
' stderr_callback=lambda s: js.__nimbus_repl_stderr_cb(s),',
|
|
265
|
+
' persistent_stream_redirection=False,',
|
|
266
|
+
')',
|
|
267
|
+
// sys.ps1/ps2 are advisory; the host renders the actual
|
|
268
|
+
// prompts. Set so user code reading sys.ps1 sees sane values.
|
|
269
|
+
'sys.ps1 = ">>> "',
|
|
270
|
+
'sys.ps2 = "... "',
|
|
271
|
+
// Source-level displayhook helper — CPython's REPL calls
|
|
272
|
+
// sys.displayhook(value) on the last expression's value; if
|
|
273
|
+
// value is not None, displayhook prints repr(value) + '\\n'
|
|
274
|
+
// to stdout and binds builtins._ to the value. We use the
|
|
275
|
+
// stdlib default sys.displayhook via direct call.
|
|
276
|
+
// The 'expression result' is the value of the trailing
|
|
277
|
+
// expression statement IF the source ended in one.
|
|
278
|
+
//
|
|
279
|
+
// PyodideConsole.push() returns a ConsoleFuture with these
|
|
280
|
+
// attrs: .syntax_check ∈ {incomplete, syntax-error, complete},
|
|
281
|
+
// .formatted_error (set when syntax-error). On `complete`,
|
|
282
|
+
// awaiting yields the value of the last expression OR None
|
|
283
|
+
// for statements. On runtime exception it raises.
|
|
284
|
+
//
|
|
285
|
+
// Per-push driver returns a dict for the JS host to inspect:
|
|
286
|
+
// {kind: incomplete|complete|syntax-error|exit, exit_code}
|
|
287
|
+
//
|
|
288
|
+
// REPL-R7-2 (2026-05-12): reset the PyodideConsole internal
|
|
289
|
+
// buffer before each push. PyodideConsole inherits from
|
|
290
|
+
// CPython's code.InteractiveConsole, whose .push(line)
|
|
291
|
+
// *appends* to self.buffer and joins with "\\n". The host
|
|
292
|
+
// (the host file, python-repl.ts line ~252) sends the ENTIRE
|
|
293
|
+
// multi-line block on each push() — not just the new line —
|
|
294
|
+
// so without reset the buffer grows quadratically AND the
|
|
295
|
+
// joined source contains duplicate prior lines.
|
|
296
|
+
//
|
|
297
|
+
// Concrete repro:
|
|
298
|
+
// line 1 typed: "def foo():" → push #1
|
|
299
|
+
// buffer=["def foo():"] source="def foo():" → incomplete
|
|
300
|
+
// line 2 typed: " return 42" → host re-sends full block
|
|
301
|
+
// push #2 source="def foo():\\n return 42"
|
|
302
|
+
// PRE-FIX: buffer becomes
|
|
303
|
+
// ["def foo():", "def foo():\\n return 42"]
|
|
304
|
+
// joined="def foo():\\ndef foo():\\n return 42"
|
|
305
|
+
// → IndentationError: "expected an indented block after
|
|
306
|
+
// function definition on line 1" (because line 2 is
|
|
307
|
+
// "def foo():" at column 0, not indented).
|
|
308
|
+
//
|
|
309
|
+
// Fix: clear .buffer before each push so the host-provided
|
|
310
|
+
// full source IS the entire buffer state. Side effect: we
|
|
311
|
+
// also need to be able to detect "incomplete" the way
|
|
312
|
+
// InteractiveConsole does — by trying to compile and seeing
|
|
313
|
+
// E_INCOMPLETE. PyodideConsole.push does so anyway, and
|
|
314
|
+
// since we always pass the FULL accumulated source from the
|
|
315
|
+
// host, "incomplete" is signalled correctly on the partial-
|
|
316
|
+
// block case.
|
|
317
|
+
'def __nimbus_repl_step(source):',
|
|
318
|
+
' __nimbus_repl_console.buffer.clear()',
|
|
319
|
+
' fut = __nimbus_repl_console.push(source)',
|
|
320
|
+
' sc = fut.syntax_check',
|
|
321
|
+
' if sc == "incomplete":',
|
|
322
|
+
' return {"kind": "incomplete"}',
|
|
323
|
+
' if sc == "syntax-error":',
|
|
324
|
+
// PyodideConsole already wrote formatted_error to stderr_cb;
|
|
325
|
+
// verify by emitting it if formatted_error is set. Some
|
|
326
|
+
// Pyodide versions only set the attribute and let the host
|
|
327
|
+
// render — emit defensively (idempotent if already streamed).
|
|
328
|
+
' fe = getattr(fut, "formatted_error", None)',
|
|
329
|
+
' if fe and isinstance(fe, str):',
|
|
330
|
+
' js.__nimbus_repl_stderr_cb(fe)',
|
|
331
|
+
' return {"kind": "syntax-error"}',
|
|
332
|
+
' return {"kind": "pending", "fut": fut}',
|
|
333
|
+
// Per-push complete-stage: await the future, handle SystemExit
|
|
334
|
+
// + runtime exceptions + display the result.
|
|
335
|
+
// REPL-A2 displayhook: PyodideConsole's async path (code.run_async
|
|
336
|
+
// inside a ConsoleFuture) does NOT auto-invoke sys.displayhook
|
|
337
|
+
// on the last expression value the way the CPython REPL does.
|
|
338
|
+
// We replicate the displayhook behavior explicitly: if the
|
|
339
|
+
// awaited result is not None, write repr(result)+"\\n" to
|
|
340
|
+
// stdout_callback and bind builtins._ to the value (matches
|
|
341
|
+
// CPython REPL convention where `_` holds the last result).
|
|
342
|
+
//
|
|
343
|
+
// Bare expressions (`a`, `1+1`, `obj.method()`) are compiled
|
|
344
|
+
// in 'single' mode by PyodideConsole but the auto-displayhook
|
|
345
|
+
// hook isn't wired — we wire it here. Statements (`a = 1`,
|
|
346
|
+
// `def f(): ...`) return None so the displayhook is a no-op.
|
|
347
|
+
'import builtins as __nimbus_builtins',
|
|
348
|
+
'async def __nimbus_repl_finish(fut):',
|
|
349
|
+
' try:',
|
|
350
|
+
' result = await fut',
|
|
351
|
+
' if result is not None:',
|
|
352
|
+
' try:',
|
|
353
|
+
' rendered = repr(result)',
|
|
354
|
+
' except BaseException as re:',
|
|
355
|
+
' rendered = "<repr() failed: " + repr(re) + ">"',
|
|
356
|
+
' js.__nimbus_repl_stdout_cb(rendered + "\\n")',
|
|
357
|
+
' __nimbus_builtins._ = result',
|
|
358
|
+
' except SystemExit as se:',
|
|
359
|
+
' code = se.code',
|
|
360
|
+
' if code is None:',
|
|
361
|
+
' n = 0',
|
|
362
|
+
' elif isinstance(code, int):',
|
|
363
|
+
' n = code',
|
|
364
|
+
' else:',
|
|
365
|
+
// Real CPython exits with 1 on string arg + prints msg to stderr.
|
|
366
|
+
' js.__nimbus_repl_stderr_cb(str(code) + "\\n")',
|
|
367
|
+
' n = 1',
|
|
368
|
+
' return {"kind": "exit", "exit_code": n}',
|
|
369
|
+
' except BaseException as e:',
|
|
370
|
+
// Runtime exception (NameError, TypeError, etc.). Format the
|
|
371
|
+
// traceback the way CPython's REPL does: traceback.format_exception
|
|
372
|
+
// returns a list of strings; join them and emit to stderr_cb.
|
|
373
|
+
// We omit the top frame (the REPL driver itself) by limiting
|
|
374
|
+
// to the user's frame chain — CPython's interactive interpreter
|
|
375
|
+
// strips its own frame via tb.tb_next.
|
|
376
|
+
' tb = e.__traceback__',
|
|
377
|
+
' if tb is not None:',
|
|
378
|
+
' tb = tb.tb_next # skip __nimbus_repl_finish frame',
|
|
379
|
+
' lines = traceback.format_exception(type(e), e, tb)',
|
|
380
|
+
' js.__nimbus_repl_stderr_cb("".join(lines))',
|
|
381
|
+
' return {"kind": "error"}',
|
|
382
|
+
// No exception → result is the expression value (or None for
|
|
383
|
+
// statements). PyodideConsole's runsource compiles in
|
|
384
|
+
// "single" mode which already invokes sys.displayhook for
|
|
385
|
+
// expression statements. So `a` at the REPL → displayhook',
|
|
386
|
+
// already wrote repr(a)+"\\n" to stdout BEFORE we got here.',
|
|
387
|
+
// We deliberately do NOT double-print result. CPython 3.13 +,
|
|
388
|
+
// PyodideConsole behaviour validated: stdout_callback received
|
|
389
|
+
// the displayhook output mid-await.
|
|
390
|
+
' return {"kind": "complete"}',
|
|
391
|
+
].join('\n'));
|
|
392
|
+
}
|
|
393
|
+
catch (e) {
|
|
394
|
+
return {
|
|
395
|
+
stdout: '',
|
|
396
|
+
stderr: '',
|
|
397
|
+
error: 'PyodideConsole init failed: ' + (e?.message || e),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
return { stdout: '', stderr: '' };
|
|
401
|
+
}
|
|
402
|
+
// ── Push path ──
|
|
403
|
+
const pyodide = g.__nimbusPyodideInstance;
|
|
404
|
+
if (!pyodide) {
|
|
405
|
+
return { stdout: '', stderr: '', error: 'pyodide not initialized (init mode not run)' };
|
|
406
|
+
}
|
|
407
|
+
const source = args.source || '';
|
|
408
|
+
// Reset capture buffer offsets.
|
|
409
|
+
const stdoutStart = g.__nimbusPyStdout.length;
|
|
410
|
+
const stderrStart = g.__nimbusPyStderr.length;
|
|
411
|
+
// REPL-A2: source-routing via Python-side global to avoid JS-string
|
|
412
|
+
// escape hazards on multi-line input (tab chars, embedded quotes,
|
|
413
|
+
// unicode). __nimbus_repl_step inspects syntax_check and either
|
|
414
|
+
// returns {kind: incomplete|syntax-error} OR returns a pending dict
|
|
415
|
+
// containing the future to await.
|
|
416
|
+
g.__nimbus_repl_src = source;
|
|
417
|
+
let stepRes;
|
|
418
|
+
try {
|
|
419
|
+
stepRes = pyodide.runPython('__nimbus_repl_step(__import__("js").__nimbus_repl_src)');
|
|
420
|
+
}
|
|
421
|
+
catch (e) {
|
|
422
|
+
// PyodideConsole.push() itself threw — extremely rare (means the
|
|
423
|
+
// tokenizer crashed). Surface as error.
|
|
424
|
+
return {
|
|
425
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
426
|
+
stderr: 'push threw: ' + (e?.message || e) + '\n',
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
// PyProxy → JS object. Convert via toJs (depth=1 to keep `fut`
|
|
430
|
+
// as PyProxy). Pyodide's PyProxy.toJs({depth:1}) returns a Map by
|
|
431
|
+
// default; pass dict_converter to get a plain object.
|
|
432
|
+
let kind;
|
|
433
|
+
let futProxy = null;
|
|
434
|
+
try {
|
|
435
|
+
const asJs = stepRes.toJs({
|
|
436
|
+
depth: 1,
|
|
437
|
+
dict_converter: Object.fromEntries,
|
|
438
|
+
});
|
|
439
|
+
kind = asJs.kind;
|
|
440
|
+
futProxy = asJs.fut;
|
|
441
|
+
}
|
|
442
|
+
catch (_e) {
|
|
443
|
+
// Fallback: access via getattr.
|
|
444
|
+
kind = stepRes.get('kind');
|
|
445
|
+
futProxy = stepRes.get('fut');
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
try {
|
|
449
|
+
stepRes.destroy();
|
|
450
|
+
}
|
|
451
|
+
catch { }
|
|
452
|
+
}
|
|
453
|
+
if (kind === 'incomplete') {
|
|
454
|
+
return {
|
|
455
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
456
|
+
stderr: g.__nimbusPyStderr.slice(stderrStart).join(''),
|
|
457
|
+
incomplete: true,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
if (kind === 'syntax-error') {
|
|
461
|
+
return {
|
|
462
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
463
|
+
stderr: g.__nimbusPyStderr.slice(stderrStart).join(''),
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
// kind === 'pending' — await Python-side __nimbus_repl_finish(fut).
|
|
467
|
+
// This Python coroutine handles SystemExit, runtime exceptions, and
|
|
468
|
+
// the displayhook side-effect (stdout already streamed mid-await).
|
|
469
|
+
//
|
|
470
|
+
// We pass the future across the JS↔Py boundary via a JS-side global:
|
|
471
|
+
// Pyodide's runPythonAsync doesn't take positional args, so stash
|
|
472
|
+
// `futProxy` on globalThis under a stable name and have Python read
|
|
473
|
+
// it via `__import__("js").__nimbus_repl_fut`.
|
|
474
|
+
g.__nimbus_repl_fut = futProxy;
|
|
475
|
+
let finishRes;
|
|
476
|
+
try {
|
|
477
|
+
// pyodide.runPythonAsync returns a Promise resolving to the
|
|
478
|
+
// coroutine's return value (a PyProxy dict).
|
|
479
|
+
finishRes = await pyodide.runPythonAsync('await __nimbus_repl_finish(__import__("js").__nimbus_repl_fut)');
|
|
480
|
+
}
|
|
481
|
+
catch (e) {
|
|
482
|
+
// __nimbus_repl_finish has its own try/except for SystemExit and
|
|
483
|
+
// BaseException — reaching here means the dispatch itself broke.
|
|
484
|
+
try {
|
|
485
|
+
futProxy?.destroy?.();
|
|
486
|
+
}
|
|
487
|
+
catch { }
|
|
488
|
+
return {
|
|
489
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
490
|
+
stderr: 'repl-finish threw: ' + (e?.message || e) + '\n',
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
let finishKind = 'complete';
|
|
494
|
+
let exitCode = 0;
|
|
495
|
+
try {
|
|
496
|
+
const asJs = finishRes.toJs({
|
|
497
|
+
depth: 1,
|
|
498
|
+
dict_converter: Object.fromEntries,
|
|
499
|
+
});
|
|
500
|
+
finishKind = asJs.kind || 'complete';
|
|
501
|
+
exitCode = typeof asJs.exit_code === 'number' ? asJs.exit_code : 0;
|
|
502
|
+
}
|
|
503
|
+
catch (_e) {
|
|
504
|
+
try {
|
|
505
|
+
finishKind = finishRes.get('kind') || 'complete';
|
|
506
|
+
exitCode = finishRes.get('exit_code') || 0;
|
|
507
|
+
}
|
|
508
|
+
catch { }
|
|
509
|
+
}
|
|
510
|
+
finally {
|
|
511
|
+
try {
|
|
512
|
+
finishRes.destroy();
|
|
513
|
+
}
|
|
514
|
+
catch { }
|
|
515
|
+
try {
|
|
516
|
+
futProxy?.destroy?.();
|
|
517
|
+
}
|
|
518
|
+
catch { }
|
|
519
|
+
}
|
|
520
|
+
if (finishKind === 'exit') {
|
|
521
|
+
return {
|
|
522
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
523
|
+
stderr: g.__nimbusPyStderr.slice(stderrStart).join(''),
|
|
524
|
+
exit: true,
|
|
525
|
+
exitCode: exitCode,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
// 'complete' or 'error' — both render via stdout/stderr buffers.
|
|
529
|
+
return {
|
|
530
|
+
stdout: g.__nimbusPyStdout.slice(stdoutStart).join(''),
|
|
531
|
+
stderr: g.__nimbusPyStderr.slice(stderrStart).join(''),
|
|
532
|
+
};
|
|
533
|
+
})();
|
|
534
|
+
}
|
|
535
|
+
/** ArrayBuffer view of a Uint8Array, without copy. */
|
|
536
|
+
function toAB(u8) {
|
|
537
|
+
return u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength);
|
|
538
|
+
}
|
|
539
|
+
/** Encode Uint8Array → base64 in chunks to avoid stack overflow on
|
|
540
|
+
* ~2 MiB stdlib payload. Mirrors python-runner.ts's helper. */
|
|
541
|
+
function uint8ToBase64(u8) {
|
|
542
|
+
const CHUNK = 0x8000;
|
|
543
|
+
let s = '';
|
|
544
|
+
for (let i = 0; i < u8.length; i += CHUNK) {
|
|
545
|
+
s += String.fromCharCode.apply(null, Array.from(u8.subarray(i, Math.min(i + CHUNK, u8.length))));
|
|
546
|
+
}
|
|
547
|
+
return btoa(s);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Top-level wrapper: builds a Python REPL adapter, drives a
|
|
551
|
+
* ReplSession to completion, returns the exit code.
|
|
552
|
+
*
|
|
553
|
+
* Called from the python factory's wrapper in init.ts when the user
|
|
554
|
+
* runs `python` with no args.
|
|
555
|
+
*/
|
|
556
|
+
export async function runPythonRepl(deps) {
|
|
557
|
+
const adapter = new PythonReplAdapter(deps);
|
|
558
|
+
// REPL-R7-1: pass shell so ReplSession can drain pasteQueue on
|
|
559
|
+
// attach. Without this, multi-line WS frames (paste cases) drop
|
|
560
|
+
// input on the floor and the REPL hangs.
|
|
561
|
+
const session = new ReplSession(adapter, deps.terminal, deps.shell);
|
|
562
|
+
return await session.run();
|
|
563
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* python-runner.ts — Pyodide v0.29.4 runner (True-OS Wave-3 v2 / Pyodide v1).
|
|
3
|
+
*
|
|
4
|
+
* v1 scope per /workspace/.seal-internal/2026-05-10-pyodide-research/plan.md
|
|
5
|
+
* D1-D7:
|
|
6
|
+
* - `python --version` / `python -c '<code>'` / `python script.py`
|
|
7
|
+
* - stdlib subset (full python_stdlib.zip ships)
|
|
8
|
+
* - stdout/stderr → processLogs (Process tab integration)
|
|
9
|
+
* - exit code via sys.exit(N) or unhandled exception → 1
|
|
10
|
+
* - argv passed through to sys.argv
|
|
11
|
+
*
|
|
12
|
+
* Out of v1 (queued for v2/v3):
|
|
13
|
+
* - REPL mode (`python` with no args)
|
|
14
|
+
* - File I/O beyond reading the entry script
|
|
15
|
+
* - `pip install` / `loadPackage` / native-extension packages
|
|
16
|
+
* - Sync HTTP (urllib3 / requests blocked without JSPI)
|
|
17
|
+
*
|
|
18
|
+
* Architecture: SAME LOADER-modules transport as clang-runner/wasm-
|
|
19
|
+
* runner. The Pyodide wasm bytes ship via the LOADER `modules` map
|
|
20
|
+
* (CSP allows wasm code-gen at module-load time, not at request
|
|
21
|
+
* time). The Pyodide.asm.js + stdlib zip ride via the loader-pool
|
|
22
|
+
* `context` field (JSON-stringified into the inner worker.js at
|
|
23
|
+
* module-load).
|
|
24
|
+
*
|
|
25
|
+
* Per wasm-csp/findings.md §4b: Pyodide.asm.wasm (10.1 MB on disk)
|
|
26
|
+
* compiles in 314 ms via LOADER on PROD. With our v1 deployment of
|
|
27
|
+
* 0.29.4 (8.25 MB asm.wasm), this is well under the empirical
|
|
28
|
+
* ~32 MiB per-call ceiling.
|
|
29
|
+
*/
|
|
30
|
+
import type { RuntimeManifest } from './runtime-catalog.js';
|
|
31
|
+
import type { SqliteVFS } from '../vfs/sqlite-vfs.js';
|
|
32
|
+
import type { FacetManager } from '../facets/manager.js';
|
|
33
|
+
/**
|
|
34
|
+
* Build the python-runner factory. Called once at session init; the
|
|
35
|
+
* returned factory binds the manifest + install root for each
|
|
36
|
+
* registered entrypoint (`python`, `python3`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function makePythonRunnerFactory(deps: {
|
|
39
|
+
facetMgr: FacetManager;
|
|
40
|
+
vfs: SqliteVFS;
|
|
41
|
+
}): (manifest: RuntimeManifest, installRoot: string, binName: string, binKind: string | undefined) => (ctx: any) => Promise<number>;
|
|
42
|
+
/**
|
|
43
|
+
* Compose the per-call preamble by splicing the pyodide.asm.js source
|
|
44
|
+
* verbatim ahead of the __pyodideRun helper. Workerd compiles this
|
|
45
|
+
* blob as JS at module-load time (where `var` declarations + globals
|
|
46
|
+
* assignment are allowed), then the asm.js's `var _createPyodideModule`
|
|
47
|
+
* is hoisted onto globalThis.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildPyodidePreamble(asmJsSrc: string, stdlibB64: string): string;
|
|
50
|
+
//# sourceMappingURL=python-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/python-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;CAChB,GAAG,CAAC,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,KAC7F,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CA2HhC;AAkPD;;;;;;GAMG;AAKH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAyFhF"}
|