@rivet-dev/agentos-core 0.2.4 → 0.2.5-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.
@@ -1,149 +1,28 @@
1
- import type { PermissionTier } from "./runtime.js";
1
+ import { type SoftwarePackageRef } from "./agentos-package.js";
2
2
  /**
3
- * Resolve a package directory by walking up the directory tree.
4
- * Supports both nested (pnpm) and flat (npm) node_modules layouts.
3
+ * Input type for the `software` option. Software is a self-contained package
4
+ * directory that the secure-exec sidecar materializes into the `/opt/agentos`
5
+ * projection. Accepts a package-dir ref or an array of refs for meta-packages.
5
6
  */
6
- export declare function resolvePackageDir(startDir: string, packageName: string): string;
7
- import type { AgentConfig } from "./agents.js";
8
- export interface SoftwareDescriptor {
9
- name: string;
10
- type: "agent" | "tool" | "wasm-commands";
11
- }
12
- export interface AgentSoftwareDescriptor extends SoftwareDescriptor {
13
- type: "agent";
14
- /**
15
- * Root directory of this npm package on the host. Used to resolve
16
- * dependencies listed in `requires` from this package's node_modules/.
17
- */
18
- packageDir: string;
19
- /** npm packages that must be available inside the VM. */
20
- requires: string[];
21
- agent: {
22
- /** Unique agent ID used in createSession(id). */
23
- id: string;
24
- /** npm package name of the ACP adapter. Must be in requires. */
25
- acpAdapter: string;
26
- /** npm package name of the agent CLI. Must be in requires. */
27
- agentPackage: string;
28
- /**
29
- * Whether to evaluate this agent's SDK into the per-sidecar V8 heap
30
- * snapshot so it is loaded once per sidecar and reused across sessions
31
- * (instead of re-evaluated on every `createSession`). Opt-in: the agent's
32
- * SDK must be **snapshot-safe** — its module-init must not create native
33
- * (`.node` addon / WASM / External) handles, open fds/sockets, start
34
- * timers, read per-session config, or leave pending promises. SDKs that
35
- * are not snapshot-safe (or where snapshot creation fails) automatically
36
- * fall back to the per-session dynamic-import path, so this flag is a
37
- * safety/performance switch, not a correctness requirement. Defaults to
38
- * `false`. See the Custom Agents / dependencies docs for the full rules.
39
- */
40
- snapshot?: boolean;
41
- /** Static env vars passed when spawning the adapter. */
42
- staticEnv?: Record<string, string>;
43
- /** Dynamic env vars computed at boot time. */
44
- env?: (ctx: SoftwareContext) => Record<string, string>;
45
- /** Additional CLI args prepended when launching the ACP adapter. */
46
- launchArgs?: string[];
47
- };
48
- }
49
- export interface ToolSoftwareDescriptor extends SoftwareDescriptor {
50
- type: "tool";
51
- /**
52
- * Root directory of this npm package on the host. Used to resolve
53
- * dependencies listed in `requires` from this package's node_modules/.
54
- */
55
- packageDir: string;
56
- /** npm packages that must be available inside the VM. */
57
- requires: string[];
58
- /** Map of bin command name -> npm package name. */
59
- bins: Record<string, string>;
60
- }
61
- export interface WasmCommandSoftwareDescriptor extends SoftwareDescriptor {
62
- type: "wasm-commands";
63
- /** Absolute path to directory containing WASM command binaries on the host. */
64
- commandDir: string;
65
- /** Symlink aliases: aliasName -> targetCommandName. */
66
- aliases?: Record<string, string>;
67
- /** Permission tier assignments. */
68
- permissions?: {
69
- full?: string[];
70
- readWrite?: string[];
71
- readOnly?: string[] | "*";
72
- isolated?: string[];
73
- };
74
- }
75
- /**
76
- * Any object with a commandDir property is treated as a WASM command package.
77
- * This allows registry packages (e.g., @agentos-software/coreutils) to be
78
- * passed directly to the `software` option without wrapping.
79
- */
80
- export interface WasmCommandDirDescriptor {
81
- readonly commandDir: string;
82
- [key: string]: unknown;
83
- }
84
- export type AnySoftwareDescriptor = AgentSoftwareDescriptor | ToolSoftwareDescriptor | WasmCommandSoftwareDescriptor | WasmCommandDirDescriptor;
85
- /** Input type for the `software` option. Accepts descriptors or arrays of descriptors (for meta-packages). */
86
- export type SoftwareInput = AnySoftwareDescriptor | AnySoftwareDescriptor[];
87
- export interface SoftwareContext {
88
- /**
89
- * Resolve the bin entry for an npm package to a VM-side path.
90
- * Uses require.resolve on the HOST, then maps to /root/node_modules/...
91
- *
92
- * Example: ctx.resolveBin("@mariozechner/pi-coding-agent", "pi")
93
- * -> "/root/node_modules/@mariozechner/pi-coding-agent/dist/cli.js"
94
- */
95
- resolveBin(packageName: string, binName?: string): string;
96
- /**
97
- * Resolve a package's root directory to a VM-side path.
98
- *
99
- * Example: ctx.resolvePackage("pi-acp")
100
- * -> "/root/node_modules/pi-acp"
101
- */
102
- resolvePackage(packageName: string): string;
103
- }
7
+ export type SoftwareEntry = SoftwarePackageRef;
8
+ export type SoftwareInput = SoftwareEntry | SoftwareEntry[];
104
9
  /** Host-to-VM path mapping for a software package's `/root/node_modules/<pkg>` mount. */
