@nimbus-sh/core 0.7.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.
@@ -21,6 +21,7 @@ import { normalizeVfsPath, stripLeadingSlashes } from '../vfs/path.js';
21
21
  import { errorText } from '../_shared/error-text.js';
22
22
  import { tokenizer, tokTypes } from 'acorn';
23
23
  import { literalStringValue, nodeList, nodeName, nodeProp, parseJavaScriptModule, } from './javascript-ast.js';
24
+ import { scanJsSource } from './comment-strip.js';
24
25
  /**
25
26
  * Bundler version tag. BUMP THIS whenever bundling semantics change —
26
27
  * the esbuild plugin's resolver logic, the shared-externals rules, the
@@ -195,203 +196,14 @@ function hasEsmExports(src) {
195
196
  return /^[ \t]*export\b/m.test(stripped);
196
197
  }
197
198
  /**
198
- * Strip `//` and `/* * /` comments and string / template literals from
199
- * source, replacing each with a single space. The result is byte-aligned
200
- * with the input on a per-line basis (newlines are preserved), so error
201
- * line numbers from downstream parsers still align with the original.
202
- * Shared by the import/export classifiers. Pure function no caching needed
203
- * for the small entry points that reach the true-TLA fallback.
199
+ * Strip `//` and `/* *\/` comments and string / template literals from
200
+ * source for the import/export classifiers one scanner shared with
201
+ * prefetch's import detection in `comment-strip.ts`. The result is
202
+ * byte-aligned with the input per line (comment and literal newlines are
203
+ * preserved), so error line numbers still match the original.
204
204
  */
