@rivet-dev/agentos-core 0.2.4 → 0.2.5-rc.1
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 +1 -4
- package/dist/agent-os.d.ts +101 -29
- package/dist/agent-os.js +549 -298
- package/dist/agentos-package.d.ts +29 -0
- package/dist/agentos-package.js +82 -0
- package/dist/agents.d.ts +20 -4
- package/dist/agents.js +6 -0
- package/dist/base-filesystem.d.ts +2 -15
- package/dist/base-filesystem.js +23 -171
- package/dist/default-software.d.ts +48 -0
- package/dist/default-software.js +93 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/layers.d.ts +1 -2
- package/dist/layers.js +0 -7
- package/dist/options-schema.d.ts +3 -1
- package/dist/options-schema.js +2 -0
- package/dist/packages.d.ts +11 -132
- package/dist/packages.js +12 -344
- package/dist/runtime-compat.d.ts +3 -3
- package/dist/runtime-compat.js +9 -5
- package/dist/runtime.d.ts +3 -3
- package/dist/sidecar/agentos-protocol.d.ts +61 -0
- package/dist/sidecar/agentos-protocol.js +59 -0
- package/dist/sidecar/rpc-client.js +106 -37
- package/dist/types.d.ts +3 -2
- package/package.json +37 -32
package/dist/packages.d.ts
CHANGED
|
@@ -1,149 +1,28 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SoftwarePackageRef } from "./agentos-package.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
|
7
|
-
|
|
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.
|
|
116
|
-
*
|
|
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
|
|
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
|
-
* `<
|
|
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
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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.
|
|
116
|
-
*
|
|
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
|
-
* `<
|
|
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
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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(
|
|
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
|
-
}
|
package/dist/runtime-compat.d.ts
CHANGED
|
@@ -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;
|
package/dist/runtime-compat.js
CHANGED
|
@@ -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 = [
|
|
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;
|