105
10
  export interface SoftwareRoot {
106
11
  hostPath: string;
107
12
  vmPath: string;
108
13
  }
109
- export interface CommandPackageMetadata {
110
- commandDir: string;
111
- declaredCommands: string[];
112
- aliases: Record<string, string>;
113
- }
114
14
  /**
115
- * Define a software descriptor. This is a type-safe identity function that
116
- * validates the descriptor shape at compile time.
15
+ * Define a software descriptor. A type-safe identity function that validates the
16
+ * package-dir reference at compile time. The sidecar materializes the package into
17
+ * the `/opt/agentos` projection.
117
18
  */
118
- export declare function defineSoftware<T extends AnySoftwareDescriptor>(desc: T): T;
19
+ export declare function defineSoftware<T extends SoftwareEntry>(desc: T): T;
119
20
  /**
120
21
  * Resolve the agent-SDK snapshot bundle (an esbuild IIFE at
121
- * `<packageDir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent in
22
+ * `<dir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent package in
122
23
  * the software set. Returns its source so it can be evaluated once into the
123
24
  * per-sidecar V8 startup snapshot (`jsRuntime.snapshotUserlandCode`) and reused
124
25
  * across sessions. Returns `undefined` when no agent opts in (`agent.snapshot`)
125
26
  * or the bundle is absent — the runtime then keeps the per-session import path.
126
27
  */
127
28
  export declare function resolveAgentSnapshotBundle(software: SoftwareInput[]): string | undefined;