205
205
  function stripCommentsAndStrings(src) {
206
- let stripped = '';
207
- let i = 0;
208
- const N = src.length;
209
- // Track the last non-whitespace non-comment output character so we
210
- // can disambiguate `/` as division (after identifier/literal/`)`/`]`)
211
- // vs regex-literal opener (after operator / punctuator / keyword /
212
- // start-of-file). Pre-fix the stripper had no regex awareness, so
213
- // patterns like `var X = /^(?:'…)/` contained an unmatched `'` that
214
- // bit it as a string opener that didn't close until many lines
215
- // later — corrupting the import/export classifiers. Real-world bite:
216
- // sv-utils@0.0.3 index.mjs has dozens of these regex literals.
217
- let lastNonWsChar = '';
218
- const recordOut = (ch) => {
219
- if (ch !== ' ' && ch !== '\t' && ch !== '\n' && ch !== '\r') {
220
- lastNonWsChar = ch;
221
- }
222
- };
223
- // Identifier-suffix detection on lastNonWsChar: any of these means
224
- // `/` is division. Anything else means `/` opens a regex.
225
- // Includes ascii word chars + `)` `]` to cover `foo()/x` `a[i]/y`.
226
- const DIVISION_AFTER = /[A-Za-z0-9_$\)\]]/;
227
- while (i < N) {
228
- const c = src[i];
229
- if (c === '/' && src[i + 1] === '/') {
230
- while (i < N && src[i] !== '\n')
231
- i++;
232
- stripped += ' ';
233
- continue;
234
- }
235
- if (c === '/' && src[i + 1] === '*') {
236
- i += 2;
237
- while (i < N && !(src[i] === '*' && src[i + 1] === '/')) {
238
- // Preserve newlines so line numbers stay aligned.
239
- if (src[i] === '\n')
240
- stripped += '\n';
241
- i++;
242
- }
243
- i += 2;
244
- stripped += ' ';
245
- continue;
246
- }
247
- // Regex literal: `/` not followed by `/` or `*` (already handled
248
- // above), AND preceded by something that makes regex valid here.
249
- // The classifier looks at lastNonWsChar — for `(`, `,`, `=`, `;`,
250
- // `{`, `[`, `:`, `!`, `&`, `|`, `?`, operators, or start-of-file,
251
- // a slash is a regex opener.
252
- if (c === '/' && !DIVISION_AFTER.test(lastNonWsChar)) {
253
- stripped += ' ';
254
- i++;
255
- while (i < N) {
256
- const rc = src[i];
257
- if (rc === '\\') {
258
- i += 2;
259
- continue;
260
- }
261
- // Regex character class [...]: `/` inside it is content.
262
- if (rc === '[') {
263
- i++;
264
- while (i < N && src[i] !== ']') {
265
- if (src[i] === '\\') {
266
- i += 2;
267
- continue;
268
- }
269
- if (src[i] === '\n') {
270
- stripped += '\n';
271
- }
272
- i++;
273
- }
274
- if (i < N)
275
- i++; // consume ']'
276
- continue;
277
- }
278
- if (rc === '/') {
279
- i++;
280
- break;
281
- }
282
- if (rc === '\n') {
283
- // Regex literals can't span newlines. If we hit one without
284
- // finding the closing `/`, this was probably NOT a regex —
285
- // bail out gracefully (rare in practice; better than getting
286
- // stuck in a wrong state).
287
- break;
288
- }
289
- i++;
290
- }
291
- // Skip regex flags (g, i, m, s, u, y, d).
292
- while (i < N && /[gimsuyd]/.test(src[i]))
293
- i++;
294
- recordOut('/');
295
- continue;
296
- }
297
- if (c === '"' || c === "'" || c === '`') {
298
- const q = c;
299
- stripped += ' ';
300
- i++;
301
- while (i < N) {
302
- const cc = src[i];
303
- if (cc === '\\') {
304
- i += 2;
305
- continue;
306
- }
307
- if (cc === q) {
308
- i++;
309
- break;
310
- }
311
- // Template interpolation: ${...} — preserve the inner
312
- // expression as raw code so the caller's depth-tracker can
313
- // see `await` etc. inside it. Strip the wrapping `${`/`}`
314
- // (those don't affect brace-depth from the caller's POV).
315
- //
316
- // CRITICAL: inside the interpolation expression, we must
317
- // recognise NESTED strings (`'}'`, `"}"`, `` `${...}` ``) so
318
- // their internal `}` characters don't decrement the depth
319
- // counter — otherwise we exit the interpolation early and
320
- // start consuming code as string content, eventually parsing
321
- // the rest of the file as one massive unclosed string. This
322
- // bit sv-utils/dist/index.mjs: multi-line backticks with
323
- // `${url.replace('}', '_')}`-style interpolations corrupted
324
- // line classification downstream. Recursive-by-loop here.
325
- if (q === '`' && cc === '$' && src[i + 1] === '{') {
326
- stripped += '${';
327
- i += 2;
328
- let depth = 1;
329
- while (i < N && depth > 0) {
330
- const ic = src[i];
331
- // Nested string inside interpolation: skip its content.
332
- if (ic === '"' || ic === "'" || ic === '`') {
333
- const iq = ic;
334
- stripped += ' ';
335
- i++;
336
- while (i < N) {
337
- const icc = src[i];
338
- if (icc === '\\') {
339
- i += 2;
340
- continue;
341
- }
342
- if (icc === iq) {
343
- i++;
344
- break;
345
- }
346
- // Nested template inside interpolation can also have its
347
- // own ${...} — recurse once more (the practical depth
348
- // observed in real code never exceeds 2; deeper nesting
349
- // falls back to brace counting which is a best-effort).
350
- if (iq === '`' && icc === '$' && src[i + 1] === '{') {
351
- stripped += '${';
352
- i += 2;
353
- let d2 = 1;
354
- while (i < N && d2 > 0) {
355
- const i2 = src[i];
356
- if (i2 === '{')
357
- d2++;
358
- else if (i2 === '}')
359
- d2--;
360
- if (d2 > 0)
361
- stripped += i2;
362
- i++;
363
- }
364
- stripped += '}';
365
- continue;
366
- }
367
- if (icc === '\n')
368
- stripped += '\n';
369
- i++;
370
- }
371
- continue;
372
- }
373
- if (ic === '{')
374
- depth++;
375
- else if (ic === '}')
376
- depth--;
377
- if (depth > 0)
378
- stripped += ic;
379
- i++;
380
- }
381
- stripped += '}';
382
- continue;
383
- }
384
- if (cc === '\n')
385
- stripped += '\n';
386
- i++;
387
- }
388
- continue;
389
- }
390
- stripped += c;
391
- recordOut(c);
392
- i++;
393
- }
394
- return stripped;
206
+ return scanJsSource(src, 'blank');
395
207
  }
396
208
  /**
397
209
  * Convert ESM `import` statements at the top of `src` to CJS
@@ -1196,6 +1008,9 @@ async function transformWithEsbuild(esbuildApi, source, options) {
1196
1008
  /** Source needed by the slim Worker Loader transform isolate. */
