@rivet-dev/agentos-core 0.2.7 → 0.2.8-rc.2

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.
package/README.md CHANGED
@@ -104,7 +104,7 @@ await vm.dispose();
104
104
  | `connectTerminal` | `connectTerminal(options?: ConnectTerminalOptions): Promise<number>` | Attach a shell directly to the host terminal and wait for exit |
105
105
  | `openShell` | `openShell(options?: OpenShellOptions): { shellId: string }` | Open an interactive shell with PTY support |
106
106
  | `writeShell` | `writeShell(shellId: string, data: string \| Uint8Array): void` | Write data to a shell's PTY input |
107
- | `onShellData` | `onShellData(shellId: string, handler: (data: Uint8Array) => void): () => void` | Subscribe to shell output data |
107
+ | `onShellData` | `onShellData(shellId: string, handler: (data: Uint8Array) => void): () => void` | Subscribe to ordered PTY output (stdout and stderr exactly once) |
108
108
  | `resizeShell` | `resizeShell(shellId: string, cols: number, rows: number): void` | Notify terminal resize |
109
109
  | `closeShell` | `closeShell(shellId: string): void` | Kill the shell process |
110
110
 
@@ -499,10 +499,16 @@ export declare class AgentOs {
499
499
  stat(path: string): Promise<VirtualStat>;
500
500
  exists(path: string): Promise<boolean>;
501
501
  snapshotRootFilesystem(): Promise<RootSnapshotExport>;
502
+ /**
503
+ * Mount a filesystem into the running VM. Resolves once the mount has been
504
+ * delivered to the native sidecar, so guest code can use it immediately
505
+ * after the returned promise settles; a delivery failure rejects instead of
506
+ * leaving the mount silently host-only.
507
+ */
502
508
  mountFs(path: string, driver: VirtualFileSystem, options?: {
503
509
  readOnly?: boolean;
504
- }): void;
505
- unmountFs(path: string): void;
510
+ }): Promise<void>;
511
+ unmountFs(path: string): Promise<void>;
506
512
  move(from: string, to: string): Promise<void>;