128
- /** Result of processing all software descriptors at boot time. */
129
- export interface ProcessedSoftware {
130
- /** WASM command directories to pass to the WasmVM driver. */
131
- commandDirs: string[];
132
- /** Per-package command metadata used to preserve command availability on the sidecar path. */
133
- commandPackages: CommandPackageMetadata[];
134
- /** Per-command permission tiers propagated into the WasmVM runtime. */
135
- commandPermissions: Record<string, PermissionTier>;
136
- /** Host-to-VM path mappings for software-package `/root/node_modules/<pkg>` mounts. */
137
- softwareRoots: SoftwareRoot[];
138
- /** Agent configs registered by agent software. */
139
- agentConfigs: Map<string, AgentConfig>;
140
- }
141
- /**
142
- * Process an array of software descriptors at boot time.
143
- * Collects WASM command dirs, module access roots, and agent configurations.
144
- *
145
- * Any object with a `commandDir` property (e.g., registry packages) is treated
146
- * as a WASM command source. Typed descriptors with `type: "agent"` or `type: "tool"`
147
- * are processed for module mounting and agent registration.
148
- */
149
- export declare function processSoftware(software: SoftwareInput[]): ProcessedSoftware;
package/dist/packages.js CHANGED
@@ -1,126 +1,18 @@
1
- import { existsSync, readFileSync, realpathSync } from "node:fs";
2
- import { dirname, join, resolve, sep } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- /**
5
- * Resolve a package directory by walking up the directory tree.
6
- * Supports both nested (pnpm) and flat (npm) node_modules layouts.
7
- */
8
- export function resolvePackageDir(startDir, packageName) {
9
- const localPkgJson = join(startDir, "package.json");
10
- if (existsSync(localPkgJson)) {
11
- try {
12
- const localPkg = JSON.parse(readFileSync(localPkgJson, "utf-8"));
13
- if (localPkg.name === packageName) {
14
- return realpathSync(startDir);
15
- }
16
- }
17
- catch {
18
- // Ignore malformed local package metadata and continue walking.
19
- }
20
- }
21
- let searchDir = startDir;
22
- while (true) {
23
- const candidate = join(searchDir, "node_modules", packageName);
24
- if (existsSync(join(candidate, "package.json"))) {
25
- return realpathSync(candidate);
26
- }
27
- const parent = dirname(searchDir);
28
- if (parent === searchDir)
29
- break;
30
- searchDir = parent;
31
- }
32
- throw new Error(`Package "${packageName}" not found starting from ${startDir}. ` +
33
- `Ensure it is installed.`);
34
- }
35
- const LOCAL_REGISTRY_COMMAND_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../secure-exec", "registry/native/target/wasm32-wasip1/release/commands");
36
- function readPackageName(packageDir) {
37
- const pkg = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf-8"));
38
- if (typeof pkg.name !== "string" || pkg.name.length === 0) {
39
- throw new Error(`Package at ${packageDir} is missing a valid name`);
40
- }
41
- return pkg.name;
42
- }
43
- function pushSoftwareRoot(softwareRoots, seenVmPaths, hostPath, vmPath) {
44
- if (seenVmPaths.has(vmPath)) {
45
- return;
46
- }
47
- seenVmPaths.add(vmPath);
48
- softwareRoots.push({ hostPath, vmPath });
49
- }
50
- function findPnpmStoreRoot(hostPath) {
51
- const marker = `${sep}node_modules${sep}.pnpm${sep}`;
52
- const markerIndex = hostPath.indexOf(marker);
53
- if (markerIndex === -1) {
54
- return null;
55
- }
56
- const nodeModulesRoot = `${hostPath.slice(0, markerIndex)}${sep}node_modules`;
57
- const pnpmStoreRoot = join(nodeModulesRoot, ".pnpm");
58
- return existsSync(pnpmStoreRoot) ? pnpmStoreRoot : null;
59
- }
60
- function pushPackageSoftwareRoot(softwareRoots, seenVmPaths, hostPath, vmPath) {
61
- pushSoftwareRoot(softwareRoots, seenVmPaths, hostPath, vmPath);
62
- const pnpmStoreRoot = findPnpmStoreRoot(hostPath);
63
- if (!pnpmStoreRoot) {
64
- return;
65
- }
66
- pushSoftwareRoot(softwareRoots, seenVmPaths, pnpmStoreRoot, "/root/node_modules/.pnpm");
67
- }
68
- /**
69
- * Create a SoftwareContext for a software descriptor.
70
- * Resolves npm package paths relative to the descriptor's packageDir.
71
- */
72
- function createSoftwareContext(packageDir, requires) {
73
- // Pre-resolve all required packages to host paths
74
- const resolvedPackages = new Map();
75
- for (const reqPkg of requires) {
76
- const hostDir = resolvePackageDir(packageDir, reqPkg);
77
- const pkg = JSON.parse(readFileSync(join(hostDir, "package.json"), "utf-8"));
78
- const vmDir = `/root/node_modules/${reqPkg}`;
79
- resolvedPackages.set(reqPkg, { hostDir, vmDir, pkg });
80
- }
81
- return {
82
- resolveBin(packageName, binName) {
83
- const resolved = resolvedPackages.get(packageName);
84
- if (!resolved) {
85
- throw new Error(`Package "${packageName}" is not in the requires list. ` +
86
- `Available: ${[...resolvedPackages.keys()].join(", ")}`);
87
- }
88
- const { pkg, vmDir } = resolved;
89
- let binEntry;
90
- const effectiveBinName = binName ?? packageName;
91
- if (typeof pkg.bin === "string") {
92
- binEntry = pkg.bin;
93
- }
94
- else if (typeof pkg.bin === "object" && pkg.bin !== null) {
95
- const binMap = pkg.bin;
96
- binEntry = binMap[effectiveBinName] ?? Object.values(binMap)[0];
97
- }
98
- if (!binEntry) {
99
- throw new Error(`No bin entry "${effectiveBinName}" found in ${packageName}/package.json`);
100
- }
101
- return `${vmDir}/${binEntry}`;
102
- },
103
- resolvePackage(packageName) {
104
- const resolved = resolvedPackages.get(packageName);
105
- if (!resolved) {
106
- throw new Error(`Package "${packageName}" is not in the requires list. ` +
107
- `Available: ${[...resolvedPackages.keys()].join(", ")}`);
108
- }
109
- return resolved.vmDir;
110
- },
111
- };
112
- }
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { tryReadAgentosPackageManifest, } from "./agentos-package.js";
113
4
  // ── defineSoftware ───────────────────────────────────────────────────
