@nimbus-sh/worker 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/facets/compose.d.ts +3 -0
  2. package/dist/facets/compose.d.ts.map +1 -1
  3. package/dist/facets/compose.js +1 -1
  4. package/dist/facets/manager.d.ts +26 -15
  5. package/dist/facets/manager.d.ts.map +1 -1
  6. package/dist/facets/manager.js +154 -112
  7. package/dist/facets/real-vite-hmr.d.ts +3 -1
  8. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  9. package/dist/facets/real-vite-hmr.js +18 -8
  10. package/dist/facets/ws-terminal.d.ts +9 -31
  11. package/dist/facets/ws-terminal.d.ts.map +1 -1
  12. package/dist/facets/ws-terminal.js +58 -51
  13. package/dist/hosted/commands.d.ts +12 -0
  14. package/dist/hosted/commands.d.ts.map +1 -0
  15. package/dist/hosted/commands.js +1647 -0
  16. package/dist/hosted/runtime.d.ts +135 -0
  17. package/dist/hosted/runtime.d.ts.map +1 -0
  18. package/dist/hosted/runtime.js +344 -0
  19. package/dist/hosted/services.d.ts +44 -0
  20. package/dist/hosted/services.d.ts.map +1 -0
  21. package/dist/hosted/services.js +522 -0
  22. package/dist/loaders/generated-workers.d.ts +1 -1
  23. package/dist/loaders/generated-workers.d.ts.map +1 -1
  24. package/dist/loaders/generated-workers.js +2 -2
  25. package/dist/node-shims-artifact.generated.js +3 -3
  26. package/dist/runtime/bash-repl.d.ts +6 -4
  27. package/dist/runtime/bash-repl.d.ts.map +1 -1
  28. package/dist/runtime/bash-repl.js +46 -7
  29. package/dist/runtime/bun-runner.js +1 -1
  30. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  31. package/dist/runtime/facet-loader-host.js +1 -3
  32. package/dist/runtime/node-runner.d.ts +1 -1
  33. package/dist/runtime/node-runner.d.ts.map +1 -1
  34. package/dist/runtime/node-runner.js +2 -2
  35. package/dist/runtime/node-shims.d.ts.map +1 -1
  36. package/dist/runtime/node-shims.js +14 -1
  37. package/dist/runtime/opencode-facet-runner.js +14 -14
  38. package/dist/runtime/package-manager.d.ts +35 -122
  39. package/dist/runtime/package-manager.d.ts.map +1 -1
  40. package/dist/runtime/package-manager.js +61 -596
  41. package/dist/runtime/process-logs-api.d.ts +1 -1
  42. package/dist/runtime/process-logs-api.d.ts.map +1 -1
  43. package/dist/runtime/process-logs-api.js +1 -1
  44. package/dist/runtime/python-repl.d.ts +6 -4
  45. package/dist/runtime/python-repl.d.ts.map +1 -1
  46. package/dist/runtime/python-repl.js +92 -67
  47. package/dist/runtime/repl-session.d.ts +9 -47
  48. package/dist/runtime/repl-session.d.ts.map +1 -1
  49. package/dist/runtime/repl-session.js +105 -105
  50. package/dist/runtime/ruby-repl.d.ts +3 -2
  51. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  52. package/dist/runtime/ruby-repl.js +7 -6
  53. package/dist/runtime/runtime-catalog.d.ts +13 -0
  54. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  55. package/dist/runtime/runtime-catalog.js +88 -0
  56. package/dist/runtime/wasi/preamble.d.ts.map +1 -1
  57. package/dist/runtime/wasi/preamble.js +74 -56
  58. package/dist/runtime-catalog.generated.js +1 -1
  59. package/dist/session/agent.d.ts +1 -21
  60. package/dist/session/agent.d.ts.map +1 -1
  61. package/dist/session/ai.d.ts +5 -1
  62. package/dist/session/ai.d.ts.map +1 -1
  63. package/dist/session/ai.js +7 -0
  64. package/dist/session/hibernation.d.ts +2 -1
  65. package/dist/session/hibernation.d.ts.map +1 -1
  66. package/dist/session/hibernation.js +7 -4
  67. package/dist/session/init.d.ts +1 -36
  68. package/dist/session/init.d.ts.map +1 -1
  69. package/dist/session/init.js +18 -1773
  70. package/dist/session/loopback.d.ts +2 -29
  71. package/dist/session/loopback.d.ts.map +1 -1
  72. package/dist/session/loopback.js +3 -27
  73. package/dist/session/nimbus-session.d.ts +28 -34
  74. package/dist/session/nimbus-session.d.ts.map +1 -1
  75. package/dist/session/nimbus-session.js +78 -518
  76. package/dist/session/npm-install-port.d.ts +3 -1
  77. package/dist/session/npm-install-port.d.ts.map +1 -1
  78. package/dist/session/port-capability.d.ts.map +1 -1
  79. package/dist/session/port-capability.js +11 -1
  80. package/dist/session/programmatic.d.ts +5 -38
  81. package/dist/session/programmatic.d.ts.map +1 -1
  82. package/dist/session/programmatic.js +17 -49
  83. package/dist/session/rpc.d.ts +3 -43
  84. package/dist/session/rpc.d.ts.map +1 -1
  85. package/dist/session/rpc.js +8 -67
  86. package/dist/session/supervisor-op.d.ts +10 -5
  87. package/dist/session/supervisor-op.d.ts.map +1 -1
  88. package/dist/session/supervisor-op.js +21 -48
  89. package/dist/session/supervisor-rpc.d.ts +33 -16
  90. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  91. package/dist/session/supervisor-rpc.js +49 -4
  92. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  93. package/dist/vfs/facet-resident-store.js +4 -2
  94. package/dist/workspace-host.d.ts +7 -0
  95. package/dist/workspace-host.d.ts.map +1 -0
  96. package/dist/workspace-host.js +5 -0
  97. package/dist/workspace.d.ts +2 -0
  98. package/dist/workspace.d.ts.map +1 -0
  99. package/dist/workspace.js +1 -0
  100. package/package.json +17 -12
  101. package/public/_assets/runtime/{node-shims-8f8c64edd2a1f0f5.js → node-shims-acaa037e6d26ec0d.js} +14 -1
  102. package/scripts/bundle-runtime.mjs +35 -8
@@ -21,6 +21,7 @@ import { getRealNodeImportsCode } from '@nimbus-sh/core/_shared/real-node-import
21
21
  import { FACET_RESIDENT_STORE_SOURCE } from '../vfs/facet-resident-store.js';
22
22
  import { VFS_CURSOR_SEED_SOURCE, serializeFacetVfsCursor, } from '@nimbus-sh/core/_shared/facet-vfs-cursor.js';
23
23
  import { VFS_WRITE_LEDGER_SOURCE } from '@nimbus-sh/core/_shared/vfs-write-ledger.js';
24
+ import { ExecutionFs } from '@nimbus-sh/core/shell/execution-fs.js';
24
25
  import { stripLeadingSlashes, vfsPathExtension } from '@nimbus-sh/core/vfs/path.js';
25
26
  import { clearPortCapability, listPortReservations, readPortReservation, readPortReservationByOwner, releasePortReservation, restoreReservedPortCapability, } from '../session/port-capability.js';
26
27
  import { deriveResidentOwner } from './resident-identity.js';