507
513
  delete(path: string, options?: {
508
514
  recursive?: boolean;
@@ -514,7 +520,11 @@ export declare class AgentOs {
514
520
  connectTerminal(options?: ConnectTerminalOptions): Promise<number>;
515
521
  /** Write data to a shell's PTY input. */
516
522
  writeShell(shellId: string, data: string | Uint8Array): Promise<void>;
517
- /** Subscribe to data output from a shell. Returns an unsubscribe function. */
523
+ /**
524
+ * Subscribe to ordered PTY output (stdout and stderr). Returns an unsubscribe
525
+ * function. `OpenShellOptions.onStderr` is a diagnostic tap for callers that
526
+ * need channel identity; do not render both surfaces.
527
+ */
518
528
  onShellData(shellId: string, handler: (data: Uint8Array) => void): () => void;
519
529
  /** Notify a shell of terminal resize. */
520
530
  resizeShell(shellId: string, cols: number, rows: number): void;
package/dist/agent-os.js CHANGED
@@ -43,7 +43,7 @@ import { resolveDefaultSoftware } from "./default-software.js";
43
43
  import { allowAll } from "./runtime-compat.js";
44
44
  import { AcpRuntimeKind, decodeAcpCallback, decodeAcpEvent, decodeAcpResponse, encodeAcpCallbackResponse, encodeAcpRequest, } from "./sidecar/agentos-protocol.js";
45
45
  import { serializePermissionsForSidecar } from "./sidecar/permissions.js";
46
- import { createAgentOsSidecarClient, NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarKernelProxy, SidecarProcess, serializeRootFilesystemForSidecar, } from "./sidecar/rpc-client.js";
46
+ import { createAgentOsSidecarClient, NativeSidecarKernelProxy, SidecarProcess, serializeRootFilesystemForSidecar, } from "./sidecar/rpc-client.js";
47
47
  function defaultAgentStderrHandler(event) {
48
48
  process.stderr.write(event.chunk);
49
49
  }
@@ -1600,6 +1600,12 @@ export class AgentOs {
1600
1600
  permissions: sidecarPermissions,
1601
1601
  commandPermissions: {},
1602
1602
  loopbackExemptPorts: options?.loopbackExemptPorts,
1603
+ // Retained for runtime mount reconfigures: `configure_vm` is
1604
+ // replace-on-write for the whole payload, so post-boot mountFs
1605
+ // must resend the boot packages and tool shims.
1606
+ packages: sidecarPackages,
1607
+ packagesMountAt: OPT_AGENTOS_ROOT,
1608
+ toolShimCommands: toolBootstrapCommands,
1603
1609
  commandGuestPaths,
1604
1610
  onDispose: cleanup,
1605
1611
  // The native process is owned by the AgentOsSidecar handle and
@@ -1920,13 +1926,19 @@ export class AgentOs {
1920
1926
  }
1921
1927
  return createSnapshotExport(await snapshotVirtualFilesystem(this._rootFilesystem));
1922
1928
  }
1923
- mountFs(path, driver, options) {
1929
+ /**
1930
+ * Mount a filesystem into the running VM. Resolves once the mount has been
1931
+ * delivered to the native sidecar, so guest code can use it immediately
1932
+ * after the returned promise settles; a delivery failure rejects instead of
1933
+ * leaving the mount silently host-only.
1934
+ */
1935
+ async mountFs(path, driver, options) {
1924
1936
  this._assertSafeAbsolutePath(path);
1925
- this.#kernel.mountFs(path, driver, { readOnly: options?.readOnly });
1937
+ await this.#kernel.mountFs(path, driver, { readOnly: options?.readOnly });
1926
1938
  }
1927
- unmountFs(path) {
1939
+ async unmountFs(path) {
1928
1940
  this._assertSafeAbsolutePath(path);
1929
- this.#kernel.unmountFs(path);
1941
+ await this.#kernel.unmountFs(path);
1930
1942
  }
1931
1943
  async move(from, to) {
1932
1944
  this._assertWritableAbsolutePath(from);
@@ -2005,7 +2017,11 @@ export class AgentOs {
2005
2017
  throw new Error(`Shell not found: ${shellId}`);
2006
2018
  return entry.handle.write(data);
2007
2019
  }
2008
- /** Subscribe to data output from a shell. Returns an unsubscribe function. */
2020
+ /**
2021
+ * Subscribe to ordered PTY output (stdout and stderr). Returns an unsubscribe
2022
+ * function. `OpenShellOptions.onStderr` is a diagnostic tap for callers that
2023
+ * need channel identity; do not render both surfaces.
2024
+ */
2009
2025
  onShellData(shellId, handler) {
2010
2026
  const entry = this._shells.get(shellId);
2011
2027
  if (!entry)
@@ -2174,6 +2190,10 @@ export class AgentOs {
2174
2190
  command.name,
2175
2191
  command.guestPath,
2176
2192
  ])));
2193
+ // Retain the linked package for runtime mount reconfigures:
2194
+ // `configure_vm` is replace-on-write, so a later `mountFs` that
2195
+ // resent only the boot packages would unproject this one.
2196
+ this.#kernel.registerLinkedPackage({ path: ref.path });
2177
2197
  }
2178
2198
  // The client parses no manifests: an `agent` block in the linked package is
2179
2199
  // picked up by the sidecar (it owns the projected `/opt/agentos` and answers
@@ -3194,9 +3214,6 @@ export class AgentOs {
3194
3214
  ...(cwd ? { cwd } : {}),
3195
3215
  ...(cols !== undefined ? { cols: Math.trunc(cols) } : {}),
3196
3216
  ...(rows !== undefined ? { rows: Math.trunc(rows) } : {}),
3197
- onStderr: (data) => {
3198
- this._appendAcpTerminalOutput(terminal, data);
3199
- },
3200
3217
  }),
3201
3218
  output: "",
3202
3219
  truncated: false,
@@ -3621,7 +3638,6 @@ function ensureSharedSidecarNativeProcess(sidecar) {
3621
3638
  cwd: REPO_ROOT,
3622
3639
  command: ensureNativeSidecarBinary(),
3623
3640
  args: [],
3624
- frameTimeoutMs: NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
3625
3641
  });
3626
3642
  // Track the child immediately — BEFORE the handshake await — so a
3627
3643
  // failed `authenticateAndOpenSession()` can still reap it (otherwise
@@ -16,6 +16,7 @@ export interface VirtualDirEntry {
16
16
  export interface VirtualStat {
17
17
  mode: number;
18
18
  size: number;
19
+ sizeExact?: bigint;
19
20
  blocks: number;
20
21
  dev: number;
21
22
  rdev: number;
@@ -26,7 +27,9 @@ export interface VirtualStat {
26
27
  ctimeMs: number;
27
28
  birthtimeMs: number;
28
29
  ino: number;
30
+ inoExact?: bigint;
29
31
  nlink: number;
32
+ nlinkExact?: bigint;
30
33
  uid: number;
31
34
  gid: number;
32
35
  }
@@ -108,6 +111,7 @@ export interface ManagedProcess {
108
111
  export interface ShellHandle {
109
112
  pid: number;
110
113
  write(data: Uint8Array | string): Promise<void>;
114
+ /** Ordered PTY output containing stdout and stderr exactly once. */
111
115
  onData: ((data: Uint8Array) => void) | null;
112
116
  resize(cols: number, rows: number): void;
113
117
  kill(signal?: number): void;
@@ -120,6 +124,7 @@ export interface OpenShellOptions {
120
124
  cwd?: string;
121
125
  cols?: number;
122
126
  rows?: number;
127
+ /** Optional stderr-only diagnostic tap; do not render it alongside `onData`. */
123
128
  onStderr?: (data: Uint8Array) => void;
124
129
  }
125
130
  export interface ConnectTerminalOptions extends OpenShellOptions {
@@ -281,8 +286,8 @@ export interface Kernel extends KernelInterface {
281
286
  connectTerminal(options?: ConnectTerminalOptions): Promise<number>;
282
287
  mountFs(path: string, fs: VirtualFileSystem, options?: {
283
288
  readOnly?: boolean;
284
- }): void;
285
- unmountFs(path: string): void;
289
+ }): void | Promise<void>;
290
+ unmountFs(path: string): void | Promise<void>;
286
291
  readFile(path: string): Promise<Uint8Array>;
287
292
  writeFile(path: string, content: string | Uint8Array): Promise<void>;
288
293
  mkdir(path: string): Promise<void>;
@@ -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;
@@ -1804,9 +1804,10 @@ class NativeKernel {
1804
1804
  this.pendingLocalMounts.unshift(localMount);
1805
1805
  this.pendingLocalMounts.sort((left, right) => right.path.length - left.path.length);
1806
1806
  if (!this.proxy) {
1807
+ // Pre-boot mounts apply during kernel initialization.
1807
1808
  return;
1808
1809
  }
1809
- this.proxy.mountFs(mountPath, filesystem, {
1810
+ return this.proxy.mountFs(mountPath, filesystem, {
1810
1811
  readOnly: localMount.readOnly,
1811
1812
  sidecarMount: localMount.sidecarMount,
1812
1813
  });
@@ -1817,7 +1818,7 @@ class NativeKernel {
1817
1818
  if (pendingIndex >= 0) {
1818
1819
  this.pendingLocalMounts.splice(pendingIndex, 1);
1819
1820
  }
1820
- this.proxy?.unmountFs(mountPath);
1821
+ return this.proxy?.unmountFs(mountPath);
1821
1822
  }
1822
1823
  async readFile(targetPath) {
1823
1824
  await this.ensureReady();
@@ -1917,7 +1918,6 @@ class NativeKernel {
1917
1918
  cwd: REPO_ROOT,
1918
1919
  command: ensureNativeSidecarBinary(),
1919
1920
  args: [],
1920
- frameTimeoutMs: NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
1921
1921
  });
1922
1922
  const session = await client.authenticateAndOpenSession();
1923
1923
  const createVmConfig = {
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
  }
@@ -102,6 +105,7 @@ export interface ManagedProcess {
102
105
  export interface ShellHandle {
103
106
  pid: number;
104
107
  write(data: Uint8Array | string): Promise<void>;
108
+ /** Ordered PTY output containing stdout and stderr exactly once. */
105
109
  onData: ((data: Uint8Array) => void) | null;
106
110
  resize(cols: number, rows: number): void;
107
111
  kill(signal?: number): void;
@@ -114,6 +118,7 @@ export interface OpenShellOptions {
114
118
  cwd?: string;
115
119
  cols?: number;
116
120
  rows?: number;
121
+ /** Optional stderr-only diagnostic tap; do not render it alongside `onData`. */
117
122
  onStderr?: (data: Uint8Array) => void;
118
123
  }
119
124
  export interface ConnectTerminalOptions extends OpenShellOptions {
@@ -275,8 +280,8 @@ export interface Kernel extends KernelInterface {
275
280
  connectTerminal(options?: ConnectTerminalOptions): Promise<number>;
276
281
  mountFs(path: string, fs: VirtualFileSystem, options?: {
277
282
  readOnly?: boolean;
278
- }): void;
279
- unmountFs(path: string): void;
283
+ }): void | Promise<void>;
284
+ unmountFs(path: string): void | Promise<void>;
280
285
  readFile(path: string): Promise<Uint8Array>;
281
286
  writeFile(path: string, content: string | Uint8Array): Promise<void>;
282
287
  mkdir(path: string): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import "@rivet-dev/agentos-runtime-core/native-client";
2
2
  import { SidecarProcess } from "@rivet-dev/agentos-runtime-core/sidecar-client";
3
- export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
3
+ export { SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
4
4
  export declare const NativeSidecarProcessClient: typeof SidecarProcess;
5
5
  export type { AuthenticatedSession, CreatedVm, ExtEnvelope, GuestFilesystemStat, RootFilesystemEntry, RootFilesystemLowerDescriptor, SidecarEventSelector, SidecarFsPermissionRule, SidecarLinkPackageResult, SidecarMountDescriptor, SidecarMountPluginDescriptor, SidecarPatternPermissionRule, SidecarPermissionMode, SidecarPermissionScope, SidecarPermissionsPolicy, SidecarProcessSnapshotEntry, SidecarProjectedAgent, SidecarProjectedModuleDescriptor, SidecarRegisteredHostCallbackDefinition, SidecarRegisteredHostCallbackExample, SidecarRequestFrame, SidecarRequestHandler, SidecarRequestPayload, SidecarResponseFrame, SidecarResponsePayload, SidecarRulePermissions, SidecarSessionState, SidecarSignalHandlerRegistration, SidecarSignalState, SidecarSocketStateEntry, SidecarSoftwareDescriptor, SidecarSpawnOptions, SidecarSpawnOptions as NativeSidecarSpawnOptions, SidecarZombieTimerCount, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
6
6
  export type { SidecarVmConfiguredResponse as SidecarConfigureVmResult, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
@@ -4,5 +4,5 @@
4
4
  // SidecarProcess.spawn works in this native runtime.
5
5
  import "@rivet-dev/agentos-runtime-core/native-client";
6
6
  import { SidecarProcess } from "@rivet-dev/agentos-runtime-core/sidecar-client";
7
- export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
7
+ export { SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "@rivet-dev/agentos-runtime-core/sidecar-client";
8
8
  export const NativeSidecarProcessClient = SidecarProcess;
@@ -35,6 +35,16 @@ interface NativeSidecarKernelProxyOptions {
35
35
  permissions?: SidecarPermissionsPolicy;
36
36
  commandPermissions?: Parameters<SidecarProcess["configureVm"]>[2]["commandPermissions"];
37
37
  loopbackExemptPorts?: number[];
38
+ /**
39
+ * The boot `configureVm` payload pieces beyond mounts/permissions. Rust
40
+ * `configure_vm` rebuilds the whole VM configuration from each payload, so
41
+ * every runtime mount reconfigure must resend these or a post-boot
42
+ * `mountFs()` silently drops the `/opt/agentos` package projections and
43
+ * tool shim commands applied at boot.
44
+ */
45
+ packages?: Parameters<SidecarProcess["configureVm"]>[2]["packages"];
46
+ packagesMountAt?: string;
47
+ toolShimCommands?: string[];
38
48
  commandGuestPaths: ReadonlyMap<string, string>;
39
49
  onWasmCommandResolved?: (command: string) => void;
40
50
  onDispose?: () => Promise<void>;
@@ -63,6 +73,9 @@ export declare class NativeSidecarKernelProxy {
63
73
  private readonly permissions;
64
74
  private readonly commandPermissions;
65
75
  private readonly loopbackExemptPorts;
76
+ private packages;
77
+ private readonly packagesMountAt;
78
+ private readonly toolShimCommands;
66
79
  private readonly commandDrivers;
67
80
  private readonly onWasmCommandResolved;
68
81
  private readonly onDispose;
@@ -88,6 +101,15 @@ export declare class NativeSidecarKernelProxy {
88
101
  createRootView(): VirtualFileSystem;
89
102
  get zombieTimerCount(): number;
90
103
  registerCommandGuestPaths(commandGuestPaths: ReadonlyMap<string, string>): void;
104
+ /**
105
+ * Record a runtime-linked package (`linkSoftware`) so mount reconfigures
106
+ * resend it. Rust `configure_vm` rebuilds the whole VM configuration from
107
+ * each payload, so a linked package omitted here would be silently
108
+ * unprojected from `/opt/agentos` by the next `mountFs`/`unmountFs`.
109
+ */
110
+ registerLinkedPackage(descriptor: {
111
+ path: string;
112
+ }): void;
91
113
  dispose(): Promise<void>;
92
114
  /** Test-only snapshot of the per-VM tracking collection sizes. */
93
115
  __trackingSizesForTest(): {
@@ -137,8 +159,8 @@ export declare class NativeSidecarKernelProxy {
137
159
  mountFs(path: string, driver: VirtualFileSystem, options?: {
138
160
  readOnly?: boolean;
139
161
  sidecarMount?: SidecarMountDescriptor;
140
- }): void;
141
- unmountFs(path: string): void;
162
+ }): Promise<void>;
163
+ unmountFs(path: string): Promise<void>;
142
164
  private desiredSidecarMounts;
143
165
  private reconfigureSidecarMounts;
144
166
  private waitForMountReconfigure;
@@ -184,7 +206,7 @@ export declare class NativeSidecarKernelProxy {
184
206
  private updateTrackedProcessSnapshot;
185
207
  }
186
208
  export type { AuthenticatedSession, CreatedVm, GuestFilesystemStat, RootFilesystemEntry, SidecarConfigureVmResult, SidecarEventSelector, SidecarLinkPackageResult, SidecarPermissionsPolicy, SidecarProjectedAgent, SidecarRegisteredHostCallbackDefinition, SidecarRequestFrame, SidecarResponsePayload, SidecarSessionState, SidecarSignalHandlerRegistration, SidecarSocketStateEntry, SidecarSpawnOptions, } from "./native-process-client.js";
187
- export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
209
+ export { NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
188
210
  export type AgentOsSidecarPlacement = {
189
211
  kind: "shared";
190
212
  pool?: string;
@@ -214,6 +214,11 @@ export class NativeSidecarKernelProxy {
214
214
  permissions;
215
215
  commandPermissions;
216
216
  loopbackExemptPorts;
217
+ // Mutable: runtime `linkSoftware` appends via `registerLinkedPackage` so
218
+ // later mount reconfigures resend linked packages too, not just boot ones.
219
+ packages;
220
+ packagesMountAt;
221
+ toolShimCommands;
217
222
  commandDrivers;
218
223
  onWasmCommandResolved;
219
224
  onDispose;
@@ -250,6 +255,9 @@ export class NativeSidecarKernelProxy {
250
255
  this.permissions = options.permissions;
251
256
  this.commandPermissions = options.commandPermissions;
252
257
  this.loopbackExemptPorts = options.loopbackExemptPorts;
258
+ this.packages = options.packages ? [...options.packages] : [];
259
+ this.packagesMountAt = options.packagesMountAt;
260
+ this.toolShimCommands = options.toolShimCommands;
253
261
  this.commandDrivers = buildCommandMap(options.commandGuestPaths);
254
262
  this.onWasmCommandResolved = options.onWasmCommandResolved;
255
263
  this.onDispose = options.onDispose;
@@ -273,6 +281,17 @@ export class NativeSidecarKernelProxy {
273
281
  this.commandDrivers.set(name, "wasmvm");
274
282
  }
275
283
  }
284
+ /**
285
+ * Record a runtime-linked package (`linkSoftware`) so mount reconfigures
286
+ * resend it. Rust `configure_vm` rebuilds the whole VM configuration from
287
+ * each payload, so a linked package omitted here would be silently
288
+ * unprojected from `/opt/agentos` by the next `mountFs`/`unmountFs`.
289
+ */
290
+ registerLinkedPackage(descriptor) {
291
+ if (!this.packages.some((pkg) => pkg.path === descriptor.path)) {
292
+ this.packages.push({ path: descriptor.path });
293
+ }
294
+ }
276
295
  async dispose() {
277
296
  if (this.disposed) {
278
297
  return;
@@ -564,7 +583,7 @@ export class NativeSidecarKernelProxy {
564
583
  return proc;
565
584
  }
566
585
  openShell(options) {
567
- const stdoutHandlers = new Set();
586
+ const terminalHandlers = new Set();
568
587
  const stderrHandlers = new Set();
569
588
  const command = options?.command ?? "sh";
570
589
  const args = options?.args ??
@@ -619,7 +638,7 @@ export class NativeSidecarKernelProxy {
619
638
  const normalized = normalizeSyntheticTerminalText(text);
620
639
  updateSyntheticCursor(normalized);
621
640
  const chunk = textEncoder.encode(normalized);
622
- for (const handler of stdoutHandlers) {
641
+ for (const handler of terminalHandlers) {
623
642
  handler(chunk);
624
643
  }
625
644
  };
@@ -630,7 +649,7 @@ export class NativeSidecarKernelProxy {
630
649
  const normalized = normalizeSyntheticTerminalText(text);
631
650
  updateSyntheticCursor(normalized);
632
651
  const chunk = textEncoder.encode(normalized);
633
- for (const handler of stdoutHandlers) {
652
+ for (const handler of terminalHandlers) {
634
653
  handler(chunk);
635
654
  }
636
655
  };
@@ -675,7 +694,7 @@ export class NativeSidecarKernelProxy {
675
694
  commandInFlight = false;
676
695
  const promptPrefix = syntheticCursorAtLineStart ? "" : "\r\n";
677
696
  const promptChunk = textEncoder.encode(`${promptPrefix}${promptText}`);
678
- for (const handler of stdoutHandlers) {
697
+ for (const handler of terminalHandlers) {
679
698
  handler(promptChunk);
680
699
  }
681
700
  syntheticCursorAtLineStart = false;
@@ -733,7 +752,7 @@ export class NativeSidecarKernelProxy {
733
752
  }
734
753
  };
735
754
  let onData = null;
736
- stdoutHandlers.add((data) => onData?.(data));
755
+ terminalHandlers.add((data) => onData?.(data));
737
756
  if (options?.onStderr) {
738
757
  stderrHandlers.add(options.onStderr);
739
758
  }
@@ -902,7 +921,7 @@ export class NativeSidecarKernelProxy {
902
921
  if (!sanitized) {
903
922
  return;
904
923
  }
905
- for (const handler of stdoutHandlers) {
924
+ for (const handler of terminalHandlers) {
906
925
  handler(sanitized);
907
926
  }
908
927
  if (commandInFlight) {
@@ -914,6 +933,11 @@ export class NativeSidecarKernelProxy {
914
933
  if (!sanitized) {
915
934
  return;
916
935
  }
936
+ // `onData` is the ordered PTY rendering stream. `onStderr` remains an
937
+ // optional channel-specific diagnostic tap and must not also be rendered.
938
+ for (const handler of terminalHandlers) {
939
+ handler(sanitized);
940
+ }
917
941
  for (const handler of stderrHandlers) {
918
942
  handler(sanitized);
919
943
  }
@@ -967,13 +991,7 @@ export class NativeSidecarKernelProxy {
967
991
  const stdin = process.stdin;
968
992
  const stdout = process.stdout;
969
993
  const { onData, ...shellOptions } = options ?? {};
970
- const shell = this.openShell({
971
- ...shellOptions,
972
- onStderr: shellOptions.onStderr ??
973
- ((data) => {
974
- process.stderr.write(data);
975
- }),
976
- });
994
+ const shell = this.openShell(shellOptions);
977
995
  const outputHandler = onData ??
978
996
  ((data) => {
979
997
  stdout.write(data);
@@ -1058,7 +1076,7 @@ export class NativeSidecarKernelProxy {
1058
1076
  if (local) {
1059
1077
  return this.readdirRecursiveLocal(local.mount.fs, local.relativePath, options?.maxDepth);
1060
1078
  }
1061
- return this.client.readdirRecursive(this.session, this.vm, path, options);
1079
+ return (await this.client.readdirRecursive(this.session, this.vm, path, options)).map((entry) => ({ ...entry, size: Number(entry.size) }));
1062
1080
  }
1063
1081
  async removeFile(path) {
1064
1082
  return this.dispatchWrite(path, (mount, relativePath) => mount.fs.removeFile(relativePath), () => this.client.removeFile(this.session, this.vm, path));
@@ -1126,15 +1144,24 @@ export class NativeSidecarKernelProxy {
1126
1144
  sidecarMount: options?.sidecarMount,
1127
1145
  });
1128
1146
  this.localMounts.sort((left, right) => right.path.length - left.path.length);
1129
- void this.reconfigureSidecarMounts().catch(() => { });
1147
+ // Resolves once the sidecar has the mount; a swallowed rejection here
1148
+ // used to turn reconfigure failures into silently missing guest mounts.
1149
+ // The local catch only guards callers that drop the promise — awaiting
1150
+ // callers still observe the rejection.
1151
+ const applied = this.reconfigureSidecarMounts();
1152
+ applied.catch(() => { });
1153
+ return applied;
1130
1154
  }
1131
1155
  unmountFs(path) {
1132
1156
  const normalized = posixPath.normalize(path);
1133
1157
  const index = this.localMounts.findIndex((mount) => mount.path === normalized);
1134
- if (index >= 0) {
1135
- this.localMounts.splice(index, 1);
1136
- void this.reconfigureSidecarMounts().catch(() => { });
1158
+ if (index < 0) {
1159
+ return Promise.resolve();
1137
1160
  }
1161
+ this.localMounts.splice(index, 1);
1162
+ const applied = this.reconfigureSidecarMounts();
1163
+ applied.catch(() => { });
1164
+ return applied;
1138
1165
  }
1139
1166
  desiredSidecarMounts() {
1140
1167
  return [
@@ -1154,11 +1181,18 @@ export class NativeSidecarKernelProxy {
1154
1181
  if (this.disposed) {
1155
1182
  return;
1156
1183
  }
1184
+ // Rust `configure_vm` rebuilds the whole VM configuration from this
1185
+ // payload, so resend the boot packages / tool shim commands too —
1186
+ // omitting them here strips the `/opt/agentos` projections and tool
1187
+ // shims from the VM as a side effect of a runtime mount change.
1157
1188
  await this.client.configureVm(this.session, this.vm, {
1158
1189
  mounts: this.desiredSidecarMounts(),
1159
1190
  permissions: this.permissions,
1160
1191
  commandPermissions: this.commandPermissions,
1161
1192
  loopbackExemptPorts: this.loopbackExemptPorts,
1193
+ packages: this.packages,
1194
+ packagesMountAt: this.packagesMountAt,
1195
+ toolShimCommands: this.toolShimCommands,
1162
1196
  });
1163
1197
  };
1164
1198
  const previous = this.mountReconfigurePromise ?? Promise.resolve();
@@ -1957,21 +1991,27 @@ function isMissingHostProcessError(error) {
1957
1991
  function errnoError(code, message) {
1958
1992
  return Object.assign(new Error(`${code}: ${message}`), { code });
1959
1993
  }
1994
+ // VirtualStat is a numeric, Node-default-shaped view: u64 fields above
1995
+ // Number.MAX_SAFE_INTEGER lose precision here, same as Node's non-bigint
1996
+ // fs.stat on the host.
1960
1997
  function toVirtualStat(stat) {
1961
1998
  return {
1962
1999
  mode: stat.mode,
1963
- size: stat.size,
1964
- blocks: stat.blocks,
1965
- dev: stat.dev,
1966
- rdev: stat.rdev,
2000
+ size: Number(stat.size),
2001
+ sizeExact: stat.size,
2002
+ blocks: Number(stat.blocks),
2003
+ dev: Number(stat.dev),
2004
+ rdev: Number(stat.rdev),
1967
2005
  isDirectory: stat.is_directory,
1968
2006
  isSymbolicLink: stat.is_symbolic_link,
1969
2007
  atimeMs: stat.atime_ms,
1970
2008
  mtimeMs: stat.mtime_ms,
1971
2009
  ctimeMs: stat.ctime_ms,
1972
2010
  birthtimeMs: stat.birthtime_ms,
1973
- ino: stat.ino,
1974
- nlink: stat.nlink,
2011
+ ino: Number(stat.ino),
2012
+ inoExact: stat.ino,
2013
+ nlink: Number(stat.nlink),
2014
+ nlinkExact: stat.nlink,
1975
2015
  uid: stat.uid,
1976
2016
  gid: stat.gid,
1977
2017
  };
@@ -2004,7 +2044,7 @@ function socketLookupKey(kind, request) {
2004
2044
  path: request.path ?? null,
2005
2045
  });
2006
2046
  }
2007
- export { NATIVE_SIDECAR_FRAME_TIMEOUT_MS, NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
2047
+ export { NativeSidecarProcessClient, SidecarEventBufferOverflow, SidecarProcess, SidecarProcessError, SidecarProcessExited, } from "./native-process-client.js";
2008
2048
  export class AgentOsSidecarVmHandle {
2009
2049
  client;
2010
2050
  sessionId;
@@ -20,9 +20,6 @@ export class TerminalHarness {
20
20
  rows,
21
21
  env: options?.env,
22
22
  cwd: options?.cwd,
23
- onStderr: (data) => {
24
- this.term.write(data);
25
- },
26
23
  });
27
24
  this.shell.onData = (data) => {
28
25
  this.term.write(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivet-dev/agentos-core",
3
- "version": "0.2.7",
3
+ "version": "0.2.8-rc.2",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -53,17 +53,17 @@
53
53
  "test": "vitest run --reporter=verbose"
54
54
  },
55
55
  "dependencies": {
56
- "@agentos-software/claude-code": "0.2.7",
57
- "@agentos-software/codex-cli": "0.3.3",
58
- "@agentos-software/common": "0.2.7",
59
- "@agentos-software/manifest": "0.2.7",
60
- "@agentos-software/opencode": "0.2.7",
61
- "@agentos-software/pi": "0.2.7",
62
- "@agentos-software/pi-cli": "0.2.7",
56
+ "@agentos-software/claude-code": "0.2.8-rc.2",
57
+ "@agentos-software/codex-cli": "0.3.4",
58
+ "@agentos-software/common": "0.2.8-rc.2",
59
+ "@agentos-software/manifest": "0.2.8-rc.2",
60
+ "@agentos-software/opencode": "0.2.8-rc.2",
61
+ "@agentos-software/pi": "0.2.8-rc.2",
62
+ "@agentos-software/pi-cli": "0.2.8-rc.2",
63
63
  "@aws-sdk/client-s3": "^3.1019.0",
64
- "@rivet-dev/agentos-sidecar": "0.2.7",
64
+ "@rivet-dev/agentos-sidecar": "0.2.8-rc.2",
65
65
  "@rivetkit/bare-ts": "^0.6.2",
66
- "@rivet-dev/agentos-runtime-core": "0.2.7",
66
+ "@rivet-dev/agentos-runtime-core": "0.2.8-rc.2",
67
67
  "@xterm/headless": "^6.0.0",
68
68
  "better-sqlite3": "^12.8.0",
69
69
  "croner": "^10.0.1",
@@ -75,8 +75,8 @@
75
75
  "zod-to-json-schema": "^3.25.2"
76
76
  },
77
77
  "devDependencies": {
78
- "@agentos-software/claude-code": "0.2.7",
79
- "@agentos-software/codex": "0.2.7",
78
+ "@agentos-software/claude-code": "0.2.8-rc.2",
79
+ "@agentos-software/codex": "0.2.8-rc.2",
80
80
  "@agentos-software/coreutils": "0.3.3",
81
81
  "@agentos-software/curl": "0.3.3",
82
82
  "@agentos-software/diffutils": "0.3.3",
@@ -90,9 +90,9 @@
90
90
  "@agentos-software/gzip": "0.3.3",
91
91
  "@agentos-software/http-get": "0.3.3",
92
92
  "@agentos-software/jq": "0.3.3",
93
- "@agentos-software/opencode": "0.2.7",
94
- "@agentos-software/pi": "0.2.7",
95
- "@agentos-software/pi-cli": "0.2.7",
93
+ "@agentos-software/opencode": "0.2.8-rc.2",
94
+ "@agentos-software/pi": "0.2.8-rc.2",
95
+ "@agentos-software/pi-cli": "0.2.8-rc.2",
96
96
  "@agentos-software/ripgrep": "0.3.3",
97
97
  "@agentos-software/sed": "0.3.3",
98
98
  "@agentos-software/tar": "0.3.3",