@madarco/agentbox 0.11.3 → 0.13.0
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/CHANGELOG.md +90 -0
- package/README.md +11 -0
- package/dist/{_cloud-attach-XWCVLO5V.js → _cloud-attach-HJC672UR.js} +3 -3
- package/dist/{chunk-ZGVMN54V.js → chunk-2LF5YILI.js} +21 -3
- package/dist/chunk-2LF5YILI.js.map +1 -0
- package/dist/{chunk-MXXXKJYS.js → chunk-4NQXNQ53.js} +234 -83
- package/dist/chunk-4NQXNQ53.js.map +1 -0
- package/dist/{chunk-ZJXTIH6C.js → chunk-B4QG2MCW.js} +1352 -851
- package/dist/chunk-B4QG2MCW.js.map +1 -0
- package/dist/{chunk-GYJ62GFL.js → chunk-QYRK5H6Q.js} +297 -33
- package/dist/chunk-QYRK5H6Q.js.map +1 -0
- package/dist/{dist-WMQDMTWS.js → dist-7KVUIKJX.js} +8 -5
- package/dist/dist-7KVUIKJX.js.map +1 -0
- package/dist/{dist-RAZP76VX.js → dist-JAN5VABY.js} +3 -3
- package/dist/{dist-ASLPRUQR.js → dist-OG6NW6SM.js} +28 -2
- package/dist/{dist-PTJ6CEQY.js → dist-OPIBZ7XM.js} +4 -4
- package/dist/index.js +1720 -876
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/runtime/docker/packages/ctl/dist/bin.cjs +341 -5
- package/runtime/docker/packages/sandbox-docker/scripts/gh-shim +86 -5
- package/runtime/hetzner/ctl.cjs +341 -5
- package/runtime/hetzner/gh-shim +86 -5
- package/runtime/relay/bin.cjs +293 -4
- package/runtime/vercel/ctl.cjs +341 -5
- package/runtime/vercel/gh-shim +86 -5
- package/share/host-skills/agentbox/SKILL.md +16 -5
- package/share/host-skills/agentbox-info/SKILL.md +3 -1
- package/dist/chunk-GYJ62GFL.js.map +0 -1
- package/dist/chunk-MXXXKJYS.js.map +0 -1
- package/dist/chunk-ZGVMN54V.js.map +0 -1
- package/dist/chunk-ZJXTIH6C.js.map +0 -1
- package/dist/dist-WMQDMTWS.js.map +0 -1
- /package/dist/{_cloud-attach-XWCVLO5V.js.map → _cloud-attach-HJC672UR.js.map} +0 -0
- /package/dist/{dist-RAZP76VX.js.map → dist-JAN5VABY.js.map} +0 -0
- /package/dist/{dist-ASLPRUQR.js.map → dist-OG6NW6SM.js.map} +0 -0
- /package/dist/{dist-PTJ6CEQY.js.map → dist-OPIBZ7XM.js.map} +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
BOX_DYNAMIC_SYNC_MANIFEST,
|
|
4
|
+
BOX_MEMORY_DIR,
|
|
5
|
+
BOX_WORKFLOWS_DIR,
|
|
3
6
|
CLAUDE_FORWARDED_ENV_KEYS,
|
|
4
7
|
CODEX_CREDENTIALS_BACKUP_FILE,
|
|
5
8
|
CODEX_FORWARDED_ENV_KEYS,
|
|
@@ -7,7 +10,9 @@ import {
|
|
|
7
10
|
OPENCODE_CREDENTIALS_BACKUP_FILE,
|
|
8
11
|
OPENCODE_FORWARDED_ENV_KEYS,
|
|
9
12
|
buildHostEnvFindArgs,
|
|
13
|
+
buildHostSyncManifest,
|
|
10
14
|
buildTmuxConfigShellSnippet,
|
|
15
|
+
computeSyncDelta,
|
|
11
16
|
ensureRelay,
|
|
12
17
|
forgetBoxFromRelay,
|
|
13
18
|
generateBoxId,
|
|
@@ -25,13 +30,16 @@ import {
|
|
|
25
30
|
stageClaudeStaticForUpload,
|
|
26
31
|
stageCodexCredentialsForUpload,
|
|
27
32
|
stageCodexStaticForUpload,
|
|
33
|
+
stageDynamicSyncTarball,
|
|
28
34
|
stageOpencodeCredentialsForUpload,
|
|
29
35
|
stageOpencodeStateForUpload,
|
|
30
36
|
stageOpencodeStaticForUpload
|
|
31
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-B4QG2MCW.js";
|
|
32
38
|
import {
|
|
33
39
|
allocateProjectIndex,
|
|
34
40
|
detectGitRepos,
|
|
41
|
+
readCliStamp,
|
|
42
|
+
readPreparedStateRaw,
|
|
35
43
|
readState,
|
|
36
44
|
recordBox,
|
|
37
45
|
removeBoxRecord
|
|
@@ -41,24 +49,28 @@ import {
|
|
|
41
49
|
import { basename as basename2 } from "path";
|
|
42
50
|
import { chmod, mkdir, writeFile } from "fs/promises";
|
|
43
51
|
import { dirname } from "path";
|
|
44
|
-
import {
|
|
45
|
-
import { homedir } from "os";
|
|
46
|
-
import { basename, join } from "path";
|
|
47
|
-
import { mkdtemp, rm as rm2, writeFile as writeFile3 } from "fs/promises";
|
|
52
|
+
import { mkdtemp, rm, writeFile as writeFile2 } from "fs/promises";
|
|
48
53
|
import { tmpdir } from "os";
|
|
49
|
-
import {
|
|
54
|
+
import { dirname as dirname2, join } from "path";
|
|
50
55
|
import { execa } from "execa";
|
|
51
|
-
import {
|
|
56
|
+
import { mkdir as mkdir2, readFile, readdir, rm as rm2, writeFile as writeFile3 } from "fs/promises";
|
|
57
|
+
import { homedir } from "os";
|
|
58
|
+
import { basename, join as join2 } from "path";
|
|
59
|
+
import { mkdtemp as mkdtemp2, rm as rm3, writeFile as writeFile4 } from "fs/promises";
|
|
52
60
|
import { tmpdir as tmpdir2 } from "os";
|
|
53
61
|
import { join as join3 } from "path";
|
|
54
62
|
import { execa as execa2 } from "execa";
|
|
55
|
-
import {
|
|
63
|
+
import { mkdtemp as mkdtemp3, rm as rm4 } from "fs/promises";
|
|
64
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
56
65
|
import { join as join4 } from "path";
|
|
57
|
-
import { parse as parseYaml } from "yaml";
|
|
58
66
|
import { execa as execa3 } from "execa";
|
|
67
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
68
|
+
import { join as join5 } from "path";
|
|
69
|
+
import { parse as parseYaml } from "yaml";
|
|
70
|
+
import { execa as execa4 } from "execa";
|
|
59
71
|
import { existsSync, mkdirSync, renameSync, statSync } from "fs";
|
|
60
|
-
import { mkdtemp as
|
|
61
|
-
import { tmpdir as
|
|
72
|
+
import { mkdtemp as mkdtemp4, rm as rm5 } from "fs/promises";
|
|
73
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
62
74
|
import {
|
|
63
75
|
basename as hostBasename,
|
|
64
76
|
dirname as hostDirname,
|
|
@@ -66,10 +78,10 @@ import {
|
|
|
66
78
|
resolve as hostResolve
|
|
67
79
|
} from "path";
|
|
68
80
|
import { posix } from "path";
|
|
69
|
-
import { execa as
|
|
70
|
-
import { mkdtemp as
|
|
71
|
-
import { tmpdir as
|
|
72
|
-
import { join as
|
|
81
|
+
import { execa as execa5 } from "execa";
|
|
82
|
+
import { mkdtemp as mkdtemp5, rm as rm6, stat } from "fs/promises";
|
|
83
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
84
|
+
import { join as join6 } from "path";
|
|
73
85
|
var CREDENTIALS_VOLUME = "agentbox-credentials";
|
|
74
86
|
var AGENT_SPECS = [
|
|
75
87
|
{
|
|
@@ -267,30 +279,132 @@ async function extractCloudAgentCredentials(backend, handle, opts = {}) {
|
|
|
267
279
|
}
|
|
268
280
|
return extracted;
|
|
269
281
|
}
|
|
270
|
-
|
|
282
|
+
function sq(p) {
|
|
283
|
+
return `'${p.replace(/'/g, `'\\''`)}'`;
|
|
284
|
+
}
|
|
285
|
+
var REMOTE_TAR = "/tmp/agentbox-dynsync.tar.gz";
|
|
286
|
+
var BOX_STAGE = "/tmp/agentbox-dynsync-stage";
|
|
287
|
+
async function seedDynamicConfig(backend, handle, opts) {
|
|
288
|
+
const log = opts.onLog ?? (() => {
|
|
289
|
+
});
|
|
290
|
+
try {
|
|
291
|
+
let boxManifest = null;
|
|
292
|
+
try {
|
|
293
|
+
const res = await backend.exec(handle, `cat ${BOX_DYNAMIC_SYNC_MANIFEST} 2>/dev/null || true`);
|
|
294
|
+
const out = res.stdout.trim();
|
|
295
|
+
if (res.exitCode === 0 && out.length > 0) {
|
|
296
|
+
boxManifest = JSON.parse(out);
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
boxManifest = null;
|
|
300
|
+
}
|
|
301
|
+
const host = await buildHostSyncManifest(opts.workspacePath);
|
|
302
|
+
const delta = computeSyncDelta(host, boxManifest);
|
|
303
|
+
if (delta.uploads.length === 0 && delta.deletions.length === 0) {
|
|
304
|
+
log("claude workflows + memory already up to date in box");
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
delta.nextManifest.syncedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
308
|
+
const staged = await stageDynamicSyncTarball(delta.uploads);
|
|
309
|
+
const manifestDir = await mkdtemp(join(tmpdir(), "agentbox-dynsync-manifest-"));
|
|
310
|
+
const manifestTmp = join(manifestDir, "dynamic-sync.json");
|
|
311
|
+
await writeFile2(manifestTmp, JSON.stringify(delta.nextManifest, null, 2));
|
|
312
|
+
try {
|
|
313
|
+
const steps = [
|
|
314
|
+
"set -e",
|
|
315
|
+
`mkdir -p /home/vscode/.agentbox ${BOX_WORKFLOWS_DIR} ${BOX_MEMORY_DIR}`
|
|
316
|
+
];
|
|
317
|
+
if (staged.tarballPath) {
|
|
318
|
+
await backend.uploadFile(handle, staged.tarballPath, REMOTE_TAR);
|
|
319
|
+
steps.push(
|
|
320
|
+
`rm -rf ${BOX_STAGE}`,
|
|
321
|
+
`mkdir -p ${BOX_STAGE}`,
|
|
322
|
+
`tar -xzf ${REMOTE_TAR} -C ${BOX_STAGE}`,
|
|
323
|
+
`if [ -d ${BOX_STAGE}/workflows ]; then cp -a ${BOX_STAGE}/workflows/. ${BOX_WORKFLOWS_DIR}/; fi`,
|
|
324
|
+
`if [ -d ${BOX_STAGE}/memory ]; then cp -a ${BOX_STAGE}/memory/. ${BOX_MEMORY_DIR}/; fi`,
|
|
325
|
+
`rm -rf ${BOX_STAGE} ${REMOTE_TAR}`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
for (const d of delta.deletions) {
|
|
329
|
+
steps.push(`rm -f ${sq(d.dst)}`);
|
|
330
|
+
}
|
|
331
|
+
const res = await backend.exec(handle, steps.join("; "));
|
|
332
|
+
if (res.exitCode !== 0) {
|
|
333
|
+
log(
|
|
334
|
+
`dynamic config seed failed (exit ${String(res.exitCode)}): ${res.stderr.slice(-200)}`
|
|
335
|
+
);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
await backend.uploadFile(handle, manifestTmp, BOX_DYNAMIC_SYNC_MANIFEST);
|
|
339
|
+
log(
|
|
340
|
+
`seeded claude workflows + memory: ${String(delta.uploads.length)} file(s) updated, ${String(delta.deletions.length)} removed`
|
|
341
|
+
);
|
|
342
|
+
} finally {
|
|
343
|
+
await staged.cleanup();
|
|
344
|
+
await rm(dirname2(manifestTmp), { recursive: true, force: true });
|
|
345
|
+
}
|
|
346
|
+
} catch (err) {
|
|
347
|
+
log(
|
|
348
|
+
`claude workflows + memory seed skipped (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function quoteShellArgv(argv) {
|
|
353
|
+
return argv.map(quoteShellArg).join(" ");
|
|
354
|
+
}
|
|
355
|
+
function quoteShellArg(arg) {
|
|
356
|
+
if (arg.length === 0) return "''";
|
|
357
|
+
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return arg;
|
|
358
|
+
return "'" + arg.replace(/'/g, "'\\''") + "'";
|
|
359
|
+
}
|
|
360
|
+
function bashScript(body) {
|
|
361
|
+
return `bash -c ${quoteShellArg(body)}`;
|
|
362
|
+
}
|
|
363
|
+
var FALLBACK_NAME = "agentbox";
|
|
364
|
+
var FALLBACK_EMAIL = "agentbox@users.noreply.github.com";
|
|
365
|
+
async function seedGitIdentity(backend, handle, opts = {}) {
|
|
366
|
+
const log = opts.onLog ?? (() => {
|
|
367
|
+
});
|
|
368
|
+
const name = await readHostGitConfig("user.name", opts.hostRepo) ?? FALLBACK_NAME;
|
|
369
|
+
const email = await readHostGitConfig("user.email", opts.hostRepo) ?? FALLBACK_EMAIL;
|
|
370
|
+
const script = `git config --global user.name ${quoteShellArg(name)} && git config --global user.email ${quoteShellArg(email)}`;
|
|
371
|
+
const r = await backend.exec(handle, bashScript(script));
|
|
372
|
+
if (r.exitCode !== 0) {
|
|
373
|
+
log(`git: identity config failed (exit ${String(r.exitCode)}): ${(r.stderr || r.stdout).trim()}`);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
log(`git: configured committer identity ${name} <${email}>`);
|
|
377
|
+
}
|
|
378
|
+
async function readHostGitConfig(key, hostRepo) {
|
|
379
|
+
const args = hostRepo ? ["-C", hostRepo, "config", key] : ["config", key];
|
|
380
|
+
const r = await execa("git", args, { reject: false });
|
|
381
|
+
if (r.exitCode !== 0) return null;
|
|
382
|
+
const value = (r.stdout ?? "").trim();
|
|
383
|
+
return value.length > 0 ? value : null;
|
|
384
|
+
}
|
|
385
|
+
var CLOUD_CHECKPOINTS_ROOT = join2(homedir(), ".agentbox", "cloud-checkpoints");
|
|
271
386
|
var CLOUD_SNAPSHOT_NAME_PREFIX = "agentbox-ckpt-";
|
|
272
387
|
function cloudSnapshotName(projectRoot, name) {
|
|
273
388
|
const mnemonic = sanitizeMnemonic(basename(projectRoot));
|
|
274
389
|
return `${CLOUD_SNAPSHOT_NAME_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}-${name}`;
|
|
275
390
|
}
|
|
276
391
|
function backendDir(backend, projectRoot) {
|
|
277
|
-
return
|
|
392
|
+
return join2(CLOUD_CHECKPOINTS_ROOT, backend, projectDirSegment(projectRoot));
|
|
278
393
|
}
|
|
279
394
|
function checkpointDir(backend, projectRoot, name) {
|
|
280
|
-
return
|
|
395
|
+
return join2(backendDir(backend, projectRoot), name);
|
|
281
396
|
}
|
|
282
397
|
async function readManifest(dir) {
|
|
283
398
|
try {
|
|
284
|
-
const raw = await readFile(
|
|
399
|
+
const raw = await readFile(join2(dir, "manifest.json"), "utf8");
|
|
285
400
|
const m = JSON.parse(raw);
|
|
286
|
-
if (m.schema !== 1) return null;
|
|
401
|
+
if (m.schema !== 1 && m.schema !== 2) return null;
|
|
287
402
|
return m;
|
|
288
403
|
} catch {
|
|
289
404
|
return null;
|
|
290
405
|
}
|
|
291
406
|
}
|
|
292
|
-
async function
|
|
293
|
-
const root = backendDir(backend, projectRoot);
|
|
407
|
+
async function listCloudCheckpointsInDir(root) {
|
|
294
408
|
let entries;
|
|
295
409
|
try {
|
|
296
410
|
entries = (await readdir(root, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -299,13 +413,31 @@ async function listCloudCheckpoints(projectRoot, backend) {
|
|
|
299
413
|
}
|
|
300
414
|
const out = [];
|
|
301
415
|
for (const name of entries) {
|
|
302
|
-
const dir =
|
|
416
|
+
const dir = join2(root, name);
|
|
303
417
|
const manifest = await readManifest(dir);
|
|
304
418
|
if (manifest) out.push({ name, dir, manifest });
|
|
305
419
|
}
|
|
306
420
|
out.sort((a, b) => a.manifest.createdAt.localeCompare(b.manifest.createdAt));
|
|
307
421
|
return out;
|
|
308
422
|
}
|
|
423
|
+
async function listCloudCheckpoints(projectRoot, backend) {
|
|
424
|
+
return listCloudCheckpointsInDir(backendDir(backend, projectRoot));
|
|
425
|
+
}
|
|
426
|
+
async function listAllCloudCheckpoints(backend) {
|
|
427
|
+
const backendRoot = join2(CLOUD_CHECKPOINTS_ROOT, backend);
|
|
428
|
+
let segments;
|
|
429
|
+
try {
|
|
430
|
+
segments = (await readdir(backendRoot, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
431
|
+
} catch {
|
|
432
|
+
return [];
|
|
433
|
+
}
|
|
434
|
+
const out = [];
|
|
435
|
+
for (const segment of segments) {
|
|
436
|
+
const items = await listCloudCheckpointsInDir(join2(backendRoot, segment));
|
|
437
|
+
if (items.length > 0) out.push({ segment, items });
|
|
438
|
+
}
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
309
441
|
async function resolveCloudCheckpoint(projectRoot, backend, ref) {
|
|
310
442
|
const dir = checkpointDir(backend, projectRoot, ref);
|
|
311
443
|
const manifest = await readManifest(dir);
|
|
@@ -316,22 +448,33 @@ async function writeCloudCheckpointManifest(projectRoot, backend, name, fields)
|
|
|
316
448
|
const dir = checkpointDir(backend, projectRoot, name);
|
|
317
449
|
await mkdir2(dir, { recursive: true });
|
|
318
450
|
const manifest = {
|
|
319
|
-
schema:
|
|
451
|
+
schema: 2,
|
|
320
452
|
name,
|
|
321
453
|
backend,
|
|
322
454
|
snapshotName: fields.snapshotName,
|
|
323
455
|
sourceBoxId: fields.sourceBoxId,
|
|
324
456
|
sourceBoxName: fields.sourceBoxName,
|
|
457
|
+
baseProvider: fields.baseProvider,
|
|
458
|
+
baseFingerprint: fields.baseFingerprint,
|
|
459
|
+
cliVersion: fields.cliVersion,
|
|
325
460
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
326
461
|
};
|
|
327
|
-
await
|
|
462
|
+
await writeFile3(join2(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
328
463
|
return { name, dir, manifest };
|
|
329
464
|
}
|
|
465
|
+
function currentCloudBaseFingerprint(provider) {
|
|
466
|
+
try {
|
|
467
|
+
const raw = readPreparedStateRaw(provider);
|
|
468
|
+
return raw?.base?.contextSha256;
|
|
469
|
+
} catch {
|
|
470
|
+
return void 0;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
330
473
|
async function removeCloudCheckpointDir(projectRoot, backend, name) {
|
|
331
474
|
const dir = checkpointDir(backend, projectRoot, name);
|
|
332
475
|
const existed = await readManifest(dir) !== null;
|
|
333
476
|
if (!existed) return false;
|
|
334
|
-
await
|
|
477
|
+
await rm2(dir, { recursive: true, force: true });
|
|
335
478
|
return true;
|
|
336
479
|
}
|
|
337
480
|
async function probeCloudCheckpoint(backend, projectRoot, ref) {
|
|
@@ -362,7 +505,7 @@ async function uploadEnvFiles(args) {
|
|
|
362
505
|
});
|
|
363
506
|
if (args.files.length === 0) return { copied: 0 };
|
|
364
507
|
const workspaceDir = args.workspaceDir ?? WORKSPACE_DIR_DEFAULT;
|
|
365
|
-
const found = await
|
|
508
|
+
const found = await execa2("find", buildHostEnvFindArgs(args.files).slice(1), {
|
|
366
509
|
cwd: args.workspacePath,
|
|
367
510
|
reject: false
|
|
368
511
|
});
|
|
@@ -372,10 +515,10 @@ async function uploadEnvFiles(args) {
|
|
|
372
515
|
}
|
|
373
516
|
const list = String(found.stdout).split("\0").filter((p) => p.length > 0);
|
|
374
517
|
if (list.length === 0) return { copied: 0 };
|
|
375
|
-
const stage = await
|
|
376
|
-
const localTar =
|
|
518
|
+
const stage = await mkdtemp2(join3(tmpdir2(), "agentbox-envfiles-"));
|
|
519
|
+
const localTar = join3(stage, "envfiles.tar");
|
|
377
520
|
try {
|
|
378
|
-
const packed = await
|
|
521
|
+
const packed = await execa2(
|
|
379
522
|
"tar",
|
|
380
523
|
["-C", args.workspacePath, "--null", "-T", "-", "-cf", localTar],
|
|
381
524
|
{ input: list.join("\0"), reject: false }
|
|
@@ -384,7 +527,7 @@ async function uploadEnvFiles(args) {
|
|
|
384
527
|
log(`env-file tar pack failed: ${String(packed.stderr).slice(0, 300)}`);
|
|
385
528
|
return { copied: 0 };
|
|
386
529
|
}
|
|
387
|
-
await
|
|
530
|
+
await writeFile4(join3(stage, ".marker"), "").catch(() => {
|
|
388
531
|
});
|
|
389
532
|
await args.backend.uploadFile(args.handle, localTar, REMOTE_TAR_PATH);
|
|
390
533
|
const extract = await args.backend.exec(
|
|
@@ -398,7 +541,7 @@ async function uploadEnvFiles(args) {
|
|
|
398
541
|
return { copied: 0 };
|
|
399
542
|
}
|
|
400
543
|
} finally {
|
|
401
|
-
await
|
|
544
|
+
await rm3(stage, { recursive: true, force: true });
|
|
402
545
|
}
|
|
403
546
|
return { copied: list.length };
|
|
404
547
|
}
|
|
@@ -409,7 +552,7 @@ async function uploadCarryPaths(args) {
|
|
|
409
552
|
if (args.entries.length === 0) {
|
|
410
553
|
return { copied: 0, errors: [], applied: [] };
|
|
411
554
|
}
|
|
412
|
-
const stage = await
|
|
555
|
+
const stage = await mkdtemp3(join4(tmpdir3(), "agentbox-carry-"));
|
|
413
556
|
const errors = [];
|
|
414
557
|
const applied = [];
|
|
415
558
|
let copied = 0;
|
|
@@ -437,7 +580,7 @@ async function uploadCarryPaths(args) {
|
|
|
437
580
|
}
|
|
438
581
|
}
|
|
439
582
|
} finally {
|
|
440
|
-
await
|
|
583
|
+
await rm4(stage, { recursive: true, force: true });
|
|
441
584
|
}
|
|
442
585
|
return { copied, errors, applied };
|
|
443
586
|
}
|
|
@@ -447,9 +590,9 @@ async function uploadOneEntry(args) {
|
|
|
447
590
|
const boxDest = entry.absDest.startsWith("~/") ? `${BOX_HOME}/${entry.absDest.slice(2)}` : entry.absDest;
|
|
448
591
|
const isDir = entry.kind === "dir";
|
|
449
592
|
const parentDir = isDir ? boxDest : dirnameUnix(boxDest);
|
|
450
|
-
const localTar =
|
|
593
|
+
const localTar = join4(args.stageDir, `carry-${String(args.index)}.tar`);
|
|
451
594
|
const tarArgs = isDir ? ["-C", entry.absSrc, "-cf", localTar, "."] : ["-C", dirnameUnix(entry.absSrc), "-cf", localTar, basenameUnix(entry.absSrc)];
|
|
452
|
-
const packed = await
|
|
595
|
+
const packed = await execa3("tar", tarArgs, { reject: false });
|
|
453
596
|
if (packed.exitCode !== 0) {
|
|
454
597
|
throw new Error(`tar pack failed: ${String(packed.stderr).slice(0, 300)}`);
|
|
455
598
|
}
|
|
@@ -501,7 +644,7 @@ function shellQuote(s) {
|
|
|
501
644
|
async function readExposedServicePorts(workspacePath) {
|
|
502
645
|
let text;
|
|
503
646
|
try {
|
|
504
|
-
text = await readFile2(
|
|
647
|
+
text = await readFile2(join5(workspacePath, "agentbox.yaml"), "utf8");
|
|
505
648
|
} catch {
|
|
506
649
|
return [];
|
|
507
650
|
}
|
|
@@ -529,17 +672,6 @@ async function readExposedServicePorts(workspacePath) {
|
|
|
529
672
|
function isPlainObject(v) {
|
|
530
673
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
531
674
|
}
|
|
532
|
-
function quoteShellArgv(argv) {
|
|
533
|
-
return argv.map(quoteShellArg).join(" ");
|
|
534
|
-
}
|
|
535
|
-
function quoteShellArg(arg) {
|
|
536
|
-
if (arg.length === 0) return "''";
|
|
537
|
-
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return arg;
|
|
538
|
-
return "'" + arg.replace(/'/g, "'\\''") + "'";
|
|
539
|
-
}
|
|
540
|
-
function bashScript(body) {
|
|
541
|
-
return `bash -c ${quoteShellArg(body)}`;
|
|
542
|
-
}
|
|
543
675
|
var REMOTE_UP_TAR = "/tmp/agentbox-cp-up.tar.gz";
|
|
544
676
|
var REMOTE_DOWN_TAR = "/tmp/agentbox-cp-down.tar.gz";
|
|
545
677
|
async function uploadToCloudBox(backend, handle, hostSrc, boxDst) {
|
|
@@ -557,10 +689,10 @@ async function uploadToCloudBox(backend, handle, hostSrc, boxDst) {
|
|
|
557
689
|
finalName = posix.basename(boxDst);
|
|
558
690
|
}
|
|
559
691
|
const finalPath = boxParent === "/" ? `/${finalName}` : `${boxParent}/${finalName}`;
|
|
560
|
-
const stage = await
|
|
692
|
+
const stage = await mkdtemp4(hostJoin(tmpdir4(), "agentbox-cp-up-"));
|
|
561
693
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
562
694
|
try {
|
|
563
|
-
await
|
|
695
|
+
await execa4("tar", ["-C", srcParent, "-czf", localTar, srcBasename], {
|
|
564
696
|
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
565
697
|
});
|
|
566
698
|
await backend.uploadFile(handle, localTar, REMOTE_UP_TAR);
|
|
@@ -586,14 +718,14 @@ async function uploadToCloudBox(backend, handle, hostSrc, boxDst) {
|
|
|
586
718
|
throw new Error(`cloud upload extract failed: ${r.stderr || r.stdout}`);
|
|
587
719
|
}
|
|
588
720
|
} finally {
|
|
589
|
-
await
|
|
721
|
+
await rm5(stage, { recursive: true, force: true });
|
|
590
722
|
}
|
|
591
723
|
return { finalPath };
|
|
592
724
|
}
|
|
593
725
|
async function pullCloudDirContents(backend, handle, boxSrcDir, hostDstDir) {
|
|
594
726
|
const dstAbs = hostResolve(hostDstDir);
|
|
595
727
|
mkdirSync(dstAbs, { recursive: true });
|
|
596
|
-
const stage = await
|
|
728
|
+
const stage = await mkdtemp4(hostJoin(tmpdir4(), "agentbox-pull-"));
|
|
597
729
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
598
730
|
try {
|
|
599
731
|
const packScript = [
|
|
@@ -606,11 +738,11 @@ async function pullCloudDirContents(backend, handle, boxSrcDir, hostDstDir) {
|
|
|
606
738
|
throw new Error(`cloud workspace pack failed: ${r.stderr || r.stdout}`);
|
|
607
739
|
}
|
|
608
740
|
await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);
|
|
609
|
-
await
|
|
741
|
+
await execa4("tar", ["-xzf", localTar, "-C", dstAbs]);
|
|
610
742
|
await backend.exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`).catch(() => {
|
|
611
743
|
});
|
|
612
744
|
} finally {
|
|
613
|
-
await
|
|
745
|
+
await rm5(stage, { recursive: true, force: true });
|
|
614
746
|
}
|
|
615
747
|
return { finalPath: dstAbs };
|
|
616
748
|
}
|
|
@@ -630,7 +762,7 @@ async function downloadFromCloudBox(backend, handle, boxSrc, hostDst) {
|
|
|
630
762
|
}
|
|
631
763
|
mkdirSync(hostParent, { recursive: true });
|
|
632
764
|
const finalPath = hostJoin(hostParent, finalName);
|
|
633
|
-
const stage = await
|
|
765
|
+
const stage = await mkdtemp4(hostJoin(tmpdir4(), "agentbox-cp-down-"));
|
|
634
766
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
635
767
|
try {
|
|
636
768
|
const packScript = [
|
|
@@ -643,14 +775,14 @@ async function downloadFromCloudBox(backend, handle, boxSrc, hostDst) {
|
|
|
643
775
|
throw new Error(`cloud download pack failed: ${r.stderr || r.stdout}`);
|
|
644
776
|
}
|
|
645
777
|
await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);
|
|
646
|
-
await
|
|
778
|
+
await execa4("tar", ["-xzf", localTar, "-C", hostParent]);
|
|
647
779
|
if (finalName !== srcBasename) {
|
|
648
780
|
renameSync(hostJoin(hostParent, srcBasename), finalPath);
|
|
649
781
|
}
|
|
650
782
|
await backend.exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`).catch(() => {
|
|
651
783
|
});
|
|
652
784
|
} finally {
|
|
653
|
-
await
|
|
785
|
+
await rm5(stage, { recursive: true, force: true });
|
|
654
786
|
}
|
|
655
787
|
return { finalPath };
|
|
656
788
|
}
|
|
@@ -785,16 +917,16 @@ var LARGE_BUNDLE_THRESHOLD_BYTES = 20 * 1024 * 1024;
|
|
|
785
917
|
async function seedFromGitClone(args) {
|
|
786
918
|
const log = args.onLog ?? (() => {
|
|
787
919
|
});
|
|
788
|
-
const stage = await
|
|
789
|
-
const cloneDir =
|
|
790
|
-
const tarPath =
|
|
791
|
-
const untrackedTarPath =
|
|
920
|
+
const stage = await mkdtemp5(join6(tmpdir5(), "agentbox-clone-"));
|
|
921
|
+
const cloneDir = join6(stage, "clone");
|
|
922
|
+
const tarPath = join6(stage, "workspace.tar.gz");
|
|
923
|
+
const untrackedTarPath = join6(stage, "untracked.tar.gz");
|
|
792
924
|
const stashSha = args.useBranch ? null : await safeStashCreate(args.hostRepo);
|
|
793
925
|
const untrackedSize = args.useBranch ? 0 : await maybeBuildUntrackedTar(args.hostRepo, untrackedTarPath);
|
|
794
926
|
let stashRefCreated = false;
|
|
795
927
|
try {
|
|
796
928
|
if (stashSha) {
|
|
797
|
-
const ref = await
|
|
929
|
+
const ref = await execa5(
|
|
798
930
|
"git",
|
|
799
931
|
["-C", args.hostRepo, "update-ref", STASH_CARRYOVER_REF, stashSha],
|
|
800
932
|
{ reject: false }
|
|
@@ -817,8 +949,8 @@ async function seedFromGitClone(args) {
|
|
|
817
949
|
log(
|
|
818
950
|
`clone tar exceeded ${String(LARGE_BUNDLE_THRESHOLD_BYTES / (1024 * 1024))} MB at depth ${String(DEFAULT_BUNDLE_DEPTH)} (${mb} MB), rebuilding at depth ${String(LARGE_BUNDLE_DEPTH)}`
|
|
819
951
|
);
|
|
820
|
-
await
|
|
821
|
-
await
|
|
952
|
+
await rm6(cloneDir, { recursive: true, force: true });
|
|
953
|
+
await rm6(tarPath, { force: true });
|
|
822
954
|
await runShallowClone(args.hostRepo, cloneDir, LARGE_BUNDLE_DEPTH, stashRefCreated, cloneBranch);
|
|
823
955
|
await tarCloneDir(cloneDir, tarPath);
|
|
824
956
|
}
|
|
@@ -869,11 +1001,11 @@ async function seedFromGitClone(args) {
|
|
|
869
1001
|
}
|
|
870
1002
|
} finally {
|
|
871
1003
|
if (stashRefCreated) {
|
|
872
|
-
await
|
|
1004
|
+
await execa5("git", ["-C", args.hostRepo, "update-ref", "-d", STASH_CARRYOVER_REF], {
|
|
873
1005
|
reject: false
|
|
874
1006
|
});
|
|
875
1007
|
}
|
|
876
|
-
await
|
|
1008
|
+
await rm6(stage, { recursive: true, force: true });
|
|
877
1009
|
}
|
|
878
1010
|
}
|
|
879
1011
|
async function runShallowClone(hostRepo, cloneDir, depth, includeStashRef, fromBranch) {
|
|
@@ -881,7 +1013,7 @@ async function runShallowClone(hostRepo, cloneDir, depth, includeStashRef, fromB
|
|
|
881
1013
|
if (depth !== null) cloneArgs.push(`--depth=${String(depth)}`);
|
|
882
1014
|
if (fromBranch) cloneArgs.push("--branch", fromBranch);
|
|
883
1015
|
cloneArgs.push(`file://${hostRepo}`, cloneDir);
|
|
884
|
-
await
|
|
1016
|
+
await execa5("git", cloneArgs);
|
|
885
1017
|
if (includeStashRef) {
|
|
886
1018
|
const fetchArgs = ["-C", cloneDir, "fetch", "--quiet"];
|
|
887
1019
|
if (depth !== null) fetchArgs.push(`--depth=${String(depth)}`);
|
|
@@ -889,11 +1021,11 @@ async function runShallowClone(hostRepo, cloneDir, depth, includeStashRef, fromB
|
|
|
889
1021
|
`file://${hostRepo}`,
|
|
890
1022
|
`+${STASH_CARRYOVER_REF}:refs/remotes/origin/agentbox-carryover/stash`
|
|
891
1023
|
);
|
|
892
|
-
await
|
|
1024
|
+
await execa5("git", fetchArgs, { reject: false });
|
|
893
1025
|
}
|
|
894
1026
|
}
|
|
895
1027
|
async function tarCloneDir(cloneDir, outPath) {
|
|
896
|
-
await
|
|
1028
|
+
await execa5("tar", ["-C", cloneDir, "-czf", outPath, "."], {
|
|
897
1029
|
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
898
1030
|
});
|
|
899
1031
|
}
|
|
@@ -905,19 +1037,19 @@ async function safeFileSize(path) {
|
|
|
905
1037
|
}
|
|
906
1038
|
}
|
|
907
1039
|
async function safeStashCreate(hostRepo) {
|
|
908
|
-
const r = await
|
|
1040
|
+
const r = await execa5("git", ["-C", hostRepo, "stash", "create"], { reject: false });
|
|
909
1041
|
if (r.exitCode !== 0) return null;
|
|
910
1042
|
const sha = r.stdout.trim();
|
|
911
1043
|
return sha.length > 0 ? sha : null;
|
|
912
1044
|
}
|
|
913
1045
|
async function maybeBuildUntrackedTar(hostRepo, outPath) {
|
|
914
|
-
const list = await
|
|
1046
|
+
const list = await execa5(
|
|
915
1047
|
"git",
|
|
916
1048
|
["-C", hostRepo, "ls-files", "--others", "--exclude-standard", "-z"],
|
|
917
1049
|
{ reject: false }
|
|
918
1050
|
);
|
|
919
1051
|
if (list.exitCode !== 0 || list.stdout.length === 0) return 0;
|
|
920
|
-
const tar = await
|
|
1052
|
+
const tar = await execa5(
|
|
921
1053
|
"tar",
|
|
922
1054
|
["-C", hostRepo, "--null", "-T", "-", "-czf", outPath],
|
|
923
1055
|
{
|
|
@@ -936,16 +1068,16 @@ async function maybeBuildUntrackedTar(hostRepo, outPath) {
|
|
|
936
1068
|
}
|
|
937
1069
|
}
|
|
938
1070
|
async function readOriginUrl(hostRepo) {
|
|
939
|
-
const r = await
|
|
1071
|
+
const r = await execa5("git", ["-C", hostRepo, "remote", "get-url", "origin"], { reject: false });
|
|
940
1072
|
if (r.exitCode !== 0) return null;
|
|
941
1073
|
const out = (r.stdout ?? "").trim();
|
|
942
1074
|
return out.length > 0 ? out : null;
|
|
943
1075
|
}
|
|
944
1076
|
async function seedFromTar(args) {
|
|
945
|
-
const stage = await
|
|
946
|
-
const tarPath =
|
|
1077
|
+
const stage = await mkdtemp5(join6(tmpdir5(), "agentbox-tar-"));
|
|
1078
|
+
const tarPath = join6(stage, "workspace.tar.gz");
|
|
947
1079
|
try {
|
|
948
|
-
await
|
|
1080
|
+
await execa5("tar", ["-C", args.hostDir, "-czf", tarPath, "."]);
|
|
949
1081
|
const remoteTar = "/tmp/agentbox-workspace.tar.gz";
|
|
950
1082
|
await args.backend.uploadFile(args.handle, tarPath, remoteTar);
|
|
951
1083
|
const SUDO = `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`;
|
|
@@ -969,7 +1101,7 @@ async function seedFromTar(args) {
|
|
|
969
1101
|
throw new Error(`workspace seed (tar) failed: ${r.stderr || r.stdout}`);
|
|
970
1102
|
}
|
|
971
1103
|
} finally {
|
|
972
|
-
await
|
|
1104
|
+
await rm6(stage, { recursive: true, force: true });
|
|
973
1105
|
}
|
|
974
1106
|
}
|
|
975
1107
|
var CLOUD_WORKSPACE_DIR = "/workspace";
|
|
@@ -1220,17 +1352,25 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1220
1352
|
const timeoutMs = typeof timeoutOverride === "number" && timeoutOverride > 0 ? timeoutOverride : void 0;
|
|
1221
1353
|
const networkPolicyOpt = req.providerOptions?.["networkPolicy"];
|
|
1222
1354
|
const networkPolicy = typeof networkPolicyOpt === "string" && networkPolicyOpt.trim() !== "" ? networkPolicyOpt.trim() : void 0;
|
|
1355
|
+
const sizeOpt = req.providerOptions?.["size"];
|
|
1356
|
+
const size = typeof sizeOpt === "string" && sizeOpt.trim() !== "" ? sizeOpt.trim() : void 0;
|
|
1223
1357
|
const relayToken = generateRelayToken();
|
|
1224
1358
|
const bridgeToken = generateRelayToken();
|
|
1225
1359
|
try {
|
|
1226
1360
|
await ensureRelay({ onLog: log });
|
|
1227
1361
|
} catch (err) {
|
|
1228
|
-
log(
|
|
1362
|
+
log(
|
|
1363
|
+
`relay ensure failed (continuing): ${err instanceof Error ? err.message : String(err)}`
|
|
1364
|
+
);
|
|
1229
1365
|
}
|
|
1230
1366
|
let snapshotName;
|
|
1231
1367
|
let resolvedCheckpointRef;
|
|
1232
1368
|
if (req.checkpointRef && req.projectRoot) {
|
|
1233
|
-
const found = await resolveCloudCheckpoint(
|
|
1369
|
+
const found = await resolveCloudCheckpoint(
|
|
1370
|
+
req.projectRoot,
|
|
1371
|
+
backend.name,
|
|
1372
|
+
req.checkpointRef
|
|
1373
|
+
);
|
|
1234
1374
|
if (found) {
|
|
1235
1375
|
snapshotName = found.manifest.snapshotName;
|
|
1236
1376
|
resolvedCheckpointRef = found.name;
|
|
@@ -1264,6 +1404,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1264
1404
|
image,
|
|
1265
1405
|
snapshot,
|
|
1266
1406
|
resources,
|
|
1407
|
+
size,
|
|
1267
1408
|
timeoutMs,
|
|
1268
1409
|
exposePorts: exposeServicePorts,
|
|
1269
1410
|
networkPolicy,
|
|
@@ -1317,6 +1458,8 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1317
1458
|
});
|
|
1318
1459
|
}
|
|
1319
1460
|
await seedOpencodeModelState(backend, handle, { onLog: log });
|
|
1461
|
+
await seedDynamicConfig(backend, handle, { workspacePath: req.workspacePath, onLog: log });
|
|
1462
|
+
await seedGitIdentity(backend, handle, { hostRepo: req.workspacePath, onLog: log });
|
|
1320
1463
|
if (req.envFilesToImport && req.envFilesToImport.length > 0) {
|
|
1321
1464
|
const { copied } = await uploadEnvFiles({
|
|
1322
1465
|
backend,
|
|
@@ -1358,9 +1501,12 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1358
1501
|
log("launching in-box dockerd");
|
|
1359
1502
|
try {
|
|
1360
1503
|
const dockerd = await launchCloudDockerdDaemon({ backend, handle, timeoutMs: 6e4 });
|
|
1361
|
-
if (!dockerd.up)
|
|
1504
|
+
if (!dockerd.up)
|
|
1505
|
+
log(`dockerd did not become ready (continuing): ${dockerd.reason ?? "unknown"}`);
|
|
1362
1506
|
} catch (err) {
|
|
1363
|
-
log(
|
|
1507
|
+
log(
|
|
1508
|
+
`dockerd daemon launch failed (continuing): ${err instanceof Error ? err.message : String(err)}`
|
|
1509
|
+
);
|
|
1364
1510
|
}
|
|
1365
1511
|
}
|
|
1366
1512
|
const vncEnabled = req.vnc?.enabled !== false;
|
|
@@ -1719,7 +1865,10 @@ function makeCloudCheckpoint(backend) {
|
|
|
1719
1865
|
const info = await writeCloudCheckpointManifest(box.projectRoot, backend.name, name, {
|
|
1720
1866
|
snapshotName,
|
|
1721
1867
|
sourceBoxId: box.id,
|
|
1722
|
-
sourceBoxName: box.name
|
|
1868
|
+
sourceBoxName: box.name,
|
|
1869
|
+
baseProvider: backend.name,
|
|
1870
|
+
baseFingerprint: currentCloudBaseFingerprint(backend.name),
|
|
1871
|
+
cliVersion: readCliStamp().cliVersion
|
|
1723
1872
|
});
|
|
1724
1873
|
return { ref: info.name };
|
|
1725
1874
|
},
|
|
@@ -1797,11 +1946,13 @@ export {
|
|
|
1797
1946
|
seedAgentVolumesIfFresh,
|
|
1798
1947
|
agentSpecsForCloud,
|
|
1799
1948
|
listCloudCheckpoints,
|
|
1949
|
+
listAllCloudCheckpoints,
|
|
1800
1950
|
resolveCloudCheckpoint,
|
|
1801
1951
|
writeCloudCheckpointManifest,
|
|
1952
|
+
currentCloudBaseFingerprint,
|
|
1802
1953
|
removeCloudCheckpointDir,
|
|
1803
1954
|
probeCloudCheckpoint,
|
|
1804
1955
|
createCloudProvider,
|
|
1805
1956
|
renderInnerCommand
|
|
1806
1957
|
};
|
|
1807
|
-
//# sourceMappingURL=chunk-
|
|
1958
|
+
//# sourceMappingURL=chunk-4NQXNQ53.js.map
|