@nimbus-sh/worker 0.1.4 → 0.1.5

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.
@@ -50,6 +50,13 @@ export interface NimbusLoaderPoolOptions {
50
50
  * that don't need DO callbacks (e.g. a pure CPU compute pool).
51
51
  */
52
52
  omitSupervisor?: boolean;
53
+ /**
54
+ * Loader cache scope. Defaults to `session`, which bakes the owning DO id
55
+ * into the loader key so stateful facets cannot leak bindings or globals
56
+ * across sessions. Use `global` only for stateless compute modules that do
57
+ * not receive a Supervisor binding and do not retain user state.
58
+ */
59
+ cacheScope?: 'session' | 'global';
53
60
  /**
54
61
  * Override the `doId` baked into the auto-injected SUPERVISOR binding.
55
62
  * Default: `ctx.id.toString()` (the DO that constructs the pool).
@@ -1 +1 @@
1
- {"version":3,"file":"loader-pool.d.ts","sourceRoot":"","sources":["../../src/loaders/loader-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAeH,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;;;;;;;;;;OAgBG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C;AAED,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C;AAED,oEAAoE;AACpE,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CACrC;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAgB;;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAE/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAOzB;IACH;;;;4DAIwD;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGjC,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,kBAAkB,EACvB,IAAI,CAAC,EAAE,uBAAuB;IA2FhC,wEAAwE;IACxE,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAgYD;;;OAGG;IACG,MAAM,CAAC,CAAC,EAAE,CAAC,EACf,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxC,GAAG,EAAE,CAAC,EACN,IAAI,CAAC,EAAE,uBAAuB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IActB;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,CAAC,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACzC,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAOpC;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,CAAC,CAAC,EAAE,CAAC,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAgEpC;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,IAAI;CAchB;AAED,iEAAiE;AACjE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"loader-pool.d.ts","sourceRoot":"","sources":["../../src/loaders/loader-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAeH,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAClC;;;;;;;;;;;;;;;;OAgBG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C;AAED,qDAAqD;AACrD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC3C;AAED,oEAAoE;AACpE,MAAM,WAAW,sBAAuB,SAAQ,uBAAuB;IACrE,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CACrC;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,gBAAgB;;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAE/D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW,CAOzB;IACH;;;;4DAIwD;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAGjC,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,kBAAkB,EACvB,IAAI,CAAC,EAAE,uBAAuB;IA6FhC,wEAAwE;IACxE,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAgYD;;;OAGG;IACG,MAAM,CAAC,CAAC,EAAE,CAAC,EACf,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxC,GAAG,EAAE,CAAC,EACN,IAAI,CAAC,EAAE,uBAAuB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IActB;;;;;OAKG;IACG,GAAG,CAAC,CAAC,EAAE,CAAC,EACZ,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACzC,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAOpC;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,CAAC,CAAC,EAAE,CAAC,EAClB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,CAAC,EAAE,EACV,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAgEpC;;;;;;;;;;;;;;OAcG;IACH,OAAO,IAAI,IAAI;CAchB;AAED,iEAAiE;AACjE,OAAO,EACL,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,YAAY,GACb,MAAM,oBAAoB,CAAC"}
@@ -109,7 +109,9 @@ export class NimbusLoaderPool {
109
109
  // Include preamble in the cache-bucket key so changes to bundled helpers
110
110
  // invalidate warm slots. Empty preamble → '0' suffix (stable).
111
111
  this.preambleHash = this.preamble ? hashSource(this.preamble) : '0';
112
- this.doIdShort = ctx.id.toString().slice(0, 12);
112
+ this.doIdShort = opts?.cacheScope === 'global'
113
+ ? 'global'
114
+ : ctx.id.toString().slice(0, 12);
113
115
  // Materialise the wasm-modules table. Sanitise each name into a
114
116
  // valid JS identifier for the static import binding; key collisions
115
117
  // (e.g. 'esbuild.wasm' and 'esbuild_wasm' both sanitise to
@@ -19,8 +19,8 @@
19
19
  * tiny .o = ~20 MiB.
20
20
  *
21
21
  * Sysroot subset extraction happens supervisor-side via a small ustar
22
- * parser. The full 9.3 MiB sysroot.tar is parsed once per compile;
23
- * only the files matching the role's prefix-allowlist are forwarded.
22
+ * parser. The full sysroot.tar is parsed once when the clang runtime
23
+ * warms for a session; compile/link calls reuse the filtered subsets.
24
24
  *
25
25
  * Dispatch stays direct: no sleeps, no caller-side retries, and no
26
26
  * catch-and-continue around loader failures.
@@ -1 +1 @@
1
- {"version":3,"file":"clang-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/clang-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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,4DAA4D;AAC5D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,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,CAqShC;AAqZD,eAAO,MAAM,qBAAqB,imXA4UjC,CAAC"}
1
+ {"version":3,"file":"clang-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/clang-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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;AAGzD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,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,CAyShC;AAgcD,eAAO,MAAM,qBAAqB,imXA4UjC,CAAC"}
@@ -19,8 +19,8 @@
19
19
  * tiny .o = ~20 MiB.
20
20
  *
21
21
  * Sysroot subset extraction happens supervisor-side via a small ustar
22
- * parser. The full 9.3 MiB sysroot.tar is parsed once per compile;
23
- * only the files matching the role's prefix-allowlist are forwarded.
22
+ * parser. The full sysroot.tar is parsed once when the clang runtime
23
+ * warms for a session; compile/link calls reuse the filtered subsets.
24
24
  *
25
25
  * Dispatch stays direct: no sleeps, no caller-side retries, and no
26
26
  * catch-and-continue around loader failures.
@@ -37,6 +37,7 @@ export function makeClangRunnerFactory(deps) {
37
37
  const lldVfsPath = findFile('bin/wasm-ld');
38
38
  const memfsVfsPath = findFile('share/clang/memfs.wasm');
39
39
  const sysrootVfsPath = findFile('share/clang/sysroot.tar');
40
+ let runtimePromise = null;
40
41
  return async function clangBinHandler(ctx) {
41
42
  const argv = ctx.args || [];
42
43
  const cwd = ctx.cwd || '/home/user';
@@ -66,8 +67,6 @@ export function makeClangRunnerFactory(deps) {
66
67
  ctx.stderr.write(`${binName}: clang/wasm-ld missing from install\n`);
67
68
  return 127;
68
69
  }
69
- const memfsBytes = vfs.readFile(memfsVfsPath);
70
- const sysrootBytes = vfs.readFile(sysrootVfsPath);
71
70
  // Parse argv: find input .c + output path.
72
71
  const parsed = parseUserArgv(argv);
73
72
  if (parsed.error) {
@@ -80,8 +79,6 @@ export function makeClangRunnerFactory(deps) {
80
79
  ctx.stderr.write(`${binName}: direct wasm-ld invocation not yet wired (v1.2)\n`);
81
80
  return 2;
82
81
  }
83
- // Parse sysroot.tar ONCE on supervisor side.
84
- const sysroot = parseUstar(sysrootBytes);
85
82
  // Validate all user-supplied source inputs exist in the user's
86
83
  // session VFS. Collect their bytes for memfs population.
87
84
  const userSourceFiles = {};
@@ -110,6 +107,24 @@ export function makeClangRunnerFactory(deps) {
110
107
  ctx.stderr.write(`${binName}: no compilable / linkable inputs\n`);
111
108
  return 1;
112
109
  }
110
+ let runtime;
111
+ try {
112
+ if (!runtimePromise) {
113
+ runtimePromise = createClangFacetRuntime(facetMgr, {
114
+ clangVfsPath,
115
+ lldVfsPath,
116
+ memfsVfsPath,
117
+ sysrootVfsPath,
118
+ vfs,
119
+ });
120
+ }
121
+ runtime = await runtimePromise;
122
+ }
123
+ catch (e) {
124
+ runtimePromise = null;
125
+ ctx.stderr.write(`${binName}: clang runtime warm-up failed: ${e?.message || e}\n`);
126
+ return 1;
127
+ }
113
128
  // Walk the user's cwd to gather headers (.h/.hpp/.hxx/.inc/...)
114
129
  // and any sibling headers users typically expect to be visible
115
130
  // to #include "..." resolution. Real clang/gcc auto-search the
@@ -122,10 +137,8 @@ export function makeClangRunnerFactory(deps) {
122
137
  // are vastly under the cap.
123
138
  const userIncludeBundle = collectIncludeBundle(vfs, cwd.replace(/^\/+/, ''));
124
139
  // ── COMPILE PHASE ────────────────────────────────────────────
125
- // Ship: clang.wasm + memfs.wasm + C-include subset of sysroot
126
- // + user's source files + user's header bundle.
127
- const compileSysroot = filterSysrootForCompile(sysroot);
128
- const clangBytes = vfs.readFile(clangVfsPath);
140
+ // Reuse the warm clang/memfs pool and ship only the C-include
141
+ // subset plus user source/header files for this invocation.
129
142
  // Build -I flag list. We pass each user -I path verbatim AND add
130
143
  // an implicit '.' (cwd) for quote-form lookup. wasm-clang's -cc1
131
144
  // mode does NOT add cwd to the quote search list by default
@@ -170,12 +183,9 @@ export function makeClangRunnerFactory(deps) {
170
183
  // so sibling sources stay out of memfs (smaller payload, no
171
184
  // surface for unintended cross-TU textual inclusion via -I.).
172
185
  const oneSourceFile = { [src]: userSourceFiles[src] };
173
- const compileResult = await dispatchClangFacet(facetMgr, {
174
- primaryName: 'clang',
175
- primaryBytes: clangBytes,
176
- memfsBytes,
186
+ const compileResult = await dispatchClangFacet(runtime.compile, {
177
187
  sysrootFiles: {
178
- ...compileSysroot,
188
+ ...runtime.compile.sysrootFiles,
179
189
  ...oneSourceFile,
180
190
  // User's headers from cwd tree (so quote-form #include
181
191
  // resolves; this is the primary clang-include-fix payload).
@@ -235,9 +245,8 @@ export function makeClangRunnerFactory(deps) {
235
245
  preBuiltBytesMap[lp] = userSourceFiles[lp];
236
246
  }
237
247
  // ── LINK PHASE ───────────────────────────────────────────────
238
- // Ship: lld.wasm + memfs.wasm + lib subset of sysroot + .o's.
239
- const linkSysroot = filterSysrootForLink(sysroot);
240
- const lldBytes = vfs.readFile(lldVfsPath);
248
+ // Reuse the warm wasm-ld/memfs pool and ship only the link
249
+ // sysroot subset plus object/archive inputs for this invocation.
241
250
  const stackSize = 1024 * 1024;
242
251
  // User-supplied -L paths and -l libraries flow through. The user
243
252
  // -L paths point at user-VFS dirs; we currently don't ship user
@@ -270,11 +279,8 @@ export function makeClangRunnerFactory(deps) {
270
279
  '-lclang_rt.builtins-wasm32',
271
280
  '-o', parsed.outputPath,
272
281
  ];
273
- const linkResult = await dispatchClangFacet(facetMgr, {
274
- primaryName: 'wasm-ld',
275
- primaryBytes: lldBytes,
276
- memfsBytes,
277
- sysrootFiles: { ...linkSysroot, ...objBytesMap, ...preBuiltBytesMap },
282
+ const linkResult = await dispatchClangFacet(runtime.link, {
283
+ sysrootFiles: { ...runtime.link.sysrootFiles, ...objBytesMap, ...preBuiltBytesMap },
278
284
  argv: linkArgv,
279
285
  outputPaths: [parsed.outputPath],
280
286
  });
@@ -600,23 +606,45 @@ function filterSysrootForLink(all) {
600
606
  }
601
607
  return out;
602
608
  }
603
- async function dispatchClangFacet(facetMgr, args) {
609
+ async function createClangFacetRuntime(facetMgr, args) {
610
+ if (!args.clangVfsPath || !args.lldVfsPath || !args.memfsVfsPath || !args.sysrootVfsPath) {
611
+ throw new Error('installed clang manifest is missing required files');
612
+ }
604
613
  const toAB = (u8) => u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength);
614
+ const memfsBytes = args.vfs.readFile(args.memfsVfsPath);
615
+ const clangBytes = args.vfs.readFile(args.clangVfsPath);
616
+ const lldBytes = args.vfs.readFile(args.lldVfsPath);
617
+ const sysroot = parseUstar(args.vfs.readFile(args.sysrootVfsPath));
618
+ const { NimbusLoaderPool } = await import('../loaders/loader-pool.js');
619
+ const env = facetMgr.env;
620
+ const ctx = facetMgr.ctx;
621
+ const makeTarget = (primaryName, primaryBytes, sysrootFiles) => ({
622
+ primaryName,
623
+ sysrootFiles,
624
+ pool: new NimbusLoaderPool(env, ctx, {
625
+ tag: `clang-runner-${primaryName}`,
626
+ concurrency: 1,
627
+ omitSupervisor: true,
628
+ cacheScope: 'global',
629
+ preamble: CLANG_RUNNER_PREAMBLE,
630
+ wasmModules: {
631
+ 'memfs.wasm': toAB(memfsBytes),
632
+ 'primary.wasm': toAB(primaryBytes),
633
+ },
634
+ }),
635
+ });
636
+ return {
637
+ compile: makeTarget('clang', clangBytes, filterSysrootForCompile(sysroot)),
638
+ link: makeTarget('wasm-ld', lldBytes, filterSysrootForLink(sysroot)),
639
+ };
640
+ }
641
+ async function dispatchClangFacet(target, args) {
605
642
  // Encode sysroot files as base64 for context ferrying. We do this on
606
643
  // the supervisor to keep the facet preamble small and CPU-light.
607
644
  const filesB64 = {};
608
645
  for (const [path, bytes] of Object.entries(args.sysrootFiles)) {
609
646
  filesB64[path] = uint8ToBase64(bytes);
610
647
  }
611
- const { NimbusLoaderPool } = await import('../loaders/loader-pool.js');
612
- const env = facetMgr.env;
613
- const ctx = facetMgr.ctx;
614
- const pool = new NimbusLoaderPool(env, ctx, {
615
- tag: `clang-runner-${args.primaryName}`,
616
- concurrency: 1,
617
- omitSupervisor: true,
618
- preamble: CLANG_RUNNER_PREAMBLE,
619
- });
620
648
  const facetFn = async function clangFacetCall(inArgs) {
621
649
  const wasmTable = globalThis.__NIMBUS_WASM || {};
622
650
  const memfsMod = wasmTable['memfs.wasm'];
@@ -646,16 +674,12 @@ async function dispatchClangFacet(facetMgr, args) {
646
674
  });
647
675
  };
648
676
  try {
649
- const result = await pool.submit(facetFn, {
650
- primaryName: args.primaryName,
677
+ const result = await target.pool.submit(facetFn, {
678
+ primaryName: target.primaryName,
651
679
  argv: args.argv,
652
680
  filesB64,
653
681
  outputPaths: args.outputPaths,
654
682
  }, {
655
- wasmModules: {
656
- 'memfs.wasm': toAB(args.memfsBytes),
657
- 'primary.wasm': toAB(args.primaryBytes),
658
- },
659
683
  timeoutMs: 300_000,
660
684
  });
661
685
  // Decode outputFiles from base64 → Uint8Array.
@@ -27,12 +27,31 @@
27
27
  */
28
28
  import { type RuntimeCatalogEnv, type RuntimeManifest } from './runtime-catalog.js';
29
29
  import type { SqliteVFS } from '../vfs/sqlite-vfs.js';
30
+ /** Minimal shell ctx shape we depend on (matches existing handlers). */
31
+ export interface ShellCtx {
32
+ args: string[];
33
+ env: Record<string, string>;
34
+ cwd: string;
35
+ stdout: {
36
+ write(s: string): void;
37
+ };
38
+ stderr: {
39
+ write(s: string): void;
40
+ };
41
+ }
30
42
  /** Minimal shell-registry shape we depend on. */
31
43
  export interface MinShellRegistry {
32
44
  register(name: string, handler: (ctx: any) => Promise<number>): void;
33
45
  unregister?(name: string): void;
34
46
  resolve?(name: string): any;
35
47
  }
48
+ export interface RuntimeWarmTarget {
49
+ name: string;
50
+ version: string;
51
+ root: string;
52
+ manifest: RuntimeManifest;
53
+ }
54
+ export type RuntimeWarmHook = (target: RuntimeWarmTarget, ctx: ShellCtx) => Promise<void>;
36
55
  /** Runner-factory contract. Each registered runner produces a shell-
37
56
  * command handler given the manifest + the installed root dir. The
38
57
  * package manager invokes the factory at install-time + at boot-time
@@ -54,6 +73,17 @@ export interface RuntimeSummary {
54
73
  sizeBytes: number;
55
74
  license: string;
56
75
  }
76
+ export interface RuntimeInstallTarget {
77
+ runtimeName: string;
78
+ versionOverride: string | null;
79
+ requestedName: string;
80
+ }
81
+ export interface RuntimeCommandHint {
82
+ command: string;
83
+ runtimeName: string;
84
+ installSpec: string;
85
+ }
86
+ export declare function createRuntimeCommandHintResolver(env: RuntimeCatalogEnv): (command: string) => Promise<RuntimeCommandHint | null>;
57
87
  /** Compute the per-user install root for (name, version). Uses
58
88
  * `process.env.HOME` if present; falls back to `/home/user`. */
59
89
  export declare function installRoot(homeDir: string, name: string, version: string): string;
@@ -109,5 +139,6 @@ export declare function makeNimbusVerbHandler(deps: {
109
139
  /** Returns `process.env.HOME` for the session. Computed by the
110
140
  * caller (init.ts) from the shell env. */
111
141
  getHome(): string;
142
+ warmRuntime?: RuntimeWarmHook;
112
143
  }): (ctx: any) => Promise<number>;
113
144
  //# sourceMappingURL=package-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/runtime/package-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAA0C,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5H,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAWtD,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACrE,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC;CAC7B;AAED;;;mBAGmB;AACnB,MAAM,MAAM,aAAa,GAAG,CAC1B,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,SAAS,KACxB,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAKnC,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAE/E;AAED,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;iEACiE;AACjE,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKlF;AAED;iCACiC;AACjC,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,MAAM,GACd,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAA;CAAE,CAAC,CAyBpD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,MAAM,GACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAYnC;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,MAAM,GACd,cAAc,EAAE,CASlB;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1E,CAAC,CAAC,CAeF;AAED,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACrD,GAAG,EAAE,iBAAiB,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,IAAI,MAAM,CAAC;CACnB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkB/E;AAED,wBAAsB,0BAA0B,CAAC,IAAI,EAAE;IACrD,GAAG,EAAE,iBAAiB,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,IAAI,MAAM,CAAC;CACnB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAMpF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,GAAG,EAAE,iBAAiB,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;+CAC2C;IAC3C,OAAO,IAAI,MAAM,CAAC;CACnB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAoBhC"}
1
+ {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/runtime/package-manager.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,98 @@ export function registerRunnerFactory(key, factory) {
34
34
  export function getRegisteredRunners() {
35
35
  return Object.keys(runnerFactories);
36
36
  }
37
+ const RUNTIME_NAME_ALIASES = {
38
+ python3: 'python',
39
+ ruby3: 'ruby',
40
+ 'wasm-ld': 'clang',
41
+ };
42
+ function splitRuntimeSpec(spec) {
43
+ const atIdx = spec.indexOf('@');
44
+ return {
45
+ name: atIdx >= 0 ? spec.slice(0, atIdx) : spec,
46
+ versionOverride: atIdx >= 0 ? spec.slice(atIdx + 1) : null,
47
+ };
48
+ }
49
+ async function resolveRuntimeInstallTarget(env, catalog, spec) {
50
+ const parsed = splitRuntimeSpec(spec);
51
+ const aliased = RUNTIME_NAME_ALIASES[parsed.name] ?? parsed.name;
52
+ if (catalog.runtimes[aliased]) {
53
+ return {
54
+ runtimeName: aliased,
55
+ versionOverride: parsed.versionOverride,
56
+ requestedName: parsed.name,
57
+ };
58
+ }
59
+ for (const [runtimeName, entry] of Object.entries(catalog.runtimes)) {
60
+ const version = entry.default;
61
+ const versionEntry = entry.versions[version];
62
+ if (!versionEntry)
63
+ continue;
64
+ try {
65
+ const manifest = await fetchManifest(env, versionEntry.manifest);
66
+ if (manifest.entrypoints.some((ep) => ep.binName === parsed.name)) {
67
+ return {
68
+ runtimeName,
69
+ versionOverride: parsed.versionOverride,
70
+ requestedName: parsed.name,
71
+ };
72
+ }
73
+ }
74
+ catch {
75
+ // A bad manifest should not prevent canonical catalog names from
76
+ // resolving; it only suppresses bin-name aliasing for that runtime.
77
+ }
78
+ }
79
+ return null;
80
+ }
81
+ export function createRuntimeCommandHintResolver(env) {
82
+ let hintsPromise = null;
83
+ const loadHints = async () => {
84
+ const catalog = await fetchCatalog(env);
85
+ const hints = new Map();
86
+ const add = (command, runtimeName) => {
87
+ if (!command || command.includes('/'))
88
+ return;
89
+ if (!hints.has(command)) {
90
+ hints.set(command, { command, runtimeName, installSpec: command });
91
+ }
92
+ };
93
+ for (const runtimeName of Object.keys(catalog.runtimes)) {
94
+ add(runtimeName, runtimeName);
95
+ }
96
+ for (const [alias, runtimeName] of Object.entries(RUNTIME_NAME_ALIASES)) {
97
+ if (catalog.runtimes[runtimeName])
98
+ add(alias, runtimeName);
99
+ }
100
+ for (const [runtimeName, entry] of Object.entries(catalog.runtimes)) {
101
+ const versionEntry = entry.versions[entry.default];
102
+ if (!versionEntry)
103
+ continue;
104
+ try {
105
+ const manifest = await fetchManifest(env, versionEntry.manifest);
106
+ for (const ep of manifest.entrypoints)
107
+ add(ep.binName, runtimeName);
108
+ }
109
+ catch {
110
+ // Hints are best-effort UX. Install itself still surfaces the
111
+ // manifest/catalog error through the normal package-manager path.
112
+ }
113
+ }
114
+ return hints;
115
+ };
116
+ return async (command) => {
117
+ if (!command || command.includes('/'))
118
+ return null;
119
+ if (!hintsPromise) {
120
+ hintsPromise = loadHints().catch((e) => {
121
+ hintsPromise = null;
122
+ throw e;
123
+ });
124
+ }
125
+ const hints = await hintsPromise;
126
+ return hints.get(command) ?? null;
127
+ };
128
+ }
37
129
  /** Compute the per-user install root for (name, version). Uses
38
130
  * `process.env.HOME` if present; falls back to `/home/user`. */
39
131
  export function installRoot(homeDir, name, version) {
@@ -151,13 +243,13 @@ export async function ensureRuntimesProgrammatic(deps, specs, opts = {}) {
151
243
  * `nimbus uninstall …`. Registered under the name `nimbus`.
152
244
  */
153
245
  export function makeNimbusVerbHandler(deps) {
154
- const { env, vfs, registry, getHome } = deps;
246
+ const { env, vfs, registry, getHome, warmRuntime } = deps;
155
247
  return async function nimbus(ctx) {
156
248
  const argv = ctx.args || [];
157
249
  const verb = argv[0];
158
250
  const rest = argv.slice(1);
159
251
  if (verb === 'install') {
160
- return runInstall(rest, ctx, { env, vfs, registry, getHome });
252
+ return runInstall(rest, ctx, { env, vfs, registry, getHome, warmRuntime });
161
253
  }
162
254
  if (verb === 'uninstall') {
163
255
  return runUninstall(rest, ctx, { vfs, registry, getHome });
@@ -184,11 +276,7 @@ async function runInstall(args, ctx, deps) {
184
276
  ctx.stderr.write('usage: nimbus install <name>[@<version>]\n');
185
277
  return 2;
186
278
  }
187
- // Parse `<name>` or `<name>@<version>`.
188
279
  const spec = positional[0];
189
- const atIdx = spec.indexOf('@');
190
- const name = atIdx >= 0 ? spec.slice(0, atIdx) : spec;
191
- const versionOverride = atIdx >= 0 ? spec.slice(atIdx + 1) : null;
192
280
  // Fetch catalog.
193
281
  let catalog;
194
282
  try {
@@ -198,13 +286,16 @@ async function runInstall(args, ctx, deps) {
198
286
  ctx.stderr.write(`nimbus install: ${e?.message || e}\n`);
199
287
  return 1;
200
288
  }
201
- const runtimeEntry = catalog.runtimes[name];
202
- if (!runtimeEntry) {
203
- ctx.stderr.write(`nimbus install: '${name}' is not in catalog\n`);
289
+ const target = await resolveRuntimeInstallTarget(deps.env, catalog, spec);
290
+ if (!target) {
291
+ const parsed = splitRuntimeSpec(spec);
292
+ ctx.stderr.write(`nimbus install: '${parsed.name}' is not in catalog\n`);
204
293
  ctx.stderr.write(`nimbus install: try 'nimbus install --available' to see installable runtimes\n`);
205
294
  return 1;
206
295
  }
207
- const version = versionOverride || runtimeEntry.default;
296
+ const name = target.runtimeName;
297
+ const runtimeEntry = catalog.runtimes[name];
298
+ const version = target.versionOverride || runtimeEntry.default;
208
299
  const versionEntry = runtimeEntry.versions[version];
209
300
  if (!versionEntry) {
210
301
  ctx.stderr.write(`nimbus install: '${name}@${version}' not in catalog\n`);
@@ -219,6 +310,21 @@ async function runInstall(args, ctx, deps) {
219
310
  ctx.stdout.write(`[${name}] already installed at ${root} (use --reinstall to refetch)\n`);
220
311
  // Still re-register bins in case the registry lost them — idempotent.
221
312
  rehydrateInstalledRuntimes(deps.vfs, deps.registry, home);
313
+ let manifest = null;
314
+ try {
315
+ manifest = JSON.parse(deps.vfs.readFileString(`${root}/manifest.json`));
316
+ }
317
+ catch {
318
+ manifest = null;
319
+ }
320
+ if (manifest) {
321
+ await warmRuntimeIfConfigured(ctx, deps, {
322
+ name,
323
+ version,
324
+ root,
325
+ manifest,
326
+ });
327
+ }
222
328
  return 0;
223
329
  }
224
330
  // Fetch manifest from R2.
@@ -310,8 +416,24 @@ async function runInstall(args, ctx, deps) {
310
416
  deps.registry.register(ep.binName, handler);
311
417
  }
312
418
  ctx.stdout.write(`[${name}] installed at ${root} (${(totalBytes / 1024 / 1024).toFixed(1)} MiB)\n`);
419
+ await warmRuntimeIfConfigured(ctx, deps, {
420
+ name,
421
+ version,
422
+ root,
423
+ manifest,
424
+ });
313
425
  return 0;
314
426
  }
427
+ async function warmRuntimeIfConfigured(ctx, deps, target) {
428
+ if (!deps.warmRuntime)
429
+ return;
430
+ try {
431
+ await deps.warmRuntime(target, ctx);
432
+ }
433
+ catch (e) {
434
+ ctx.stderr.write(`[${target.name}] warning: runtime warm-up failed: ${e?.message || e}\n`);
435
+ }
436
+ }
315
437
  // ── --list ───────────────────────────────────────────────────────────
316
438
  async function runList(ctx, deps) {
317
439
  const home = deps.getHome();
@@ -62,4 +62,5 @@ export interface PythonReplDeps {
62
62
  * runs `python` with no args.
63
63
  */
64
64
  export declare function runPythonRepl(deps: PythonReplDeps): Promise<number>;
65
+ export declare function warmPythonRepl(deps: Pick<PythonReplDeps, 'facetMgr' | 'vfs' | 'installRoot'>): Promise<void>;
65
66
  //# sourceMappingURL=python-repl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"python-repl.d.ts","sourceRoot":"","sources":["../../src/runtime/python-repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAKlE,yDAAyD;AACzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAwhBD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzE"}
1
+ {"version":3,"file":"python-repl.d.ts","sourceRoot":"","sources":["../../src/runtime/python-repl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAKlE,yDAAyD;AACzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAuhBD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzE;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,KAAK,GAAG,aAAa,CAAC,GAC7D,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -153,14 +153,13 @@ class PythonReplAdapter {
153
153
  concurrency: 1,
154
154
  omitSupervisor: true,
155
155
  preamble,
156
+ wasmModules: {
157
+ 'pyodide.asm.wasm': toAB(wasmBytes),
158
+ },
156
159
  });
157
- // Stash the wasm bytes for first submit's wasmModules.
158
- this.__wasmBytesAB = toAB(wasmBytes);
159
160
  }
160
161
  async submitFacetFn(args) {
161
- const wasmModules = { 'pyodide.asm.wasm': this.__wasmBytesAB };
162
162
  return await this.pool.submit(replStepFacetFn, args, {
163
- wasmModules,
164
163
  timeoutMs: 60_000,
165
164
  });
166
165
  }
@@ -560,3 +559,8 @@ export async function runPythonRepl(deps) {
560
559
  const session = new ReplSession(adapter, deps.terminal, deps.shell);
561
560
  return await session.run();
562
561
  }
562
+ export async function warmPythonRepl(deps) {
563
+ const adapter = new PythonReplAdapter(deps);
564
+ await adapter.push('');
565
+ await adapter.close();
566
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"python-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/python-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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"}
1
+ {"version":3,"file":"python-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/python-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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;AAGzD;;;;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,CAuIhC;AA6ND;;;;;;GAMG;AAKH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAyFhF"}