@rivet-dev/agentos-core 0.2.8-rc.2 → 0.2.8-rc.3
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 +40 -37
- package/dist/agent-os.d.ts +184 -230
- package/dist/agent-os.js +751 -1158
- package/dist/agentos-package.d.ts +5 -3
- package/dist/agentos-package.js +5 -2
- 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 +133 -31
- package/dist/options-schema.js +143 -26
- package/dist/runtime-compat.d.ts +4 -35
- package/dist/runtime-compat.js +84 -372
- package/dist/runtime.d.ts +3 -1
- 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 +429 -29
- package/dist/sidecar/agentos-protocol.js +691 -93
- package/dist/sidecar/rpc-client.d.ts +18 -6
- package/dist/sidecar/rpc-client.js +66 -18
- package/dist/test/runtime.d.ts +2 -1
- package/dist/test/runtime.js +2 -1
- package/dist/types.d.ts +4 -5
- package/package.json +20 -19
- 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
|
@@ -13,10 +13,6 @@ 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,9 +870,13 @@ function createBootstrapEntries() {
|
|
|
1194
870
|
...KERNEL_POSIX_BOOTSTRAP_DIRS.map((entryPath) => ({
|
|
1195
871
|
path: entryPath,
|
|
1196
872
|
kind: "directory",
|
|
1197
|
-
mode:
|
|
1198
|
-
|
|
1199
|
-
|
|
873
|
+
mode: entryPath === "/tmp" || entryPath === "/var/tmp"
|
|
874
|
+
? 0o1777
|
|
875
|
+
: entryPath === "/home/agentos"
|
|
876
|
+
? 0o2755
|
|
877
|
+
: 0o755,
|
|
878
|
+
uid: entryPath === "/home/agentos" || entryPath === "/workspace" ? 1000 : 0,
|
|
879
|
+
gid: entryPath === "/home/agentos" || entryPath === "/workspace" ? 1000 : 0,
|
|
1200
880
|
executable: false,
|
|
1201
881
|
})),
|
|
1202
882
|
{
|
|
@@ -1457,7 +1137,10 @@ const VIRTUAL_FILESYSTEM_METHOD_NAMES = [
|
|
|
1457
1137
|
"pread",
|
|
1458
1138
|
"pwrite",
|
|
1459
1139
|
];
|
|
1460
|
-
const
|
|
1140
|
+
const DEFAULT_LIVE_FILESYSTEM_SYNC_MAX_BYTES = 64 * 1024 * 1024;
|
|
1141
|
+
class LiveFilesystemSyncLimitError extends Error {
|
|
1142
|
+
code = "ERR_AGENTOS_LIVE_FILESYSTEM_SYNC_LIMIT";
|
|
1143
|
+
}
|
|
1461
1144
|
function topLevelSyncRoot(targetPath) {
|
|
1462
1145
|
const normalized = normalizePath(targetPath);
|
|
1463
1146
|
const [first] = normalized.split("/").filter(Boolean);
|
|
@@ -1489,50 +1172,79 @@ async function ensureBoundParentDirectory(methods, targetPath) {
|
|
|
1489
1172
|
recursive: true,
|
|
1490
1173
|
});
|
|
1491
1174
|
}
|
|
1492
|
-
async function syncLiveFilesystemToBoundMethods(live, methods, paths) {
|
|
1175
|
+
async function syncLiveFilesystemToBoundMethods(live, methods, paths, maxBytes) {
|
|
1176
|
+
const snapshot = [];
|
|
1177
|
+
const usage = { bytes: 0 };
|
|
1493
1178
|
for (const targetPath of [...new Set(paths.map(normalizePath))].sort((left, right) => left.localeCompare(right))) {
|
|
1494
1179
|
if (!(await live.exists(targetPath).catch(() => false))) {
|
|
1495
1180
|
continue;
|
|
1496
1181
|
}
|
|
1497
|
-
await
|
|
1182
|
+
await snapshotLiveFilesystemPath(live, targetPath, snapshot, usage, maxBytes);
|
|
1183
|
+
}
|
|
1184
|
+
if (usage.bytes >= maxBytes * 0.8) {
|
|
1185
|
+
process.emitWarning(`live filesystem sync retained ${usage.bytes} of ${maxBytes} bytes; ` +
|
|
1186
|
+
"raise createKernel({ maxFilesystemBytes }) before increasing VM filesystem limits", { code: "AGENTOS_LIVE_FILESYSTEM_SYNC_NEAR_LIMIT" });
|
|
1187
|
+
}
|
|
1188
|
+
for (const entry of snapshot) {
|
|
1189
|
+
await applyLiveFilesystemSnapshotEntry(methods, entry);
|
|
1498
1190
|
}
|
|
1499
1191
|
}
|
|
1500
|
-
async function
|
|
1501
|
-
const stat =
|
|
1502
|
-
|
|
1503
|
-
|
|
1192
|
+
async function snapshotLiveFilesystemPath(live, targetPath, snapshot, usage, maxBytes, knownEntry) {
|
|
1193
|
+
const stat = knownEntry ??
|
|
1194
|
+
(targetPath === "/"
|
|
1195
|
+
? await live.stat(targetPath)
|
|
1196
|
+
: await live.lstat(targetPath));
|
|
1504
1197
|
if (stat.isSymbolicLink) {
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1198
|
+
snapshot.push({
|
|
1199
|
+
kind: "symlink",
|
|
1200
|
+
path: targetPath,
|
|
1201
|
+
target: await live.readlink(targetPath),
|
|
1202
|
+
});
|
|
1508
1203
|
return;
|
|
1509
1204
|
}
|
|
1510
1205
|
if (stat.isDirectory) {
|
|
1511
|
-
|
|
1512
|
-
recursive: true,
|
|
1513
|
-
});
|
|
1206
|
+
snapshot.push({ kind: "directory", path: targetPath });
|
|
1514
1207
|
const children = (await live.readDirWithTypes(targetPath))
|
|
1515
|
-
.
|
|
1516
|
-
.
|
|
1517
|
-
.sort((left, right) => left.localeCompare(right));
|
|
1208
|
+
.filter((entry) => entry.name !== "." && entry.name !== "..")
|
|
1209
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
1518
1210
|
for (const child of children) {
|
|
1519
|
-
await
|
|
1520
|
-
? posixPath.join("/", child)
|
|
1521
|
-
: posixPath.join(targetPath, child));
|
|
1211
|
+
await snapshotLiveFilesystemPath(live, targetPath === "/"
|
|
1212
|
+
? posixPath.join("/", child.name)
|
|
1213
|
+
: posixPath.join(targetPath, child.name), snapshot, usage, maxBytes, child);
|
|
1522
1214
|
}
|
|
1523
1215
|
return;
|
|
1524
1216
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1217
|
+
const fileSize = "size" in stat && typeof stat.size === "number"
|
|
1218
|
+
? stat.size
|
|
1219
|
+
: (await live.lstat(targetPath)).size;
|
|
1220
|
+
if (fileSize > maxBytes - usage.bytes) {
|
|
1221
|
+
throw new LiveFilesystemSyncLimitError(`live filesystem sync for ${targetPath} exceeds ${maxBytes} bytes ` +
|
|
1222
|
+
"(createKernel maxFilesystemBytes); raise createKernel({ maxFilesystemBytes })");
|
|
1223
|
+
}
|
|
1224
|
+
const content = await live.readFile(targetPath);
|
|
1225
|
+
if (content.byteLength > maxBytes - usage.bytes) {
|
|
1226
|
+
throw new LiveFilesystemSyncLimitError(`live filesystem sync for ${targetPath} exceeds ${maxBytes} bytes ` +
|
|
1227
|
+
"(createKernel maxFilesystemBytes); raise createKernel({ maxFilesystemBytes })");
|
|
1228
|
+
}
|
|
1229
|
+
usage.bytes += content.byteLength;
|
|
1230
|
+
snapshot.push({ kind: "file", path: targetPath, content });
|
|
1231
|
+
}
|
|
1232
|
+
async function applyLiveFilesystemSnapshotEntry(methods, entry) {
|
|
1233
|
+
if (entry.kind === "directory") {
|
|
1234
|
+
await callBoundFilesystemMethod(methods, "mkdir", entry.path, {
|
|
1235
|
+
recursive: true,
|
|
1236
|
+
});
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
await ensureBoundParentDirectory(methods, entry.path);
|
|
1240
|
+
if (entry.kind === "symlink") {
|
|
1241
|
+
await callBoundFilesystemMethod(methods, "removeFile", entry.path).catch(() => { });
|
|
1242
|
+
await callBoundFilesystemMethod(methods, "symlink", entry.target, entry.path);
|
|
1243
|
+
return;
|
|
1533
1244
|
}
|
|
1245
|
+
await callBoundFilesystemMethod(methods, "writeFile", entry.path, entry.content);
|
|
1534
1246
|
}
|
|
1535
|
-
function bindLiveFilesystem(target, getFilesystem) {
|
|
1247
|
+
function bindLiveFilesystem(target, getFilesystem, maxBytes) {
|
|
1536
1248
|
const fallback = {};
|
|
1537
1249
|
for (const method of VIRTUAL_FILESYSTEM_METHOD_NAMES) {
|
|
1538
1250
|
const candidate = target[method];
|
|
@@ -1558,7 +1270,7 @@ function bindLiveFilesystem(target, getFilesystem) {
|
|
|
1558
1270
|
if (!filesystem) {
|
|
1559
1271
|
return;
|
|
1560
1272
|
}
|
|
1561
|
-
await syncLiveFilesystemToBoundMethods(filesystem, fallback, paths);
|
|
1273
|
+
await syncLiveFilesystemToBoundMethods(filesystem, fallback, paths, maxBytes);
|
|
1562
1274
|
},
|
|
1563
1275
|
restore() {
|
|
1564
1276
|
for (const [method, delegate] of Object.entries(fallback)) {
|
|
@@ -1641,7 +1353,7 @@ class NativeKernel {
|
|
|
1641
1353
|
}));
|
|
1642
1354
|
}
|
|
1643
1355
|
this.vfs = new DeferredFileSystem(() => this.rootFilesystem);
|
|
1644
|
-
this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem);
|
|
1356
|
+
this.liveFilesystemBinding = bindLiveFilesystem(this.options.filesystem, () => this.rootFilesystem, options.maxFilesystemBytes ?? DEFAULT_LIVE_FILESYSTEM_SYNC_MAX_BYTES);
|
|
1645
1357
|
}
|
|
1646
1358
|
get zombieTimerCount() {
|
|
1647
1359
|
return this.proxy?.zombieTimerCount ?? 0;
|
package/dist/runtime.d.ts
CHANGED
|
@@ -48,7 +48,9 @@ export interface VirtualFileSystem {
|
|
|
48
48
|
lstat(path: string): Promise<VirtualStat>;
|
|
49
49
|
link(oldPath: string, newPath: string): Promise<void>;
|
|
50
50
|
chmod(path: string, mode: number): Promise<void>;
|
|
51
|
-
chown(path: string, uid: number, gid: number
|
|
51
|
+
chown(path: string, uid: number, gid: number, options?: {
|
|
52
|
+
followSymlinks?: boolean;
|
|
53
|
+
}): Promise<void>;
|
|
52
54
|
utimes(path: string, atime: number, mtime: number): Promise<void>;
|
|
53
55
|
truncate(path: string, length: number): Promise<void>;
|
|
54
56
|
pread(path: string, offset: number, length: number): Promise<Uint8Array>;
|
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
|
}
|