114
5
  /**
115
- * Define a software descriptor. This is a type-safe identity function that
116
- * validates the descriptor shape at compile time.
6
+ * Define a software descriptor. A type-safe identity function that validates the
7
+ * package-dir reference at compile time. The sidecar materializes the package into
8
+ * the `/opt/agentos` projection.
117
9
  */
118
10
  export function defineSoftware(desc) {
119
11
  return desc;
120
12
  }
121
13
  /**
122
14
  * Resolve the agent-SDK snapshot bundle (an esbuild IIFE at
123
- * `<packageDir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent in
15
+ * `<dir>/dist/sdk-snapshot.js`) for the first snapshot-enabled agent package in
124
16
  * the software set. Returns its source so it can be evaluated once into the
125
17
  * per-sidecar V8 startup snapshot (`jsRuntime.snapshotUserlandCode`) and reused
126
18
  * across sessions. Returns `undefined` when no agent opts in (`agent.snapshot`)
@@ -128,239 +20,15 @@ export function defineSoftware(desc) {
128
20
  */
129
21
  export function resolveAgentSnapshotBundle(software) {
130
22
  const descriptors = software.flat();
131
- for (const desc of descriptors) {
132
- if (desc.type !== "agent")
133
- continue;
134
- const agent = desc;
135
- if (!agent.agent.snapshot)
23
+ for (const entry of descriptors) {
24
+ const dir = entry.packageDir;
25
+ const manifest = tryReadAgentosPackageManifest(dir);
26
+ if (!manifest?.agent?.snapshot)
136
27
  continue;
137
- const bundlePath = join(agent.packageDir, "dist", "sdk-snapshot.js");
28
+ const bundlePath = join(dir, "dist", "sdk-snapshot.js");
138
29
  if (existsSync(bundlePath)) {
139
30
  return readFileSync(bundlePath, "utf-8");
140
31
  }
141
32
  }
142
33
  return undefined;
143
34
  }
144
- /** Check if a descriptor is a typed software descriptor (has a `type` field). */
145
- function isTypedDescriptor(desc) {
146
- return ("type" in desc && typeof desc.type === "string");
147
- }
148
- const VALID_PERMISSION_TIERS = new Set([
149
- "full",
150
- "read-write",
151
- "read-only",
152
- "isolated",
153
- ]);
154
- function isPermissionTier(value) {
155
- return (typeof value === "string" &&
156
- VALID_PERMISSION_TIERS.has(value));
157
- }
158
- function registerPermission(commandPermissions, commandName, tier) {
159
- if (commandName in commandPermissions)
160
- return;
161
- commandPermissions[commandName] = tier;
162
- }
163
- function appendDeclaredCommand(declaredCommands, seen, commandName) {
164
- if (typeof commandName !== "string" || seen.has(commandName)) {
165
- return;
166
- }
167
- seen.add(commandName);
168
- declaredCommands.push(commandName);
169
- }
170
- function collectCommandMetadata(pkg) {
171
- const declaredCommands = [];
172
- const seen = new Set();
173
- const aliases = {};
174
- if ("aliases" in pkg && pkg.aliases) {
175
- for (const [aliasName, targetName] of Object.entries(pkg.aliases)) {
176
- if (typeof targetName !== "string") {
177
- continue;
178
- }
179
- aliases[aliasName] = targetName;
180
- appendDeclaredCommand(declaredCommands, seen, aliasName);
181
- appendDeclaredCommand(declaredCommands, seen, targetName);
182
- }
183
- }
184
- const rawCommands = pkg.commands;
185
- if (Array.isArray(rawCommands)) {
186
- for (const rawCommand of rawCommands) {
187
- if (typeof rawCommand !== "object" || rawCommand === null) {
188
- continue;
189
- }
190
- const name = rawCommand.name;
191
- const aliasOf = rawCommand.aliasOf;
192
- appendDeclaredCommand(declaredCommands, seen, name);
193
- appendDeclaredCommand(declaredCommands, seen, aliasOf);
194
- if (typeof name === "string" && typeof aliasOf === "string") {
195
- aliases[name] = aliasOf;
196
- }
197
- }
198
- }
199
- const permissions = pkg.permissions;
200
- if (permissions) {
201
- for (const commandName of permissions.full ?? []) {
202
- appendDeclaredCommand(declaredCommands, seen, commandName);
203
- }
204
- for (const commandName of permissions.readWrite ?? []) {
205
- appendDeclaredCommand(declaredCommands, seen, commandName);
206
- }
207
- if (Array.isArray(permissions.readOnly)) {
208
- for (const commandName of permissions.readOnly) {
209
- appendDeclaredCommand(declaredCommands, seen, commandName);
210
- }
211
- }
212
- for (const commandName of permissions.isolated ?? []) {
213
- appendDeclaredCommand(declaredCommands, seen, commandName);
214
- }
215
- }
216
- const commandDir = resolveLocalCommandDirFallback(pkg.commandDir, declaredCommands);
217
- return {
218
- commandDir,
219
- declaredCommands,
220
- aliases,
221
- };
222
- }
223
- function hasUsableCommandDir(commandDir, declaredCommands) {
224
- if (!existsSync(commandDir)) {
225
- return false;
226
- }
227
- return declaredCommands.every((commandName) => existsSync(join(commandDir, commandName)));
228
- }
229
- function resolveLocalCommandDirFallback(commandDir, declaredCommands) {
230
- if (declaredCommands.length === 0 ||
231
- hasUsableCommandDir(commandDir, declaredCommands) ||
232
- !hasUsableCommandDir(LOCAL_REGISTRY_COMMAND_DIR, declaredCommands)) {
233
- return commandDir;
234
- }
235
- return LOCAL_REGISTRY_COMMAND_DIR;
236
- }
237
- function collectRegistryPackagePermissions(commandPermissions, pkg) {
238
- const rawCommands = pkg.commands;
239
- if (!Array.isArray(rawCommands))
240
- return;
241
- for (const rawCommand of rawCommands) {
242
- if (typeof rawCommand !== "object" ||
243
- rawCommand === null ||
244
- !Object.hasOwn(rawCommand, "name") ||
245
- !Object.hasOwn(rawCommand, "permissionTier")) {
246
- continue;
247
- }
248
- const name = rawCommand.name;
249
- const permissionTier = rawCommand
250
- .permissionTier;
251
- if (typeof name !== "string" || !isPermissionTier(permissionTier))
252
- continue;
253
- registerPermission(commandPermissions, name, permissionTier);
254
- }
255
- }
256
- function collectTypedDescriptorPermissions(commandPermissions, pkg) {
257
- const permissions = pkg.permissions;
258
- if (!permissions)
259
- return;
260
- for (const commandName of permissions.full ?? []) {
261
- registerPermission(commandPermissions, commandName, "full");
262
- }
263
- for (const commandName of permissions.readWrite ?? []) {
264
- registerPermission(commandPermissions, commandName, "read-write");
265
- }
266
- if (Array.isArray(permissions.readOnly)) {
267
- for (const commandName of permissions.readOnly) {
268
- registerPermission(commandPermissions, commandName, "read-only");
269
- }
270
- }
271
- for (const commandName of permissions.isolated ?? []) {
272
- registerPermission(commandPermissions, commandName, "isolated");
273
- }
274
- }
275
- /**
276
- * Process an array of software descriptors at boot time.
277
- * Collects WASM command dirs, module access roots, and agent configurations.
278
- *
279
- * Any object with a `commandDir` property (e.g., registry packages) is treated
280
- * as a WASM command source. Typed descriptors with `type: "agent"` or `type: "tool"`
281
- * are processed for module mounting and agent registration.
282
- */
283
- export function processSoftware(software) {
284
- const commandDirs = [];
285
- const commandPackages = [];
286
- const commandPermissions = {};
287
- const softwareRoots = [];
288
- const seenSoftwareVmPaths = new Set();
289
- const agentConfigs = new Map();
290
- // Flatten nested arrays (meta-packages export arrays of sub-packages).
291
- const flat = software.flat();
292
- for (const pkg of flat) {
293
- if (!isTypedDescriptor(pkg)) {
294
- // Duck-typed: any object with commandDir is a WASM command source.
295
- const commandMetadata = collectCommandMetadata(pkg);
296
- if (!existsSync(commandMetadata.commandDir)) {
297
- console.warn(`[agentos] skipping WASM command source with missing commandDir: ${commandMetadata.commandDir} (build its wasm artifacts to enable these commands)`);
298
- continue;
299
- }
300
- commandDirs.push(commandMetadata.commandDir);
301
- commandPackages.push(commandMetadata);
302
- collectRegistryPackagePermissions(commandPermissions, pkg);
303
- continue;
304
- }
305
- switch (pkg.type) {
306
- case "wasm-commands": {
307
- const commandMetadata = collectCommandMetadata(pkg);
308
- if (!existsSync(commandMetadata.commandDir)) {
309
- console.warn(`[agentos] skipping WASM command source with missing commandDir: ${commandMetadata.commandDir} (build its wasm artifacts to enable these commands)`);
310
- break;
311
- }
312
- commandDirs.push(commandMetadata.commandDir);
313
- commandPackages.push(commandMetadata);
314
- collectTypedDescriptorPermissions(commandPermissions, pkg);
315
- break;
316
- }
317
- case "agent": {
318
- // Collect module roots for all required npm packages.
319
- // Walks up directory tree to support flat (npm) and nested (pnpm) layouts.
320
- const ctx = createSoftwareContext(pkg.packageDir, pkg.requires);
321
- const declaringPackageName = readPackageName(pkg.packageDir);
322
- pushPackageSoftwareRoot(softwareRoots, seenSoftwareVmPaths, pkg.packageDir, `/root/node_modules/${declaringPackageName}`);
323
- for (const reqPkg of pkg.requires) {
324
- const hostDir = resolvePackageDir(pkg.packageDir, reqPkg);
325
- const vmDir = `/root/node_modules/${reqPkg}`;
326
- pushPackageSoftwareRoot(softwareRoots, seenSoftwareVmPaths, hostDir, vmDir);
327
- }
328
- // Compute static + dynamic env vars.
329
- const staticEnv = pkg.agent.staticEnv ?? {};
330
- const dynamicEnv = pkg.agent.env ? pkg.agent.env(ctx) : {};
331
- const combinedEnv = { ...staticEnv, ...dynamicEnv };
332
- // Register agent config.
333
- const agentConfig = {
334
- acpAdapter: pkg.agent.acpAdapter,
335
- agentPackage: pkg.agent.agentPackage,
336
- declaringPackageDir: pkg.packageDir,
337
- launchArgs: pkg.agent.launchArgs,
338
- defaultEnv: Object.keys(combinedEnv).length > 0 ? combinedEnv : undefined,
339
- };
340
- agentConfigs.set(pkg.agent.id, agentConfig);
341
- break;
342
- }
343
- case "tool": {
344
- // Collect module roots for all required npm packages.
345
- // Walks up directory tree to support flat (npm) and nested (pnpm) layouts.
346
- const declaringPackageName = readPackageName(pkg.packageDir);
347
- pushPackageSoftwareRoot(softwareRoots, seenSoftwareVmPaths, pkg.packageDir, `/root/node_modules/${declaringPackageName}`);
348
- for (const reqPkg of pkg.requires) {
349
- const hostDir = resolvePackageDir(pkg.packageDir, reqPkg);
350
- const vmDir = `/root/node_modules/${reqPkg}`;
351
- pushPackageSoftwareRoot(softwareRoots, seenSoftwareVmPaths, hostDir, vmDir);
352
- }
353
- // Tool bin registration is handled by the caller (AgentOs.create)
354
- // since it requires kernel access.
355
- break;
356
- }
357
- }
358
- }
359
- return {
360
- commandDirs,
361
- commandPackages,
362
- commandPermissions,
363
- softwareRoots,
364
- agentConfigs,
365
- };
366
- }
@@ -98,15 +98,15 @@ export interface ProcessInfo {
98
98
  }
99
99
  export interface ManagedProcess {
100
100
  pid: number;
101
- writeStdin(data: Uint8Array | string): void;
102
- closeStdin(): void;
101
+ writeStdin(data: Uint8Array | string): Promise<void>;
102
+ closeStdin(): Promise<void>;
103
103
  kill(signal?: number): void;
104
104
  wait(): Promise<number>;
105
105
  readonly exitCode: number | null;
106
106
  }
107
107
  export interface ShellHandle {
108
108
  pid: number;
109
- write(data: Uint8Array | string): void;
109
+ write(data: Uint8Array | string): Promise<void>;
110
110
  onData: ((data: Uint8Array) => void) | null;
111
111
  resize(cols: number, rows: number): void;
112
112
  kill(signal?: number): void;
@@ -18,7 +18,13 @@ const S_IFDIR = 0o040000;
18
18
  const S_IFLNK = 0o120000;
19
19
  const MAX_SYMLINK_DEPTH = 40;
20
20
  const KERNEL_COMMAND_STUB = "#!/bin/sh\n# kernel command stub\n";
21
- const NODE_RUNTIME_BOOTSTRAP_COMMANDS = ["node", "npm", "npx"];
21
+ const NODE_RUNTIME_BOOTSTRAP_COMMANDS = [
22
+ "node",
23
+ "npm",
24
+ "npx",
25
+ "python",
26
+ "python3",
27
+ ];
22
28
  const KERNEL_POSIX_BOOTSTRAP_DIRS = [
23
29
  "/dev",
24
30
  "/proc",
@@ -819,7 +825,6 @@ export const WASMVM_COMMANDS = Object.freeze([
819
825
  "sqlite3",
820
826
  "curl",
821
827
  "wget",
822
- "make",
823
828
  "git",
824
829
  "git-remote-http",
825
830
  "git-remote-https",
@@ -918,7 +923,6 @@ export const DEFAULT_FIRST_PARTY_TIERS = Object.freeze({
918
923
  nice: "full",
919
924
  nohup: "full",
920
925
  stdbuf: "full",
921
- make: "full",
922
926
  codex: "full",
923
927
  "codex-exec": "full",
924
928
  git: "full",
@@ -1800,10 +1804,10 @@ class NativeKernel {
1800
1804
  return {
1801
1805
  pid: proc.pid,
1802
1806
  writeStdin(data) {
1803
- proc.writeStdin(data);
1807
+ return proc.writeStdin(data);
1804
1808
  },
1805
1809
  closeStdin() {
1806
- proc.closeStdin();
1810
+ return proc.closeStdin();
1807
1811
  },
1808
1812
  kill(signal) {
1809
1813
  proc.kill(signal);
package/dist/runtime.d.ts CHANGED
@@ -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;