1197
1009
  export function generateEsbuildTransformRuntimeSource() {
1198
1010
  return [
1011
+ // scanJsSource is self-contained — its constants live in the body —
1012
+ // so this serialized copy carries the whole scanner.
1013
+ scanJsSource.toString(),
1199
1014
  stripCommentsAndStrings.toString(),
1200
1015
  hasEsmImports.toString(),
1201
1016
  hasEsmExports.toString(),
@@ -88,6 +88,7 @@ export interface RubyFacetResult {
88
88
  * no degraded version — it gets none, and says so.
89
89
  */
90
90
  export type RubyResidentStart = (spawn: {
91
+ argv: string[];
91
92
  /** VFS path of the interpreter. By path, not by value: it is 34.3 MiB. */
92
93
  wasmVfsPath: string;
93
94
  startArgs: RubyFacetCallArgs;
@@ -1 +1 @@
1
- {"version":3,"file":"ruby-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/ruby-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qCAAqC,CAAC;AAGnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAiBrF,KAAK,iBAAiB,GAAG,CACvB,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,SAAS,KACxB,OAAO,CAAC;AAEb;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;QAC/C,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;KAC1F,CAAC;IACF,8EAA8E;IAC9E,aAAa,CAAC,EAAE,iBAAiB,CAAC;CACnC,GAAG,iBAAiB,CA6LpB;AA2TD,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE;IACtC,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAS/B;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAS7E;AAgGD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA2B1C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,q4kCAgrBrC,CAAC"}
1
+ {"version":3,"file":"ruby-runner.d.ts","sourceRoot":"","sources":["../../src/runtime/ruby-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,qCAAqC,CAAC;AAGnF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAA8B,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAiBrF,KAAK,iBAAiB,GAAG,CACvB,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GAAG,SAAS,KACxB,OAAO,CAAC;AAEb;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;QAC/C,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;KAC1F,CAAC;IACF,8EAA8E;IAC9E,aAAa,CAAC,EAAE,iBAAiB,CAAC;CACnC,GAAG,iBAAiB,CA8LpB;AA2TD,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,cAAc,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE;IACtC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAS/B;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAS7E;AAgGD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA2B1C;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,q4kCAgrBrC,CAAC"}
@@ -220,6 +220,7 @@ export function makeRubyRunnerFactory(deps) {
220
220
  startArgs: toRubyCallArgs(facetArgs),
221
221
  cwd,
222
222
  command: formatRubyCommand(binName, argv),
223
+ argv: [binName, ...argv],
223
224
  });
224
225
  }
225
226
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../../../../src/substrate/lifo/commands/system/npm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAapD,eAAO,MAAM,WAAW,WAAW,CAAC;AAIpC,UAAU,WAAW;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,MAAM,cAAc,GAAG,CAC5B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,cAAc,KACf,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC9B,OAAO,CACN,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC;QACV,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;CACpC;AAuLD,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMtE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAaxH;AAomBD,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,CAAC,EAAE,cAAc,EAC7B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,GACnB,OAAO,CA+CT;AAiCD,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,CAAC,EAAE,cAAc,GAC3B,OAAO,CAyGT;AAED,wBAAsB,gBAAgB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,eAAe,EACzB,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
1
+ {"version":3,"file":"npm.d.ts","sourceRoot":"","sources":["../../../../../src/substrate/lifo/commands/system/npm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAuB,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAapD,eAAO,MAAM,WAAW,WAAW,CAAC;AAIpC,UAAU,WAAW;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,MAAM,cAAc,GAAG,CAC5B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,cAAc,KACf,OAAO,CAAC,MAAM,CAAC,CAAC;AAErB,kFAAkF;AAClF,MAAM,WAAW,cAAc;IAC9B,OAAO,CACN,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC;QACV,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;CACpC;AAuLD,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMtE;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAaxH;AAimBD,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,CAAC,EAAE,cAAc,EAC7B,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,cAAc,GACnB,OAAO,CA+CT;AAiCD,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,eAAe,EACzB,YAAY,CAAC,EAAE,cAAc,GAC3B,OAAO,CAyGT;AAED,wBAAsB,gBAAgB,CACrC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,eAAe,EACzB,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
@@ -186,10 +186,9 @@ async function installSinglePackage(name, version, targetBase, vfs, npmRegistry,
186
186
  }
187
187
  stdout.write(` ${name}${version ? '@' + version : ''}...\n`);
188
188
  const info = await fetchPackageInfo(npmRegistry, name, version, signal);
189
- const written = await fetchAndStreamPackage(info.dist.tarball, targetDir, vfs, signal);
190
- if (written.files === 0 || !vfs.exists(join(targetDir, 'package.json'))) {
191
- throw new Error(`${name}: extraction wrote ${written.files} files and left no package.json in ${targetDir}`);
192
- }
189
+ // writeTarballStream throws when the archive carried no manifest and writes
190
+ // package.json last, so a return here is a complete package on disk.
191
+ await fetchAndStreamPackage(info.dist.tarball, targetDir, vfs, signal);
193
192
  let installed = 1;
194
193
  // Global install: link binaries
195
194
  if (isGlobal) {
@@ -41,8 +41,14 @@ export interface NimbusWorkspaceOptions {
41
41
  * Every atomic write in the filesystem rests on this being a real
42
42
  * transaction. An implementation that merely calls the callback converts
43
43
  * each one into a torn write that reports success.
44
+ *
45
+ * `NimbusWorkspace.create` is a first-write-wins composition root beside
46
+ * `worker/index.ts` and `loom/actor.ts`: when `ctxExports` is absent the
47
+ * host's ctx `exports` bag is adopted as the isolate's.
44
48
  */
45
- readonly transactions?: TransactionHost;
49
+ readonly transactions?: TransactionHost & {
50
+ readonly exports?: CtxExports;
51
+ };
46
52
  /**
47
53
  * The filesystem already open over `sql`, for a host that has one.
48
54
  *
@@ -1 +1 @@
1
- {"version":3,"file":"nimbus-workspace.d.ts","sourceRoot":"","sources":["../../src/workspace/nimbus-workspace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nimbus-workspace.d.ts","sourceRoot":"","sources":["../../src/workspace/nimbus-workspace.ts"],"names":[],"mappings":"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"}
@@ -86,8 +86,7 @@ export class NimbusWorkspace {
86
86
  static async create(options) {
87
87
  if (options.fabric)
88
88
  composeFabric(options.fabric);
89
- const exports = options.ctxExports
90
- ?? options.transactions?.exports;
89
+ const exports = options.ctxExports ?? options.transactions?.exports;
91
90
  if (exports)
92
91
  adoptCtxExports(exports);
93
92
  const vfs = options.vfs ?? openFilesystem(options);
@@ -1,23 +1,107 @@
1
1
  import type { SqliteVFS } from '../vfs/sqlite-vfs.js';
2
+ import { type VfsCred } from '../runtime/os-contracts.js';
3
+ import { SqliteRuntimeFsBridge } from '../runtime/sqlite-runtime-fs-bridge.js';
2
4
  import type { SessionProcessSupervisor } from '../runtime/session-process-supervisor.js';
3
5
  /** Identity comes from the supervisor binding, never from facet arguments. */
4
6
  export interface SupervisorOpEnvelope {
5
- readonly op: string;
7
+ readonly op: SupervisorOpName;
6
8
  readonly args?: readonly unknown[];
7
9
  readonly pid?: number;
8
10
  readonly writerId?: string;
9
11
  readonly mutationOwner?: string;
10
12
  readonly stream?: ReadableStream<Uint8Array>;
11
13
  }
12
- export type SupervisorOpHandler = (envelope: SupervisorOpEnvelope) => unknown;
14
+ export type SupervisorOpHandler = (envelope: SupervisorOpEnvelope, tools: SupervisorOpTools) => unknown;
13
15
  export interface SupervisorOpDeps {
14
16
  readonly vfs: SqliteVFS;
15
17
  /** Absent a process table, operations use the unprivileged session user. */
16
18
  readonly processes?: SessionProcessSupervisor;
17
19
  readonly output?: (stream: 'stdout' | 'stderr', pid: number, data: string) => void;
18
- /** Host handlers override defaults, for example to account for stream drains. */
19
- readonly extend?: Readonly<Record<string, SupervisorOpHandler>>;
20
+ /**
21
+ * The host's `_rpc*` surface for ops beyond the native set — an in-process
22
+ * workspace's dispatch record, or the session itself for
23
+ * `sessionSupervisorOps`. A native op never consults it.
24
+ */
25
+ readonly host?: SupervisorOpHost;
26
+ /**
27
+ * A pid-keyed bridge cache to serve the native ops from. Supplied by the
28
+ * session so `supervisorBridge` hands callers the same bridges the handler
29
+ * uses; in-process workspaces let the handler build its own.
30
+ */
31
+ readonly bridge?: SupervisorOpBridgeStore;
32
+ readonly extend?: Partial<Record<SupervisorOpName, SupervisorOpHandler>>;
20
33
  }
34
+ /**
35
+ * One slot in an op's argument plan: a number takes `envelope.args[n]`, a
36
+ * name takes the envelope's identity field (`pid`, `writerId`, `stream`,
37
+ * `mutationOwner`). The envelope is always the shape — a host never
38
+ * re-parses it.
39
+ */
40
+ export type SupervisorOpArg = number | 'pid' | 'writerId' | 'stream' | 'mutationOwner';
41
+ export interface SupervisorOpRoute {
42
+ /** The host method this op dispatches to. */
43
+ readonly method: string;
44
+ /** Positional plan for the host call — envelope fields, not raw args. */
45
+ readonly args: readonly SupervisorOpArg[];
46
+ }
47
+ /**
48
+ * The embedder's dispatch surface — the `_rpc*` methods SUPERVISOR_OP_ROUTES
49
+ * names. The session satisfies it with its own class; an in-process
50
+ * workspace supplies its host object.
51
+ */
52
+ export interface SupervisorOpHost {
53
+ readonly [method: string]: unknown;
54
+ }
55
+ /**
56
+ * The canonical supervisor op set — every operation the supervisor RPC
57
+ * serves. Three consumers key on these names:
58
+ *
59
+ * - `sessionSupervisorOp` (worker): the DO's host — `extend` overrides for
60
+ * hosted accounting plus the non-filesystem ops it answers itself.
61
+ * - `createSupervisorOpHandler`: an in-process workspace — filesystem ops
62
+ * run against the VFS directly; every other op dispatches to
63
+ * `deps.host` through SUPERVISOR_OP_ROUTES, the embedder's `_rpc*`
64
+ * surface.
65
+ * - `supervisor-host-dispatch`: the test — derives every case's delegate
66
+ * and expected arguments from SUPERVISOR_OP_ROUTES, not a copied list.
67
+ *
68
+ * An op absent here is not served, on any host.
69
+ */
70
+ export declare const SUPERVISOR_OPS: readonly ["readFile", "readFileBytes", "writeFile", "stat", "lstat", "hasLegacySymlinkUnder", "utimes", "chmod", "access", "chown", "setUmask", "readdir", "exists", "mkdir", "rmdir", "rename", "unlink", "readlink", "symlink", "fsAcquire", "fsRevision", "fsList", "wsOpen", "wsPoll", "wsSend", "wsClose", "fsOpen", "fsRead", "fsWrite", "fsClose", "fsReadRange", "fsReadRangeUncached", "fsReadBatch", "fsWriteRange", "fsAppend", "fsAppendAck", "fsTruncate", "writeBatch", "writeBatchStream", "putRegistryEntries", "stdout", "stderr", "prefetch", "registerPort", "unregisterPort", "reportExit", "routeLoopback", "transform", "cpSpawn", "cpStdinWrite", "cpStdinEnd", "cpReadStdin", "cpReadOutput", "cpDrainOutput", "cpKill", "cpWait", "cpDispatchInline"];
71
+ export type SupervisorOpName = (typeof SUPERVISOR_OPS)[number];
72
+ /**
73
+ * What the shared handler hands a host override: the pid-keyed bridge and
74
+ * the deps it was built with, so an override that wraps a filesystem op
75
+ * (read-allocation accounting, stream-drain timing) reuses the same bridge
76
+ * the default handler would have used instead of caching its own.
77
+ */
78
+ export interface SupervisorOpTools {
79
+ readonly bridge: (pid?: number) => SqliteRuntimeFsBridge;
80
+ readonly vfs: SqliteVFS;
81
+ readonly cred: (pid?: number) => VfsCred;
82
+ readonly output?: (stream: 'stdout' | 'stderr', pid: number, data: string) => void;
83
+ }
84
+ /** The host-side argument plan per op — how an envelope becomes an _rpc* call. */
85
+ export declare const SUPERVISOR_OP_ROUTES: Readonly<Record<SupervisorOpName, SupervisorOpRoute>>;
86
+ /**
87
+ * The ops `createSupervisorOpHandler` serves natively — one pid-keyed
88
+ * filesystem bridge, plus the output stream. A session's `extend` overrides
89
+ * never cover these by accident: `sessionSupervisorOps` builds its delegate
90
+ * set from this name list, not a hand-copied table.
91
+ */
92
+ export declare const SUPERVISOR_NATIVE_OPS: ReadonlySet<string>;
93
+ /** The pid-keyed bridge cache behind the native filesystem ops. */
94
+ export interface SupervisorOpBridgeStore {
95
+ readonly bridge: (pid?: number) => SqliteRuntimeFsBridge;
96
+ /** Drop a pid's bridge — a process exit ends its credential's validity. */
97
+ readonly forget: (pid: number) => void;
98
+ }
99
+ /**
100
+ * Exported so the session's `supervisorBridge` — used by RPC bodies the
101
+ * envelope delegates back to (fsOpen, fsAppend, writeBatch, …) — is the
102
+ * same cache the handler's native ops serve from, never a second one.
103
+ */
104
+ export declare function createSupervisorBridgeStore(deps: Pick<SupervisorOpDeps, 'vfs' | 'processes'>): SupervisorOpBridgeStore;
21
105
  /** One dispatch method lets any host serve its workspace to process facets. */
22
106
  export declare function createSupervisorOpHandler(deps: SupervisorOpDeps): (envelope: SupervisorOpEnvelope) => Promise<unknown>;
23
107
  //# sourceMappingURL=supervisor-op.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"supervisor-op.d.ts","sourceRoot":"","sources":["../../src/workspace/supervisor-op.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AAEzF,8EAA8E;AAC9E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnF,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC;CACjE;AAiCD,+EAA+E;AAC/E,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,gBAAgB,GACrB,CAAC,QAAQ,EAAE,oBAAoB,KAAK,OAAO,CAAC,OAAO,CAAC,CAuDtD"}
1
+ {"version":3,"file":"supervisor-op.d.ts","sourceRoot":"","sources":["../../src/workspace/supervisor-op.ts"],"names":[],"mappings":"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"}
@@ -31,20 +31,138 @@ function credFor(deps, pid) {
31
31
  }
32
32
  return deps.processes ? deps.processes.cred(pid) : CRED_SESSION_USER;
33
33
  }
34
+ /**
35
+ * The canonical supervisor op set — every operation the supervisor RPC
36
+ * serves. Three consumers key on these names:
37
+ *
38
+ * - `sessionSupervisorOp` (worker): the DO's host — `extend` overrides for
39
+ * hosted accounting plus the non-filesystem ops it answers itself.
40
+ * - `createSupervisorOpHandler`: an in-process workspace — filesystem ops
41
+ * run against the VFS directly; every other op dispatches to
42
+ * `deps.host` through SUPERVISOR_OP_ROUTES, the embedder's `_rpc*`
43
+ * surface.
44
+ * - `supervisor-host-dispatch`: the test — derives every case's delegate
45
+ * and expected arguments from SUPERVISOR_OP_ROUTES, not a copied list.
46
+ *
47
+ * An op absent here is not served, on any host.
48
+ */
49
+ export const SUPERVISOR_OPS = [
50
+ 'readFile', 'readFileBytes', 'writeFile', 'stat', 'lstat',
51
+ 'hasLegacySymlinkUnder', 'utimes', 'chmod', 'access', 'chown', 'setUmask',
52
+ 'readdir', 'exists', 'mkdir', 'rmdir', 'rename', 'unlink', 'readlink',
53
+ 'symlink', 'fsAcquire', 'fsRevision', 'fsList', 'wsOpen', 'wsPoll',
54
+ 'wsSend', 'wsClose', 'fsOpen', 'fsRead', 'fsWrite', 'fsClose',
55
+ 'fsReadRange', 'fsReadRangeUncached', 'fsReadBatch', 'fsWriteRange',
56
+ 'fsAppend', 'fsAppendAck', 'fsTruncate', 'writeBatch', 'writeBatchStream',
57
+ 'putRegistryEntries', 'stdout', 'stderr', 'prefetch', 'registerPort',
58
+ 'unregisterPort', 'reportExit', 'routeLoopback', 'transform', 'cpSpawn',
59
+ 'cpStdinWrite', 'cpStdinEnd', 'cpReadStdin', 'cpReadOutput',
60
+ 'cpDrainOutput', 'cpKill', 'cpWait', 'cpDispatchInline',
61
+ ];
62
+ /** The host-side argument plan per op — how an envelope becomes an _rpc* call. */
63
+ export const SUPERVISOR_OP_ROUTES = {
64
+ readFile: { method: '_rpcReadFile', args: [0, 'pid'] },
65
+ readFileBytes: { method: '_rpcReadFileBytes', args: [0, 'pid'] },
66
+ writeFile: { method: '_rpcWriteFile', args: [0, 1, 'pid'] },
67
+ stat: { method: '_rpcStat', args: [0, 'pid'] },
68
+ lstat: { method: '_rpcLstat', args: [0, 'pid'] },
69
+ hasLegacySymlinkUnder: { method: '_rpcHasLegacySymlinkUnder', args: [0, 'pid'] },
70
+ utimes: { method: '_rpcUtimes', args: [0, 1, 2, 'pid'] },
71
+ chmod: { method: '_rpcChmod', args: [0, 1, 'pid'] },
72
+ access: { method: '_rpcAccess', args: [0, 1, 'pid'] },
73
+ chown: { method: '_rpcChown', args: [0, 1, 2, 'pid', 3] },
74
+ setUmask: { method: '_rpcSetUmask', args: [0, 'pid'] },
75
+ readdir: { method: '_rpcReaddir', args: [0, 'pid'] },
76
+ exists: { method: '_rpcExists', args: [0, 'pid'] },
77
+ mkdir: { method: '_rpcMkdir', args: [0, 'pid'] },
78
+ rmdir: { method: '_rpcRmdir', args: [0, 'pid'] },
79
+ rename: { method: '_rpcRename', args: [0, 1, 'pid'] },
80
+ unlink: { method: '_rpcUnlink', args: [0, 'pid'] },
81
+ readlink: { method: '_rpcReadlink', args: [0, 'pid'] },
82
+ symlink: { method: '_rpcSymlink', args: [0, 1, 'pid'] },
83
+ fsAcquire: { method: '_rpcFsAcquire', args: [0, 1, 'pid'] },
84
+ fsRevision: { method: '_rpcFsRevision', args: [0, 'pid'] },
85
+ fsList: { method: '_rpcFsList', args: [0, 1, 'pid'] },
86
+ wsOpen: { method: '_rpcWsOpen', args: [0, 1, 'pid'] },
87
+ wsPoll: { method: '_rpcWsPoll', args: [0, 1, 'pid'] },
88
+ wsSend: { method: '_rpcWsSend', args: [0, 1, 2, 'pid'] },
89
+ wsClose: { method: '_rpcWsClose', args: [0, 1, 2, 'pid'] },
90
+ fsOpen: { method: '_rpcFsOpen', args: [0, 1, 'pid'] },
91
+ fsRead: { method: '_rpcFsRead', args: [0, 1, 2, 'pid'] },
92
+ fsWrite: { method: '_rpcFsWrite', args: [0, 1, 2, 'pid'] },
93
+ fsClose: { method: '_rpcFsClose', args: [0, 'pid'] },
94
+ fsReadRange: { method: '_rpcFsReadRange', args: [0, 1, 2, 'pid'] },
95
+ fsReadRangeUncached: { method: '_rpcFsReadRangeUncached', args: [0, 1, 2, 'pid'] },
96
+ fsReadBatch: { method: '_rpcFsReadBatch', args: [0, 'pid'] },
97
+ fsWriteRange: { method: '_rpcFsWriteRange', args: [0, 1, 2, 'pid'] },
98
+ fsAppend: { method: '_rpcFsAppend', args: [0, 'writerId', 1, 2, 3, 'pid'] },
99
+ fsAppendAck: { method: '_rpcFsAppendAck', args: ['writerId', 0, 1, 'pid'] },
100
+ fsTruncate: { method: '_rpcFsTruncate', args: [0, 1, 'pid'] },
101
+ writeBatch: { method: '_rpcWriteBatch', args: [0, 'pid'] },
102
+ writeBatchStream: { method: '_rpcWriteBatchStream', args: ['stream', 'mutationOwner', 'pid'] },
103
+ putRegistryEntries: { method: '_rpcPutRegistryEntries', args: [0] },
104
+ stdout: { method: '_rpcStdout', args: ['pid', 0] },
105
+ stderr: { method: '_rpcStderr', args: ['pid', 0] },
106
+ prefetch: { method: '_rpcPrefetch', args: [0, 1] },
107
+ registerPort: { method: '_rpcRegisterPort', args: ['pid', 0] },
108
+ unregisterPort: { method: '_rpcUnregisterPort', args: [0] },
109
+ reportExit: { method: '_rpcReportExit', args: ['pid', 0, 1] },
110
+ routeLoopback: { method: '_rpcRouteLoopback', args: [0, 1] },
111
+ transform: { method: '_rpcTransform', args: [0, 1] },
112
+ cpSpawn: { method: '_rpcCpSpawn', args: [0] },
113
+ cpStdinWrite: { method: '_rpcCpStdinWrite', args: [0, 1] },
114
+ cpStdinEnd: { method: '_rpcCpStdinEnd', args: [0] },
115
+ cpReadStdin: { method: '_rpcCpReadStdin', args: [0, 1] },
116
+ cpReadOutput: { method: '_rpcCpReadOutput', args: [0, 1, 2, 3] },
117
+ cpDrainOutput: { method: '_rpcCpDrainOutput', args: [0] },
118
+ cpKill: { method: '_rpcCpKill', args: [0, 1] },
119
+ cpWait: { method: '_rpcCpWait', args: [0, 1] },
120
+ cpDispatchInline: { method: '_rpcCpDispatchInline', args: [0, 1] },
121
+ };
122
+ /**
123
+ * The ops `createSupervisorOpHandler` serves natively — one pid-keyed
124
+ * filesystem bridge, plus the output stream. A session's `extend` overrides
125
+ * never cover these by accident: `sessionSupervisorOps` builds its delegate
126
+ * set from this name list, not a hand-copied table.
127
+ */
128
+ export const SUPERVISOR_NATIVE_OPS = new Set([
129
+ 'readFile', 'readFileBytes', 'stat', 'lstat', 'exists', 'readdir',
130
+ 'readlink', 'fsReadRange', 'fsReadRangeUncached', 'fsRevision',
131
+ 'hasLegacySymlinkUnder', 'writeFile', 'mkdir', 'rmdir', 'unlink',
132
+ 'rename', 'symlink', 'chmod', 'utimes', 'fsTruncate',
133
+ 'writeBatchStream', 'stdout', 'stderr',
134
+ ]);
135
+ /**
136
+ * Exported so the session's `supervisorBridge` — used by RPC bodies the
137
+ * envelope delegates back to (fsOpen, fsAppend, writeBatch, …) — is the
138
+ * same cache the handler's native ops serve from, never a second one.
139
+ */
140
+ export function createSupervisorBridgeStore(deps) {
141
+ const bridges = new Map();
142
+ return {
143
+ bridge: (pid) => {
144
+ const key = pid ?? 0;
145
+ const credentialed = deps.vfs.as(credFor(deps, pid));
146
+ const held = bridges.get(key);
147
+ if (held) {
148
+ held.updateCredential(credentialed);
149
+ return held;
150
+ }
151
+ const built = new SqliteRuntimeFsBridge(credentialed, deps.vfs);
152
+ bridges.set(key, built);
153
+ return built;
154
+ },
155
+ forget: (pid) => { bridges.delete(pid); },
156
+ };
157
+ }
34
158
  /** One dispatch method lets any host serve its workspace to process facets. */
35
159
  export function createSupervisorOpHandler(deps) {
36
- const bridges = new Map();
37
- const bridgeFor = (pid) => {
38
- const key = pid ?? 0;
39
- const credentialed = deps.vfs.as(credFor(deps, pid));
40
- const held = bridges.get(key);
41
- if (held) {
42
- held.updateCredential(credentialed);
43
- return held;
44
- }
45
- const built = new SqliteRuntimeFsBridge(credentialed, deps.vfs);
46
- bridges.set(key, built);
47
- return built;
160
+ const bridgeFor = deps.bridge?.bridge ?? createSupervisorBridgeStore(deps).bridge;
161
+ const tools = {
162
+ bridge: bridgeFor,
163
+ vfs: deps.vfs,
164
+ cred: (pid) => credFor(deps, pid),
165
+ output: deps.output,
48
166
  };
49
167
  const ops = {
50
168
  readFile: async (e) => {
@@ -83,10 +201,24 @@ export function createSupervisorOpHandler(deps) {
83
201
  if (!envelope || typeof envelope.op !== 'string') {
84
202
  throw new Error('supervisor op: envelope names no operation');
85
203
  }
204
+ // Priority: the embedder's own handler → the native filesystem op → the
205
+ // canonical route table onto the host's _rpc* methods. An op in none of
206
+ // these is not served by this host.
86
207
  const handler = Object.hasOwn(extend, envelope.op) ? extend[envelope.op]
87
208
  : Object.hasOwn(ops, envelope.op) ? ops[envelope.op] : undefined;
88
- if (!handler)
209
+ if (handler)
210
+ return handler(envelope, tools);
211
+ const route = Object.hasOwn(SUPERVISOR_OP_ROUTES, envelope.op)
212
+ ? SUPERVISOR_OP_ROUTES[envelope.op] : undefined;
213
+ if (!route)
89
214
  throw new Error(`supervisor op: '${envelope.op}' is not served by this host`);
90
- return handler(envelope);
215
+ const host = deps.host;
216
+ if (!host)
217
+ throw new Error(`supervisor op: '${envelope.op}' needs a host that this workspace does not have`);
218
+ const method = host[route.method];
219
+ if (typeof method !== 'function')
220
+ throw new Error(`supervisor op: missing host method ${route.method}`);
221
+ const args = route.args.map((slot) => typeof slot === 'number' ? envelope.args?.[slot] : envelope[slot]);
222
+ return Reflect.apply(method, host, args);
91
223
  };
92
224
  }