@rivet-dev/agentos-core 0.0.0-codex-actor-plugin-contract-coverage.c7d8f87 → 0.0.0-fix-main-wasm-ownership.150c49a
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 +39 -36
- package/dist/agent-os.d.ts +197 -232
- package/dist/agent-os.js +769 -1162
- package/dist/agentos-package.d.ts +4 -2
- package/dist/agentos-package.js +4 -1
- package/dist/{host-tools-zod.d.ts → bindings-zod.d.ts} +1 -1
- package/dist/{host-tools-zod.js → bindings-zod.js} +27 -20
- package/dist/bindings.d.ts +43 -0
- package/dist/bindings.js +34 -0
- package/dist/cron/cron-manager.js +43 -10
- package/dist/cron/index.d.ts +1 -1
- package/dist/cron/types.d.ts +25 -9
- package/dist/filesystem-snapshot.d.ts +1 -2
- package/dist/filesystem-snapshot.js +0 -43
- package/dist/generated/AcpLimitsConfig.d.ts +16 -0
- package/dist/generated/BindingLimitsConfig.d.ts +10 -0
- package/dist/generated/CreateVmConfig.d.ts +2 -0
- package/dist/generated/ProcessLimitsConfig.d.ts +7 -0
- package/dist/generated/ProcessLimitsConfig.js +2 -0
- package/dist/generated/VmGroupConfig.d.ts +5 -0
- package/dist/generated/VmGroupConfig.js +2 -0
- package/dist/generated/VmLimitsConfig.d.ts +4 -2
- package/dist/generated/VmUserAccountConfig.d.ts +9 -0
- package/dist/generated/VmUserAccountConfig.js +2 -0
- package/dist/generated/VmUserConfig.d.ts +19 -0
- package/dist/generated/WasmLimitsConfig.d.ts +1 -0
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -5
- package/dist/layers.d.ts +5 -2
- package/dist/layers.js +0 -185
- package/dist/options-schema.d.ts +134 -31
- package/dist/options-schema.js +144 -26
- package/dist/runtime-compat.d.ts +11 -37
- package/dist/runtime-compat.js +74 -374
- package/dist/runtime.d.ts +10 -3
- package/dist/sandbox.d.ts +4 -4
- package/dist/sandbox.js +4 -4
- package/dist/session-api.d.ts +180 -0
- package/dist/session-api.js +1 -0
- package/dist/sidecar/agentos-protocol.d.ts +420 -29
- package/dist/sidecar/agentos-protocol.js +683 -93
- package/dist/sidecar/native-process-client.d.ts +1 -1
- package/dist/sidecar/native-process-client.js +1 -1
- package/dist/sidecar/rpc-client.d.ts +39 -6
- package/dist/sidecar/rpc-client.js +111 -30
- package/dist/test/runtime.d.ts +2 -1
- package/dist/test/runtime.js +2 -1
- package/dist/test/terminal-harness.js +0 -3
- package/dist/types.d.ts +4 -5
- package/package.json +19 -17
- package/dist/agent-session-types.d.ts +0 -67
- package/dist/generated/ToolLimitsConfig.d.ts +0 -10
- package/dist/host-tools.d.ts +0 -45
- package/dist/host-tools.js +0 -35
- package/dist/overlay-filesystem.d.ts +0 -19
- package/dist/overlay-filesystem.js +0 -645
- /package/dist/generated/{ToolLimitsConfig.js → BindingLimitsConfig.js} +0 -0
- /package/dist/{agent-session-types.js → generated/VmUserConfig.js} +0 -0
package/dist/runtime-compat.js
CHANGED
|
@@ -7,16 +7,12 @@ 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 {
|
|
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;
|
|
14
14
|
export const SOCK_DGRAM = 2;
|
|
15
15
|
export const SIGTERM = 15;
|
|
16
|
-
const S_IFREG = 0o100000;
|
|
17
|
-
const S_IFDIR = 0o040000;
|
|
18
|
-
const S_IFLNK = 0o120000;
|
|
19
|
-
const MAX_SYMLINK_DEPTH = 40;
|
|
20
16
|
const NODE_RUNTIME_BOOTSTRAP_COMMANDS = [
|
|
21
17
|
"node",
|
|
22
18
|
"npm",
|
|
@@ -71,9 +67,23 @@ const SIDECAR_BUILD_INPUTS = [
|
|
|
71
67
|
path.join(REPO_ROOT, "Cargo.toml"),
|
|
72
68
|
path.join(REPO_ROOT, "Cargo.lock"),
|
|
73
69
|
path.join(REPO_ROOT, "crates/bridge"),
|
|
70
|
+
path.join(REPO_ROOT, "crates/build-support"),
|
|
74
71
|
path.join(REPO_ROOT, "crates/execution"),
|
|
75
72
|
path.join(REPO_ROOT, "crates/kernel"),
|
|
76
|
-
path.join(REPO_ROOT, "crates/
|
|
73
|
+
path.join(REPO_ROOT, "crates/agentos-protocol"),
|
|
74
|
+
path.join(REPO_ROOT, "crates/agentos-sidecar"),
|
|
75
|
+
path.join(REPO_ROOT, "crates/native-sidecar"),
|
|
76
|
+
path.join(REPO_ROOT, "crates/native-sidecar-core"),
|
|
77
|
+
path.join(REPO_ROOT, "crates/sidecar-protocol"),
|
|
78
|
+
path.join(REPO_ROOT, "crates/v8-runtime"),
|
|
79
|
+
path.join(REPO_ROOT, "crates/vfs"),
|
|
80
|
+
path.join(REPO_ROOT, "crates/vm-config"),
|
|
81
|
+
path.join(REPO_ROOT, "packages/build-tools/bridge-src"),
|
|
82
|
+
path.join(REPO_ROOT, "packages/build-tools/package.json"),
|
|
83
|
+
path.join(REPO_ROOT, "packages/build-tools/scripts/build-v8-bridge.mjs"),
|
|
84
|
+
path.join(REPO_ROOT, "packages/core/fixtures/base-filesystem.json"),
|
|
85
|
+
path.join(REPO_ROOT, "packages/runtime-core/fixtures/base-filesystem.json"),
|
|
86
|
+
path.join(REPO_ROOT, "pnpm-lock.yaml"),
|
|
77
87
|
];
|
|
78
88
|
let ensuredSidecarBinary = null;
|
|
79
89
|
export class KernelError extends Error {
|
|
@@ -112,338 +122,6 @@ function dirnameVirtual(inputPath) {
|
|
|
112
122
|
const parts = normalized.split("/").filter(Boolean);
|
|
113
123
|
return parts.length <= 1 ? "/" : `/${parts.slice(0, -1).join("/")}`;
|
|
114
124
|
}
|
|
115
|
-
let nextInode = 1;
|
|
116
|
-
export class InMemoryFileSystem {
|
|
117
|
-
entries = new Map();
|
|
118
|
-
constructor() {
|
|
119
|
-
this.entries.set("/", this.newDirectory());
|
|
120
|
-
}
|
|
121
|
-
async readFile(targetPath) {
|
|
122
|
-
const entry = this.resolveEntry(targetPath);
|
|
123
|
-
if (!entry || entry.type !== "file") {
|
|
124
|
-
throw errnoError("ENOENT", `open '${targetPath}'`);
|
|
125
|
-
}
|
|
126
|
-
entry.atimeMs = Date.now();
|
|
127
|
-
return new Uint8Array(entry.data);
|
|
128
|
-
}
|
|
129
|
-
async readTextFile(targetPath) {
|
|
130
|
-
return new TextDecoder().decode(await this.readFile(targetPath));
|
|
131
|
-
}
|
|
132
|
-
async readDir(targetPath) {
|
|
133
|
-
return (await this.readDirWithTypes(targetPath)).map((entry) => entry.name);
|
|
134
|
-
}
|
|
135
|
-
async readDirWithTypes(targetPath) {
|
|
136
|
-
const resolved = this.resolvePath(targetPath);
|
|
137
|
-
const entry = this.entries.get(resolved);
|
|
138
|
-
if (!entry || entry.type !== "dir") {
|
|
139
|
-
throw errnoError("ENOENT", `scandir '${targetPath}'`);
|
|
140
|
-
}
|
|
141
|
-
const prefix = resolved === "/" ? "/" : `${resolved}/`;
|
|
142
|
-
const output = new Map();
|
|
143
|
-
for (const [entryPath, candidate] of this.entries) {
|
|
144
|
-
if (!entryPath.startsWith(prefix))
|
|
145
|
-
continue;
|
|
146
|
-
const rest = entryPath.slice(prefix.length);
|
|
147
|
-
if (!rest || rest.includes("/"))
|
|
148
|
-
continue;
|
|
149
|
-
output.set(rest, {
|
|
150
|
-
name: rest,
|
|
151
|
-
isDirectory: candidate.type === "dir",
|
|
152
|
-
isSymbolicLink: candidate.type === "symlink",
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
return [...output.values()];
|
|
156
|
-
}
|
|
157
|
-
async writeFile(targetPath, content) {
|
|
158
|
-
const normalized = normalizePath(targetPath);
|
|
159
|
-
await this.mkdir(dirnameVirtual(normalized), { recursive: true });
|
|
160
|
-
const data = typeof content === "string"
|
|
161
|
-
? new TextEncoder().encode(content)
|
|
162
|
-
: new Uint8Array(content);
|
|
163
|
-
const existing = this.entries.get(normalized);
|
|
164
|
-
if (existing?.type === "file") {
|
|
165
|
-
existing.data = data;
|
|
166
|
-
existing.mtimeMs = Date.now();
|
|
167
|
-
existing.ctimeMs = Date.now();
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const now = Date.now();
|
|
171
|
-
this.entries.set(normalized, {
|
|
172
|
-
type: "file",
|
|
173
|
-
data,
|
|
174
|
-
mode: S_IFREG | 0o644,
|
|
175
|
-
uid: 0,
|
|
176
|
-
gid: 0,
|
|
177
|
-
nlink: 1,
|
|
178
|
-
ino: nextInode++,
|
|
179
|
-
atimeMs: now,
|
|
180
|
-
mtimeMs: now,
|
|
181
|
-
ctimeMs: now,
|
|
182
|
-
birthtimeMs: now,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
async createDir(targetPath) {
|
|
186
|
-
const normalized = normalizePath(targetPath);
|
|
187
|
-
if (!this.entries.has(dirnameVirtual(normalized))) {
|
|
188
|
-
throw errnoError("ENOENT", `mkdir '${targetPath}'`);
|
|
189
|
-
}
|
|
190
|
-
if (!this.entries.has(normalized)) {
|
|
191
|
-
this.entries.set(normalized, this.newDirectory());
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
async mkdir(targetPath, options) {
|
|
195
|
-
const normalized = normalizePath(targetPath);
|
|
196
|
-
if (options?.recursive === false) {
|
|
197
|
-
return this.createDir(normalized);
|
|
198
|
-
}
|
|
199
|
-
let current = "";
|
|
200
|
-
for (const part of normalized.split("/").filter(Boolean)) {
|
|
201
|
-
current += `/${part}`;
|
|
202
|
-
if (!this.entries.has(current)) {
|
|
203
|
-
this.entries.set(current, this.newDirectory());
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
async exists(targetPath) {
|
|
208
|
-
try {
|
|
209
|
-
return this.entries.has(this.resolvePath(targetPath));
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
async stat(targetPath) {
|
|
216
|
-
const entry = this.resolveEntry(targetPath);
|
|
217
|
-
if (!entry)
|
|
218
|
-
throw errnoError("ENOENT", `stat '${targetPath}'`);
|
|
219
|
-
return this.toStat(entry);
|
|
220
|
-
}
|
|
221
|
-
async removeFile(targetPath) {
|
|
222
|
-
const resolved = normalizePath(targetPath);
|
|
223
|
-
const entry = this.entries.get(resolved);
|
|
224
|
-
if (!entry || entry.type === "dir") {
|
|
225
|
-
throw errnoError("ENOENT", `unlink '${targetPath}'`);
|
|
226
|
-
}
|
|
227
|
-
this.entries.delete(resolved);
|
|
228
|
-
}
|
|
229
|
-
async removeDir(targetPath) {
|
|
230
|
-
const resolved = this.resolvePath(targetPath);
|
|
231
|
-
if (resolved === "/") {
|
|
232
|
-
throw errnoError("EPERM", "operation not permitted");
|
|
233
|
-
}
|
|
234
|
-
const entry = this.entries.get(resolved);
|
|
235
|
-
if (!entry || entry.type !== "dir") {
|
|
236
|
-
throw errnoError("ENOENT", `rmdir '${targetPath}'`);
|
|
237
|
-
}
|
|
238
|
-
const prefix = `${resolved}/`;
|
|
239
|
-
for (const key of this.entries.keys()) {
|
|
240
|
-
if (key.startsWith(prefix)) {
|
|
241
|
-
throw errnoError("ENOTEMPTY", `directory not empty '${targetPath}'`);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
this.entries.delete(resolved);
|
|
245
|
-
}
|
|
246
|
-
async rename(oldPath, newPath) {
|
|
247
|
-
const oldResolved = this.resolvePath(oldPath);
|
|
248
|
-
const newResolved = normalizePath(newPath);
|
|
249
|
-
const entry = this.entries.get(oldResolved);
|
|
250
|
-
if (!entry)
|
|
251
|
-
throw errnoError("ENOENT", `rename '${oldPath}'`);
|
|
252
|
-
if (!this.entries.has(dirnameVirtual(newResolved))) {
|
|
253
|
-
throw errnoError("ENOENT", `rename '${newPath}'`);
|
|
254
|
-
}
|
|
255
|
-
if (entry.type !== "dir") {
|
|
256
|
-
this.entries.set(newResolved, entry);
|
|
257
|
-
this.entries.delete(oldResolved);
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const prefix = `${oldResolved}/`;
|
|
261
|
-
const moved = [];
|
|
262
|
-
for (const candidate of this.entries) {
|
|
263
|
-
if (candidate[0] === oldResolved || candidate[0].startsWith(prefix)) {
|
|
264
|
-
moved.push(candidate);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
for (const [candidatePath] of moved) {
|
|
268
|
-
this.entries.delete(candidatePath);
|
|
269
|
-
}
|
|
270
|
-
for (const [candidatePath, candidate] of moved) {
|
|
271
|
-
const nextPath = candidatePath === oldResolved
|
|
272
|
-
? newResolved
|
|
273
|
-
: `${newResolved}${candidatePath.slice(oldResolved.length)}`;
|
|
274
|
-
this.entries.set(nextPath, candidate);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
async realpath(targetPath) {
|
|
278
|
-
return this.resolvePath(targetPath);
|
|
279
|
-
}
|
|
280
|
-
async symlink(target, linkPath) {
|
|
281
|
-
const normalized = normalizePath(linkPath);
|
|
282
|
-
if (this.entries.has(normalized)) {
|
|
283
|
-
throw errnoError("EEXIST", `symlink '${linkPath}'`);
|
|
284
|
-
}
|
|
285
|
-
const now = Date.now();
|
|
286
|
-
this.entries.set(normalized, {
|
|
287
|
-
type: "symlink",
|
|
288
|
-
target,
|
|
289
|
-
mode: S_IFLNK | 0o777,
|
|
290
|
-
uid: 0,
|
|
291
|
-
gid: 0,
|
|
292
|
-
nlink: 1,
|
|
293
|
-
ino: nextInode++,
|
|
294
|
-
atimeMs: now,
|
|
295
|
-
mtimeMs: now,
|
|
296
|
-
ctimeMs: now,
|
|
297
|
-
birthtimeMs: now,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
async readlink(targetPath) {
|
|
301
|
-
const normalized = normalizePath(targetPath);
|
|
302
|
-
const entry = this.entries.get(normalized);
|
|
303
|
-
if (!entry || entry.type !== "symlink") {
|
|
304
|
-
throw errnoError("ENOENT", `readlink '${targetPath}'`);
|
|
305
|
-
}
|
|
306
|
-
return entry.target;
|
|
307
|
-
}
|
|
308
|
-
async lstat(targetPath) {
|
|
309
|
-
const entry = this.entries.get(normalizePath(targetPath));
|
|
310
|
-
if (!entry)
|
|
311
|
-
throw errnoError("ENOENT", `lstat '${targetPath}'`);
|
|
312
|
-
return this.toStat(entry);
|
|
313
|
-
}
|
|
314
|
-
async link(oldPath, newPath) {
|
|
315
|
-
const entry = this.resolveEntry(oldPath);
|
|
316
|
-
if (!entry || entry.type !== "file") {
|
|
317
|
-
throw errnoError("ENOENT", `link '${oldPath}'`);
|
|
318
|
-
}
|
|
319
|
-
const normalized = normalizePath(newPath);
|
|
320
|
-
if (this.entries.has(normalized)) {
|
|
321
|
-
throw errnoError("EEXIST", `link '${newPath}'`);
|
|
322
|
-
}
|
|
323
|
-
entry.nlink += 1;
|
|
324
|
-
this.entries.set(normalized, entry);
|
|
325
|
-
}
|
|
326
|
-
async chmod(targetPath, mode) {
|
|
327
|
-
const entry = this.resolveEntry(targetPath);
|
|
328
|
-
if (!entry)
|
|
329
|
-
throw errnoError("ENOENT", `chmod '${targetPath}'`);
|
|
330
|
-
const typeBits = mode & 0o170000;
|
|
331
|
-
entry.mode =
|
|
332
|
-
typeBits === 0 ? (entry.mode & 0o170000) | (mode & 0o7777) : mode;
|
|
333
|
-
entry.ctimeMs = Date.now();
|
|
334
|
-
}
|
|
335
|
-
async chown(targetPath, uid, gid) {
|
|
336
|
-
const entry = this.resolveEntry(targetPath);
|
|
337
|
-
if (!entry)
|
|
338
|
-
throw errnoError("ENOENT", `chown '${targetPath}'`);
|
|
339
|
-
entry.uid = uid;
|
|
340
|
-
entry.gid = gid;
|
|
341
|
-
entry.ctimeMs = Date.now();
|
|
342
|
-
}
|
|
343
|
-
async utimes(targetPath, atime, mtime) {
|
|
344
|
-
const entry = this.resolveEntry(targetPath);
|
|
345
|
-
if (!entry)
|
|
346
|
-
throw errnoError("ENOENT", `utimes '${targetPath}'`);
|
|
347
|
-
entry.atimeMs = atime;
|
|
348
|
-
entry.mtimeMs = mtime;
|
|
349
|
-
entry.ctimeMs = Date.now();
|
|
350
|
-
}
|
|
351
|
-
async truncate(targetPath, length) {
|
|
352
|
-
const entry = this.resolveEntry(targetPath);
|
|
353
|
-
if (!entry || entry.type !== "file") {
|
|
354
|
-
throw errnoError("ENOENT", `truncate '${targetPath}'`);
|
|
355
|
-
}
|
|
356
|
-
if (length < entry.data.length) {
|
|
357
|
-
entry.data = entry.data.slice(0, length);
|
|
358
|
-
}
|
|
359
|
-
else if (length > entry.data.length) {
|
|
360
|
-
const expanded = new Uint8Array(length);
|
|
361
|
-
expanded.set(entry.data);
|
|
362
|
-
entry.data = expanded;
|
|
363
|
-
}
|
|
364
|
-
entry.mtimeMs = Date.now();
|
|
365
|
-
entry.ctimeMs = Date.now();
|
|
366
|
-
}
|
|
367
|
-
async pread(targetPath, offset, length) {
|
|
368
|
-
const entry = this.resolveEntry(targetPath);
|
|
369
|
-
if (!entry || entry.type !== "file") {
|
|
370
|
-
throw errnoError("ENOENT", `open '${targetPath}'`);
|
|
371
|
-
}
|
|
372
|
-
if (offset >= entry.data.length)
|
|
373
|
-
return new Uint8Array(0);
|
|
374
|
-
return entry.data.slice(offset, Math.min(offset + length, entry.data.length));
|
|
375
|
-
}
|
|
376
|
-
async pwrite(targetPath, offset, data) {
|
|
377
|
-
const entry = this.resolveEntry(targetPath);
|
|
378
|
-
if (!entry || entry.type !== "file") {
|
|
379
|
-
throw errnoError("ENOENT", `open '${targetPath}'`);
|
|
380
|
-
}
|
|
381
|
-
const nextSize = Math.max(entry.data.length, offset + data.length);
|
|
382
|
-
const updated = new Uint8Array(nextSize);
|
|
383
|
-
updated.set(entry.data);
|
|
384
|
-
updated.set(new Uint8Array(data), offset);
|
|
385
|
-
entry.data = updated;
|
|
386
|
-
entry.mtimeMs = Date.now();
|
|
387
|
-
entry.ctimeMs = Date.now();
|
|
388
|
-
}
|
|
389
|
-
resolvePath(targetPath, depth = 0) {
|
|
390
|
-
if (depth > MAX_SYMLINK_DEPTH) {
|
|
391
|
-
throw errnoError("ELOOP", `too many symbolic links '${targetPath}'`);
|
|
392
|
-
}
|
|
393
|
-
const normalized = normalizePath(targetPath);
|
|
394
|
-
const entry = this.entries.get(normalized);
|
|
395
|
-
if (!entry)
|
|
396
|
-
return normalized;
|
|
397
|
-
if (entry.type === "symlink") {
|
|
398
|
-
const target = entry.target.startsWith("/")
|
|
399
|
-
? entry.target
|
|
400
|
-
: `${dirnameVirtual(normalized)}/${entry.target}`;
|
|
401
|
-
return this.resolvePath(target, depth + 1);
|
|
402
|
-
}
|
|
403
|
-
return normalized;
|
|
404
|
-
}
|
|
405
|
-
resolveEntry(targetPath) {
|
|
406
|
-
return this.entries.get(this.resolvePath(targetPath));
|
|
407
|
-
}
|
|
408
|
-
newDirectory() {
|
|
409
|
-
const now = Date.now();
|
|
410
|
-
return {
|
|
411
|
-
type: "dir",
|
|
412
|
-
mode: S_IFDIR | 0o755,
|
|
413
|
-
uid: 0,
|
|
414
|
-
gid: 0,
|
|
415
|
-
nlink: 2,
|
|
416
|
-
ino: nextInode++,
|
|
417
|
-
atimeMs: now,
|
|
418
|
-
mtimeMs: now,
|
|
419
|
-
ctimeMs: now,
|
|
420
|
-
birthtimeMs: now,
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
toStat(entry) {
|
|
424
|
-
const size = entry.type === "file" ? entry.data.length : 4096;
|
|
425
|
-
return {
|
|
426
|
-
mode: entry.mode,
|
|
427
|
-
size,
|
|
428
|
-
blocks: size === 0 ? 0 : Math.ceil(size / 512),
|
|
429
|
-
dev: 1,
|
|
430
|
-
rdev: 0,
|
|
431
|
-
isDirectory: entry.type === "dir",
|
|
432
|
-
isSymbolicLink: entry.type === "symlink",
|
|
433
|
-
atimeMs: entry.atimeMs,
|
|
434
|
-
mtimeMs: entry.mtimeMs,
|
|
435
|
-
ctimeMs: entry.ctimeMs,
|
|
436
|
-
birthtimeMs: entry.birthtimeMs,
|
|
437
|
-
ino: entry.ino,
|
|
438
|
-
nlink: entry.nlink,
|
|
439
|
-
uid: entry.uid,
|
|
440
|
-
gid: entry.gid,
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
export function createInMemoryFileSystem() {
|
|
445
|
-
return new InMemoryFileSystem();
|
|
446
|
-
}
|
|
447
125
|
export class NodeFileSystem {
|
|
448
126
|
rootPath;
|
|
449
127
|
constructor(options) {
|
|
@@ -824,7 +502,6 @@ export const WASMVM_COMMANDS = Object.freeze([
|
|
|
824
502
|
"unzip",
|
|
825
503
|
"sqlite3",
|
|
826
504
|
"curl",
|
|
827
|
-
"wget",
|
|
828
505
|
"git",
|
|
829
506
|
"git-remote-http",
|
|
830
507
|
"git-remote-https",
|
|
@@ -988,7 +665,6 @@ export const DEFAULT_FIRST_PARTY_TIERS = Object.freeze({
|
|
|
988
665
|
tac: "read-only",
|
|
989
666
|
tsort: "read-only",
|
|
990
667
|
curl: "full",
|
|
991
|
-
wget: "full",
|
|
992
668
|
sqlite3: "read-write",
|
|
993
669
|
});
|
|
994
670
|
class NativeRuntimeDescriptor {
|
|
@@ -1194,7 +870,7 @@ function createBootstrapEntries() {
|
|
|
1194
870
|
...KERNEL_POSIX_BOOTSTRAP_DIRS.map((entryPath) => ({
|
|
1195
871
|
path: entryPath,
|
|
1196
872
|
kind: "directory",
|
|
1197
|
-
mode: 0o755,
|
|
873
|
+
mode: entryPath === "/tmp" || entryPath === "/var/tmp" ? 0o1777 : 0o755,
|
|
1198
874
|
uid: 0,
|
|
1199
875
|
gid: 0,
|
|
1200
876
|
executable: false,
|
|
@@ -1457,7 +1133,10 @@ const VIRTUAL_FILESYSTEM_METHOD_NAMES = [
|
|
|
1457
1133
|
"pread",
|
|
1458
1134
|
"pwrite",
|
|
1459
1135
|
];
|
|
1460
|
-
const
|
|
1136
|
+
const DEFAULT_LIVE_FILESYSTEM_SYNC_MAX_BYTES = 64 * 1024 * 1024;
|
|
1137
|
+
class LiveFilesystemSyncLimitError extends Error {
|
|
1138
|
+
code = "ERR_AGENTOS_LIVE_FILESYSTEM_SYNC_LIMIT";
|
|
1139
|
+
}
|
|
1461
1140
|
function topLevelSyncRoot(targetPath) {
|
|
1462
1141
|
const normalized = normalizePath(targetPath);
|
|
1463
1142
|
const [first] = normalized.split("/").filter(Boolean);
|
|
@@ -1489,50 +1168,71 @@ async function ensureBoundParentDirectory(methods, targetPath) {
|
|
|
1489
1168
|
recursive: true,
|
|
1490
1169
|
});
|
|
1491
1170
|
}
|
|
1492
|
-
async function syncLiveFilesystemToBoundMethods(live, methods, paths) {
|
|
1171
|
+
async function syncLiveFilesystemToBoundMethods(live, methods, paths, maxBytes) {
|
|
1172
|
+
const snapshot = [];
|
|
1173
|
+
const usage = { bytes: 0 };
|
|
1493
1174
|
for (const targetPath of [...new Set(paths.map(normalizePath))].sort((left, right) => left.localeCompare(right))) {
|
|
1494
1175
|
if (!(await live.exists(targetPath).catch(() => false))) {
|
|
1495
1176
|
continue;
|
|
1496
1177
|
}
|
|
1497
|
-
await
|
|
1178
|
+
await snapshotLiveFilesystemPath(live, targetPath, snapshot, usage, maxBytes);
|
|
1179
|
+
}
|
|
1180
|
+
if (usage.bytes >= maxBytes * 0.8) {
|
|
1181
|
+
process.emitWarning(`live filesystem sync retained ${usage.bytes} of ${maxBytes} bytes; ` +
|
|
1182
|
+
"raise createKernel({ maxFilesystemBytes }) before increasing VM filesystem limits", { code: "AGENTOS_LIVE_FILESYSTEM_SYNC_NEAR_LIMIT" });
|
|
1183
|
+
}
|
|
1184
|
+
for (const entry of snapshot) {
|
|
1185
|
+
await applyLiveFilesystemSnapshotEntry(methods, entry);
|
|
1498
1186
|
}
|
|
1499
1187
|
}
|
|
1500
|
-
async function
|
|
1501
|
-
const stat =
|
|
1502
|
-
? await live.stat(targetPath)
|
|
1503
|
-
: await live.lstat(targetPath);
|
|
1188
|
+
async function snapshotLiveFilesystemPath(live, targetPath, snapshot, usage, maxBytes, knownEntry) {
|
|
1189
|
+
const stat = knownEntry ??
|
|
1190
|
+
(targetPath === "/" ? await live.stat(targetPath) : await live.lstat(targetPath));
|
|
1504
1191
|
if (stat.isSymbolicLink) {
|
|
1505
|
-
|
|
1506
|
-
await callBoundFilesystemMethod(methods, "removeFile", targetPath).catch(() => { });
|
|
1507
|
-
await callBoundFilesystemMethod(methods, "symlink", await live.readlink(targetPath), targetPath);
|
|
1192
|
+
snapshot.push({ kind: "symlink", path: targetPath, target: await live.readlink(targetPath) });
|
|
1508
1193
|
return;
|
|
1509
1194
|
}
|
|
1510
1195
|
if (stat.isDirectory) {
|
|
1511
|
-
|
|
1512
|
-
recursive: true,
|
|
1513
|
-
});
|
|
1196
|
+
snapshot.push({ kind: "directory", path: targetPath });
|
|
1514
1197
|
const children = (await live.readDirWithTypes(targetPath))
|
|
1515
|
-
.
|
|
1516
|
-
.
|
|
1517
|
-
.sort((left, right) => left.localeCompare(right));
|
|
1198
|
+
.filter((entry) => entry.name !== "." && entry.name !== "..")
|
|
1199
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
1518
1200
|
for (const child of children) {
|
|
1519
|
-
await
|
|
1520
|
-
? posixPath.join("/", child)
|
|
1521
|
-
: posixPath.join(targetPath, child));
|
|
1201
|
+
await snapshotLiveFilesystemPath(live, targetPath === "/"
|
|
1202
|
+
? posixPath.join("/", child.name)
|
|
1203
|
+
: posixPath.join(targetPath, child.name), snapshot, usage, maxBytes, child);
|
|
1522
1204
|
}
|
|
1523
1205
|
return;
|
|
1524
1206
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1207
|
+
const fileSize = "size" in stat && typeof stat.size === "number"
|
|
1208
|
+
? stat.size
|
|
1209
|
+
: (await live.lstat(targetPath)).size;
|
|
1210
|
+
if (fileSize > maxBytes - usage.bytes) {
|
|
1211
|
+
throw new LiveFilesystemSyncLimitError(`live filesystem sync for ${targetPath} exceeds ${maxBytes} bytes ` +
|
|
1212
|
+
"(createKernel maxFilesystemBytes); raise createKernel({ maxFilesystemBytes })");
|
|
1213
|
+
}
|
|
1214
|
+
const content = await live.readFile(targetPath);
|
|
1215
|
+
if (content.byteLength > maxBytes - usage.bytes) {
|
|
1216
|
+
throw new LiveFilesystemSyncLimitError(`live filesystem sync for ${targetPath} exceeds ${maxBytes} bytes ` +
|
|
1217
|
+
"(createKernel maxFilesystemBytes); raise createKernel({ maxFilesystemBytes })");
|
|
1218
|
+
}
|
|
1219
|
+
usage.bytes += content.byteLength;
|
|
1220
|
+
snapshot.push({ kind: "file", path: targetPath, content });
|
|
1221
|
+
}
|
|
1222
|
+
async function applyLiveFilesystemSnapshotEntry(methods, entry) {
|
|
1223
|
+
if (entry.kind === "directory") {
|
|
1224
|
+
await callBoundFilesystemMethod(methods, "mkdir", entry.path, { recursive: true });
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
await ensureBoundParentDirectory(methods, entry.path);
|
|
1228
|
+
if (entry.kind === "symlink") {
|
|
1229
|
+
await callBoundFilesystemMethod(methods, "removeFile", entry.path).catch(() => { });
|
|
1230
|
+
await callBoundFilesystemMethod(methods, "symlink", entry.target, entry.path);
|
|
1231
|
+
return;
|
|
1533
1232
|
}
|
|
1233
|
+
await callBoundFilesystemMethod(methods, "writeFile", entry.path, entry.content);
|
|
1534
1234
|
}
|
|
1535
|
-
function bindLiveFilesystem(target, getFilesystem) {
|
|
1235
|
+
function bindLiveFilesystem(target, getFilesystem, maxBytes) {
|
|
1536
1236
|
const fallback = {};
|
|
1537
1237
|
for (const method of VIRTUAL_FILESYSTEM_METHOD_NAMES) {
|
|
1538
1238
|
const candidate = target[method];
|
|
@@ -1558,7 +1258,7 @@ function bindLiveFilesystem(target, getFilesystem) {
|
|
|
1558
1258
|
if (!filesystem) {
|
|
1559
1259
|
return;
|
|
1560
1260
|
}
|
|
1561
|
-
await syncLiveFilesystemToBoundMethods(filesystem, fallback, paths);
|
|
1261
|
+
await syncLiveFilesystemToBoundMethods(filesystem, fallback, paths, maxBytes);
|
|
1562
1262
|
},
|
|
1563
1263
|
restore() {
|
|
1564
1264
|
for (const [method, delegate] of Object.entries(fallback)) {
|
|
@@ -1641,7 +1341,7 @@ class NativeKernel {
|
|
|
1641
1341
|
}));
|
|
1642
1342
|
}
|
|
1643
1343
|
this.vfs = new DeferredFileSystem(() => this.rootFilesystem);
|
|
1644
|
-
this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem);
|
|
1344
|
+
this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem, options.maxFilesystemBytes ?? DEFAULT_LIVE_FILESYSTEM_SYNC_MAX_BYTES);
|
|
1645
1345
|
}
|
|
1646
1346
|
get zombieTimerCount() {
|
|
1647
1347
|
return this.proxy?.zombieTimerCount ?? 0;
|
|
@@ -1804,9 +1504,10 @@ class NativeKernel {
|
|
|
1804
1504
|
this.pendingLocalMounts.unshift(localMount);
|
|
1805
1505
|
this.pendingLocalMounts.sort((left, right) => right.path.length - left.path.length);
|
|
1806
1506
|
if (!this.proxy) {
|
|
1507
|
+
// Pre-boot mounts apply during kernel initialization.
|
|
1807
1508
|
return;
|
|
1808
1509
|
}
|
|
1809
|
-
this.proxy.mountFs(mountPath, filesystem, {
|
|
1510
|
+
return this.proxy.mountFs(mountPath, filesystem, {
|
|
1810
1511
|
readOnly: localMount.readOnly,
|
|
1811
1512
|
sidecarMount: localMount.sidecarMount,
|
|
1812
1513
|
});
|
|
@@ -1817,7 +1518,7 @@ class NativeKernel {
|
|
|
1817
1518
|
if (pendingIndex >= 0) {
|
|
1818
1519
|
this.pendingLocalMounts.splice(pendingIndex, 1);
|
|
1819
1520
|
}
|
|
1820
|
-
this.proxy?.unmountFs(mountPath);
|
|
1521
|
+
return this.proxy?.unmountFs(mountPath);
|
|
1821
1522
|
}
|
|
1822
1523
|
async readFile(targetPath) {
|
|
1823
1524
|
await this.ensureReady();
|
|
@@ -1917,7 +1618,6 @@ class NativeKernel {
|
|
|
1917
1618
|
cwd: REPO_ROOT,
|
|
1918
1619
|
command: ensureNativeSidecarBinary(),
|
|
1919
1620
|
args: [],
|
|
1920
|
-
frameTimeoutMs: NATIVE_SIDECAR_FRAME_TIMEOUT_MS,
|
|
1921
1621
|
});
|
|
1922
1622
|
const session = await client.authenticateAndOpenSession();
|
|
1923
1623
|
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
|
}
|
|
@@ -45,7 +48,9 @@ export interface VirtualFileSystem {
|
|
|
45
48
|
lstat(path: string): Promise<VirtualStat>;
|
|
46
49
|
link(oldPath: string, newPath: string): Promise<void>;
|
|
47
50
|
chmod(path: string, mode: number): Promise<void>;
|
|
48
|
-
chown(path: string, uid: number, gid: number
|
|
51
|
+
chown(path: string, uid: number, gid: number, options?: {
|
|
52
|
+
followSymlinks?: boolean;
|
|
53
|
+
}): Promise<void>;
|
|
49
54
|
utimes(path: string, atime: number, mtime: number): Promise<void>;
|
|
50
55
|
truncate(path: string, length: number): Promise<void>;
|
|
51
56
|
pread(path: string, offset: number, length: number): Promise<Uint8Array>;
|
|
@@ -102,6 +107,7 @@ export interface ManagedProcess {
|
|
|
102
107
|
export interface ShellHandle {
|
|
103
108
|
pid: number;
|
|
104
109
|
write(data: Uint8Array | string): Promise<void>;
|
|
110
|
+
/** Ordered PTY output containing stdout and stderr exactly once. */
|
|
105
111
|
onData: ((data: Uint8Array) => void) | null;
|
|
106
112
|
resize(cols: number, rows: number): void;
|
|
107
113
|
kill(signal?: number): void;
|
|
@@ -114,6 +120,7 @@ export interface OpenShellOptions {
|
|
|
114
120
|
cwd?: string;
|
|
115
121
|
cols?: number;
|
|
116
122
|
rows?: number;
|
|
123
|
+
/** Optional stderr-only diagnostic tap; do not render it alongside `onData`. */
|
|
117
124
|
onStderr?: (data: Uint8Array) => void;
|
|
118
125
|
}
|
|
119
126
|
export interface ConnectTerminalOptions extends OpenShellOptions {
|
|
@@ -275,8 +282,8 @@ export interface Kernel extends KernelInterface {
|
|
|
275
282
|
connectTerminal(options?: ConnectTerminalOptions): Promise<number>;
|
|
276
283
|
mountFs(path: string, fs: VirtualFileSystem, options?: {
|
|
277
284
|
readOnly?: boolean;
|
|
278
|
-
}): void
|
|
279
|
-
unmountFs(path: string): void
|
|
285
|
+
}): void | Promise<void>;
|
|
286
|
+
unmountFs(path: string): void | Promise<void>;
|
|
280
287
|
readFile(path: string): Promise<Uint8Array>;
|
|
281
288
|
writeFile(path: string, content: string | Uint8Array): Promise<void>;
|
|
282
289
|
mkdir(path: string): Promise<void>;
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MountConfig, MountConfigJsonObject, NativeMountPluginDescriptor } from "./agent-os.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Bindings } from "./bindings.js";
|
|
3
3
|
export interface AgentOsSandboxProcessResult {
|
|
4
4
|
stdout?: string;
|
|
5
5
|
stderr?: string;
|
|
@@ -86,7 +86,7 @@ declare const sandboxDisposeHooks: unique symbol;
|
|
|
86
86
|
type SandboxDisposeHook = () => void | Promise<void>;
|
|
87
87
|
export type AgentOsSandboxExpandedOptions = {
|
|
88
88
|
mounts?: MountConfig[];
|
|
89
|
-
|
|
89
|
+
bindings?: Bindings[];
|
|
90
90
|
[sandboxDisposeHooks]?: SandboxDisposeHook[];
|
|
91
91
|
};
|
|
92
92
|
type ResolvedSandboxOptions = AgentOsSandboxCommonOptions & {
|
|
@@ -101,12 +101,12 @@ export type SandboxMountPluginConfig = MountConfigJsonObject & {
|
|
|
101
101
|
maxFullReadBytes?: number;
|
|
102
102
|
};
|
|
103
103
|
export declare function createSandboxFs(input: ResolvedSandboxOptions | AgentOsSandboxClientOptions): NativeMountPluginDescriptor<SandboxMountPluginConfig>;
|
|
104
|
-
export declare function createSandboxBindings(input: ResolvedSandboxOptions | AgentOsSandboxClientOptions):
|
|
104
|
+
export declare function createSandboxBindings(input: ResolvedSandboxOptions | AgentOsSandboxClientOptions): Bindings;
|
|
105
105
|
export declare function getSandboxDisposeHooks(options: object | undefined): SandboxDisposeHook[];
|
|
106
106
|
export declare function resolveSandboxOptions<T extends {
|
|
107
107
|
sandbox?: AgentOsSandboxInput;
|
|
108
108
|
}>(options: T): Promise<Omit<T, "sandbox"> & {
|
|
109
109
|
mounts?: MountConfig[];
|
|
110
|
-
|
|
110
|
+
bindings?: Bindings[];
|
|
111
111
|
}>;
|
|
112
112
|
export {};
|
package/dist/sandbox.js
CHANGED
|
@@ -49,7 +49,7 @@ export function createSandboxBindings(input) {
|
|
|
49
49
|
return {
|
|
50
50
|
name: "sandbox",
|
|
51
51
|
description: "Execute commands and manage processes in a remote sandbox environment.",
|
|
52
|
-
|
|
52
|
+
bindings: {
|
|
53
53
|
"run-command": binding({
|
|
54
54
|
description: "Run a command synchronously in the sandbox and return its stdout, stderr, and exit code.",
|
|
55
55
|
inputSchema: z.object({
|
|
@@ -252,13 +252,13 @@ export async function resolveSandboxOptions(options) {
|
|
|
252
252
|
readOnly: sandboxOptions.readOnly,
|
|
253
253
|
},
|
|
254
254
|
];
|
|
255
|
-
const
|
|
256
|
-
...(expanded.
|
|
255
|
+
const bindings = [
|
|
256
|
+
...(expanded.bindings ?? []),
|
|
257
257
|
createSandboxBindings(sandboxOptions),
|
|
258
258
|
];
|
|
259
259
|
return attachSandboxDisposeHooks({
|
|
260
260
|
...expanded,
|
|
261
261
|
mounts,
|
|
262
|
-
|
|
262
|
+
bindings,
|
|
263
263
|
}, normalizedSandbox.dispose ? [normalizedSandbox.dispose] : []);
|
|
264
264
|
}
|