@rivet-dev/agentos-core 0.0.0-agentos-dylib-plugin.bbfdf95 → 0.0.0-chdir-fix.f899dc6

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