@madarco/agentbox 0.7.0 → 0.8.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/dist/_cloud-attach-T727ZPRV.js +13 -0
- package/dist/{chunk-NW5NYTQM.js → chunk-67N47KUS.js} +359 -85
- package/dist/chunk-67N47KUS.js.map +1 -0
- package/dist/{chunk-NAVL4R34.js → chunk-6OZDFNBF.js} +1084 -516
- package/dist/chunk-6OZDFNBF.js.map +1 -0
- package/dist/chunk-BGK32PZE.js +455 -0
- package/dist/chunk-BGK32PZE.js.map +1 -0
- package/dist/{chunk-7KOEFGN2.js → chunk-FODMEHD3.js} +52 -14
- package/dist/chunk-FODMEHD3.js.map +1 -0
- package/dist/{chunk-UK72UQ5U.js → chunk-G3H2L3O2.js} +55 -4
- package/dist/chunk-G3H2L3O2.js.map +1 -0
- package/dist/{chunk-V5KZGB5V.js → chunk-LEV3KICD.js} +18 -2
- package/dist/chunk-LEV3KICD.js.map +1 -0
- package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js → cloud-poller-SUNA6ZQC-2RG5WPRN.js} +2 -2
- package/dist/{dist-R67WMLCF.js → dist-L4LCG5SJ.js} +120 -10
- package/dist/dist-L4LCG5SJ.js.map +1 -0
- package/dist/{dist-ETCFRVPA.js → dist-LOZBWMBF.js} +44 -20
- package/dist/{dist-QZGJIBT5.js → dist-ZODPD2I6.js} +142 -74
- package/dist/dist-ZODPD2I6.js.map +1 -0
- package/dist/index.js +3563 -845
- package/dist/index.js.map +1 -1
- package/dist/prepared-state-CL4CWXQA-ME4HSKDE.js +18 -0
- package/dist/prepared-state-CL4CWXQA-ME4HSKDE.js.map +1 -0
- package/package.json +4 -4
- package/runtime/daytona/custom-system-CLAUDE.md +39 -0
- package/runtime/docker/Dockerfile.box +22 -0
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +1 -1
- package/runtime/docker/packages/ctl/dist/bin.cjs +1118 -71
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +66 -35
- package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +62 -1
- package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +15 -4
- package/runtime/docker/packages/sandbox-docker/scripts/gh-shim +263 -0
- package/runtime/docker/packages/sandbox-docker/scripts/git-shim +131 -0
- package/runtime/docker/packages/sandbox-docker/scripts/opencode-agentbox-plugin.js +76 -0
- package/runtime/hetzner/agentbox-codex-hooks.json +66 -35
- package/runtime/hetzner/agentbox-setup-skill.md +1 -1
- package/runtime/hetzner/claude-managed-settings.json +62 -1
- package/runtime/hetzner/ctl.cjs +1118 -71
- package/runtime/hetzner/custom-system-CLAUDE.md +26 -14
- package/runtime/hetzner/gh-shim +263 -0
- package/runtime/hetzner/git-shim +131 -0
- package/runtime/hetzner/opencode-agentbox-plugin.js +76 -0
- package/runtime/hetzner/scripts/install-box.sh +11 -2
- package/runtime/relay/bin.cjs +927 -36
- package/share/agentbox-setup/SKILL.md +1 -1
- package/share/host-skills/agentbox/SKILL.md +29 -0
- package/share/host-skills/agentbox-info/SKILL.md +211 -0
- package/share/host-skills/codex/agentbox.md +35 -0
- package/share/host-skills/opencode/agentbox.md +26 -0
- package/dist/_cloud-attach-DMVH6GWO.js +0 -12
- package/dist/chunk-7KOEFGN2.js.map +0 -1
- package/dist/chunk-NAVL4R34.js.map +0 -1
- package/dist/chunk-NW5NYTQM.js.map +0 -1
- package/dist/chunk-UK72UQ5U.js.map +0 -1
- package/dist/chunk-V5KZGB5V.js.map +0 -1
- package/dist/dist-QZGJIBT5.js.map +0 -1
- package/dist/dist-R67WMLCF.js.map +0 -1
- /package/dist/{_cloud-attach-DMVH6GWO.js.map → _cloud-attach-T727ZPRV.js.map} +0 -0
- /package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js.map → cloud-poller-SUNA6ZQC-2RG5WPRN.js.map} +0 -0
- /package/dist/{dist-ETCFRVPA.js.map → dist-LOZBWMBF.js.map} +0 -0
|
@@ -3,9 +3,8 @@ import {
|
|
|
3
3
|
CLAUDE_FORWARDED_ENV_KEYS,
|
|
4
4
|
CODEX_FORWARDED_ENV_KEYS,
|
|
5
5
|
OPENCODE_FORWARDED_ENV_KEYS,
|
|
6
|
-
allocateProjectIndex,
|
|
7
6
|
buildHostEnvFindArgs,
|
|
8
|
-
|
|
7
|
+
buildTmuxConfigShellSnippet,
|
|
9
8
|
ensureRelay,
|
|
10
9
|
forgetBoxFromRelay,
|
|
11
10
|
generateRelayToken,
|
|
@@ -15,18 +14,23 @@ import {
|
|
|
15
14
|
portlessGetUrl,
|
|
16
15
|
portlessUnalias,
|
|
17
16
|
projectDirSegment,
|
|
18
|
-
readState,
|
|
19
|
-
recordBox,
|
|
20
17
|
registerBoxWithRelay,
|
|
21
|
-
removeBoxRecord,
|
|
22
18
|
sanitizeMnemonic,
|
|
23
19
|
stageClaudeCredentialsForUpload,
|
|
24
20
|
stageClaudeStaticForUpload,
|
|
25
21
|
stageCodexCredentialsForUpload,
|
|
26
22
|
stageCodexStaticForUpload,
|
|
27
23
|
stageOpencodeCredentialsForUpload,
|
|
24
|
+
stageOpencodeStateForUpload,
|
|
28
25
|
stageOpencodeStaticForUpload
|
|
29
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-6OZDFNBF.js";
|
|
27
|
+
import {
|
|
28
|
+
allocateProjectIndex,
|
|
29
|
+
detectGitRepos,
|
|
30
|
+
readState,
|
|
31
|
+
recordBox,
|
|
32
|
+
removeBoxRecord
|
|
33
|
+
} from "./chunk-BGK32PZE.js";
|
|
30
34
|
|
|
31
35
|
// ../../packages/sandbox-cloud/dist/index.js
|
|
32
36
|
import { randomBytes } from "crypto";
|
|
@@ -38,13 +42,17 @@ import { mkdtemp, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
|
38
42
|
import { tmpdir } from "os";
|
|
39
43
|
import { join as join2 } from "path";
|
|
40
44
|
import { execa } from "execa";
|
|
41
|
-
import {
|
|
45
|
+
import { mkdtemp as mkdtemp2, rm as rm3 } from "fs/promises";
|
|
46
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
42
47
|
import { join as join3 } from "path";
|
|
43
|
-
import { parse as parseYaml } from "yaml";
|
|
44
48
|
import { execa as execa2 } from "execa";
|
|
49
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
50
|
+
import { join as join4 } from "path";
|
|
51
|
+
import { parse as parseYaml } from "yaml";
|
|
52
|
+
import { execa as execa3 } from "execa";
|
|
45
53
|
import { existsSync, mkdirSync, renameSync, statSync } from "fs";
|
|
46
|
-
import { mkdtemp as
|
|
47
|
-
import { tmpdir as
|
|
54
|
+
import { mkdtemp as mkdtemp3, rm as rm4 } from "fs/promises";
|
|
55
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
48
56
|
import {
|
|
49
57
|
basename as hostBasename,
|
|
50
58
|
dirname as hostDirname,
|
|
@@ -52,10 +60,10 @@ import {
|
|
|
52
60
|
resolve as hostResolve
|
|
53
61
|
} from "path";
|
|
54
62
|
import { posix } from "path";
|
|
55
|
-
import { execa as
|
|
56
|
-
import { mkdtemp as
|
|
57
|
-
import { tmpdir as
|
|
58
|
-
import { join as
|
|
63
|
+
import { execa as execa4 } from "execa";
|
|
64
|
+
import { mkdtemp as mkdtemp4, rm as rm5, stat } from "fs/promises";
|
|
65
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
66
|
+
import { join as join5 } from "path";
|
|
59
67
|
var CREDENTIALS_VOLUME = "agentbox-credentials";
|
|
60
68
|
var AGENT_SPECS = [
|
|
61
69
|
{
|
|
@@ -185,6 +193,33 @@ async function seedCredentialsOne(backend, handle, spec, opts) {
|
|
|
185
193
|
await staged.cleanup();
|
|
186
194
|
}
|
|
187
195
|
}
|
|
196
|
+
var OPENCODE_STATE_DIR = "/home/vscode/.local/state/opencode";
|
|
197
|
+
async function seedOpencodeModelState(backend, handle, opts = {}) {
|
|
198
|
+
const log = opts.onLog ?? (() => {
|
|
199
|
+
});
|
|
200
|
+
const staged = await stageOpencodeStateForUpload();
|
|
201
|
+
if (staged.tarballPath === null) {
|
|
202
|
+
log("opencode: no host model selection to seed");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const remoteTar = "/tmp/agentbox-opencode-state.tar.gz";
|
|
207
|
+
await backend.uploadFile(handle, staged.tarballPath, remoteTar);
|
|
208
|
+
const res = await backend.exec(
|
|
209
|
+
handle,
|
|
210
|
+
`set -e; mkdir -p ${OPENCODE_STATE_DIR}; tar -xzf ${remoteTar} -C ${OPENCODE_STATE_DIR}; chown -R vscode:vscode ${OPENCODE_STATE_DIR} 2>/dev/null || true; rm -f ${remoteTar}`
|
|
211
|
+
);
|
|
212
|
+
if (res.exitCode !== 0) {
|
|
213
|
+
log(
|
|
214
|
+
`opencode: model-state seed failed (exit ${String(res.exitCode)}); box falls back to OpenCode's default model. stderr: ${res.stderr.slice(-200)}`
|
|
215
|
+
);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
log("opencode: model selection seeded \u2713");
|
|
219
|
+
} finally {
|
|
220
|
+
await staged.cleanup();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
188
223
|
function agentSpecsForCloud() {
|
|
189
224
|
return AGENT_SPECS.map((s) => ({
|
|
190
225
|
kind: s.kind,
|
|
@@ -307,10 +342,105 @@ async function uploadEnvFiles(args) {
|
|
|
307
342
|
}
|
|
308
343
|
return { copied: list.length };
|
|
309
344
|
}
|
|
345
|
+
var BOX_HOME = "/home/vscode";
|
|
346
|
+
async function uploadCarryPaths(args) {
|
|
347
|
+
const log = args.onLog ?? (() => {
|
|
348
|
+
});
|
|
349
|
+
if (args.entries.length === 0) {
|
|
350
|
+
return { copied: 0, errors: [], applied: [] };
|
|
351
|
+
}
|
|
352
|
+
const stage = await mkdtemp2(join3(tmpdir2(), "agentbox-carry-"));
|
|
353
|
+
const errors = [];
|
|
354
|
+
const applied = [];
|
|
355
|
+
let copied = 0;
|
|
356
|
+
try {
|
|
357
|
+
for (const [i, entry] of args.entries.entries()) {
|
|
358
|
+
const where = `carry[${String(i)}] "${entry.rawSrc}"`;
|
|
359
|
+
if (entry.kind === "missing") {
|
|
360
|
+
log(`${where}: skipped (missing on host, optional)`);
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
await uploadOneEntry({
|
|
365
|
+
backend: args.backend,
|
|
366
|
+
handle: args.handle,
|
|
367
|
+
entry,
|
|
368
|
+
stageDir: stage,
|
|
369
|
+
index: i
|
|
370
|
+
});
|
|
371
|
+
copied += 1;
|
|
372
|
+
applied.push({ src: entry.absSrc, dest: entry.absDest, bytes: entry.bytes ?? 0 });
|
|
373
|
+
} catch (err) {
|
|
374
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
375
|
+
errors.push(`${where}: ${msg}`);
|
|
376
|
+
log(`${where}: failed: ${msg}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} finally {
|
|
380
|
+
await rm3(stage, { recursive: true, force: true });
|
|
381
|
+
}
|
|
382
|
+
return { copied, errors, applied };
|
|
383
|
+
}
|
|
384
|
+
async function uploadOneEntry(args) {
|
|
385
|
+
const { entry } = args;
|
|
386
|
+
if (entry.kind === "missing") return;
|
|
387
|
+
const boxDest = entry.absDest.startsWith("~/") ? `${BOX_HOME}/${entry.absDest.slice(2)}` : entry.absDest;
|
|
388
|
+
const isDir = entry.kind === "dir";
|
|
389
|
+
const parentDir = isDir ? boxDest : dirnameUnix(boxDest);
|
|
390
|
+
const localTar = join3(args.stageDir, `carry-${String(args.index)}.tar`);
|
|
391
|
+
const tarArgs = isDir ? ["-C", entry.absSrc, "-cf", localTar, "."] : ["-C", dirnameUnix(entry.absSrc), "-cf", localTar, basenameUnix(entry.absSrc)];
|
|
392
|
+
const packed = await execa2("tar", tarArgs, { reject: false });
|
|
393
|
+
if (packed.exitCode !== 0) {
|
|
394
|
+
throw new Error(`tar pack failed: ${String(packed.stderr).slice(0, 300)}`);
|
|
395
|
+
}
|
|
396
|
+
const remoteTar = `/tmp/agentbox-carry-${String(args.index)}.tar`;
|
|
397
|
+
await args.backend.uploadFile(args.handle, localTar, remoteTar);
|
|
398
|
+
const mode = entry.mode !== void 0 ? entry.mode.toString(8).padStart(4, "0") : "";
|
|
399
|
+
const uid = entry.user ?? 1e3;
|
|
400
|
+
const fileBase = !isDir ? basenameUnix(entry.absSrc) : "";
|
|
401
|
+
const destBase = !isDir ? basenameUnix(boxDest) : "";
|
|
402
|
+
const renameNeeded = !isDir && fileBase !== destBase;
|
|
403
|
+
const parts = [
|
|
404
|
+
`mkdir -p ${shellQuote(parentDir)}`,
|
|
405
|
+
isDir ? `tar -xf ${remoteTar} -C ${shellQuote(boxDest)} --no-same-permissions --no-same-owner -m` : `tar -xf ${remoteTar} -C ${shellQuote(parentDir)} --no-same-permissions --no-same-owner -m`
|
|
406
|
+
];
|
|
407
|
+
if (renameNeeded) {
|
|
408
|
+
parts.push(
|
|
409
|
+
`mv ${shellQuote(`${parentDir}/${fileBase}`)} ${shellQuote(boxDest)}`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
if (mode) parts.push(`chmod -R ${mode} ${shellQuote(boxDest)}`);
|
|
413
|
+
parts.push(`chown -R ${String(uid)}:${String(uid)} ${shellQuote(boxDest)}`);
|
|
414
|
+
if (boxDest.startsWith(BOX_HOME + "/") && parentDir !== BOX_HOME) {
|
|
415
|
+
parts.push(
|
|
416
|
+
`parent=$(dirname ${shellQuote(boxDest)}); while [ "$parent" != "${BOX_HOME}" ] && [ "$parent" != "/" ]; do chown ${String(uid)}:${String(uid)} "$parent"; parent=$(dirname "$parent"); done`
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
parts.push(`rm -f ${remoteTar}`);
|
|
420
|
+
const cmd = parts.join(" && ");
|
|
421
|
+
const res = await args.backend.exec(args.handle, cmd);
|
|
422
|
+
if (res.exitCode !== 0) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
`in-box extract failed (exit ${String(res.exitCode)}): ${(res.stderr || res.stdout).slice(-300)}`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function dirnameUnix(p) {
|
|
429
|
+
const i = p.lastIndexOf("/");
|
|
430
|
+
if (i <= 0) return "/";
|
|
431
|
+
return p.slice(0, i);
|
|
432
|
+
}
|
|
433
|
+
function basenameUnix(p) {
|
|
434
|
+
const i = p.lastIndexOf("/");
|
|
435
|
+
return i < 0 ? p : p.slice(i + 1);
|
|
436
|
+
}
|
|
437
|
+
function shellQuote(s) {
|
|
438
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
439
|
+
}
|
|
310
440
|
async function readExposedServicePorts(workspacePath) {
|
|
311
441
|
let text;
|
|
312
442
|
try {
|
|
313
|
-
text = await readFile2(
|
|
443
|
+
text = await readFile2(join4(workspacePath, "agentbox.yaml"), "utf8");
|
|
314
444
|
} catch {
|
|
315
445
|
return [];
|
|
316
446
|
}
|
|
@@ -366,10 +496,10 @@ async function uploadToCloudBox(backend, handle, hostSrc, boxDst) {
|
|
|
366
496
|
finalName = posix.basename(boxDst);
|
|
367
497
|
}
|
|
368
498
|
const finalPath = boxParent === "/" ? `/${finalName}` : `${boxParent}/${finalName}`;
|
|
369
|
-
const stage = await
|
|
499
|
+
const stage = await mkdtemp3(hostJoin(tmpdir3(), "agentbox-cp-up-"));
|
|
370
500
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
371
501
|
try {
|
|
372
|
-
await
|
|
502
|
+
await execa3("tar", ["-C", srcParent, "-czf", localTar, srcBasename], {
|
|
373
503
|
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
374
504
|
});
|
|
375
505
|
await backend.uploadFile(handle, localTar, REMOTE_UP_TAR);
|
|
@@ -395,14 +525,14 @@ async function uploadToCloudBox(backend, handle, hostSrc, boxDst) {
|
|
|
395
525
|
throw new Error(`cloud upload extract failed: ${r.stderr || r.stdout}`);
|
|
396
526
|
}
|
|
397
527
|
} finally {
|
|
398
|
-
await
|
|
528
|
+
await rm4(stage, { recursive: true, force: true });
|
|
399
529
|
}
|
|
400
530
|
return { finalPath };
|
|
401
531
|
}
|
|
402
532
|
async function pullCloudDirContents(backend, handle, boxSrcDir, hostDstDir) {
|
|
403
533
|
const dstAbs = hostResolve(hostDstDir);
|
|
404
534
|
mkdirSync(dstAbs, { recursive: true });
|
|
405
|
-
const stage = await
|
|
535
|
+
const stage = await mkdtemp3(hostJoin(tmpdir3(), "agentbox-pull-"));
|
|
406
536
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
407
537
|
try {
|
|
408
538
|
const packScript = [
|
|
@@ -415,11 +545,11 @@ async function pullCloudDirContents(backend, handle, boxSrcDir, hostDstDir) {
|
|
|
415
545
|
throw new Error(`cloud workspace pack failed: ${r.stderr || r.stdout}`);
|
|
416
546
|
}
|
|
417
547
|
await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);
|
|
418
|
-
await
|
|
548
|
+
await execa3("tar", ["-xzf", localTar, "-C", dstAbs]);
|
|
419
549
|
await backend.exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`).catch(() => {
|
|
420
550
|
});
|
|
421
551
|
} finally {
|
|
422
|
-
await
|
|
552
|
+
await rm4(stage, { recursive: true, force: true });
|
|
423
553
|
}
|
|
424
554
|
return { finalPath: dstAbs };
|
|
425
555
|
}
|
|
@@ -439,7 +569,7 @@ async function downloadFromCloudBox(backend, handle, boxSrc, hostDst) {
|
|
|
439
569
|
}
|
|
440
570
|
mkdirSync(hostParent, { recursive: true });
|
|
441
571
|
const finalPath = hostJoin(hostParent, finalName);
|
|
442
|
-
const stage = await
|
|
572
|
+
const stage = await mkdtemp3(hostJoin(tmpdir3(), "agentbox-cp-down-"));
|
|
443
573
|
const localTar = hostJoin(stage, "payload.tar.gz");
|
|
444
574
|
try {
|
|
445
575
|
const packScript = [
|
|
@@ -452,14 +582,14 @@ async function downloadFromCloudBox(backend, handle, boxSrc, hostDst) {
|
|
|
452
582
|
throw new Error(`cloud download pack failed: ${r.stderr || r.stdout}`);
|
|
453
583
|
}
|
|
454
584
|
await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);
|
|
455
|
-
await
|
|
585
|
+
await execa3("tar", ["-xzf", localTar, "-C", hostParent]);
|
|
456
586
|
if (finalName !== srcBasename) {
|
|
457
587
|
renameSync(hostJoin(hostParent, srcBasename), finalPath);
|
|
458
588
|
}
|
|
459
589
|
await backend.exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`).catch(() => {
|
|
460
590
|
});
|
|
461
591
|
} finally {
|
|
462
|
-
await
|
|
592
|
+
await rm4(stage, { recursive: true, force: true });
|
|
463
593
|
}
|
|
464
594
|
return { finalPath };
|
|
465
595
|
}
|
|
@@ -547,24 +677,29 @@ async function seedCloudWorkspace(args) {
|
|
|
547
677
|
const nested = repos.filter((r) => r.kind === "nested");
|
|
548
678
|
if (root) {
|
|
549
679
|
log(
|
|
550
|
-
nested.length > 0 ? `seeding /workspace from git
|
|
680
|
+
nested.length > 0 ? `seeding /workspace from shallow git clone (+${String(nested.length)} nested repo${nested.length === 1 ? "" : "s"})` : "seeding /workspace from shallow git clone"
|
|
551
681
|
);
|
|
552
|
-
await
|
|
682
|
+
await seedFromGitClone({
|
|
553
683
|
backend: args.backend,
|
|
554
684
|
handle: args.handle,
|
|
555
685
|
hostRepo: root.hostMainRepo,
|
|
556
686
|
branch: args.branch,
|
|
557
|
-
workspaceDir
|
|
687
|
+
workspaceDir,
|
|
688
|
+
bundleDepth: args.bundleDepth,
|
|
689
|
+
fromBranch: args.fromBranch,
|
|
690
|
+
onLog: log
|
|
558
691
|
});
|
|
559
692
|
for (const r of nested) {
|
|
560
693
|
const sub = `${workspaceDir}/${r.relPathFromWorkspace}`;
|
|
561
|
-
log(`seeding nested repo ${r.relPathFromWorkspace} from git
|
|
562
|
-
await
|
|
694
|
+
log(`seeding nested repo ${r.relPathFromWorkspace} from shallow git clone`);
|
|
695
|
+
await seedFromGitClone({
|
|
563
696
|
backend: args.backend,
|
|
564
697
|
handle: args.handle,
|
|
565
698
|
hostRepo: r.hostMainRepo,
|
|
566
699
|
branch: args.branch,
|
|
567
|
-
workspaceDir: sub
|
|
700
|
+
workspaceDir: sub,
|
|
701
|
+
bundleDepth: args.bundleDepth,
|
|
702
|
+
onLog: log
|
|
568
703
|
});
|
|
569
704
|
}
|
|
570
705
|
return { fromGit: true, branch: args.branch };
|
|
@@ -580,41 +715,52 @@ async function seedCloudWorkspace(args) {
|
|
|
580
715
|
}
|
|
581
716
|
var STASH_CARRYOVER_REF = "refs/agentbox-carryover/stash";
|
|
582
717
|
var REMOTE_UNTRACKED_TAR = "/tmp/agentbox-carryover-untracked.tar.gz";
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
718
|
+
var DEFAULT_BUNDLE_DEPTH = 200;
|
|
719
|
+
var LARGE_BUNDLE_DEPTH = 100;
|
|
720
|
+
var LARGE_BUNDLE_THRESHOLD_BYTES = 20 * 1024 * 1024;
|
|
721
|
+
async function seedFromGitClone(args) {
|
|
722
|
+
const log = args.onLog ?? (() => {
|
|
723
|
+
});
|
|
724
|
+
const stage = await mkdtemp4(join5(tmpdir4(), "agentbox-clone-"));
|
|
725
|
+
const cloneDir = join5(stage, "clone");
|
|
726
|
+
const tarPath = join5(stage, "workspace.tar.gz");
|
|
727
|
+
const untrackedTarPath = join5(stage, "untracked.tar.gz");
|
|
587
728
|
const stashSha = await safeStashCreate(args.hostRepo);
|
|
588
729
|
const untrackedSize = await maybeBuildUntrackedTar(args.hostRepo, untrackedTarPath);
|
|
589
730
|
let stashRefCreated = false;
|
|
590
731
|
try {
|
|
591
732
|
if (stashSha) {
|
|
592
|
-
const ref = await
|
|
733
|
+
const ref = await execa4(
|
|
593
734
|
"git",
|
|
594
735
|
["-C", args.hostRepo, "update-ref", STASH_CARRYOVER_REF, stashSha],
|
|
595
736
|
{ reject: false }
|
|
596
737
|
);
|
|
597
738
|
stashRefCreated = ref.exitCode === 0;
|
|
598
739
|
}
|
|
599
|
-
const
|
|
600
|
-
const
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
740
|
+
const configured = args.bundleDepth;
|
|
741
|
+
const adaptive = configured === void 0;
|
|
742
|
+
const initialDepth = adaptive ? DEFAULT_BUNDLE_DEPTH : configured === 0 ? null : configured;
|
|
743
|
+
log(
|
|
744
|
+
adaptive ? `clone: depth=${String(DEFAULT_BUNDLE_DEPTH)} (default, adaptive)` : initialDepth === null ? "clone: depth=full (configured)" : `clone: depth=${String(initialDepth)} (configured)`
|
|
745
|
+
);
|
|
746
|
+
await runShallowClone(args.hostRepo, cloneDir, initialDepth, stashRefCreated, args.fromBranch);
|
|
747
|
+
await tarCloneDir(cloneDir, tarPath);
|
|
748
|
+
if (adaptive && initialDepth !== null) {
|
|
749
|
+
const size = await safeFileSize(tarPath);
|
|
750
|
+
if (size > LARGE_BUNDLE_THRESHOLD_BYTES) {
|
|
751
|
+
const mb = (size / (1024 * 1024)).toFixed(1);
|
|
752
|
+
log(
|
|
753
|
+
`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)}`
|
|
754
|
+
);
|
|
755
|
+
await rm5(cloneDir, { recursive: true, force: true });
|
|
756
|
+
await rm5(tarPath, { force: true });
|
|
757
|
+
await runShallowClone(args.hostRepo, cloneDir, LARGE_BUNDLE_DEPTH, stashRefCreated, args.fromBranch);
|
|
758
|
+
await tarCloneDir(cloneDir, tarPath);
|
|
759
|
+
}
|
|
614
760
|
}
|
|
615
761
|
const remoteUrl = await readOriginUrl(args.hostRepo);
|
|
616
|
-
const
|
|
617
|
-
await args.backend.uploadFile(args.handle,
|
|
762
|
+
const remoteTar = "/tmp/agentbox-workspace.tar.gz";
|
|
763
|
+
await args.backend.uploadFile(args.handle, tarPath, remoteTar);
|
|
618
764
|
if (untrackedSize > 0) {
|
|
619
765
|
await args.backend.uploadFile(args.handle, untrackedTarPath, REMOTE_UNTRACKED_TAR);
|
|
620
766
|
}
|
|
@@ -633,50 +779,77 @@ async function seedFromGitBundle(args) {
|
|
|
633
779
|
// Move out of any cwd we might inherit from Daytona's executeCommand
|
|
634
780
|
// before we delete /workspace. The agentbox image bakes WORKDIR
|
|
635
781
|
// /workspace; if the shell's cwd is /workspace when we `rm -rf` it,
|
|
636
|
-
// the next process inherits a stale cwd FD and
|
|
637
|
-
//
|
|
782
|
+
// the next process inherits a stale cwd FD and tar's children fail
|
|
783
|
+
// with "Unable to read current working directory".
|
|
638
784
|
`cd /tmp`,
|
|
639
785
|
SUDO,
|
|
640
|
-
// rm -rf only the directory we're about to
|
|
786
|
+
// rm -rf only the directory we're about to extract into — for nested
|
|
641
787
|
// repos this is just `/workspace/<rel>`, so the root clone (already
|
|
642
788
|
// at `/workspace`) is preserved.
|
|
643
789
|
`$SUDO rm -rf ${quoteShellArgv([args.workspaceDir])}`,
|
|
644
790
|
`$SUDO mkdir -p ${quoteShellArgv([args.workspaceDir])}`,
|
|
645
791
|
`$SUDO chown "$(id -un):$(id -gn)" ${quoteShellArgv([args.workspaceDir])}`,
|
|
646
|
-
`
|
|
792
|
+
`tar -C ${quoteShellArgv([args.workspaceDir])} -xzf ${quoteShellArgv([remoteTar])}`,
|
|
647
793
|
setOrigin,
|
|
648
|
-
`git -C ${quoteShellArgv([args.workspaceDir])} fetch ${quoteShellArgv([remoteBundle])} --tags '+refs/heads/*:refs/remotes/bundle/*' || true`,
|
|
649
794
|
`git -C ${quoteShellArgv([args.workspaceDir])} checkout -B ${quoteShellArgv([args.branch])}`,
|
|
650
795
|
...carryOverSteps,
|
|
651
|
-
`rm -f ${quoteShellArgv([
|
|
796
|
+
`rm -f ${quoteShellArgv([remoteTar])}`
|
|
652
797
|
].join("\n");
|
|
653
798
|
const r = await args.backend.exec(args.handle, bashScript(script));
|
|
654
799
|
if (r.exitCode !== 0) {
|
|
655
|
-
throw new Error(`workspace seed (
|
|
800
|
+
throw new Error(`workspace seed (clone) failed: ${r.stderr || r.stdout}`);
|
|
656
801
|
}
|
|
657
802
|
} finally {
|
|
658
803
|
if (stashRefCreated) {
|
|
659
|
-
await
|
|
804
|
+
await execa4("git", ["-C", args.hostRepo, "update-ref", "-d", STASH_CARRYOVER_REF], {
|
|
660
805
|
reject: false
|
|
661
806
|
});
|
|
662
807
|
}
|
|
663
|
-
await
|
|
808
|
+
await rm5(stage, { recursive: true, force: true });
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
async function runShallowClone(hostRepo, cloneDir, depth, includeStashRef, fromBranch) {
|
|
812
|
+
const cloneArgs = ["clone", "--no-checkout", "--quiet"];
|
|
813
|
+
if (depth !== null) cloneArgs.push(`--depth=${String(depth)}`);
|
|
814
|
+
if (fromBranch) cloneArgs.push("--branch", fromBranch);
|
|
815
|
+
cloneArgs.push(`file://${hostRepo}`, cloneDir);
|
|
816
|
+
await execa4("git", cloneArgs);
|
|
817
|
+
if (includeStashRef) {
|
|
818
|
+
const fetchArgs = ["-C", cloneDir, "fetch", "--quiet"];
|
|
819
|
+
if (depth !== null) fetchArgs.push(`--depth=${String(depth)}`);
|
|
820
|
+
fetchArgs.push(
|
|
821
|
+
`file://${hostRepo}`,
|
|
822
|
+
`+${STASH_CARRYOVER_REF}:refs/remotes/origin/agentbox-carryover/stash`
|
|
823
|
+
);
|
|
824
|
+
await execa4("git", fetchArgs, { reject: false });
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
async function tarCloneDir(cloneDir, outPath) {
|
|
828
|
+
await execa4("tar", ["-C", cloneDir, "-czf", outPath, "."], {
|
|
829
|
+
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
async function safeFileSize(path) {
|
|
833
|
+
try {
|
|
834
|
+
return (await stat(path)).size;
|
|
835
|
+
} catch {
|
|
836
|
+
return 0;
|
|
664
837
|
}
|
|
665
838
|
}
|
|
666
839
|
async function safeStashCreate(hostRepo) {
|
|
667
|
-
const r = await
|
|
840
|
+
const r = await execa4("git", ["-C", hostRepo, "stash", "create"], { reject: false });
|
|
668
841
|
if (r.exitCode !== 0) return null;
|
|
669
842
|
const sha = r.stdout.trim();
|
|
670
843
|
return sha.length > 0 ? sha : null;
|
|
671
844
|
}
|
|
672
845
|
async function maybeBuildUntrackedTar(hostRepo, outPath) {
|
|
673
|
-
const list = await
|
|
846
|
+
const list = await execa4(
|
|
674
847
|
"git",
|
|
675
848
|
["-C", hostRepo, "ls-files", "--others", "--exclude-standard", "-z"],
|
|
676
849
|
{ reject: false }
|
|
677
850
|
);
|
|
678
851
|
if (list.exitCode !== 0 || list.stdout.length === 0) return 0;
|
|
679
|
-
const tar = await
|
|
852
|
+
const tar = await execa4(
|
|
680
853
|
"tar",
|
|
681
854
|
["-C", hostRepo, "--null", "-T", "-", "-czf", outPath],
|
|
682
855
|
{
|
|
@@ -687,24 +860,24 @@ async function maybeBuildUntrackedTar(hostRepo, outPath) {
|
|
|
687
860
|
);
|
|
688
861
|
if (tar.exitCode !== 0) return 0;
|
|
689
862
|
try {
|
|
690
|
-
const { stat } = await import("fs/promises");
|
|
691
|
-
const s = await
|
|
863
|
+
const { stat: stat2 } = await import("fs/promises");
|
|
864
|
+
const s = await stat2(outPath);
|
|
692
865
|
return s.size;
|
|
693
866
|
} catch {
|
|
694
867
|
return 0;
|
|
695
868
|
}
|
|
696
869
|
}
|
|
697
870
|
async function readOriginUrl(hostRepo) {
|
|
698
|
-
const r = await
|
|
871
|
+
const r = await execa4("git", ["-C", hostRepo, "remote", "get-url", "origin"], { reject: false });
|
|
699
872
|
if (r.exitCode !== 0) return null;
|
|
700
873
|
const out = (r.stdout ?? "").trim();
|
|
701
874
|
return out.length > 0 ? out : null;
|
|
702
875
|
}
|
|
703
876
|
async function seedFromTar(args) {
|
|
704
|
-
const stage = await
|
|
705
|
-
const tarPath =
|
|
877
|
+
const stage = await mkdtemp4(join5(tmpdir4(), "agentbox-tar-"));
|
|
878
|
+
const tarPath = join5(stage, "workspace.tar.gz");
|
|
706
879
|
try {
|
|
707
|
-
await
|
|
880
|
+
await execa4("tar", ["-C", args.hostDir, "-czf", tarPath, "."]);
|
|
708
881
|
const remoteTar = "/tmp/agentbox-workspace.tar.gz";
|
|
709
882
|
await args.backend.uploadFile(args.handle, tarPath, remoteTar);
|
|
710
883
|
const SUDO = `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`;
|
|
@@ -728,7 +901,7 @@ async function seedFromTar(args) {
|
|
|
728
901
|
throw new Error(`workspace seed (tar) failed: ${r.stderr || r.stdout}`);
|
|
729
902
|
}
|
|
730
903
|
} finally {
|
|
731
|
-
await
|
|
904
|
+
await rm5(stage, { recursive: true, force: true });
|
|
732
905
|
}
|
|
733
906
|
}
|
|
734
907
|
var CLOUD_WORKSPACE_DIR = "/workspace";
|
|
@@ -759,18 +932,28 @@ function parseLoopbackPort(url) {
|
|
|
759
932
|
return void 0;
|
|
760
933
|
}
|
|
761
934
|
}
|
|
762
|
-
async function
|
|
763
|
-
const localPort = parseLoopbackPort(args.
|
|
935
|
+
async function registerHostPortlessAlias(args) {
|
|
936
|
+
const localPort = parseLoopbackPort(args.previewUrl);
|
|
764
937
|
if (localPort === void 0) return void 0;
|
|
765
|
-
const ok = await portlessAlias(args.
|
|
938
|
+
const ok = await portlessAlias(args.alias, localPort);
|
|
766
939
|
if (!ok) {
|
|
767
940
|
args.onLog(
|
|
768
|
-
`portless: alias not registered (portless CLI missing or not running) \u2014 host URL stays http://127.0.0.1:${String(localPort)}`
|
|
941
|
+
`portless: ${args.label} alias not registered (portless CLI missing or not running) \u2014 host URL stays http://127.0.0.1:${String(localPort)}`
|
|
769
942
|
);
|
|
770
943
|
return void 0;
|
|
771
944
|
}
|
|
772
|
-
const url = await portlessGetUrl(args.
|
|
945
|
+
const url = await portlessGetUrl(args.alias);
|
|
773
946
|
args.onLog(`portless alias ${url} -> 127.0.0.1:${String(localPort)}`);
|
|
947
|
+
return url;
|
|
948
|
+
}
|
|
949
|
+
async function bootstrapPortlessForCloudBox(backend, handle, args) {
|
|
950
|
+
const url = await registerHostPortlessAlias({
|
|
951
|
+
alias: args.boxName,
|
|
952
|
+
previewUrl: args.webPreviewUrl,
|
|
953
|
+
label: "web",
|
|
954
|
+
onLog: args.onLog
|
|
955
|
+
});
|
|
956
|
+
if (!url) return void 0;
|
|
774
957
|
if (backend.startInBoxPortless) {
|
|
775
958
|
const mode = parsePortlessUrl(url) ?? { proxyPort: DEFAULT_PORTLESS_PROXY_PORT, tls: false };
|
|
776
959
|
try {
|
|
@@ -860,8 +1043,10 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
860
1043
|
AGENTBOX_BOX_ID: id,
|
|
861
1044
|
AGENTBOX_BOX_NAME: name,
|
|
862
1045
|
AGENTBOX_BOX_KIND: "cloud",
|
|
863
|
-
// In-sandbox relay is on the box's loopback at the
|
|
864
|
-
|
|
1046
|
+
// In-sandbox relay is on the box's loopback at the in-box port.
|
|
1047
|
+
// 8788 is distinct from the host relay's 8787 so a nested agentbox
|
|
1048
|
+
// run inside the box can claim :8787 without colliding.
|
|
1049
|
+
AGENTBOX_RELAY_URL: `http://127.0.0.1:${String(8788)}`,
|
|
865
1050
|
AGENTBOX_RELAY_TOKEN: relayToken,
|
|
866
1051
|
AGENTBOX_BRIDGE_TOKEN: bridgeToken,
|
|
867
1052
|
...agentVolumes.env
|
|
@@ -879,6 +1064,8 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
879
1064
|
workspacePath: req.workspacePath,
|
|
880
1065
|
branch,
|
|
881
1066
|
workspaceDir: CLOUD_WORKSPACE_DIR,
|
|
1067
|
+
bundleDepth: req.bundleDepth,
|
|
1068
|
+
fromBranch: req.fromBranch,
|
|
882
1069
|
onLog: log
|
|
883
1070
|
});
|
|
884
1071
|
}
|
|
@@ -889,6 +1076,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
889
1076
|
onLog: log
|
|
890
1077
|
});
|
|
891
1078
|
}
|
|
1079
|
+
await seedOpencodeModelState(backend, handle, { onLog: log });
|
|
892
1080
|
if (req.envFilesToImport && req.envFilesToImport.length > 0) {
|
|
893
1081
|
const { copied } = await uploadEnvFiles({
|
|
894
1082
|
backend,
|
|
@@ -900,13 +1088,28 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
900
1088
|
});
|
|
901
1089
|
if (copied > 0) log(`copied ${String(copied)} env/config file(s) into /workspace`);
|
|
902
1090
|
}
|
|
1091
|
+
let carrySummary;
|
|
1092
|
+
if (req.carry && req.carry.length > 0) {
|
|
1093
|
+
log(`carry: copying ${String(req.carry.length)} host path(s) into the box`);
|
|
1094
|
+
const result = await uploadCarryPaths({
|
|
1095
|
+
backend,
|
|
1096
|
+
handle,
|
|
1097
|
+
entries: req.carry,
|
|
1098
|
+
onLog: log
|
|
1099
|
+
});
|
|
1100
|
+
log(`carry: copied ${String(result.copied)}/${String(req.carry.length)} entry/entries`);
|
|
1101
|
+
for (const err of result.errors) log(`carry: ${err}`);
|
|
1102
|
+
if (result.applied.length > 0) {
|
|
1103
|
+
carrySummary = { count: result.applied.length, entries: result.applied };
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
903
1106
|
log("launching agentbox-ctl daemon");
|
|
904
1107
|
await launchCloudCtlDaemon({
|
|
905
1108
|
backend,
|
|
906
1109
|
handle,
|
|
907
1110
|
boxId: id,
|
|
908
1111
|
boxName: name,
|
|
909
|
-
relayUrl: `http://127.0.0.1:${String(
|
|
1112
|
+
relayUrl: `http://127.0.0.1:${String(8788)}`,
|
|
910
1113
|
relayToken,
|
|
911
1114
|
bridgeToken
|
|
912
1115
|
});
|
|
@@ -950,6 +1153,29 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
950
1153
|
portlessUrlResolved = r.url;
|
|
951
1154
|
}
|
|
952
1155
|
}
|
|
1156
|
+
let vncPreview;
|
|
1157
|
+
if (portlessOpt && vncEnabled) {
|
|
1158
|
+
try {
|
|
1159
|
+
vncPreview = await backend.previewUrl(handle, CLOUD_VNC_PORT);
|
|
1160
|
+
} catch {
|
|
1161
|
+
vncPreview = void 0;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
let portlessVncAliasName;
|
|
1165
|
+
let portlessVncUrlResolved;
|
|
1166
|
+
if (portlessOpt && vncPreview) {
|
|
1167
|
+
const vncAlias = `vnc-${name}`;
|
|
1168
|
+
const url = await registerHostPortlessAlias({
|
|
1169
|
+
alias: vncAlias,
|
|
1170
|
+
previewUrl: vncPreview.url,
|
|
1171
|
+
label: "vnc",
|
|
1172
|
+
onLog: log
|
|
1173
|
+
});
|
|
1174
|
+
if (url) {
|
|
1175
|
+
portlessVncAliasName = vncAlias;
|
|
1176
|
+
portlessVncUrlResolved = url;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
953
1179
|
const servicePorts = await readExposedServicePorts(req.workspacePath);
|
|
954
1180
|
const servicePreviews = {};
|
|
955
1181
|
for (const port of servicePorts) {
|
|
@@ -962,7 +1188,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
962
1188
|
}
|
|
963
1189
|
let relayPreview;
|
|
964
1190
|
try {
|
|
965
|
-
relayPreview = await backend.previewUrl(handle,
|
|
1191
|
+
relayPreview = await backend.previewUrl(handle, 8788);
|
|
966
1192
|
} catch {
|
|
967
1193
|
relayPreview = void 0;
|
|
968
1194
|
}
|
|
@@ -1005,8 +1231,11 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1005
1231
|
relayToken,
|
|
1006
1232
|
withPlaywright: req.withPlaywright,
|
|
1007
1233
|
withEnv: req.withEnv,
|
|
1234
|
+
carry: carrySummary,
|
|
1008
1235
|
portlessAlias: portlessAliasName,
|
|
1009
1236
|
portlessUrl: portlessUrlResolved,
|
|
1237
|
+
portlessVncAlias: portlessVncAliasName,
|
|
1238
|
+
portlessVncUrl: portlessVncUrlResolved,
|
|
1010
1239
|
vncEnabled,
|
|
1011
1240
|
vncPassword,
|
|
1012
1241
|
vncContainerPort: vncEnabled ? CLOUD_VNC_PORT : void 0,
|
|
@@ -1069,7 +1298,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1069
1298
|
}
|
|
1070
1299
|
let relayPreview;
|
|
1071
1300
|
try {
|
|
1072
|
-
relayPreview = await backend.previewUrl(h,
|
|
1301
|
+
relayPreview = await backend.previewUrl(h, 8788);
|
|
1073
1302
|
} catch {
|
|
1074
1303
|
relayPreview = box.cloud?.relayPreviewUrl ? { url: box.cloud.relayPreviewUrl, token: box.cloud.relayPreviewToken } : void 0;
|
|
1075
1304
|
}
|
|
@@ -1093,10 +1322,31 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1093
1322
|
portlessUrlResolved = r.url;
|
|
1094
1323
|
}
|
|
1095
1324
|
}
|
|
1325
|
+
let portlessVncAliasName = box.portlessVncAlias;
|
|
1326
|
+
let portlessVncUrlResolved = box.portlessVncUrl;
|
|
1327
|
+
if (box.portlessVncAlias && box.vncEnabled) {
|
|
1328
|
+
try {
|
|
1329
|
+
const vncPreview = await backend.previewUrl(h, CLOUD_VNC_PORT);
|
|
1330
|
+
const url = await registerHostPortlessAlias({
|
|
1331
|
+
alias: box.portlessVncAlias,
|
|
1332
|
+
previewUrl: vncPreview.url,
|
|
1333
|
+
label: "vnc",
|
|
1334
|
+
onLog: () => {
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
if (url) {
|
|
1338
|
+
portlessVncAliasName = box.portlessVncAlias;
|
|
1339
|
+
portlessVncUrlResolved = url;
|
|
1340
|
+
}
|
|
1341
|
+
} catch {
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1096
1344
|
const next = {
|
|
1097
1345
|
...box,
|
|
1098
1346
|
portlessAlias: portlessAliasName,
|
|
1099
1347
|
portlessUrl: portlessUrlResolved,
|
|
1348
|
+
portlessVncAlias: portlessVncAliasName,
|
|
1349
|
+
portlessVncUrl: portlessVncUrlResolved,
|
|
1100
1350
|
cloud: {
|
|
1101
1351
|
...box.cloud ?? { backend: providerName, sandboxId: h.sandboxId },
|
|
1102
1352
|
webPort,
|
|
@@ -1111,7 +1361,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1111
1361
|
handle: h,
|
|
1112
1362
|
boxId: box.id,
|
|
1113
1363
|
boxName: box.name,
|
|
1114
|
-
relayUrl: `http://127.0.0.1:${String(
|
|
1364
|
+
relayUrl: `http://127.0.0.1:${String(8788)}`,
|
|
1115
1365
|
relayToken: box.relayToken ?? "",
|
|
1116
1366
|
bridgeToken: box.cloud?.bridgeToken
|
|
1117
1367
|
});
|
|
@@ -1168,6 +1418,12 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1168
1418
|
} catch {
|
|
1169
1419
|
}
|
|
1170
1420
|
}
|
|
1421
|
+
if (box.portlessVncAlias) {
|
|
1422
|
+
try {
|
|
1423
|
+
await portlessUnalias(box.portlessVncAlias);
|
|
1424
|
+
} catch {
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1171
1427
|
try {
|
|
1172
1428
|
await forgetBoxFromRelay(box.id);
|
|
1173
1429
|
} catch {
|
|
@@ -1232,7 +1488,7 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1232
1488
|
const handle = handleFor(box);
|
|
1233
1489
|
const baseArgv = await backend.attachArgv(handle);
|
|
1234
1490
|
const inner = renderInnerCommand(kind, opts2);
|
|
1235
|
-
const argv = [...baseArgv.slice(1), "-t", inner];
|
|
1491
|
+
const argv = opts2?.detached ? [...baseArgv.slice(1), inner] : [...baseArgv.slice(1), "-t", inner];
|
|
1236
1492
|
const fullArgv = [baseArgv[0], ...argv];
|
|
1237
1493
|
const cleanup = backend.revokeAttachToken ? async () => {
|
|
1238
1494
|
await backend.revokeAttachToken(handle, baseArgv);
|
|
@@ -1251,6 +1507,14 @@ function createCloudProvider(backend, opts = {}) {
|
|
|
1251
1507
|
async resolveUrl(box, opts2) {
|
|
1252
1508
|
const h = handleFor(box);
|
|
1253
1509
|
const kind = opts2?.kind ?? "web";
|
|
1510
|
+
if (!opts2?.loopback) {
|
|
1511
|
+
if (kind === "web" && box.portlessAlias) {
|
|
1512
|
+
return box.portlessUrl ?? `https://${box.portlessAlias}.localhost`;
|
|
1513
|
+
}
|
|
1514
|
+
if (kind === "vnc" && box.portlessVncAlias) {
|
|
1515
|
+
return box.portlessVncUrl ?? `https://${box.portlessVncAlias}.localhost`;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1254
1518
|
const port = kind === "vnc" ? CLOUD_VNC_PORT : box.cloud?.webPort ?? CLOUD_WEB_PROXY_PORT;
|
|
1255
1519
|
if (backend.signedPreviewUrl) {
|
|
1256
1520
|
const ttl = opts2?.ttl ?? DEFAULT_SIGNED_URL_TTL_SECONDS;
|
|
@@ -1322,7 +1586,17 @@ function renderInnerCommand(kind, opts) {
|
|
|
1322
1586
|
if (opts?.noTmux) {
|
|
1323
1587
|
return fallback;
|
|
1324
1588
|
}
|
|
1325
|
-
|
|
1589
|
+
const sessionQ = shellSingle(sessionName);
|
|
1590
|
+
const cwdQ = shellSingle(CLOUD_WORKSPACE_DIR);
|
|
1591
|
+
const fallbackQ = shellSingle(fallback);
|
|
1592
|
+
const configSnippet = buildTmuxConfigShellSnippet(sessionName);
|
|
1593
|
+
const lines = [
|
|
1594
|
+
`command -v tmux >/dev/null || { echo "tmux not installed in sandbox"; exit 127; }`,
|
|
1595
|
+
`tmux has-session -t ${sessionQ} 2>/dev/null || tmux new-session -d -c ${cwdQ} -s ${sessionQ} ${fallbackQ}`,
|
|
1596
|
+
configSnippet
|
|
1597
|
+
];
|
|
1598
|
+
if (opts?.detached) return lines.join("; ");
|
|
1599
|
+
return [...lines, `exec tmux attach -t ${sessionQ}`].join("; ");
|
|
1326
1600
|
}
|
|
1327
1601
|
function defaultSessionName(kind) {
|
|
1328
1602
|
switch (kind) {
|
|
@@ -1363,4 +1637,4 @@ export {
|
|
|
1363
1637
|
resolveCloudCheckpoint,
|
|
1364
1638
|
createCloudProvider
|
|
1365
1639
|
};
|
|
1366
|
-
//# sourceMappingURL=chunk-
|
|
1640
|
+
//# sourceMappingURL=chunk-67N47KUS.js.map
|