@@ -36,7 +37,7 @@ import { classifyError } from '@nimbus-sh/platform/oom-classify.js';
36
37
  import { TurnBudget, PacedWork, turnChunkMaxBytes, withResolvers } from '@nimbus-sh/fabric/turn-budget.js';
37
38
  import { onColdStart } from '@nimbus-sh/fabric/generation.js';
38
39
  import { FencedWork, FENCED_WORK_KEY_PREFIX, } from '@nimbus-sh/fabric/fenced-work.js';
39
- import { EsbuildService, rewriteBundledEsmToCjs, } from '@nimbus-sh/core/runtime/esbuild-service.js';
40
+ import { EsbuildService, rewriteBundledEsmToCjs, rewriteProvidedCommonJsModules, } from '@nimbus-sh/core/runtime/esbuild-service.js';
40
41
  import { isExecDiagEnabled, recordExecTelemetry } from './exec-telemetry.js';
41
42
  import { disposeRpcResource, disposeRpcResources } from '@nimbus-sh/platform/rpc-dispose.js';
42
43
  import { sqliteWasmModuleEntry } from './opencode-staging.js';
@@ -370,7 +371,7 @@ const SQLITE_FACET_IMPORT = `import __nimbusSqliteWasmModule from "${SQLITE_WASM
370
371
  * Generate one-shot runtime code with a plain fetch handler.
371
372
  */
372
373
  export async function generateEntrypointCode(userCode, vfsState, usesSqlite, shims, wasmImports = []) {
373
- const safeCode = JSON.stringify(userCode);
374
+ const safeCode = JSON.stringify(rewriteProvidedCommonJsModules(userCode));
374
375
  const bundleSource = await facetVfsBundleSourceFor(vfsState);
375
376
  const safeManifest = vfsState.serializedManifest ?? JSON.stringify(vfsState.manifest);
376
377
  const safeMetadata = vfsState.serializedMetadata ?? JSON.stringify(vfsState.metadata);
@@ -673,7 +674,7 @@ function facetWasmImportsSource(wasmImports) {
673
674
  + `\nglobalThis.__nimbusPrecompiledWasmByDigest = new Map([${byDigest.join(', ')}]);`;
674
675
  }
675
676
  export async function generateLongRunningNodeCode(userCode, vfsState, opts, usesSqlite, shims, pacer) {
676
- const safeCode = JSON.stringify(userCode);
677
+ const safeCode = JSON.stringify(rewriteProvidedCommonJsModules(userCode));
677
678
  const safeArgs = JSON.stringify({
678
679
  argv: opts.argv || [],
679
680
  env: opts.env || {},
@@ -1148,8 +1149,8 @@ async function facetVfsBundleSourceFor(vfsState, pacer) {
1148
1149
  * Throws on read errors (caller wraps in try/catch — matches the
1149
1150
  * pre-fix readFileString contract).
1150
1151
  */
1151
- function _readBundleCell(vfs, path) {
1152
- const bytes = vfs.readFile(path);
1152
+ async function _readBundleCell(vfs, path) {
1153
+ const bytes = await vfs.readFile(path);
1153
1154
  try {
1154
1155
  return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
1155
1156
  }
@@ -1176,10 +1177,10 @@ function _bundleCellLength(cell) {
1176
1177
  * `perFileCeiling` is the pass's own cap (e.g. CWD_SNAPSHOT_MAX_FILE_BYTES,
1177
1178
  * BIN_PACKAGE_SPECULATIVE_MAX_FILE_BYTES); omit it for budget-only checks.
1178
1179
  */
1179
- function _bundleAdmits(vfs, path, budgetState, perFileCeiling) {
1180
+ async function _bundleAdmits(vfs, path, budgetState, perFileCeiling) {
1180
1181
  let size;
1181
1182
  try {
1182
- size = vfs.lstat(path).size;
1183
+ size = (await vfs.lstat(path)).size;
1183
1184
  }
1184
1185
  catch {
1185
1186
  return false;
@@ -1650,9 +1651,9 @@ const MANIFEST_MAX_DEPTH = 12;
1650
1651
  * fs.readdirSync / fs.statSync honest regardless of which subset of
1651
1652
  * file CONTENT we ship.
1652
1653
  */
1653
- function buildManifest(vfs, cwd, scriptPath) {
1654
+ async function buildManifest(vfs, cwd, scriptPath) {
1654
1655
  const manifest = {};
1655
- function walk(dirPath, depth = 0) {
1656
+ async function walk(dirPath, depth = 0) {
1656
1657
  if (depth > MANIFEST_MAX_DEPTH)
1657
1658
  return;
1658
1659
  const stripped = dirPath.replace(/^\/+/, '');
@@ -1660,7 +1661,7 @@ function buildManifest(vfs, cwd, scriptPath) {
1660
1661
  return;
1661
1662
  let entries;
1662
1663
  try {
1663
- entries = vfs.readdir(stripped);
1664
+ entries = (await vfs.readdir(stripped));
1664
1665
  }
1665
1666
  catch {
1666
1667
  return;
@@ -1669,7 +1670,7 @@ function buildManifest(vfs, cwd, scriptPath) {
1669
1670
  for (const entry of entries) {
1670
1671
  if (entry.type === 'directory') {
1671
1672
  const childPath = stripped ? stripped + '/' + entry.name : entry.name;
1672
- walk(childPath, depth + 1);
1673
+ (await walk(childPath, depth + 1));
1673
1674
  }
1674
1675
  }
1675
1676
  }
@@ -1690,13 +1691,13 @@ function buildManifest(vfs, cwd, scriptPath) {
1690
1691
  {
1691
1692
  const segments = cwdStripped ? cwdStripped.split('/') : [];
1692
1693
  for (let i = 0; i < segments.length; i++) {
1693
- walk(segments.slice(0, i).join('/'), MANIFEST_MAX_DEPTH);
1694
+ (await walk(segments.slice(0, i).join('/'), MANIFEST_MAX_DEPTH));
1694
1695
  }
1695
1696
  }
1696
- walk(cwdStripped, 0);
1697
+ (await walk(cwdStripped, 0));
1697
1698
  const nmDir = cwdStripped + '/node_modules';
1698
- if (vfs.exists(nmDir) && vfs.isDirectory(nmDir)) {
1699
- walk(nmDir, 0);
1699
+ if ((await vfs.exists(nmDir)) && (await vfs.isDirectory(nmDir))) {
1700
+ (await walk(nmDir, 0));
1700
1701
  }
1701
1702
  // ── Bin-target package + hoisted dependency roots ─────────────────────
1702
1703
  //
@@ -1728,19 +1729,19 @@ function buildManifest(vfs, cwd, scriptPath) {
1728
1729
  const pkgEnd = isScoped ? nmIdx + 3 : nmIdx + 2;
1729
1730
  if (pkgEnd <= segs.length) {
1730
1731
  const pkgRoot = segs.slice(0, pkgEnd).join('/');
1731
- if (vfs.exists(pkgRoot) && vfs.isDirectory(pkgRoot)) {
1732
- walk(pkgRoot, 0);
1732
+ if ((await vfs.exists(pkgRoot)) && (await vfs.isDirectory(pkgRoot))) {
1733
+ (await walk(pkgRoot, 0));
1733
1734
  }
1734
1735
  }
1735
1736
  const nodeModulesRoot = segs.slice(0, nmIdx + 1).join('/');
1736
- if (vfs.exists(nodeModulesRoot) && vfs.isDirectory(nodeModulesRoot)) {
1737
- walk(nodeModulesRoot, 0);
1737
+ if ((await vfs.exists(nodeModulesRoot)) && (await vfs.isDirectory(nodeModulesRoot))) {
1738
+ (await walk(nodeModulesRoot, 0));
1738
1739
  }
1739
1740
  }
1740
1741
  }
1741
1742
  return manifest;
1742
1743
  }
1743
- function buildVfsMetadata(vfs, manifest, bundle) {
1744
+ async function buildVfsMetadata(vfs, manifest, bundle) {
1744
1745
  const paths = new Set(Object.keys(bundle).filter((path) => compiledCellPath(path) === null));
1745
1746
  for (const [directory, children] of Object.entries(manifest)) {
1746
1747
  paths.add(directory);
@@ -1751,7 +1752,9 @@ function buildVfsMetadata(vfs, manifest, bundle) {
1751
1752
  const metadata = {};
1752
1753
  for (const path of paths) {
1753
1754
  try {
1754
- const stat = vfs.lstat(path);
1755
+ const stat = await vfs.authority.stat(path, { followSymlinks: false });
1756
+ if (!stat)
1757
+ continue;
1755
1758
  metadata[path] = {
1756
1759
  type: stat.type,
1757
1760
  size: stat.size,
@@ -1767,12 +1770,12 @@ function buildVfsMetadata(vfs, manifest, bundle) {
1767
1770
  }
1768
1771
  return metadata;
1769
1772
  }
1770
- function addUnreadableDenialCells(vfs, bundle, metadata) {
1773
+ async function addUnreadableDenialCells(vfs, bundle, metadata) {
1771
1774
  for (const [path, stat] of Object.entries(metadata)) {
1772
1775
  if (stat.type === 'directory' || path in bundle)
1773
1776
  continue;
1774
1777
  try {
1775
- vfs.access(path, 0o4);
1778
+ (await vfs.access(path, 0o4));
1776
1779
  }
1777
1780
  catch (error) {
1778
1781
  if (typeof error === 'object'
@@ -1801,14 +1804,14 @@ function addUnreadableDenialCells(vfs, bundle, metadata) {
1801
1804
  // was a file-local helper. Adding the named export is a pure surface
1802
1805
  // addition — no callers other than buildPrefetchBundle (same file) and
1803
1806
  // the new probe.
1804
- export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPaths = new Set()) {
1807
+ export async function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPaths = new Set()) {
1805
1808
  let added = 0;
1806
1809
  const cwdStripped = cwd.replace(/^\/+/, '');
1807
1810
  const nmDir = cwdStripped + '/node_modules';
1808
- if (!(vfs.exists(nmDir) && vfs.isDirectory(nmDir)))
1811
+ if (!((await vfs.exists(nmDir)) && (await vfs.isDirectory(nmDir))))
1809
1812
  return { added };
1810
1813
  const exts = ['', '.js', '.cjs', '.mjs', '/index.js', '/index.cjs'];
1811
- function addOne(path) {
1814
+ async function addOne(path) {
1812
1815
  const stripped = path.replace(/^\/+/, '');
1813
1816
  if (stripped in bundle)
1814
1817
  return false;
@@ -1817,7 +1820,7 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1817
1820
  if (budgetState.totalBytes >= VFS_BUNDLE_MAX_BYTES)
1818
1821
  return false;
1819
1822
  try {
1820
- if (!vfs.exists(stripped) || vfs.isDirectory(stripped))
1823
+ if (!(await vfs.exists(stripped)) || (await vfs.isDirectory(stripped)))
1821
1824
  return false;
1822
1825
  // This is a guess at what a program might require, and the same
1823
1826
  // per-file ceiling the entry-package walk applies bounds it: a
@@ -1827,7 +1830,7 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1827
1830
  // supervisor's headroom — on every invocation that never reads it.
1828
1831
  // Anything the program really requires arrives through the closure,
1829
1832
  // which is uncapped.
1830
- if (!_bundleAdmits(vfs, stripped, budgetState, BIN_PACKAGE_SPECULATIVE_MAX_FILE_BYTES))
1833
+ if (!(await _bundleAdmits(vfs, stripped, budgetState, BIN_PACKAGE_SPECULATIVE_MAX_FILE_BYTES)))
1831
1834
  return false;
1832
1835
  // A guess must not be a native binary. Nothing in a Workers isolate can
1833
1836
  // load a `.node` addon or a `.exe` — the ABI policy classifies them
@@ -1839,7 +1842,7 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1839
1842
  if (stripped.endsWith('.node') || stripped.endsWith('.exe'))
1840
1843
  return false;
1841
1844
  // hardening-r5: preserve binary content as Uint8Array.
1842
- const content = _readBundleCell(vfs, stripped);
1845
+ const content = (await _readBundleCell(vfs, stripped));
1843
1846
  const cellLen = _bundleCellLength(content);
1844
1847
  if (budgetState.totalBytes + cellLen > VFS_BUNDLE_MAX_BYTES)
1845
1848
  return false;
@@ -1903,15 +1906,15 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1903
1906
  }
1904
1907
  return !reached;
1905
1908
  }
1906
- function addPkgEntry(pkgDir) {
1907
- addOne(pkgDir + '/package.json');
1909
+ async function addPkgEntry(pkgDir) {
1910
+ (await addOne(pkgDir + '/package.json'));
1908
1911
  // A package the closure reached keeps exactly what it reached; only an
1909
1912
  // unreached one gets the guess below.
1910
1913
  if (!mainIsSpeculative(pkgDir))
1911
1914
  return;
1912
1915
  let meta;
1913
1916
  try {
1914
- meta = JSON.parse(vfs.readFileString(pkgDir + '/package.json'));
1917
+ meta = JSON.parse((await vfs.readFileString(pkgDir + '/package.json')));
1915
1918
  }
1916
1919
  catch {
1917
1920
  meta = null;
@@ -1943,9 +1946,9 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1943
1946
  let landed = false;
1944
1947
  const tries = /\.[a-z]+$/.test(norm) ? [base] : exts.map((e) => base + e);
1945
1948
  for (const candidate of tries) {
1946
- if (vfs.exists(candidate.replace(/^\/+/, '')) &&
1947
- !vfs.isDirectory(candidate.replace(/^\/+/, ''))) {
1948
- if (addOne(candidate)) {
1949
+ if ((await vfs.exists(candidate.replace(/^\/+/, ''))) &&
1950
+ !(await vfs.isDirectory(candidate.replace(/^\/+/, '')))) {
1951
+ if ((await addOne(candidate))) {
1949
1952
  landed = true;
1950
1953
  break;
1951
1954
  }
@@ -1963,7 +1966,7 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1963
1966
  // the greedy oversample is the safety net for their reachability.
1964
1967
  const entryDir = base.replace(/\/[^/]+$/, '');
1965
1968
  try {
1966
- const sibs = vfs.readdir(entryDir);
1969
+ const sibs = (await vfs.readdir(entryDir));
1967
1970
  for (const sib of sibs) {
1968
1971
  if (sib.type !== 'file')
1969
1972
  continue;
@@ -1983,7 +1986,7 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1983
1986
  const hasMixedCase = /[A-Z]/.test(seg) && /[a-z]/.test(seg);
1984
1987
  if (!hasDigitOrDash && !hasMixedCase)
1985
1988
  continue;
1986
- addOne(entryDir + '/' + sib.name);
1989
+ (await addOne(entryDir + '/' + sib.name));
1987
1990
  }
1988
1991
  // Walk one level into `shared/` — unconditionally, since the
1989
1992
  // pattern is well-known across unbuild/rolldown/rollup chunked
@@ -1991,13 +1994,13 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
1991
1994
  // typical shared/ dir returns 1-5 files.
1992
1995
  const sharedDir = entryDir + '/shared';
1993
1996
  const sharedStripped = sharedDir.replace(/^\/+/, '');
1994
- if (vfs.exists(sharedStripped) && vfs.isDirectory(sharedStripped)) {
1995
- for (const sh of vfs.readdir(sharedDir)) {
1997
+ if ((await vfs.exists(sharedStripped)) && (await vfs.isDirectory(sharedStripped))) {
1998
+ for (const sh of (await vfs.readdir(sharedDir))) {
1996
1999
  if (sh.type !== 'file')
1997
2000
  continue;
1998
2001
  if (!/\.(cjs|mjs|js)$/.test(sh.name))
1999
2002
  continue;
2000
- addOne(sharedDir + '/' + sh.name);
2003
+ (await addOne(sharedDir + '/' + sh.name));
2001
2004
  }
2002
2005
  }
2003
2006
  }
@@ -2008,8 +2011,8 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
2008
2011
  }
2009
2012
  }
2010
2013
  }
2011
- for (const pkgDir of speculativePackageDirs(vfs, cwdStripped, bundle))
2012
- addPkgEntry(pkgDir);
2014
+ for (const pkgDir of (await speculativePackageDirs(vfs, cwdStripped, bundle)))
2015
+ (await addPkgEntry(pkgDir));
2013
2016
  return { added };
2014
2017
  }
2015
2018
  /**
@@ -2029,10 +2032,10 @@ export function greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPath
2029
2032
  * dependency of the package doing the requiring, so the bound is one hop
2030
2033
  * over `dependencies` only. Directories, sorted for a stable bundle.
2031
2034
  */
2032
- export function speculativePackageDirs(vfs, cwdStripped, bundle) {
2033
- const runtimeDeps = (pkgJsonPath) => {
2035
+ export async function speculativePackageDirs(vfs, cwdStripped, bundle) {
2036
+ const runtimeDeps = async (pkgJsonPath) => {
2034
2037
  try {
2035
- const meta = JSON.parse(vfs.readFileString(pkgJsonPath));
2038
+ const meta = JSON.parse((await vfs.readFileString(pkgJsonPath)));
2036
2039
  const names = new Set();
2037
2040
  for (const field of ['dependencies', 'optionalDependencies']) {
2038
2041
  const deps = meta?.[field];
@@ -2057,11 +2060,11 @@ export function speculativePackageDirs(vfs, cwdStripped, bundle) {
2057
2060
  };
2058
2061
  // Resolve a bare name the way require does from `fromDir`: the nearest
2059
2062
  // node_modules up the tree that has it.
2060
- const resolveDir = (name, fromDir) => {
2063
+ const resolveDir = async (name, fromDir) => {
2061
2064
  let dir = fromDir;
2062
2065
  for (;;) {
2063
2066
  const candidate = dir + '/node_modules/' + name;
2064
- if (vfs.exists(candidate + '/package.json'))
2067
+ if ((await vfs.exists(candidate + '/package.json')))
2065
2068
  return candidate;
2066
2069
  const idx = dir.lastIndexOf('/');
2067
2070
  if (idx <= 0)
@@ -2070,14 +2073,14 @@ export function speculativePackageDirs(vfs, cwdStripped, bundle) {
2070
2073
  }
2071
2074
  };
2072
2075
  const reached = new Set();
2073
- const hop = (fromDir) => {
2074
- for (const name of runtimeDeps(fromDir + '/package.json')) {
2075
- const dir = resolveDir(name, fromDir);
2076
+ const hop = async (fromDir) => {
2077
+ for (const name of (await runtimeDeps(fromDir + '/package.json'))) {
2078
+ const dir = (await resolveDir(name, fromDir));
2076
2079
  if (dir !== null)
2077
2080
  reached.add(dir);
2078
2081
  }
2079
2082
  };
2080
- hop(cwdStripped);
2083
+ (await hop(cwdStripped));
2081
2084
  const owners = new Set();
2082
2085
  for (const path of Object.keys(bundle)) {
2083
2086
  const owner = ownerOf(path);
@@ -2086,7 +2089,7 @@ export function speculativePackageDirs(vfs, cwdStripped, bundle) {
2086
2089
  }
2087
2090
  for (const owner of owners) {
2088
2091
  reached.add(owner);
2089
- hop(owner);
2092
+ (await hop(owner));
2090
2093
  }
2091
2094
  return [...reached].sort();
2092
2095
  }
@@ -2129,7 +2132,7 @@ export function speculativePackageDirs(vfs, cwdStripped, bundle) {
2129
2132
  * VFS_BUNDLE_MAX_FILES / VFS_BUNDLE_MAX_BYTES caps via the
2130
2133
  * `budgetState` counter.
2131
2134
  */
2132
- export function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2135
+ export async function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2133
2136
  let added = 0;
2134
2137
  // Asset extensions covered. Conservative whitelist — txt/json are
2135
2138
  // also legit runtime-loaded assets (e.g. mime-db json, license.txt).
@@ -2147,7 +2150,7 @@ export function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2147
2150
  // there's no `${` in the captured body (template-literal interpolation
2148
2151
  // is rejected).
2149
2152
  const RX = /(?:\bfs\s*\.)?readFileSync\s*\(\s*(?:[\w$.]+\s*\.\s*)?resolve\s*\(\s*__dirname\s*,\s*(['"`])([^'"`]+)\1\s*[\),]/g;
2150
- function addOneAsset(absPath) {
2153
+ async function addOneAsset(absPath) {
2151
2154
  const stripped = absPath.replace(/^\/+/, '');
2152
2155
  if (stripped in bundle)
2153
2156
  return false;
@@ -2156,12 +2159,12 @@ export function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2156
2159
  if (budgetState.totalBytes >= VFS_BUNDLE_MAX_BYTES)
2157
2160
  return false;
2158
2161
  try {
2159
- if (!vfs.exists(stripped) || vfs.isDirectory(stripped))
2162
+ if (!(await vfs.exists(stripped)) || (await vfs.isDirectory(stripped)))
2160
2163
  return false;
2161
- if (!_bundleAdmits(vfs, stripped, budgetState))
2164
+ if (!(await _bundleAdmits(vfs, stripped, budgetState)))
2162
2165
  return false;
2163
2166
  // hardening-r5: preserve binary content as Uint8Array.
2164
- const content = _readBundleCell(vfs, stripped);
2167
+ const content = (await _readBundleCell(vfs, stripped));
2165
2168
  const cellLen = _bundleCellLength(content);
2166
2169
  if (budgetState.totalBytes + cellLen > VFS_BUNDLE_MAX_BYTES)
2167
2170
  return false;
@@ -2231,7 +2234,7 @@ export function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2231
2234
  }
2232
2235
  resolved = out.join('/');
2233
2236
  }
2234
- addOneAsset(resolved);
2237
+ (await addOneAsset(resolved));
2235
2238
  }
2236
2239
  }
2237
2240
  return { added };
@@ -2283,7 +2286,7 @@ export function addStaticReadFileAssets(vfs, cwd, bundle, budgetState) {
2283
2286
  * Errors are swallowed: missing assets, unreadable VFS, and
2284
2287
  * non-string readFile inputs are silent skips — matches Z3 posture.
2285
2288
  */
2286
- export function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetState) {
2289
+ export async function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetState) {
2287
2290
  let added = 0;
2288
2291
  // The heuristic gate. Filenames matching either branch are eligible.
2289
2292
  // - Leading `.` covers `.ts-jest-digest`, `.cache-marker`, `.lintstagedrc`-ish
@@ -2322,7 +2325,7 @@ export function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetSta
2322
2325
  '\\s*__dirname\\s*,\\s*' +
2323
2326
  // literal: ' " ` (no ${ for backtick)
2324
2327
  '([\'"`])([^\'"`]+)\\1', 'g');
2325
- function addOneAsset(absPath) {
2328
+ async function addOneAsset(absPath) {
2326
2329
  const stripped = absPath.replace(/^\/+/, '');
2327
2330
  if (stripped in bundle)
2328
2331
  return false;
@@ -2331,12 +2334,12 @@ export function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetSta
2331
2334
  if (budgetState.totalBytes >= VFS_BUNDLE_MAX_BYTES)
2332
2335
  return false;
2333
2336
  try {
2334
- if (!vfs.exists(stripped) || vfs.isDirectory(stripped))
2337
+ if (!(await vfs.exists(stripped)) || (await vfs.isDirectory(stripped)))
2335
2338
  return false;
2336
- if (!_bundleAdmits(vfs, stripped, budgetState))
2339
+ if (!(await _bundleAdmits(vfs, stripped, budgetState)))
2337
2340
  return false;
2338
2341
  // hardening-r5: preserve binary content as Uint8Array.
2339
- const content = _readBundleCell(vfs, stripped);
2342
+ const content = (await _readBundleCell(vfs, stripped));
2340
2343
  const cellLen = _bundleCellLength(content);
2341
2344
  if (budgetState.totalBytes + cellLen > VFS_BUNDLE_MAX_BYTES)
2342
2345
  return false;
@@ -2405,7 +2408,7 @@ export function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetSta
2405
2408
  const basename = slash >= 0 ? resolved.slice(slash + 1) : resolved;
2406
2409
  if (!FILENAME_GATE.test(basename))
2407
2410
  continue;
2408
- addOneAsset(resolved);
2411
+ (await addOneAsset(resolved));
2409
2412
  }
2410
2413
  }
2411
2414
  return { added };
@@ -2438,7 +2441,7 @@ export function addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetSta
2438
2441
  * (user scripts, npx-cache files outside node_modules, eval) is
2439
2442
  * a no-op.
2440
2443
  */
2441
- export function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundleProfile) {
2444
+ export async function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundleProfile) {
2442
2445
  if (!scriptPath)
2443
2446
  return { added: 0, wasmPaths: [] };
2444
2447
  const stripped = scriptPath.replace(/^\/+/, '');
@@ -2492,7 +2495,7 @@ export function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundl
2492
2495
  const dir = queue.shift();
2493
2496
  let entries;
2494
2497
  try {
2495
- entries = vfs.readdir(dir);
2498
+ entries = (await vfs.readdir(dir));
2496
2499
  }
2497
2500
  catch {
2498
2501
  continue;
@@ -2522,7 +2525,7 @@ export function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundl
2522
2525
  continue;
2523
2526
  let size;
2524
2527
  try {
2525
- size = vfs.lstat(child).size;
2528
+ size = (await vfs.lstat(child)).size;
2526
2529
  }
2527
2530
  catch {
2528
2531
  continue;
@@ -2553,7 +2556,7 @@ export function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundl
2553
2556
  // hardening-r5: preserve binary content as Uint8Array.
2554
2557
  let content;
2555
2558
  try {
2556
- content = _readBundleCell(vfs, candidate.path);
2559
+ content = (await _readBundleCell(vfs, candidate.path));
2557
2560
  }
2558
2561
  catch {
2559
2562
  continue;
@@ -2582,7 +2585,7 @@ export function addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundl
2582
2585
  * map whether it read the bytes by path or carried them inline. A file that
2583
2586
  * cannot be read is left out; the seam's refusal names the module later.
2584
2587
  */
2585
- export function collectClosureWasmImages(vfs, bundle, unstagedPaths) {
2588
+ export async function collectClosureWasmImages(vfs, bundle, unstagedPaths) {
2586
2589
  const byPath = new Map();
2587
2590
  for (const [path, cell] of Object.entries(bundle)) {
2588
2591
  if (!path.endsWith('.wasm') || !(cell instanceof Uint8Array))
@@ -2594,7 +2597,7 @@ export function collectClosureWasmImages(vfs, bundle, unstagedPaths) {
2594
2597
  continue;
2595
2598
  let bytes;
2596
2599
  try {
2597
- bytes = vfs.readFile(path);
2600
+ bytes = await vfs.readFile(path);
2598
2601
  }
2599
2602
  catch {
2600
2603
  continue;
@@ -2619,7 +2622,7 @@ export function collectClosureWasmImages(vfs, bundle, unstagedPaths) {
2619
2622
  * budget is shared, so ordering by size maximizes the number of misses a
2620
2623
  * fixed number of bytes repairs.
2621
2624
  */
2622
- export function addObservedReads(vfs, observed, bundle, requiredPaths, budgetState) {
2625
+ export async function addObservedReads(vfs, observed, bundle, requiredPaths, budgetState) {
2623
2626
  if (!observed || observed.size === 0)
2624
2627
  return { added: 0 };
2625
2628
  const candidates = [];
@@ -2628,7 +2631,7 @@ export function addObservedReads(vfs, observed, bundle, requiredPaths, budgetSta
2628
2631
  continue;
2629
2632
  let stat;
2630
2633
  try {
2631
- stat = vfs.lstat(path);
2634
+ stat = (await vfs.lstat(path));
2632
2635
  }
2633
2636
  catch {
2634
2637
  continue;
@@ -2646,7 +2649,7 @@ export function addObservedReads(vfs, observed, bundle, requiredPaths, budgetSta
2646
2649
  continue;
2647
2650
  let content;
2648
2651
  try {
2649
- content = _readBundleCell(vfs, candidate.path);
2652
+ content = (await _readBundleCell(vfs, candidate.path));
2650
2653
  }
2651
2654
  catch {
2652
2655
  continue;
@@ -2747,7 +2750,7 @@ function binPackageRootSegment(pkgRoot, path) {
2747
2750
  function binPackageRelativePath(pkgRoot, path) {
2748
2751
  return path.startsWith(pkgRoot + '/') ? path.slice(pkgRoot.length + 1) : path;
2749
2752
  }
2750
- function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
2753
+ async function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
2751
2754
  const root = (cwd || '/home/user').replace(/^\/+/, '').replace(/\/+$/, '') || 'home/user';
2752
2755
  const MAX_PROJECT_FILES = 512;
2753
2756
  const SKIP_DIRS = new Set(['node_modules', '.git', '.nimbus']);
@@ -2758,7 +2761,7 @@ function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
2758
2761
  const dir = queue.shift();
2759
2762
  let entries;
2760
2763
  try {
2761
- entries = vfs.readdir(dir);
2764
+ entries = (await vfs.readdir(dir));
2762
2765
  }
2763
2766
  catch {
2764
2767
  continue;
@@ -2785,11 +2788,11 @@ function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
2785
2788
  // Skip an oversized file before reading it: this walk guesses at what
2786
2789
  // the program might read, and one guess must not spend the budget (or
2787
2790
  // the supervisor's headroom) that every later invocation then carries.
2788
- if (!_bundleAdmits(vfs, child, budgetState, CWD_SNAPSHOT_MAX_FILE_BYTES))
2791
+ if (!(await _bundleAdmits(vfs, child, budgetState, CWD_SNAPSHOT_MAX_FILE_BYTES)))
2789
2792
  continue;
2790
2793
  let content;
2791
2794
  try {
2792
- content = _readBundleCell(vfs, child);
2795
+ content = (await _readBundleCell(vfs, child));
2793
2796
  }
2794
2797
  catch {
2795
2798
  continue;
@@ -2832,7 +2835,7 @@ function addCwdProjectFiles(vfs, cwd, bundle, budgetState) {
2832
2835
  * / openSync / readFile in source are scanned. Entry code is always
2833
2836
  * scanned (it's the user's intent).
2834
2837
  */
2835
- function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2838
+ async function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2836
2839
  let added = 0;
2837
2840
  // Capture absolute-path string literals. The path may not contain
2838
2841
  // the quote char; the surrounding regex strips line/block comments
@@ -2841,7 +2844,7 @@ function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2841
2844
  // excludes spaces, glob chars, template syntax — all dynamic.
2842
2845
  const RX = /(['"`])(\/[A-Za-z0-9._\-\/]{1,510})\1/g;
2843
2846
  const REJECT_PREFIX = /^\/(proc|sys|dev|lib|lib64|boot|root)(\/|$)/;
2844
- function tryAdd(absPath) {
2847
+ async function tryAdd(absPath) {
2845
2848
  if (!absPath || absPath.length < 2 || absPath.length > 512)
2846
2849
  return;
2847
2850
  if (REJECT_PREFIX.test(absPath))
@@ -2854,12 +2857,12 @@ function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2854
2857
  if (budgetState.totalBytes >= VFS_BUNDLE_MAX_BYTES)
2855
2858
  return;
2856
2859
  try {
2857
- if (!vfs.exists(stripped) || vfs.isDirectory(stripped))
2860
+ if (!(await vfs.exists(stripped)) || (await vfs.isDirectory(stripped)))
2858
2861
  return;
2859
- if (!_bundleAdmits(vfs, stripped, budgetState))
2862
+ if (!(await _bundleAdmits(vfs, stripped, budgetState)))
2860
2863
  return;
2861
2864
  // hardening-r5: preserve binary content as Uint8Array.
2862
- const content = _readBundleCell(vfs, stripped);
2865
+ const content = (await _readBundleCell(vfs, stripped));
2863
2866
  const cellLen = _bundleCellLength(content);
2864
2867
  if (budgetState.totalBytes + cellLen > VFS_BUNDLE_MAX_BYTES)
2865
2868
  return;
@@ -2870,7 +2873,7 @@ function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2870
2873
  }
2871
2874
  catch { /* swallow — file may be binary, race-deleted, etc. */ }
2872
2875
  }
2873
- function scanOne(src) {
2876
+ async function scanOne(src) {
2874
2877
  if (!src)
2875
2878
  return;
2876
2879
  // Strip line + block comments so we don't match commented-out reads.
@@ -2883,11 +2886,11 @@ function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2883
2886
  // forbids most). The check on the captured group is cheap.
2884
2887
  if (/[\?\*\[\]\{\}]/.test(literal))
2885
2888
  continue;
2886
- tryAdd(literal);
2889
+ (await tryAdd(literal));
2887
2890
  }
2888
2891
  }
2889
2892
  // Always scan entry code.
2890
- scanOne(entryCode);
2893
+ (await scanOne(entryCode));
2891
2894
  // Optionally scan bundled JS sources too — useful for transitive cases
2892
2895
  // where a require'd module hardcodes an absolute path. Use the same
2893
2896
  // budget-state so we don't blow caps.
@@ -2903,7 +2906,7 @@ function addEntryAbsPathReads(vfs, entryCode, bundle, budgetState) {
2903
2906
  const cell = bundle[k];
2904
2907
  if (typeof cell !== 'string')
2905
2908
  continue;
2906
- scanOne(cell);
2909
+ (await scanOne(cell));
2907
2910
  }
2908
2911
  return { added };
2909
2912
  }
@@ -3110,9 +3113,10 @@ async function transformEsmInBundle(bundle, esbuild, pacer, isolatedTransform) {
3110
3113
  candidates.push(path);
3111
3114
  }
3112
3115
  for (const path of candidates) {
3113
- const src = bundle[path];
3114
- if (typeof src !== 'string')
3116
+ const original = bundle[path];
3117
+ if (typeof original !== 'string')
3115
3118
  continue;
3119
+ const src = bundleTypescriptLoader(path) === null ? rewriteProvidedCommonJsModules(original) : original;
3116
3120
  // A TypeScript source keeps its bytes; its emit lands beside it.
3117
3121
  const target = bundleTypescriptLoader(path) === null ? path : compiledCellKey(path);
3118
3122
  // esbuild-wasm runs inside this isolate, so a transform is computation
@@ -3230,9 +3234,10 @@ export async function buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbui
3230
3234
  async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bundleProfile = DEFAULT_FACET_BUNDLE_PROFILE, observedReads, pacer, isolatedTransform, maxBundleBytes = VFS_BUNDLE_MAX_BYTES) {
3231
3235
  // Read the cursor BEFORE the walk: a mutation that lands while the bundle
3232
3236
  // is being assembled must be reported as invalidated, not silently missed.
3233
- const cursor = { epoch: vfs.epoch, rev: vfs.revision() };
3237
+ const admitted = await vfs.authority.acquire(null, 0);
3238
+ const cursor = { epoch: admitted.epoch, rev: admitted.rev };
3234
3239
  // 1. Static reachable-set walk from entry.
3235
- const prefetch = prefetchForRequire(vfs, entryCode || '', cwd, scriptPath, maxBundleBytes);
3240
+ const prefetch = (await prefetchForRequire(vfs, entryCode || '', cwd, scriptPath, maxBundleBytes));
3236
3241
  if ('kind' in prefetch) {
3237
3242
  // A required closure larger than the bound can never launch as a
3238
3243
  // snapshot. Surface it as the process's own failure rather than a
@@ -3262,14 +3267,14 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3262
3267
  // admitted first, ahead of every guess, and they join the required set
3263
3268
  // rather than the evictable one, because a file evicted here misses
3264
3269
  // again on the next run and the loop never closes.
3265
- const observedAdd = addObservedReads(vfs, observedReads, bundle, requiredPaths, budgetState);
3270
+ const observedAdd = (await addObservedReads(vfs, observedReads, bundle, requiredPaths, budgetState));
3266
3271
  void observedAdd;
3267
3272
  await paceAfterPass();
3268
3273
  // 2. Greedy oversample — every installed pkg's pkg.json + main.
3269
3274
  // Catches dynamic-require / `bindings()` / plugin-loader cases the
3270
3275
  // regex prefetch misses. Its budget is independent from the complete
3271
3276
  // static require closure, which is correctness-critical.
3272
- const greedy = greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPaths);
3277
+ const greedy = (await greedyAddMainEntries(vfs, cwd, bundle, budgetState, requiredPaths));
3273
3278
  await paceAfterPass();
3274
3279
  // 2.25 X.5-Z3: static-readFileSync asset prefetch. Scans every
3275
3280
  // bundle .js/.mjs/.cjs source for the canonical jsdom shape:
@@ -3280,7 +3285,7 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3280
3285
  // `default-stylesheet.css` (and similar runtime asset reads in
3281
3286
  // tldts, parse5, lookup-table packages, mime-db, etc.) ENOENT
3282
3287
  // at facet runtime even though the file is on VFS-disk + in
3283
- const assetAdd = addStaticReadFileAssets(vfs, cwd, bundle, budgetState);
3288
+ const assetAdd = (await addStaticReadFileAssets(vfs, cwd, bundle, budgetState));
3284
3289
  void assetAdd;
3285
3290
  await paceAfterPass();
3286
3291
  // 2.27 X.5-U: dotfile + SWC-shape readFileSync sentinel prefetch.
@@ -3290,7 +3295,7 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3290
3295
  // pattern AND filenames outside the Z3 ASSET_EXT whitelist
3291
3296
  // (dotfiles, no-extension sentinels, "digest/hash/version/sha/md5"
3292
3297
  // shapes). Motivating case: ts-jest's `.ts-jest-digest`. See
3293
- const dotAdd = addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetState);
3298
+ const dotAdd = (await addStaticReadFileDotfilesAndCompiled(vfs, cwd, bundle, budgetState));
3294
3299
  void dotAdd;
3295
3300
  await paceAfterPass();
3296
3301
  // 2.30 G3 (runtime-pkg wave): bin-target sibling oversample. Pulls
@@ -3301,14 +3306,14 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3301
3306
  // catches custom extensions (.cow, .pem, .ttf, .wasm bundled
3302
3307
  // as data, etc.) without needing a per-pkg whitelist.
3303
3308
  // No-op when entry isn't inside node_modules.
3304
- const binSiblingAdd = addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundleProfile);
3309
+ const binSiblingAdd = (await addBinTargetSiblings(vfs, scriptPath, bundle, budgetState, bundleProfile));
3305
3310
  await paceAfterPass();
3306
3311
  // 2.34 project-data snapshot: sync Node fs cannot await the
3307
3312
  // supervisor. Include a bounded snapshot of the current working tree
3308
3313
  // for common relative project-file reads while skipping dependency
3309
3314
  // and Nimbus cache directories. Async fs still uses live supervisor
3310
3315
  // reads and child-process staleness fallback.
3311
- const cwdProjectAdd = addCwdProjectFiles(vfs, cwd, bundle, budgetState);
3316
+ const cwdProjectAdd = (await addCwdProjectFiles(vfs, cwd, bundle, budgetState));
3312
3317
  void cwdProjectAdd;
3313
3318
  await paceAfterPass();
3314
3319
  // 2.35 shell compatibility: absolute-path readFileSync scanner.
@@ -3335,7 +3340,7 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3335
3340
  // - Byte/file budget guards identical to other passes.
3336
3341
  // - Skip paths under known-untrusted prefixes (`/proc`, `/sys`,
3337
3342
  // `/dev` — we don't have these mounts; they'd never resolve).
3338
- const absScanAdd = addEntryAbsPathReads(vfs, entryCode || '', bundle, budgetState);
3343
+ const absScanAdd = (await addEntryAbsPathReads(vfs, entryCode || '', bundle, budgetState));
3339
3344
  void absScanAdd;
3340
3345
  await paceAfterPass();
3341
3346
  // 2.5 W3.5 Fix B: ESM→CJS transform pass. Walks `bundle`, sniffs each
@@ -3370,11 +3375,21 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3370
3375
  // treatment so users see WHY the ESM file couldn't be transformed.
3371
3376
  _markBundleEsmAsFailed(bundle, 'esbuild service not initialized (likely lazy-init failure)');
3372
3377
  }
3378
+ for (const path of Object.keys(bundle)) {
3379
+ if (compiledCellPath(path) === null && (!isBundleModuleCandidate(path) || bundleTypescriptLoader(path) !== null))
3380
+ continue;
3381
+ const source = bundle[path];
3382
+ if (typeof source !== 'string')
3383
+ continue;
3384
+ await pacer?.spend(source.length);
3385
+ bundle[path] = rewriteProvidedCommonJsModules(source);
3386
+ }
3387
+ await paceAfterPass();
3373
3388
  // 3. Manifest pass — UNCHANGED from W2.5b. Decouples directory shape
3374
3389
  // from content cap so fs.readdirSync remains honest even if the
3375
3390
  // content for a given file was capped out.
3376
3391
  await paceAfterPass();
3377
- const manifest = buildManifest(vfs, cwd, scriptPath);
3392
+ const manifest = (await buildManifest(vfs, cwd, scriptPath));
3378
3393
  await paceAfterPass();
3379
3394
  // 4. JSON-encoded-size guard, measured in UTF-8 bytes (not UTF-16 code
3380
3395
  // units) because that is what workerd charges against the per-module
@@ -3407,8 +3422,8 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3407
3422
  }
3408
3423
  }
3409
3424
  const fileCount = Object.keys(bundle).length;
3410
- const metadata = buildVfsMetadata(vfs, manifest, bundle);
3411
- addUnreadableDenialCells(vfs, bundle, metadata);
3425
+ const metadata = (await buildVfsMetadata(vfs, manifest, bundle));
3426
+ (await addUnreadableDenialCells(vfs, bundle, metadata));
3412
3427
  await paceAfterPass();
3413
3428
  // Denial cells land after the eviction pass, so account for them before
3414
3429
  // deciding where the bundle has to live.
@@ -3417,7 +3432,7 @@ async function _buildPrefetchBundle(vfs, scriptPath, cwd, entryCode, esbuild, bu
3417
3432
  const bundleSideModulesRequired = size.bytes > BUNDLE_MAX_ENCODED_BYTES;
3418
3433
  // Suppress lint: `greedy.added` is observed only via diagnostics.
3419
3434
  void greedy;
3420
- const wasmImages = collectClosureWasmImages(vfs, bundle, binSiblingAdd.wasmPaths);
3435
+ const wasmImages = (await collectClosureWasmImages(vfs, bundle, binSiblingAdd.wasmPaths));
3421
3436
  return {
3422
3437
  bundle,
3423
3438
  manifest,
@@ -3460,6 +3475,7 @@ export class FacetManager {
3460
3475
  processes;
3461
3476
  portRegistry;
3462
3477
  vfs = null;
3478
+ filesystem = null;
3463
3479
  hooks;
3464
3480
  /**
3465
3481
  * The resident-process scheduler (loaders/process-fabric.ts). Every
@@ -3496,6 +3512,8 @@ export class FacetManager {
3496
3512
  * journal recovery rides the first pump.
3497
3513
  */
3498
3514
  launchPump;
3515
+ launchTasks = new Set();
3516
+ launchesClosed = false;
3499
3517
  // attach-pid → serve-pid: the resident serve facet a bare-`opencode` dual
3500
3518
  // spawn created as an OS-child of the attach TUI. When the attach process
3501
3519
  // exits (reported / killed), its serve facet is torn down with it.
@@ -3599,7 +3617,7 @@ export class FacetManager {
3599
3617
  // Rooted on waitUntil: the hook fires synchronously inside whatever turn
3600
3618
  // ended the process, and the delete must not be a floating promise there.
3601
3619
  this.processes.setOnTerminal((pid) => {
3602
- this.ctx.waitUntil(this._onResidentTerminal(pid));
3620
+ this.ctx.waitUntil(this.trackLaunchTask(this._onResidentTerminal(pid)));
3603
3621
  });
3604
3622
  }
3605
3623
  /**
@@ -3619,7 +3637,7 @@ export class FacetManager {
3619
3637
  const key = `${FENCED_WORK_KEY_PREFIX}${pid}`;
3620
3638
  const row = (await this.launchJournal.rows()).get(key);
3621
3639
  const crashed = entry?.state === 'exited' && (entry.exitCode ?? 0) !== 0;
3622
- if (row === undefined || row.restart !== 'on-failure' || !crashed) {
3640
+ if (this.launchesClosed || row === undefined || row.restart !== 'on-failure' || !crashed) {
3623
3641
  await this.launchJournal.release(pid);
3624
3642
  return;
3625
3643
  }
@@ -3693,7 +3711,10 @@ export class FacetManager {
3693
3711
  });
3694
3712
  return next;
3695
3713
  }
3696
- setVfs(vfs) { this.vfs = vfs; }
3714
+ /** The authority is the caller's: a session composes exactly one, and the
3715
+ * manager credentials its processes through that one rather than a second
3716
+ * authority over the same disk. */
3717
+ setVfs(vfs, filesystem) { this.vfs = vfs; this.filesystem = filesystem; }
3697
3718
  /**
3698
3719
  * The env/ctx pair every loader-backed runtime builds its facet pools
3699
3720
  * from. A pool is constructed from exactly these two, so the manager
@@ -3793,15 +3814,17 @@ export class FacetManager {
3793
3814
  * be read is left out; the program's compile then meets the seam's own
3794
3815
  * refusal, which names the module.
3795
3816
  */
3796
- _wasmModulesByValue(entry, wasmImports) {
3817
+ async _wasmModulesByValue(entry, wasmImports) {
3797
3818
  const modules = {};
3798
3819
  if (!this.vfs || wasmImports.length === 0)
3799
3820
  return modules;
3800
- const vfs = this.vfs.as(entry.cred);
3821
+ if (!this.filesystem)
3822
+ throw new Error('Process filesystem authority is not initialized');
3823
+ const vfs = new ExecutionFs(this.filesystem.bind({ pid: entry.pid, cred: entry.cred }));
3801
3824
  for (const image of wasmImports) {
3802
3825
  let bytes;
3803
3826
  try {
3804
- bytes = vfs.readFile(stripLeadingSlashes(image.vfsPath));
3827
+ bytes = (await vfs.readFile(stripLeadingSlashes(image.vfsPath)));
3805
3828
  }
3806
3829
  catch {
3807
3830
  continue;
@@ -3824,12 +3847,14 @@ export class FacetManager {
3824
3847
  if (!this.esbuild)
3825
3848
  this.esbuild = new EsbuildService(this.vfs.as(CRED_KERNEL));
3826
3849
  this.imageStore.ensureDir();
3827
- const vfs = this.vfs.as(entry.cred);
3850
+ if (!this.filesystem)
3851
+ throw new Error('Process filesystem authority is not initialized');
3852
+ const vfs = new ExecutionFs(this.filesystem.bind({ pid: entry.pid, cred: entry.cred }));
3828
3853
  const { cred } = entry;
3829
3854
  const profile = spec.bundleProfile ?? DEFAULT_FACET_BUNDLE_PROFILE;
3830
3855
  const credKey = `${cred.uid}:${cred.gid}:${cred.groups.join(',')}`;
3831
3856
  const key = `${profile}\x00${credKey}\x00${spec.cwd}\x00${spec.scriptPath ?? ''}\x00${_fnv1a(spec.entryCode)}`;
3832
- const revision = vfs.revision();
3857
+ const revision = (await vfs.revision());
3833
3858
  // An entry built at an older revision can never be SERVED again — the
3834
3859
  // lookup below requires an exact match — so from the first write after it
3835
3860
  // was admitted it is retained garbage, held in the isolate that is
@@ -4244,7 +4269,7 @@ export class FacetManager {
4244
4269
  // images ride by value: read here, inside the scope that holds
4245
4270
  // the map, and compiled by the loader like the sqlite sidecar.
4246
4271
  const wasmImports = facetWasmImports([], vfsState.wasmImages ?? []);
4247
- const wasmModules = this._wasmModulesByValue(entry, wasmImports);
4272
+ const wasmModules = (await this._wasmModulesByValue(entry, wasmImports));
4248
4273
  const generatedWorker = await generateEntrypointCode(code, vfsState, usesSqlite, shims, wasmImports);
4249
4274
  if (diagSink) {
4250
4275
  diagSink.moduleMapBytes = _encodedSourceBytes(generatedWorker.code);
@@ -4409,7 +4434,7 @@ export class FacetManager {
4409
4434
  // other writes flush live through the SUPERVISOR RPC bridge.
4410
4435
  if (this.vfs)
4411
4436
  this.imageStore.ensureDir();
4412
- const processVfs = this.vfs?.as(entry.cred);
4437
+ const processVfs = this.filesystem ? new ExecutionFs(this.filesystem.bind({ pid: entry.pid, cred: entry.cred })) : null;
4413
4438
  const vfsState = processVfs
4414
4439
  ? await buildPrefetchBundle(processVfs, undefined, opts.cwd, '', this.esbuild || undefined, DEFAULT_FACET_BUNDLE_PROFILE, undefined, undefined, this.hooks.transformLargeEsm)
4415
4440
  : { bundle: {}, manifest: {}, metadata: {}, reachableCount: 0, truncated: false };
@@ -4718,6 +4743,18 @@ export class FacetManager {
4718
4743
  pumpResidentLaunches() {
4719
4744
  return this.launchPump.pump();
4720
4745
  }
4746
+ trackLaunchTask(task) {
4747
+ this.launchTasks.add(task);
4748
+ void task.then(() => this.launchTasks.delete(task), () => this.launchTasks.delete(task));
4749
+ return task;
4750
+ }
4751
+ async closeLaunches() {
4752
+ this.launchesClosed = true;
4753
+ this.launchPump.close();
4754
+ while (this.launchTasks.size > 0)
4755
+ await Promise.allSettled([...this.launchTasks]);
4756
+ await Promise.all(this.rowAmendments.values());
4757
+ }
4721
4758
  /** Whether any launch is suspended waiting for a turn. */
4722
4759
  get hasPendingLaunchTurns() {
4723
4760
  return this.launchPump.hasPending;
@@ -4987,7 +5024,12 @@ export class FacetManager {
4987
5024
  * terminal WebSocket needs to survive a launch, and what no amount of making
4988
5025
  * the launch faster would have given it.
4989
5026
  */
4990
- async _runResidentLaunch(entry, code, command, opts, attempt) {
5027
+ _runResidentLaunch(entry, code, command, opts, attempt) {
5028
+ if (this.launchesClosed)
5029
+ return Promise.reject(new Error('Launch scheduler is closed'));
5030
+ return this.trackLaunchTask(this._runResidentLaunchBody(entry, code, command, opts, attempt));
5031
+ }
5032
+ async _runResidentLaunchBody(entry, code, command, opts, attempt) {
4991
5033
  const cwd = opts.cwd || '/home/user';
4992
5034
  const pacer = this._launchPacer(entry.pid);
4993
5035
  // Journalled before the first byte of work. A launch that FAILS deletes