@rivet-dev/agentos-core 0.0.0-feat-on-limit-warning.62a2bc2 → 0.0.0-main.ab2ce7c

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 (100) hide show
  1. package/README.md +4 -7
  2. package/dist/agent-os.d.ts +116 -46
  3. package/dist/agent-os.js +740 -541
  4. package/dist/agentos-package.d.ts +29 -0
  5. package/dist/agentos-package.js +88 -0
  6. package/dist/base-filesystem.d.ts +2 -15
  7. package/dist/base-filesystem.js +23 -171
  8. package/dist/cron/types.d.ts +1 -1
  9. package/dist/default-software.d.ts +8 -0
  10. package/dist/default-software.js +10 -0
  11. package/dist/generated/AcpLimitsConfig.d.ts +4 -0
  12. package/dist/generated/AcpLimitsConfig.js +2 -0
  13. package/dist/generated/CreateVmConfig.d.ts +26 -0
  14. package/dist/generated/CreateVmConfig.js +1 -0
  15. package/dist/generated/FsPermissionRule.d.ts +6 -0
  16. package/dist/generated/FsPermissionRule.js +1 -0
  17. package/dist/generated/FsPermissionRuleSet.d.ts +6 -0
  18. package/dist/generated/FsPermissionRuleSet.js +1 -0
  19. package/dist/generated/FsPermissionScope.d.ts +3 -0
  20. package/dist/generated/FsPermissionScope.js +1 -0
  21. package/dist/generated/HttpLimitsConfig.d.ts +3 -0
  22. package/dist/generated/HttpLimitsConfig.js +2 -0
  23. package/dist/generated/JsModuleResolution.d.ts +1 -0
  24. package/dist/generated/JsModuleResolution.js +2 -0
  25. package/dist/generated/JsRuntimeConfig.d.ts +31 -0
  26. package/dist/generated/JsRuntimeConfig.js +1 -0
  27. package/dist/generated/JsRuntimeLimitsConfig.d.ts +11 -0
  28. package/dist/generated/JsRuntimeLimitsConfig.js +2 -0
  29. package/dist/generated/JsRuntimePlatform.d.ts +1 -0
  30. package/dist/generated/JsRuntimePlatform.js +2 -0
  31. package/dist/generated/MountPluginDescriptor.d.ts +4 -0
  32. package/dist/generated/MountPluginDescriptor.js +2 -0
  33. package/dist/generated/NativeRootFilesystemConfig.d.ts +5 -0
  34. package/dist/generated/NativeRootFilesystemConfig.js +1 -0
  35. package/dist/generated/PatternPermissionRule.d.ts +6 -0
  36. package/dist/generated/PatternPermissionRule.js +1 -0
  37. package/dist/generated/PatternPermissionRuleSet.d.ts +6 -0
  38. package/dist/generated/PatternPermissionRuleSet.js +1 -0
  39. package/dist/generated/PatternPermissionScope.d.ts +3 -0
  40. package/dist/generated/PatternPermissionScope.js +1 -0
  41. package/dist/generated/PermissionMode.d.ts +1 -0
  42. package/dist/generated/PermissionMode.js +2 -0
  43. package/dist/generated/PermissionsPolicy.d.ts +10 -0
  44. package/dist/generated/PermissionsPolicy.js +1 -0
  45. package/dist/generated/PluginLimitsConfig.d.ts +4 -0
  46. package/dist/generated/PluginLimitsConfig.js +2 -0
  47. package/dist/generated/PythonLimitsConfig.d.ts +6 -0
  48. package/dist/generated/PythonLimitsConfig.js +2 -0
  49. package/dist/generated/ResourceLimitsConfig.d.ts +24 -0
  50. package/dist/generated/ResourceLimitsConfig.js +2 -0
  51. package/dist/generated/RootFilesystemConfig.d.ts +9 -0
  52. package/dist/generated/RootFilesystemConfig.js +1 -0
  53. package/dist/generated/RootFilesystemEntry.d.ts +13 -0
  54. package/dist/generated/RootFilesystemEntry.js +1 -0
  55. package/dist/generated/RootFilesystemEntryEncoding.d.ts +1 -0
  56. package/dist/generated/RootFilesystemEntryEncoding.js +2 -0
  57. package/dist/generated/RootFilesystemEntryKind.d.ts +1 -0
  58. package/dist/generated/RootFilesystemEntryKind.js +2 -0
  59. package/dist/generated/RootFilesystemLowerDescriptor.d.ts +7 -0
  60. package/dist/generated/RootFilesystemLowerDescriptor.js +1 -0
  61. package/dist/generated/RootFilesystemMode.d.ts +1 -0
  62. package/dist/generated/RootFilesystemMode.js +2 -0
  63. package/dist/generated/ToolLimitsConfig.d.ts +10 -0
  64. package/dist/generated/ToolLimitsConfig.js +2 -0
  65. package/dist/generated/VmDnsConfig.d.ts +6 -0
  66. package/dist/generated/VmDnsConfig.js +2 -0
  67. package/dist/generated/VmLimitsConfig.d.ts +18 -0
  68. package/dist/generated/VmLimitsConfig.js +1 -0
  69. package/dist/generated/VmListenPolicyConfig.d.ts +5 -0
  70. package/dist/generated/VmListenPolicyConfig.js +2 -0
  71. package/dist/generated/WasmLimitsConfig.d.ts +7 -0
  72. package/dist/generated/WasmLimitsConfig.js +2 -0
  73. package/dist/host-dir-mount.d.ts +1 -1
  74. package/dist/host-tools.js +9 -0
  75. package/dist/index.d.ts +2 -1
  76. package/dist/index.js +1 -1
  77. package/dist/layers.d.ts +2 -2
  78. package/dist/layers.js +19 -10
  79. package/dist/options-schema.d.ts +19 -4
  80. package/dist/options-schema.js +30 -22
  81. package/dist/packages.d.ts +17 -116
  82. package/dist/packages.js +35 -322
  83. package/dist/runtime-compat.d.ts +22 -9
  84. package/dist/runtime-compat.js +126 -141
  85. package/dist/runtime.d.ts +32 -5
  86. package/dist/sandbox.d.ts +112 -0
  87. package/dist/sandbox.js +264 -0
  88. package/dist/sidecar/agentos-protocol.d.ts +88 -1
  89. package/dist/sidecar/agentos-protocol.js +134 -18
  90. package/dist/sidecar/native-process-client.d.ts +6 -3
  91. package/dist/sidecar/native-process-client.js +5 -3
  92. package/dist/sidecar/permissions.d.ts +1 -1
  93. package/dist/sidecar/permissions.js +3 -3
  94. package/dist/sidecar/rpc-client.d.ts +62 -4
  95. package/dist/sidecar/rpc-client.js +339 -85
  96. package/dist/types.d.ts +10 -3
  97. package/package.json +36 -32
  98. package/dist/agents.d.ts +0 -63
  99. package/dist/agents.js +0 -42
  100. package/fixtures/AGENTOS_SYSTEM_PROMPT.md +0 -21
@@ -17,8 +17,13 @@ const S_IFREG = 0o100000;
17
17
  const S_IFDIR = 0o040000;
18
18
  const S_IFLNK = 0o120000;
19
19
  const MAX_SYMLINK_DEPTH = 40;
20
- const KERNEL_COMMAND_STUB = "#!/bin/sh\n# kernel command stub\n";
21
- const NODE_RUNTIME_BOOTSTRAP_COMMANDS = ["node", "npm", "npx"];
20
+ const NODE_RUNTIME_BOOTSTRAP_COMMANDS = [
21
+ "node",
22
+ "npm",
23
+ "npx",
24
+ "python",
25
+ "python3",
26
+ ];
22
27
  const KERNEL_POSIX_BOOTSTRAP_DIRS = [
23
28
  "/dev",
24
29
  "/proc",
@@ -119,7 +124,7 @@ export class InMemoryFileSystem {
119
124
  throw errnoError("ENOENT", `open '${targetPath}'`);
120
125
  }
121
126
  entry.atimeMs = Date.now();
122
- return entry.data;
127
+ return new Uint8Array(entry.data);
123
128
  }
124
129
  async readTextFile(targetPath) {
125
130
  return new TextDecoder().decode(await this.readFile(targetPath));
@@ -152,7 +157,9 @@ export class InMemoryFileSystem {
152
157
  async writeFile(targetPath, content) {
153
158
  const normalized = normalizePath(targetPath);
154
159
  await this.mkdir(dirnameVirtual(normalized), { recursive: true });
155
- const data = typeof content === "string" ? new TextEncoder().encode(content) : content;
160
+ const data = typeof content === "string"
161
+ ? new TextEncoder().encode(content)
162
+ : new Uint8Array(content);
156
163
  const existing = this.entries.get(normalized);
157
164
  if (existing?.type === "file") {
158
165
  existing.data = data;
@@ -212,7 +219,7 @@ export class InMemoryFileSystem {
212
219
  return this.toStat(entry);
213
220
  }
214
221
  async removeFile(targetPath) {
215
- const resolved = this.resolvePath(targetPath);
222
+ const resolved = normalizePath(targetPath);
216
223
  const entry = this.entries.get(resolved);
217
224
  if (!entry || entry.type === "dir") {
218
225
  throw errnoError("ENOENT", `unlink '${targetPath}'`);
@@ -374,7 +381,7 @@ export class InMemoryFileSystem {
374
381
  const nextSize = Math.max(entry.data.length, offset + data.length);
375
382
  const updated = new Uint8Array(nextSize);
376
383
  updated.set(entry.data);
377
- updated.set(data, offset);
384
+ updated.set(new Uint8Array(data), offset);
378
385
  entry.data = updated;
379
386
  entry.mtimeMs = Date.now();
380
387
  entry.ctimeMs = Date.now();
@@ -730,6 +737,7 @@ export function createNodeDriver(options = {}) {
730
737
  network: options.networkAdapter,
731
738
  commandExecutor: options.commandExecutor,
732
739
  permissions: options.permissions,
740
+ mounts: options.mounts ?? [],
733
741
  runtime: {
734
742
  process: options.processConfig ?? {},
735
743
  os: options.osConfig ?? {},
@@ -817,7 +825,6 @@ export const WASMVM_COMMANDS = Object.freeze([
817
825
  "sqlite3",
818
826
  "curl",
819
827
  "wget",
820
- "make",
821
828
  "git",
822
829
  "git-remote-http",
823
830
  "git-remote-https",
@@ -916,7 +923,6 @@ export const DEFAULT_FIRST_PARTY_TIERS = Object.freeze({
916
923
  nice: "full",
917
924
  nohup: "full",
918
925
  stdbuf: "full",
919
- make: "full",
920
926
  codex: "full",
921
927
  "codex-exec": "full",
922
928
  git: "full",
@@ -1016,7 +1022,7 @@ function isWasmBinaryFile(filePath) {
1016
1022
  function discoverWasmCommandEntries(commandDirs) {
1017
1023
  const discovered = [];
1018
1024
  const seen = new Set();
1019
- commandDirs.forEach((commandDir, dirOffset) => {
1025
+ for (const commandDir of commandDirs) {
1020
1026
  let entries;
1021
1027
  try {
1022
1028
  entries = fsSync
@@ -1024,7 +1030,7 @@ function discoverWasmCommandEntries(commandDirs) {
1024
1030
  .sort((left, right) => left.localeCompare(right));
1025
1031
  }
1026
1032
  catch {
1027
- return;
1033
+ continue;
1028
1034
  }
1029
1035
  for (const entry of entries) {
1030
1036
  if (entry.startsWith("."))
@@ -1037,7 +1043,6 @@ function discoverWasmCommandEntries(commandDirs) {
1037
1043
  discovered.push({
1038
1044
  name: entry,
1039
1045
  hostPath: fullPath,
1040
- dirOffset,
1041
1046
  });
1042
1047
  continue;
1043
1048
  }
@@ -1048,13 +1053,12 @@ function discoverWasmCommandEntries(commandDirs) {
1048
1053
  discovered.push({
1049
1054
  name: entry,
1050
1055
  hostPath: fullPath,
1051
- dirOffset,
1052
1056
  });
1053
1057
  }
1054
1058
  }
1055
1059
  catch { }
1056
1060
  }
1057
- });
1061
+ }
1058
1062
  return discovered;
1059
1063
  }
1060
1064
  class WasmVmRuntimeDescriptor {
@@ -1064,7 +1068,6 @@ class WasmVmRuntimeDescriptor {
1064
1068
  commandDirs;
1065
1069
  _commandPaths = new Map();
1066
1070
  _moduleCache = new Map();
1067
- commandDirOffsets = new Map();
1068
1071
  constructor(options) {
1069
1072
  this.commandDirs =
1070
1073
  options.commandDirs && options.commandDirs.length > 0
@@ -1095,17 +1098,6 @@ class WasmVmRuntimeDescriptor {
1095
1098
  this.refreshDiscovery();
1096
1099
  return this._commandPaths.has(normalized);
1097
1100
  }
1098
- getGuestCommandPaths(startIndex) {
1099
- const guestPaths = new Map();
1100
- for (const [name] of this._commandPaths) {
1101
- const dirOffset = this.commandDirOffsets.get(name);
1102
- if (dirOffset === undefined) {
1103
- continue;
1104
- }
1105
- guestPaths.set(name, `/__secure_exec/commands/${startIndex + dirOffset}/${name}`);
1106
- }
1107
- return guestPaths;
1108
- }
1109
1101
  recordModuleExecution(command) {
1110
1102
  const normalized = normalizeCommandLookup(command);
1111
1103
  if (this._commandPaths.has(normalized) ||
@@ -1121,11 +1113,9 @@ class WasmVmRuntimeDescriptor {
1121
1113
  const discovered = discoverWasmCommandEntries(this.commandDirs);
1122
1114
  this.commands.length = 0;
1123
1115
  this._commandPaths.clear();
1124
- this.commandDirOffsets.clear();
1125
1116
  for (const entry of discovered) {
1126
1117
  this.commands.push(entry.name);
1127
1118
  this._commandPaths.set(entry.name, entry.hostPath);
1128
- this.commandDirOffsets.set(entry.name, entry.dirOffset);
1129
1119
  }
1130
1120
  }
1131
1121
  }
@@ -1191,8 +1181,8 @@ function ensureNativeSidecarBinary() {
1191
1181
  function rootEntryExecutable(kind, mode) {
1192
1182
  return kind === "file" && (mode & 0o111) !== 0;
1193
1183
  }
1194
- function createBootstrapEntries(commandNames) {
1195
- const entries = [
1184
+ function createBootstrapEntries() {
1185
+ return [
1196
1186
  {
1197
1187
  path: "/",
1198
1188
  kind: "directory",
@@ -1220,19 +1210,6 @@ function createBootstrapEntries(commandNames) {
1220
1210
  executable: false,
1221
1211
  },
1222
1212
  ];
1223
- for (const command of [...new Set(commandNames)].sort((left, right) => left.localeCompare(right))) {
1224
- entries.push({
1225
- path: `/bin/${command}`,
1226
- kind: "file",
1227
- mode: 0o755,
1228
- uid: 0,
1229
- gid: 0,
1230
- content: KERNEL_COMMAND_STUB,
1231
- encoding: "utf8",
1232
- executable: true,
1233
- });
1234
- }
1235
- return entries;
1236
1213
  }
1237
1214
  function mergeRootFilesystemEntries(baseEntries, overrideEntries) {
1238
1215
  const merged = new Map();
@@ -1373,23 +1350,6 @@ function planNodeFilesystemPassthroughMounts(filesystem, existingMounts) {
1373
1350
  passthroughDirectories,
1374
1351
  };
1375
1352
  }
1376
- function collectGuestCommandPaths(commandDirs, startIndex = 0) {
1377
- const guestPaths = new Map();
1378
- for (const entry of discoverWasmCommandEntries(commandDirs)) {
1379
- if (!guestPaths.has(entry.name)) {
1380
- guestPaths.set(entry.name, `/__secure_exec/commands/${startIndex + entry.dirOffset}/${entry.name}`);
1381
- }
1382
- }
1383
- return guestPaths;
1384
- }
1385
- async function ensureCommandStubs(proxy, commands) {
1386
- const rootView = proxy.createRootView();
1387
- for (const command of commands) {
1388
- const stubPath = `/bin/${command}`;
1389
- await rootView.writeFile(stubPath, KERNEL_COMMAND_STUB);
1390
- await rootView.chmod(stubPath, 0o755);
1391
- }
1392
- }
1393
1353
  class DeferredFileSystem {
1394
1354
  getFilesystem;
1395
1355
  constructor(getFilesystem) {
@@ -1607,6 +1567,35 @@ function bindLiveFilesystem(target, getFilesystem) {
1607
1567
  },
1608
1568
  };
1609
1569
  }
1570
+ function serializeLocalCompatMountForSidecar(mount) {
1571
+ return (mount.sidecarMount ??
1572
+ (mount.fs instanceof NodeFileSystem
1573
+ ? serializeMountConfigForSidecar({
1574
+ path: mount.path,
1575
+ readOnly: mount.readOnly,
1576
+ plugin: {
1577
+ id: "host_dir",
1578
+ config: {
1579
+ hostPath: mount.fs.rootPath,
1580
+ readOnly: mount.readOnly,
1581
+ },
1582
+ },
1583
+ })
1584
+ : serializeMountConfigForSidecar({
1585
+ path: mount.path,
1586
+ driver: mount.fs,
1587
+ readOnly: mount.readOnly,
1588
+ })));
1589
+ }
1590
+ function makeLocalCompatMount(options) {
1591
+ const localMount = {
1592
+ path: normalizePath(options.path),
1593
+ fs: options.fs,
1594
+ readOnly: options.readOnly ?? false,
1595
+ };
1596
+ localMount.sidecarMount = serializeLocalCompatMountForSidecar(localMount);
1597
+ return localMount;
1598
+ }
1610
1599
  class NativeKernel {
1611
1600
  options;
1612
1601
  env;
@@ -1628,7 +1617,6 @@ class NativeKernel {
1628
1617
  pendingLocalMounts = [];
1629
1618
  mountedCommandDirs = [];
1630
1619
  mountedRuntimeDrivers = [];
1631
- runtimeDriverCommandDirStarts = new Map();
1632
1620
  loopbackExemptPorts;
1633
1621
  constructor(options) {
1634
1622
  this.options = options;
@@ -1646,11 +1634,11 @@ class NativeKernel {
1646
1634
  };
1647
1635
  this.loopbackExemptPorts = [...(options.loopbackExemptPorts ?? [])];
1648
1636
  for (const mount of options.mounts ?? []) {
1649
- this.pendingLocalMounts.push({
1650
- path: normalizePath(mount.path),
1637
+ this.pendingLocalMounts.push(makeLocalCompatMount({
1638
+ path: mount.path,
1651
1639
  fs: mount.fs,
1652
- readOnly: mount.readOnly ?? false,
1653
- });
1640
+ readOnly: mount.readOnly,
1641
+ }));
1654
1642
  }
1655
1643
  this.vfs = new DeferredFileSystem(() => this.rootFilesystem);
1656
1644
  this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem);
@@ -1658,6 +1646,32 @@ class NativeKernel {
1658
1646
  get zombieTimerCount() {
1659
1647
  return this.proxy?.zombieTimerCount ?? 0;
1660
1648
  }
1649
+ async configureRuntimeCommandStubs(commands, commandDirs = this.mountedCommandDirs) {
1650
+ if (!this.client || !this.session || !this.vm) {
1651
+ throw new Error("kernel is not ready");
1652
+ }
1653
+ const sidecarMounts = commandDirs.map((commandDir, index) => serializeMountConfigForSidecar({
1654
+ path: `/__secure_exec/commands/${index}`,
1655
+ readOnly: true,
1656
+ plugin: {
1657
+ id: "host_dir",
1658
+ config: {
1659
+ hostPath: commandDir,
1660
+ readOnly: true,
1661
+ },
1662
+ },
1663
+ }));
1664
+ const localMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
1665
+ const configuredVm = await this.client.configureVm(this.session, this.vm, {
1666
+ mounts: [...localMounts, ...sidecarMounts],
1667
+ loopbackExemptPorts: this.loopbackExemptPorts,
1668
+ bootstrapCommands: [...new Set(commands)].sort((left, right) => left.localeCompare(right)),
1669
+ });
1670
+ return new Map(configuredVm.projectedCommands.map((command) => [
1671
+ command.name,
1672
+ command.guestPath,
1673
+ ]));
1674
+ }
1661
1675
  async mount(driver) {
1662
1676
  await this.ensureReady();
1663
1677
  if (!this.proxy || !this.client || !this.session || !this.vm) {
@@ -1669,7 +1683,7 @@ class NativeKernel {
1669
1683
  this.commands.set(command, "node");
1670
1684
  }
1671
1685
  this.mountedRuntimeDrivers.push(driver);
1672
- await ensureCommandStubs(this.proxy, driver.commands);
1686
+ await this.configureRuntimeCommandStubs(driver.commands);
1673
1687
  return;
1674
1688
  }
1675
1689
  const commandDirs = driver.commandDirs ?? [];
@@ -1678,53 +1692,17 @@ class NativeKernel {
1678
1692
  this.commands.set(command, "wasmvm");
1679
1693
  }
1680
1694
  this.mountedRuntimeDrivers.push(driver);
1681
- await ensureCommandStubs(this.proxy, driver.commands);
1695
+ await this.configureRuntimeCommandStubs(driver.commands);
1682
1696
  return;
1683
1697
  }
1684
- const startIndex = this.mountedCommandDirs.length;
1685
- const newGuestPaths = driver.getGuestCommandPaths?.(startIndex) ??
1686
- collectGuestCommandPaths(commandDirs, startIndex);
1687
1698
  const allCommandDirs = [...this.mountedCommandDirs, ...commandDirs];
1688
- const sidecarMounts = allCommandDirs.map((commandDir, index) => serializeMountConfigForSidecar({
1689
- path: `/__secure_exec/commands/${index}`,
1690
- readOnly: true,
1691
- plugin: {
1692
- id: "host_dir",
1693
- config: {
1694
- hostPath: commandDir,
1695
- readOnly: true,
1696
- },
1697
- },
1698
- }));
1699
- const localMounts = this.pendingLocalMounts.map((mount) => mount.fs instanceof NodeFileSystem
1700
- ? serializeMountConfigForSidecar({
1701
- path: mount.path,
1702
- readOnly: mount.readOnly,
1703
- plugin: {
1704
- id: "host_dir",
1705
- config: {
1706
- hostPath: mount.fs.rootPath,
1707
- readOnly: mount.readOnly,
1708
- },
1709
- },
1710
- })
1711
- : serializeMountConfigForSidecar({
1712
- path: mount.path,
1713
- driver: mount.fs,
1714
- readOnly: mount.readOnly,
1715
- }));
1716
- await this.client.configureVm(this.session, this.vm, {
1717
- mounts: [...localMounts, ...sidecarMounts],
1718
- loopbackExemptPorts: this.loopbackExemptPorts,
1719
- });
1720
- this.proxy.registerCommandGuestPaths(newGuestPaths);
1699
+ const projectedCommands = await this.configureRuntimeCommandStubs(driver.commands, allCommandDirs);
1700
+ this.proxy.registerCommandGuestPaths(projectedCommands);
1721
1701
  this.mountedCommandDirs.push(...commandDirs);
1722
1702
  this.mountedRuntimeDrivers.push(driver);
1723
- this.runtimeDriverCommandDirStarts.set(driver, startIndex);
1724
- for (const command of newGuestPaths.keys()) {
1703
+ for (const command of projectedCommands.keys()) {
1725
1704
  this.commands.set(command, "wasmvm");
1726
1705
  }
1727
- await ensureCommandStubs(this.proxy, newGuestPaths.keys());
1728
1706
  }
1729
1707
  async dispose() {
1730
1708
  await this.readyPromise?.catch(() => { });
@@ -1785,10 +1763,10 @@ class NativeKernel {
1785
1763
  return {
1786
1764
  pid: proc.pid,
1787
1765
  writeStdin(data) {
1788
- proc.writeStdin(data);
1766
+ return proc.writeStdin(data);
1789
1767
  },
1790
1768
  closeStdin() {
1791
- proc.closeStdin();
1769
+ return proc.closeStdin();
1792
1770
  },
1793
1771
  kill(signal) {
1794
1772
  proc.kill(signal);
@@ -1818,17 +1796,27 @@ class NativeKernel {
1818
1796
  return this.proxy.connectTerminal(options);
1819
1797
  }
1820
1798
  mountFs(mountPath, filesystem, options) {
1799
+ const localMount = makeLocalCompatMount({
1800
+ path: mountPath,
1801
+ fs: filesystem,
1802
+ readOnly: options?.readOnly,
1803
+ });
1804
+ this.pendingLocalMounts.unshift(localMount);
1805
+ this.pendingLocalMounts.sort((left, right) => right.path.length - left.path.length);
1821
1806
  if (!this.proxy) {
1822
- this.pendingLocalMounts.push({
1823
- path: normalizePath(mountPath),
1824
- fs: filesystem,
1825
- readOnly: options?.readOnly ?? false,
1826
- });
1827
1807
  return;
1828
1808
  }
1829
- this.proxy.mountFs(mountPath, filesystem, options);
1809
+ this.proxy.mountFs(mountPath, filesystem, {
1810
+ readOnly: localMount.readOnly,
1811
+ sidecarMount: localMount.sidecarMount,
1812
+ });
1830
1813
  }
1831
1814
  unmountFs(mountPath) {
1815
+ const normalized = normalizePath(mountPath);
1816
+ const pendingIndex = this.pendingLocalMounts.findIndex((mount) => mount.path === normalized);
1817
+ if (pendingIndex >= 0) {
1818
+ this.pendingLocalMounts.splice(pendingIndex, 1);
1819
+ }
1832
1820
  this.proxy?.unmountFs(mountPath);
1833
1821
  }
1834
1822
  async readFile(targetPath) {
@@ -1847,6 +1835,10 @@ class NativeKernel {
1847
1835
  await this.ensureReady();
1848
1836
  return this.proxy.readdir(targetPath);
1849
1837
  }
1838
+ async readdirRecursive(targetPath, options) {
1839
+ await this.ensureReady();
1840
+ return this.proxy.readdirRecursive(targetPath, options);
1841
+ }
1850
1842
  async stat(targetPath) {
1851
1843
  await this.ensureReady();
1852
1844
  return this.proxy.stat(targetPath);
@@ -1863,10 +1855,18 @@ class NativeKernel {
1863
1855
  await this.ensureReady();
1864
1856
  return this.proxy.removeDir(targetPath);
1865
1857
  }
1858
+ async removePath(targetPath, options) {
1859
+ await this.ensureReady();
1860
+ return this.proxy.removePath(targetPath, options);
1861
+ }
1866
1862
  async rename(oldPath, newPath) {
1867
1863
  await this.ensureReady();
1868
1864
  return this.proxy.rename(oldPath, newPath);
1869
1865
  }
1866
+ async movePath(oldPath, newPath) {
1867
+ await this.ensureReady();
1868
+ return this.proxy.movePath(oldPath, newPath);
1869
+ }
1870
1870
  tryResolveMountedCommand(command) {
1871
1871
  const normalized = normalizeCommandLookup(command);
1872
1872
  for (const driver of this.mountedRuntimeDrivers) {
@@ -1874,15 +1874,6 @@ class NativeKernel {
1874
1874
  continue;
1875
1875
  }
1876
1876
  this.commands.set(normalized, driver.kind);
1877
- if (driver.kind === "wasmvm" && this.proxy) {
1878
- const startIndex = this.runtimeDriverCommandDirStarts.get(driver);
1879
- if (startIndex !== undefined) {
1880
- const guestPaths = driver.getGuestCommandPaths?.(startIndex);
1881
- if (guestPaths?.has(normalized)) {
1882
- this.proxy.registerCommandGuestPaths(new Map([[normalized, guestPaths.get(normalized)]]));
1883
- }
1884
- }
1885
- }
1886
1877
  return true;
1887
1878
  }
1888
1879
  return false;
@@ -1917,7 +1908,7 @@ class NativeKernel {
1917
1908
  lowers: [
1918
1909
  {
1919
1910
  kind: "snapshot",
1920
- entries: rootFilesystemEntriesForConfig(mergeRootFilesystemEntries(createBootstrapEntries([...NODE_RUNTIME_BOOTSTRAP_COMMANDS]), snapshotEntries)),
1911
+ entries: rootFilesystemEntriesForConfig(mergeRootFilesystemEntries(createBootstrapEntries(), snapshotEntries)),
1921
1912
  },
1922
1913
  ],
1923
1914
  bootstrapEntries: [],
@@ -1936,6 +1927,7 @@ class NativeKernel {
1936
1927
  ? serializePermissionsForSidecar(bootstrapPermissions)
1937
1928
  : undefined,
1938
1929
  loopbackExemptPorts: this.loopbackExemptPorts,
1930
+ bootstrapCommands: [...NODE_RUNTIME_BOOTSTRAP_COMMANDS],
1939
1931
  };
1940
1932
  const vm = await client.createVm(session, {
1941
1933
  runtime: "java_script",
@@ -1955,33 +1947,23 @@ class NativeKernel {
1955
1947
  await materializeSnapshotEntriesIntoVm(client, session, vm, snapshotEntries);
1956
1948
  }
1957
1949
  if (rootPassthroughPlan.mounts.length > 0) {
1958
- this.pendingLocalMounts.push(...rootPassthroughPlan.mounts);
1950
+ this.pendingLocalMounts.push(...rootPassthroughPlan.mounts.map((mount) => makeLocalCompatMount({
1951
+ path: mount.path,
1952
+ fs: mount.fs,
1953
+ readOnly: mount.readOnly,
1954
+ })));
1959
1955
  }
1960
1956
  if (this.pendingLocalMounts.length > 0 ||
1961
1957
  this.loopbackExemptPorts.length > 0 ||
1962
1958
  requestedPermissions) {
1959
+ const sidecarMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
1963
1960
  await client.configureVm(session, vm, {
1964
- mounts: this.pendingLocalMounts.map((mount) => mount.fs instanceof NodeFileSystem
1965
- ? serializeMountConfigForSidecar({
1966
- path: mount.path,
1967
- readOnly: mount.readOnly,
1968
- plugin: {
1969
- id: "host_dir",
1970
- config: {
1971
- hostPath: mount.fs.rootPath,
1972
- readOnly: mount.readOnly,
1973
- },
1974
- },
1975
- })
1976
- : serializeMountConfigForSidecar({
1977
- path: mount.path,
1978
- driver: mount.fs,
1979
- readOnly: mount.readOnly,
1980
- })),
1961
+ mounts: sidecarMounts,
1981
1962
  permissions: requestedPermissions,
1982
1963
  loopbackExemptPorts: this.loopbackExemptPorts,
1983
1964
  });
1984
1965
  }
1966
+ const configuredSidecarMounts = this.pendingLocalMounts.map((mount) => serializeLocalCompatMountForSidecar(mount));
1985
1967
  const proxy = new NativeSidecarKernelProxy({
1986
1968
  client,
1987
1969
  session,
@@ -1990,6 +1972,9 @@ class NativeKernel {
1990
1972
  cwd: this.cwd,
1991
1973
  defaultExecCwd: this.options.cwd === undefined ? "/workspace" : this.cwd,
1992
1974
  localMounts: this.pendingLocalMounts,
1975
+ sidecarMounts: configuredSidecarMounts,
1976
+ permissions: requestedPermissions,
1977
+ loopbackExemptPorts: this.loopbackExemptPorts,
1993
1978
  commandGuestPaths: new Map(),
1994
1979
  onWasmCommandResolved: (command) => {
1995
1980
  this.recordModuleExecution(command);
package/dist/runtime.d.ts CHANGED
@@ -76,7 +76,7 @@ export type NetworkPermissions = PermissionMode | RulePermissions<PatternPermiss
76
76
  export type ChildProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
77
77
  export type ProcessPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
78
78
  export type EnvPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
79
- export type ToolPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
79
+ export type BindingPermissions = PermissionMode | RulePermissions<PatternPermissionRule>;
80
80
  export interface ProcessInfo {
81
81
  pid: number;
82
82
  ppid: number;
@@ -93,15 +93,15 @@ export interface ProcessInfo {
93
93
  }
94
94
  export interface ManagedProcess {
95
95
  pid: number;
96
- writeStdin(data: Uint8Array | string): void;
97
- closeStdin(): void;
96
+ writeStdin(data: Uint8Array | string): Promise<void>;
97
+ closeStdin(): Promise<void>;
98
98
  kill(signal?: number): void;
99
99
  wait(): Promise<number>;
100
100
  readonly exitCode: number | null;
101
101
  }
102
102
  export interface ShellHandle {
103
103
  pid: number;
104
- write(data: Uint8Array | string): void;
104
+ write(data: Uint8Array | string): Promise<void>;
105
105
  onData: ((data: Uint8Array) => void) | null;
106
106
  resize(cols: number, rows: number): void;
107
107
  kill(signal?: number): void;
@@ -163,7 +163,7 @@ export interface Permissions {
163
163
  childProcess?: ChildProcessPermissions;
164
164
  process?: ProcessPermissions;
165
165
  env?: EnvPermissions;
166
- tool?: ToolPermissions;
166
+ binding?: BindingPermissions;
167
167
  }
168
168
  export interface ResourceBudgets {
169
169
  maxOutputBytes?: number;
@@ -224,6 +224,7 @@ export interface SystemDriver {
224
224
  network?: NetworkAdapter;
225
225
  commandExecutor?: CommandExecutor;
226
226
  permissions?: Permissions;
227
+ mounts: readonly NodeModulesMountConfig[];
227
228
  runtime: {
228
229
  process: ProcessConfig;
229
230
  os: OSConfig;
@@ -258,6 +259,13 @@ export interface NodeRuntimeDriverFactory {
258
259
  export interface KernelInterface {
259
260
  vfs: VirtualFileSystem;
260
261
  }
262
+ export interface KernelRecursiveDirEntry {
263
+ name: string;
264
+ path: string;
265
+ isDirectory: boolean;
266
+ isSymbolicLink: boolean;
267
+ size: number;
268
+ }
261
269
  export interface Kernel extends KernelInterface {
262
270
  mount(driver: KernelRuntimeDriver): Promise<void>;
263
271
  dispose(): Promise<void>;
@@ -273,11 +281,18 @@ export interface Kernel extends KernelInterface {
273
281
  writeFile(path: string, content: string | Uint8Array): Promise<void>;
274
282
  mkdir(path: string): Promise<void>;
275
283
  readdir(path: string): Promise<string[]>;
284
+ readdirRecursive(path: string, options?: {
285
+ maxDepth?: number;
286
+ }): Promise<KernelRecursiveDirEntry[]>;
276
287
  stat(path: string): Promise<VirtualStat>;
277
288
  exists(path: string): Promise<boolean>;
278
289
  removeFile(path: string): Promise<void>;
279
290
  removeDir(path: string): Promise<void>;
291
+ removePath(path: string, options?: {
292
+ recursive?: boolean;
293
+ }): Promise<void>;
280
294
  rename(oldPath: string, newPath: string): Promise<void>;
295
+ movePath(oldPath: string, newPath: string): Promise<void>;
281
296
  readonly commands: ReadonlyMap<string, string>;
282
297
  readonly processes: ReadonlyMap<number, ProcessInfo>;
283
298
  readonly env: Record<string, string>;
@@ -299,11 +314,23 @@ export interface BindingTree {
299
314
  [key: string]: BindingFunction | BindingTree;
300
315
  }
301
316
  export type BindingFunction = (...args: unknown[]) => unknown;
317
+ export interface NodeModulesMountConfig {
318
+ path: string;
319
+ plugin: {
320
+ id: "host_dir";
321
+ config: {
322
+ hostPath: string;
323
+ readOnly: boolean;
324
+ };
325
+ };
326
+ readOnly: boolean;
327
+ }
302
328
  export interface NodeDriverOptions {
303
329
  filesystem?: VirtualFileSystem;
304
330
  networkAdapter?: NetworkAdapter;
305
331
  commandExecutor?: CommandExecutor;
306
332
  permissions?: Permissions;
333
+ mounts?: readonly NodeModulesMountConfig[];
307
334
  processConfig?: ProcessConfig;
308
335
  osConfig?: OSConfig;
309
336
  }