@madarco/agentbox 0.12.0 → 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 +31 -0
- package/README.md +11 -0
- package/dist/{_cloud-attach-XKO4SHR3.js → _cloud-attach-HJC672UR.js} +3 -3
- package/dist/{chunk-DHJ7OMIP.js → chunk-4NQXNQ53.js} +2 -2
- package/dist/{chunk-IZXPJPPV.js → chunk-B4QG2MCW.js} +9 -3
- package/dist/{chunk-IZXPJPPV.js.map → chunk-B4QG2MCW.js.map} +1 -1
- package/dist/{chunk-HFV6THYG.js → chunk-QYRK5H6Q.js} +297 -33
- package/dist/chunk-QYRK5H6Q.js.map +1 -0
- package/dist/{dist-SWUOU34W.js → dist-7KVUIKJX.js} +3 -3
- package/dist/{dist-24PY2ZMO.js → dist-JAN5VABY.js} +3 -3
- package/dist/{dist-RZZSSUNB.js → dist-OG6NW6SM.js} +2 -2
- package/dist/{dist-47LVLYUV.js → dist-OPIBZ7XM.js} +3 -3
- package/dist/index.js +547 -291
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/runtime/docker/packages/ctl/dist/bin.cjs +6 -1
- package/runtime/hetzner/ctl.cjs +6 -1
- package/runtime/relay/bin.cjs +8 -2
- package/runtime/vercel/ctl.cjs +6 -1
- package/dist/chunk-HFV6THYG.js.map +0 -1
- /package/dist/{_cloud-attach-XKO4SHR3.js.map → _cloud-attach-HJC672UR.js.map} +0 -0
- /package/dist/{chunk-DHJ7OMIP.js.map → chunk-4NQXNQ53.js.map} +0 -0
- /package/dist/{dist-SWUOU34W.js.map → dist-7KVUIKJX.js.map} +0 -0
- /package/dist/{dist-24PY2ZMO.js.map → dist-JAN5VABY.js.map} +0 -0
- /package/dist/{dist-RZZSSUNB.js.map → dist-OG6NW6SM.js.map} +0 -0
- /package/dist/{dist-47LVLYUV.js.map → dist-OPIBZ7XM.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
probeCloudCheckpoint,
|
|
34
34
|
resolveCloudCheckpoint,
|
|
35
35
|
seedAgentVolumesIfFresh
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-4NQXNQ53.js";
|
|
37
37
|
import {
|
|
38
38
|
ADVANCED_HINT_GROUPS,
|
|
39
39
|
ALERT_BAND_ROWS,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
statusLine,
|
|
65
65
|
stripTitleGlyph,
|
|
66
66
|
subscribePrompts
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-QYRK5H6Q.js";
|
|
68
68
|
import {
|
|
69
69
|
AmbiguousBoxError,
|
|
70
70
|
BOX_STATUS_EVENT,
|
|
@@ -217,7 +217,7 @@ import {
|
|
|
217
217
|
waitForTmuxPaneContent,
|
|
218
218
|
warmUpClaudeCredentials,
|
|
219
219
|
writeJob
|
|
220
|
-
} from "./chunk-
|
|
220
|
+
} from "./chunk-B4QG2MCW.js";
|
|
221
221
|
import {
|
|
222
222
|
DEFAULT_BOX_IMAGE,
|
|
223
223
|
STATE_DIR,
|
|
@@ -234,11 +234,11 @@ import {
|
|
|
234
234
|
import "./chunk-G3H2L3O2.js";
|
|
235
235
|
|
|
236
236
|
// src/version.ts
|
|
237
|
-
var AGENTBOX_VERSION = true ? "0.
|
|
238
|
-
var AGENTBOX_COMMIT = true ? "
|
|
237
|
+
var AGENTBOX_VERSION = true ? "0.13.0" : "0.0.0-dev";
|
|
238
|
+
var AGENTBOX_COMMIT = true ? "7a59c0de" : "dev";
|
|
239
239
|
|
|
240
240
|
// src/index.ts
|
|
241
|
-
import { Command as
|
|
241
|
+
import { Command as Command47 } from "commander";
|
|
242
242
|
|
|
243
243
|
// src/engine-override.ts
|
|
244
244
|
async function applyEngineOverrideAtStartup() {
|
|
@@ -912,7 +912,7 @@ async function dirSizeCapped(dir, cap) {
|
|
|
912
912
|
|
|
913
913
|
// src/lib/carry-resync.ts
|
|
914
914
|
async function resyncCarryFiles(args) {
|
|
915
|
-
const
|
|
915
|
+
const log46 = args.onLog ?? (() => {
|
|
916
916
|
});
|
|
917
917
|
const prior = args.box.carry?.entries ?? [];
|
|
918
918
|
if (prior.length === 0) return { recopied: 0, skippedNew: 0 };
|
|
@@ -920,7 +920,7 @@ async function resyncCarryFiles(args) {
|
|
|
920
920
|
if (items.length === 0) return { recopied: 0, skippedNew: 0 };
|
|
921
921
|
const resolved = await resolveCarry(items, { projectRoot: args.projectRoot });
|
|
922
922
|
if (resolved.errors.length > 0) {
|
|
923
|
-
|
|
923
|
+
log46(`carry: resync skipped (resolve errors: ${resolved.errors.length})`);
|
|
924
924
|
return { recopied: 0, skippedNew: 0 };
|
|
925
925
|
}
|
|
926
926
|
const priorByDest = new Map(prior.map((e) => [e.dest, e]));
|
|
@@ -937,7 +937,7 @@ async function resyncCarryFiles(args) {
|
|
|
937
937
|
if (hash === void 0 || hash !== existing.hash) changed.push(entry);
|
|
938
938
|
}
|
|
939
939
|
if (skippedNew > 0) {
|
|
940
|
-
|
|
940
|
+
log46(
|
|
941
941
|
`carry: ${String(skippedNew)} new entry/entries not applied on resync \u2014 recreate the box to approve`
|
|
942
942
|
);
|
|
943
943
|
}
|
|
@@ -945,9 +945,9 @@ async function resyncCarryFiles(args) {
|
|
|
945
945
|
const result = await copyCarryPathsToBox({
|
|
946
946
|
container: args.box.container,
|
|
947
947
|
entries: changed,
|
|
948
|
-
onLog:
|
|
948
|
+
onLog: log46
|
|
949
949
|
});
|
|
950
|
-
for (const err of result.errors)
|
|
950
|
+
for (const err of result.errors) log46(`carry: ${err}`);
|
|
951
951
|
const updatedByDest = new Map(result.applied.map((e) => [e.dest, e]));
|
|
952
952
|
const mergedEntries = prior.map((e) => updatedByDest.get(e.dest) ?? e);
|
|
953
953
|
await recordBox({
|
|
@@ -955,7 +955,7 @@ async function resyncCarryFiles(args) {
|
|
|
955
955
|
carry: { count: mergedEntries.length, entries: mergedEntries }
|
|
956
956
|
});
|
|
957
957
|
if (result.applied.length > 0) {
|
|
958
|
-
|
|
958
|
+
log46(`carry: re-copied ${String(result.applied.length)} changed file(s)`);
|
|
959
959
|
}
|
|
960
960
|
return { recopied: result.applied.length, skippedNew };
|
|
961
961
|
}
|
|
@@ -2056,11 +2056,11 @@ import { basename as basename2 } from "path";
|
|
|
2056
2056
|
async function cloudBackendForProvider(provider) {
|
|
2057
2057
|
switch (provider) {
|
|
2058
2058
|
case "daytona":
|
|
2059
|
-
return (await import("./dist-
|
|
2059
|
+
return (await import("./dist-OPIBZ7XM.js")).daytonaBackend;
|
|
2060
2060
|
case "hetzner":
|
|
2061
|
-
return (await import("./dist-
|
|
2061
|
+
return (await import("./dist-7KVUIKJX.js")).hetznerBackend;
|
|
2062
2062
|
case "vercel":
|
|
2063
|
-
return (await import("./dist-
|
|
2063
|
+
return (await import("./dist-JAN5VABY.js")).vercelBackend;
|
|
2064
2064
|
default:
|
|
2065
2065
|
return null;
|
|
2066
2066
|
}
|
|
@@ -3177,11 +3177,11 @@ var CLOUD_BACKENDS = ["daytona", "hetzner", "vercel"];
|
|
|
3177
3177
|
async function cloudProviderFor(backend) {
|
|
3178
3178
|
switch (backend) {
|
|
3179
3179
|
case "daytona":
|
|
3180
|
-
return (await import("./dist-
|
|
3180
|
+
return (await import("./dist-OPIBZ7XM.js")).daytonaProvider;
|
|
3181
3181
|
case "hetzner":
|
|
3182
|
-
return (await import("./dist-
|
|
3182
|
+
return (await import("./dist-7KVUIKJX.js")).hetznerProvider;
|
|
3183
3183
|
case "vercel":
|
|
3184
|
-
return (await import("./dist-
|
|
3184
|
+
return (await import("./dist-JAN5VABY.js")).vercelProvider;
|
|
3185
3185
|
}
|
|
3186
3186
|
}
|
|
3187
3187
|
var CHECKPOINT_NOTICE = "Checkpoint in progress \u2014 the box will be unresponsive for a moment";
|
|
@@ -5916,7 +5916,7 @@ var createCommand = new Command9("create").description(
|
|
|
5916
5916
|
}
|
|
5917
5917
|
outro4("done");
|
|
5918
5918
|
if (attachClaudeAfter) {
|
|
5919
|
-
const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-
|
|
5919
|
+
const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-HJC672UR.js");
|
|
5920
5920
|
await cloudAgentAttach2({
|
|
5921
5921
|
box: result.record,
|
|
5922
5922
|
binary: "claude",
|
|
@@ -6107,9 +6107,8 @@ var InputParser = class {
|
|
|
6107
6107
|
else if (c === "c") this.onEvent({ type: "action", name: "code" });
|
|
6108
6108
|
else if (c === "t") this.onEvent({ type: "action", name: "stop" });
|
|
6109
6109
|
else if (c === "p") this.onEvent({ type: "action", name: "pause" });
|
|
6110
|
-
else if (c === "
|
|
6110
|
+
else if (c === "k") this.onEvent({ type: "action", name: "destroy" });
|
|
6111
6111
|
else if (c === "q") this.onEvent({ type: "quit" });
|
|
6112
|
-
else if (c === "k") this.onEvent({ type: "switch", dir: "prev" });
|
|
6113
6112
|
else if (c === "j" || c === "n" || c === "N") this.onEvent({ type: "switch", dir: "next" });
|
|
6114
6113
|
else {
|
|
6115
6114
|
this.fwd.push(b);
|
|
@@ -9219,19 +9218,19 @@ var forkCommand = new Command23("fork").description(
|
|
|
9219
9218
|
});
|
|
9220
9219
|
|
|
9221
9220
|
// src/commands/install.ts
|
|
9222
|
-
import { confirm as confirm14, intro as
|
|
9223
|
-
import { Command as
|
|
9221
|
+
import { confirm as confirm14, intro as intro7, isCancel as isCancel15, log as log31, note as note3, outro as outro6, select as select2, spinner as spinner8 } from "@clack/prompts";
|
|
9222
|
+
import { Command as Command26 } from "commander";
|
|
9224
9223
|
import {
|
|
9225
|
-
existsSync as
|
|
9224
|
+
existsSync as existsSync8,
|
|
9226
9225
|
lstatSync,
|
|
9227
|
-
mkdirSync as
|
|
9228
|
-
readFileSync,
|
|
9226
|
+
mkdirSync as mkdirSync6,
|
|
9227
|
+
readFileSync as readFileSync2,
|
|
9229
9228
|
rmSync,
|
|
9230
9229
|
symlinkSync as symlinkSync2,
|
|
9231
|
-
writeFileSync as
|
|
9230
|
+
writeFileSync as writeFileSync5
|
|
9232
9231
|
} from "fs";
|
|
9233
|
-
import { homedir as
|
|
9234
|
-
import { dirname as
|
|
9232
|
+
import { homedir as homedir16 } from "os";
|
|
9233
|
+
import { dirname as dirname3, join as join18, resolve as resolve3, sep } from "path";
|
|
9235
9234
|
import { fileURLToPath } from "url";
|
|
9236
9235
|
|
|
9237
9236
|
// src/lib/doctor-checks.ts
|
|
@@ -9357,7 +9356,7 @@ async function dockerChecks() {
|
|
|
9357
9356
|
];
|
|
9358
9357
|
}
|
|
9359
9358
|
const daemonRes = { label: "docker daemon", status: "ok", detail: "reachable" };
|
|
9360
|
-
const mod = await import("./dist-
|
|
9359
|
+
const mod = await import("./dist-OG6NW6SM.js");
|
|
9361
9360
|
let imgRes;
|
|
9362
9361
|
try {
|
|
9363
9362
|
const img = await mod.imageInfo(mod.DEFAULT_BOX_IMAGE);
|
|
@@ -9388,7 +9387,7 @@ async function dockerChecks() {
|
|
|
9388
9387
|
}
|
|
9389
9388
|
async function daytonaChecks() {
|
|
9390
9389
|
try {
|
|
9391
|
-
const mod = await import("./dist-
|
|
9390
|
+
const mod = await import("./dist-OPIBZ7XM.js");
|
|
9392
9391
|
const status = await mod.getDaytonaStatus();
|
|
9393
9392
|
if (!status.configured) {
|
|
9394
9393
|
return [
|
|
@@ -9424,7 +9423,7 @@ async function daytonaChecks() {
|
|
|
9424
9423
|
}
|
|
9425
9424
|
async function hetznerChecks() {
|
|
9426
9425
|
try {
|
|
9427
|
-
const mod = await import("./dist-
|
|
9426
|
+
const mod = await import("./dist-7KVUIKJX.js");
|
|
9428
9427
|
const cred = mod.readHetznerCredStatus();
|
|
9429
9428
|
const credRes = cred.source === "none" ? {
|
|
9430
9429
|
label: "credentials",
|
|
@@ -9456,7 +9455,7 @@ async function hetznerChecks() {
|
|
|
9456
9455
|
}
|
|
9457
9456
|
async function vercelChecks() {
|
|
9458
9457
|
try {
|
|
9459
|
-
const mod = await import("./dist-
|
|
9458
|
+
const mod = await import("./dist-JAN5VABY.js");
|
|
9460
9459
|
const cred = mod.readVercelCredStatus();
|
|
9461
9460
|
const credRes = cred.auth === "none" ? {
|
|
9462
9461
|
label: "credentials",
|
|
@@ -9603,9 +9602,92 @@ function markSetupComplete(provider) {
|
|
|
9603
9602
|
writeFileSync3(path, JSON.stringify(body, null, 2) + "\n");
|
|
9604
9603
|
}
|
|
9605
9604
|
|
|
9606
|
-
// src/commands/
|
|
9607
|
-
import { intro as intro5, log as log29,
|
|
9605
|
+
// src/commands/install-cmux.ts
|
|
9606
|
+
import { intro as intro5, log as log29, note as note2, outro as outro5 } from "@clack/prompts";
|
|
9608
9607
|
import { Command as Command24 } from "commander";
|
|
9608
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
9609
|
+
import { homedir as homedir15 } from "os";
|
|
9610
|
+
import { dirname as dirname2, join as join17 } from "path";
|
|
9611
|
+
var CONTROL_ID = "agentbox";
|
|
9612
|
+
function cmuxDockPath(env = process.env) {
|
|
9613
|
+
const xdg = env["XDG_CONFIG_HOME"];
|
|
9614
|
+
const base = xdg && xdg.length > 0 ? xdg : join17(homedir15(), ".config");
|
|
9615
|
+
return join17(base, "cmux", "dock.json");
|
|
9616
|
+
}
|
|
9617
|
+
function upsertAgentboxControl(doc, opts) {
|
|
9618
|
+
const controls = Array.isArray(doc.controls) ? doc.controls : [];
|
|
9619
|
+
const next = {
|
|
9620
|
+
id: CONTROL_ID,
|
|
9621
|
+
title: opts.title,
|
|
9622
|
+
command: opts.command,
|
|
9623
|
+
height: opts.height
|
|
9624
|
+
};
|
|
9625
|
+
const idx = controls.findIndex((c) => c && c.id === CONTROL_ID);
|
|
9626
|
+
const merged = idx >= 0 ? controls.map((c, i) => i === idx ? { ...c, ...next } : c) : [...controls, next];
|
|
9627
|
+
return { ...doc, controls: merged };
|
|
9628
|
+
}
|
|
9629
|
+
function parseHeight(raw) {
|
|
9630
|
+
const n = Number(raw);
|
|
9631
|
+
if (!Number.isFinite(n) || n <= 0) return 320;
|
|
9632
|
+
return Math.round(n);
|
|
9633
|
+
}
|
|
9634
|
+
var installCmuxCommand = new Command24("cmux").description(
|
|
9635
|
+
"Add an AgentBox panel to the cmux sidebar dock (~/.config/cmux/dock.json) showing the live list of all your boxes."
|
|
9636
|
+
).option("--height <points>", "panel height in points", "320").option("--title <text>", "panel title shown in the dock header", "AgentBox").option("--dry-run", "print the resulting dock.json without writing it").option("--force", "reset a dock.json that fails to parse (backed up to dock.json.bak)").action((opts) => {
|
|
9637
|
+
const dockPath = cmuxDockPath();
|
|
9638
|
+
const command = `agentbox list --cmux --watch`;
|
|
9639
|
+
const controlOpts = {
|
|
9640
|
+
command,
|
|
9641
|
+
title: opts.title ?? "AgentBox",
|
|
9642
|
+
height: parseHeight(opts.height)
|
|
9643
|
+
};
|
|
9644
|
+
let doc = { controls: [] };
|
|
9645
|
+
if (existsSync7(dockPath)) {
|
|
9646
|
+
const raw = readFileSync(dockPath, "utf8");
|
|
9647
|
+
try {
|
|
9648
|
+
const parsed = JSON.parse(raw);
|
|
9649
|
+
if (parsed && typeof parsed === "object") doc = parsed;
|
|
9650
|
+
} catch {
|
|
9651
|
+
if (!opts.force) {
|
|
9652
|
+
log29.error(
|
|
9653
|
+
`existing dock config is not valid JSON: ${dockPath}
|
|
9654
|
+
fix it by hand, or pass --force to back it up and write a fresh one`
|
|
9655
|
+
);
|
|
9656
|
+
process.exit(1);
|
|
9657
|
+
}
|
|
9658
|
+
if (!opts.dryRun) {
|
|
9659
|
+
renameSync2(dockPath, dockPath + ".bak");
|
|
9660
|
+
log29.warn(`backed up unparseable dock config to ${dockPath}.bak`);
|
|
9661
|
+
}
|
|
9662
|
+
doc = { controls: [] };
|
|
9663
|
+
}
|
|
9664
|
+
}
|
|
9665
|
+
const updated = upsertAgentboxControl(doc, controlOpts);
|
|
9666
|
+
const json = JSON.stringify(updated, null, 2) + "\n";
|
|
9667
|
+
if (opts.dryRun) {
|
|
9668
|
+
intro5("agentbox install cmux (dry run)");
|
|
9669
|
+
process.stdout.write(json);
|
|
9670
|
+
outro5(`would write ${dockPath}`);
|
|
9671
|
+
return;
|
|
9672
|
+
}
|
|
9673
|
+
mkdirSync5(dirname2(dockPath), { recursive: true });
|
|
9674
|
+
writeFileSync4(dockPath, json);
|
|
9675
|
+
intro5("AgentBox cmux dock panel");
|
|
9676
|
+
note2(
|
|
9677
|
+
`Wrote ${dockPath}
|
|
9678
|
+
Panel command: ${command}
|
|
9679
|
+
|
|
9680
|
+
To see it:
|
|
9681
|
+
1. Enable Dock in cmux Settings -> Beta features -> Dock (it is off by default).
|
|
9682
|
+
2. Open the right sidebar and switch it to the Dock tab.`,
|
|
9683
|
+
"Installed"
|
|
9684
|
+
);
|
|
9685
|
+
outro5("done");
|
|
9686
|
+
});
|
|
9687
|
+
|
|
9688
|
+
// src/commands/prepare.ts
|
|
9689
|
+
import { intro as intro6, log as log30, spinner as spinner7 } from "@clack/prompts";
|
|
9690
|
+
import { Command as Command25 } from "commander";
|
|
9609
9691
|
async function dockerStatus() {
|
|
9610
9692
|
let img;
|
|
9611
9693
|
try {
|
|
@@ -9667,7 +9749,7 @@ async function renderDocker(status) {
|
|
|
9667
9749
|
}
|
|
9668
9750
|
async function daytonaStatus() {
|
|
9669
9751
|
try {
|
|
9670
|
-
const mod = await import("./dist-
|
|
9752
|
+
const mod = await import("./dist-OPIBZ7XM.js");
|
|
9671
9753
|
return await mod.getDaytonaStatus();
|
|
9672
9754
|
} catch (err) {
|
|
9673
9755
|
return {
|
|
@@ -9741,7 +9823,7 @@ async function runPrepare(providerName, opts = {}) {
|
|
|
9741
9823
|
}
|
|
9742
9824
|
const provider = await getProvider(providerName);
|
|
9743
9825
|
if (typeof provider.prepare !== "function") {
|
|
9744
|
-
|
|
9826
|
+
log30.error(`provider '${providerName}' does not implement prepare`);
|
|
9745
9827
|
process.exit(1);
|
|
9746
9828
|
}
|
|
9747
9829
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -9762,10 +9844,10 @@ async function runPrepare(providerName, opts = {}) {
|
|
|
9762
9844
|
const configKey = boxImageConfigKey(providerName);
|
|
9763
9845
|
try {
|
|
9764
9846
|
const written = await setConfigValue("project", configKey, result.snapshotName, cwd);
|
|
9765
|
-
|
|
9847
|
+
log30.success(`${configKey} = ${result.snapshotName} (written to ${written.path})`);
|
|
9766
9848
|
} catch (err) {
|
|
9767
9849
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9768
|
-
|
|
9850
|
+
log30.warn(
|
|
9769
9851
|
`prepared snapshot '${result.snapshotName}', but failed to pin it into the project config: ${msg}
|
|
9770
9852
|
Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manually.`
|
|
9771
9853
|
);
|
|
@@ -9779,21 +9861,21 @@ Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manual
|
|
|
9779
9861
|
if (typeof projectImage === "string" && projectImage.length > 0 && projectImage !== DEFAULT_BOX_IMAGE) {
|
|
9780
9862
|
const cleared = await unsetConfigValue("project", "box.image", cwd);
|
|
9781
9863
|
if (cleared.existed) {
|
|
9782
|
-
|
|
9864
|
+
log30.warn(
|
|
9783
9865
|
`migrated stale \`box.image\` from a previous prepare (was \`${projectImage}\`); re-set manually if you actually meant it: \`agentbox config set --project box.image <ref>\``
|
|
9784
9866
|
);
|
|
9785
9867
|
}
|
|
9786
9868
|
}
|
|
9787
9869
|
} catch (err) {
|
|
9788
9870
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9789
|
-
|
|
9871
|
+
log30.warn(`could not migrate stale box.image (continuing): ${msg}`);
|
|
9790
9872
|
}
|
|
9791
9873
|
if (!opts.suppressStatus) {
|
|
9792
9874
|
process.stdout.write("\n");
|
|
9793
9875
|
await showStatus({ onlyProvider: providerName });
|
|
9794
9876
|
}
|
|
9795
9877
|
if (!opts.suppressTip) {
|
|
9796
|
-
|
|
9878
|
+
log30.info(
|
|
9797
9879
|
"tip: install the agentbox host skill so Claude Code on this machine can drive AgentBox for you:\n npx skills add https://github.com/madarco/agentbox --skill agentbox"
|
|
9798
9880
|
);
|
|
9799
9881
|
}
|
|
@@ -9802,7 +9884,7 @@ Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manual
|
|
|
9802
9884
|
throw err;
|
|
9803
9885
|
}
|
|
9804
9886
|
}
|
|
9805
|
-
var prepareCommand = new
|
|
9887
|
+
var prepareCommand = new Command25("prepare").description(
|
|
9806
9888
|
"Build base sandbox images / snapshots, or show what is already prepared across providers."
|
|
9807
9889
|
).option(
|
|
9808
9890
|
"-p, --provider <name>",
|
|
@@ -9816,7 +9898,7 @@ var prepareCommand = new Command24("prepare").description(
|
|
|
9816
9898
|
return;
|
|
9817
9899
|
}
|
|
9818
9900
|
const providerName = opts.provider.trim();
|
|
9819
|
-
|
|
9901
|
+
intro6(`preparing ${providerName} base image`);
|
|
9820
9902
|
await runPrepare(providerName, {
|
|
9821
9903
|
name: opts.name,
|
|
9822
9904
|
force: opts.force,
|
|
@@ -9925,34 +10007,34 @@ ${LOGO_L2}\x1B[0m` + SYNC_END2);
|
|
|
9925
10007
|
}
|
|
9926
10008
|
var LEGACY_INFO_MARKER = "Drive AgentBox from the host:";
|
|
9927
10009
|
function installTargets() {
|
|
9928
|
-
const home =
|
|
9929
|
-
const claudeSkills =
|
|
10010
|
+
const home = homedir16();
|
|
10011
|
+
const claudeSkills = join18(home, ".claude", "skills");
|
|
9930
10012
|
return [
|
|
9931
|
-
{ src:
|
|
10013
|
+
{ src: join18("agentbox", "SKILL.md"), dest: join18(claudeSkills, "agentbox", "SKILL.md") },
|
|
9932
10014
|
{
|
|
9933
|
-
src:
|
|
9934
|
-
dest:
|
|
10015
|
+
src: join18("agentbox-info", "SKILL.md"),
|
|
10016
|
+
dest: join18(claudeSkills, "agentbox-info", "SKILL.md")
|
|
9935
10017
|
},
|
|
9936
10018
|
{
|
|
9937
|
-
src:
|
|
9938
|
-
dest:
|
|
9939
|
-
gateDir:
|
|
10019
|
+
src: join18("codex", "agentbox.md"),
|
|
10020
|
+
dest: join18(home, ".codex", "prompts", "agentbox.md"),
|
|
10021
|
+
gateDir: join18(home, ".codex")
|
|
9940
10022
|
},
|
|
9941
10023
|
{
|
|
9942
|
-
src:
|
|
9943
|
-
dest:
|
|
9944
|
-
gateDir:
|
|
10024
|
+
src: join18("opencode", "agentbox.md"),
|
|
10025
|
+
dest: join18(home, ".config", "opencode", "commands", "agentbox.md"),
|
|
10026
|
+
gateDir: join18(home, ".config", "opencode")
|
|
9945
10027
|
}
|
|
9946
10028
|
];
|
|
9947
10029
|
}
|
|
9948
10030
|
function resolveHostSkillsDir() {
|
|
9949
|
-
const here =
|
|
10031
|
+
const here = dirname3(fileURLToPath(import.meta.url));
|
|
9950
10032
|
const candidates = [
|
|
9951
10033
|
resolve3(here, "..", "share", "host-skills"),
|
|
9952
10034
|
resolve3(here, "..", "..", "share", "host-skills")
|
|
9953
10035
|
];
|
|
9954
10036
|
for (const c of candidates) {
|
|
9955
|
-
if (
|
|
10037
|
+
if (existsSync8(c)) return c;
|
|
9956
10038
|
}
|
|
9957
10039
|
throw new Error(`could not locate bundled host skills; tried:
|
|
9958
10040
|
${candidates.join("\n ")}`);
|
|
@@ -9968,11 +10050,11 @@ function isSourceCheckout(srcDir) {
|
|
|
9968
10050
|
return !srcDir.split(sep).includes("node_modules");
|
|
9969
10051
|
}
|
|
9970
10052
|
function writableReason(target, force) {
|
|
9971
|
-
if (!
|
|
10053
|
+
if (!existsSync8(target)) {
|
|
9972
10054
|
if (isSymlink(target)) return "managed";
|
|
9973
10055
|
return "new";
|
|
9974
10056
|
}
|
|
9975
|
-
const existing =
|
|
10057
|
+
const existing = readFileSync2(target, "utf8");
|
|
9976
10058
|
if (existing.includes(MANAGED_SENTINEL) || existing.includes(LEGACY_INFO_MARKER)) {
|
|
9977
10059
|
return "managed";
|
|
9978
10060
|
}
|
|
@@ -9988,32 +10070,32 @@ function installHostSkills(opts = {}) {
|
|
|
9988
10070
|
const blocked = [];
|
|
9989
10071
|
let skipped = 0;
|
|
9990
10072
|
for (const t of installTargets()) {
|
|
9991
|
-
const src =
|
|
9992
|
-
if (!
|
|
9993
|
-
if (!quiet)
|
|
10073
|
+
const src = join18(srcDir, t.src);
|
|
10074
|
+
if (!existsSync8(src)) {
|
|
10075
|
+
if (!quiet) log31.warn(`bundled file missing (skipped): ${src}`);
|
|
9994
10076
|
skipped++;
|
|
9995
10077
|
continue;
|
|
9996
10078
|
}
|
|
9997
|
-
if (t.gateDir && !
|
|
10079
|
+
if (t.gateDir && !existsSync8(t.gateDir)) continue;
|
|
9998
10080
|
const reason = writableReason(t.dest, force);
|
|
9999
10081
|
if (reason === "skip") {
|
|
10000
|
-
if (!quiet)
|
|
10082
|
+
if (!quiet) log31.warn(`user-modified file at ${t.dest}, skipping; pass --force to overwrite`);
|
|
10001
10083
|
blocked.push(t.dest);
|
|
10002
10084
|
skipped++;
|
|
10003
10085
|
continue;
|
|
10004
10086
|
}
|
|
10005
10087
|
if (dryRun) {
|
|
10006
|
-
if (!quiet)
|
|
10088
|
+
if (!quiet) log31.info(`would ${link ? "link" : "write"} ${t.dest} (${reason})`);
|
|
10007
10089
|
written.push(t.dest);
|
|
10008
10090
|
continue;
|
|
10009
10091
|
}
|
|
10010
|
-
|
|
10092
|
+
mkdirSync6(dirname3(t.dest), { recursive: true });
|
|
10011
10093
|
if (link) {
|
|
10012
10094
|
rmSync(t.dest, { force: true });
|
|
10013
10095
|
symlinkSync2(resolve3(srcDir, t.src), t.dest);
|
|
10014
10096
|
} else {
|
|
10015
10097
|
if (isSymlink(t.dest)) rmSync(t.dest, { force: true });
|
|
10016
|
-
|
|
10098
|
+
writeFileSync5(t.dest, readFileSync2(src, "utf8"));
|
|
10017
10099
|
}
|
|
10018
10100
|
written.push(t.dest);
|
|
10019
10101
|
}
|
|
@@ -10041,10 +10123,10 @@ function ensureTty() {
|
|
|
10041
10123
|
async function runProviderLogin(name) {
|
|
10042
10124
|
if (name === "docker") return true;
|
|
10043
10125
|
if (name === "daytona") {
|
|
10044
|
-
const mod2 = await import("./dist-
|
|
10126
|
+
const mod2 = await import("./dist-OPIBZ7XM.js");
|
|
10045
10127
|
const status2 = await mod2.getDaytonaStatus();
|
|
10046
10128
|
if (status2.configured) {
|
|
10047
|
-
|
|
10129
|
+
log31.info("daytona: already configured");
|
|
10048
10130
|
const rotate = await confirm14({ message: "Re-authenticate Daytona?", initialValue: false });
|
|
10049
10131
|
if (isCancel15(rotate)) return false;
|
|
10050
10132
|
if (rotate) await mod2.ensureDaytonaCredentials({ force: true });
|
|
@@ -10054,10 +10136,10 @@ async function runProviderLogin(name) {
|
|
|
10054
10136
|
return true;
|
|
10055
10137
|
}
|
|
10056
10138
|
if (name === "hetzner") {
|
|
10057
|
-
const mod2 = await import("./dist-
|
|
10139
|
+
const mod2 = await import("./dist-7KVUIKJX.js");
|
|
10058
10140
|
const status2 = mod2.readHetznerCredStatus();
|
|
10059
10141
|
if (status2.source !== "none") {
|
|
10060
|
-
|
|
10142
|
+
log31.info("hetzner: already configured");
|
|
10061
10143
|
const rotate = await confirm14({ message: "Re-authenticate Hetzner?", initialValue: false });
|
|
10062
10144
|
if (isCancel15(rotate)) return false;
|
|
10063
10145
|
if (rotate) await mod2.ensureHetznerCredentials({ force: true });
|
|
@@ -10066,10 +10148,10 @@ async function runProviderLogin(name) {
|
|
|
10066
10148
|
await mod2.ensureHetznerCredentials();
|
|
10067
10149
|
return true;
|
|
10068
10150
|
}
|
|
10069
|
-
const mod = await import("./dist-
|
|
10151
|
+
const mod = await import("./dist-JAN5VABY.js");
|
|
10070
10152
|
const status = mod.readVercelCredStatus();
|
|
10071
10153
|
if (status.auth !== "none") {
|
|
10072
|
-
|
|
10154
|
+
log31.info(`vercel: already configured (${status.auth})`);
|
|
10073
10155
|
const rotate = await confirm14({ message: "Re-authenticate Vercel?", initialValue: false });
|
|
10074
10156
|
if (isCancel15(rotate)) return false;
|
|
10075
10157
|
if (rotate) await mod.ensureVercelCredentials({ force: true });
|
|
@@ -10094,17 +10176,17 @@ function isProviderName(s) {
|
|
|
10094
10176
|
async function runInstallWizard(opts = {}) {
|
|
10095
10177
|
if (!ensureTty()) return false;
|
|
10096
10178
|
await animateBanner();
|
|
10097
|
-
|
|
10179
|
+
intro7("Check system compatibility");
|
|
10098
10180
|
const sysResults = await runSystemChecks();
|
|
10099
10181
|
const sysGroup = { title: "system", results: sysResults };
|
|
10100
10182
|
process.stdout.write(" " + formatCompact([sysGroup]) + "\n");
|
|
10101
10183
|
const hardFail = sysResults.find((r) => r.status === "fail");
|
|
10102
10184
|
if (hardFail) {
|
|
10103
|
-
|
|
10104
|
-
|
|
10185
|
+
log31.error(`system check failed: ${hardFail.label} \u2014 ${hardFail.detail}`);
|
|
10186
|
+
log31.info("run `agentbox doctor` for full detail");
|
|
10105
10187
|
const cont = await confirm14({ message: "Continue anyway?", initialValue: false });
|
|
10106
10188
|
if (isCancel15(cont) || !cont) {
|
|
10107
|
-
|
|
10189
|
+
outro6("aborted");
|
|
10108
10190
|
return false;
|
|
10109
10191
|
}
|
|
10110
10192
|
}
|
|
@@ -10112,7 +10194,7 @@ async function runInstallWizard(opts = {}) {
|
|
|
10112
10194
|
if (opts.provider) {
|
|
10113
10195
|
const candidate = opts.provider.trim();
|
|
10114
10196
|
if (!isProviderName(candidate)) {
|
|
10115
|
-
|
|
10197
|
+
log31.error(`unknown --provider: ${candidate}`);
|
|
10116
10198
|
return false;
|
|
10117
10199
|
}
|
|
10118
10200
|
providerName = candidate;
|
|
@@ -10127,7 +10209,7 @@ async function runInstallWizard(opts = {}) {
|
|
|
10127
10209
|
}))
|
|
10128
10210
|
});
|
|
10129
10211
|
if (isCancel15(picked)) {
|
|
10130
|
-
|
|
10212
|
+
outro6("cancelled");
|
|
10131
10213
|
return false;
|
|
10132
10214
|
}
|
|
10133
10215
|
providerName = picked;
|
|
@@ -10135,14 +10217,14 @@ async function runInstallWizard(opts = {}) {
|
|
|
10135
10217
|
if (providerName !== "docker") {
|
|
10136
10218
|
const loggedIn = await runProviderLogin(providerName);
|
|
10137
10219
|
if (!loggedIn) {
|
|
10138
|
-
|
|
10220
|
+
outro6("cancelled");
|
|
10139
10221
|
return false;
|
|
10140
10222
|
}
|
|
10141
10223
|
}
|
|
10142
10224
|
const prepareMsg = providerName === "docker" ? "Build the box image now? (~1GB, a few minutes)" : `Bake the ${providerName} base snapshot now? (a few minutes, uses cloud time)`;
|
|
10143
10225
|
const wantPrepare = opts.yes ? true : await confirm14({ message: prepareMsg, initialValue: true });
|
|
10144
10226
|
if (isCancel15(wantPrepare)) {
|
|
10145
|
-
|
|
10227
|
+
outro6("cancelled");
|
|
10146
10228
|
return false;
|
|
10147
10229
|
}
|
|
10148
10230
|
if (wantPrepare) {
|
|
@@ -10154,12 +10236,12 @@ async function runInstallWizard(opts = {}) {
|
|
|
10154
10236
|
suppressTip: true
|
|
10155
10237
|
});
|
|
10156
10238
|
} catch (err) {
|
|
10157
|
-
|
|
10239
|
+
log31.warn(
|
|
10158
10240
|
`prepare failed: ${err instanceof Error ? err.message : String(err)} \u2014 you can rerun \`agentbox prepare --provider ${providerName}\` later`
|
|
10159
10241
|
);
|
|
10160
10242
|
}
|
|
10161
10243
|
} else {
|
|
10162
|
-
|
|
10244
|
+
log31.info(
|
|
10163
10245
|
`skipped \u2014 the ${providerName} base will build lazily on first \`agentbox ${providerName === "docker" ? "" : providerName + " "}create\``
|
|
10164
10246
|
);
|
|
10165
10247
|
}
|
|
@@ -10174,25 +10256,25 @@ async function runInstallWizard(opts = {}) {
|
|
|
10174
10256
|
sp.stop(`Agentbox Skills: nothing to write (${String(skillRes.skipped)} skipped)`);
|
|
10175
10257
|
}
|
|
10176
10258
|
if (skillRes.blocked.length > 0) {
|
|
10177
|
-
|
|
10259
|
+
log31.warn(
|
|
10178
10260
|
`user-modified host skill file(s) left in place: ${skillRes.blocked.join(", ")}
|
|
10179
10261
|
pass \`agentbox install --skills-only --force\` to overwrite`
|
|
10180
10262
|
);
|
|
10181
10263
|
}
|
|
10182
10264
|
} catch (err) {
|
|
10183
10265
|
sp.stop("Agentbox Skills: failed");
|
|
10184
|
-
|
|
10266
|
+
log31.warn(err instanceof Error ? err.message : String(err));
|
|
10185
10267
|
}
|
|
10186
10268
|
markSetupComplete(providerName);
|
|
10187
10269
|
const providerGroup = await runProviderChecks(providerName);
|
|
10188
10270
|
process.stdout.write(" " + formatCompact([sysGroup, providerGroup]) + "\n");
|
|
10189
|
-
|
|
10190
|
-
|
|
10271
|
+
note3(tutorialBody(providerName), "Next steps");
|
|
10272
|
+
outro6(
|
|
10191
10273
|
opts.fromAutoTrigger ? "\u2728 Setup complete \u2014 continuing with your command\u2026" : "\u2728 Setup complete"
|
|
10192
10274
|
);
|
|
10193
10275
|
return true;
|
|
10194
10276
|
}
|
|
10195
|
-
var installCommand = new
|
|
10277
|
+
var installCommand = new Command26("install").description(
|
|
10196
10278
|
"Interactive setup wizard: system check, pick a provider, log in, prepare its base image/snapshot, and install the host /agentbox skill. `--skills-only` runs just the skill install."
|
|
10197
10279
|
).option(
|
|
10198
10280
|
"--skills-only",
|
|
@@ -10202,25 +10284,25 @@ var installCommand = new Command25("install").description(
|
|
|
10202
10284
|
"pre-select the provider to set up (docker | daytona | hetzner | vercel)"
|
|
10203
10285
|
).option("-y, --yes", "auto-confirm the prepare step").action(async (opts) => {
|
|
10204
10286
|
if (opts.skillsOnly) {
|
|
10205
|
-
|
|
10287
|
+
intro7("Installing AgentBox host commands...");
|
|
10206
10288
|
let res;
|
|
10207
10289
|
try {
|
|
10208
10290
|
res = installHostSkills({ force: opts.force, dryRun: opts.dryRun });
|
|
10209
10291
|
} catch (err) {
|
|
10210
|
-
|
|
10292
|
+
log31.error(err instanceof Error ? err.message : String(err));
|
|
10211
10293
|
process.exit(1);
|
|
10212
10294
|
}
|
|
10213
10295
|
if (opts.dryRun) {
|
|
10214
|
-
|
|
10296
|
+
outro6(
|
|
10215
10297
|
`dry-run: ${String(res.written.length)} file(s) would be written, ${String(res.skipped)} skipped`
|
|
10216
10298
|
);
|
|
10217
10299
|
return;
|
|
10218
10300
|
}
|
|
10219
10301
|
if (res.written.length === 0) {
|
|
10220
|
-
|
|
10302
|
+
outro6(`nothing installed (${String(res.skipped)} skipped)`);
|
|
10221
10303
|
return;
|
|
10222
10304
|
}
|
|
10223
|
-
|
|
10305
|
+
outro6(`installed: ${res.written.join(", ")}`);
|
|
10224
10306
|
return;
|
|
10225
10307
|
}
|
|
10226
10308
|
const ok = await runInstallWizard({
|
|
@@ -10231,10 +10313,12 @@ var installCommand = new Command25("install").description(
|
|
|
10231
10313
|
});
|
|
10232
10314
|
if (!ok) process.exit(1);
|
|
10233
10315
|
});
|
|
10316
|
+
installCommand.enablePositionalOptions();
|
|
10317
|
+
installCommand.addCommand(installCmuxCommand);
|
|
10234
10318
|
|
|
10235
10319
|
// src/commands/doctor.ts
|
|
10236
|
-
import { Command as
|
|
10237
|
-
var doctorCommand = new
|
|
10320
|
+
import { Command as Command27 } from "commander";
|
|
10321
|
+
var doctorCommand = new Command27("doctor").description(
|
|
10238
10322
|
"Diagnose system compatibility and provider readiness (Node, git, ssh, Docker daemon, provider credentials, prepared snapshots)."
|
|
10239
10323
|
).option(
|
|
10240
10324
|
"-p, --provider <name>",
|
|
@@ -10274,7 +10358,7 @@ var doctorCommand = new Command26("doctor").description(
|
|
|
10274
10358
|
});
|
|
10275
10359
|
|
|
10276
10360
|
// src/commands/git.ts
|
|
10277
|
-
import { Command as
|
|
10361
|
+
import { Command as Command28 } from "commander";
|
|
10278
10362
|
var WORKSPACE = "/workspace";
|
|
10279
10363
|
var TOKEN_TTL_MS = 12e4;
|
|
10280
10364
|
async function runInBox(box, argv2) {
|
|
@@ -10306,7 +10390,7 @@ function buildPredictedGhPrParams(ghArgs) {
|
|
|
10306
10390
|
async function exitWith(code) {
|
|
10307
10391
|
process.exit(code);
|
|
10308
10392
|
}
|
|
10309
|
-
var pushCommand = new
|
|
10393
|
+
var pushCommand = new Command28("push").description("Push the box's branch via the host relay (host creds, no prompt)").argument("<box>", "box ref: project index, id, id prefix, name, or container").argument("[args...]", "extra flags forwarded to `agentbox-ctl git push` (e.g. --force-with-lease, --tags)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
|
|
10310
10394
|
try {
|
|
10311
10395
|
const box = await resolveBoxOrExit(boxRef);
|
|
10312
10396
|
const predicted = buildPredictedGitParams(opts.remote, args);
|
|
@@ -10319,7 +10403,7 @@ var pushCommand = new Command27("push").description("Push the box's branch via t
|
|
|
10319
10403
|
handleLifecycleError(err);
|
|
10320
10404
|
}
|
|
10321
10405
|
});
|
|
10322
|
-
var fetchCommand = new
|
|
10406
|
+
var fetchCommand = new Command28("fetch").description("Fetch via the host relay (refs land in the shared .git)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `agentbox-ctl git fetch` (e.g. --prune)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
|
|
10323
10407
|
try {
|
|
10324
10408
|
const box = await resolveBoxOrExit(boxRef);
|
|
10325
10409
|
const predicted = buildPredictedGitParams(opts.remote, args);
|
|
@@ -10332,7 +10416,7 @@ var fetchCommand = new Command27("fetch").description("Fetch via the host relay
|
|
|
10332
10416
|
handleLifecycleError(err);
|
|
10333
10417
|
}
|
|
10334
10418
|
});
|
|
10335
|
-
var pullCommand = new
|
|
10419
|
+
var pullCommand = new Command28("pull").description(
|
|
10336
10420
|
"Fetch via the relay then merge in /workspace. With <branch>: first `git checkout <branch>` so the box switches base branch and pulls latest \u2014 useful for reusing a box on a new task."
|
|
10337
10421
|
).argument("<box>", "box ref").argument("[branch]", "optional branch to switch to before pulling (e.g. main)").argument("[args...]", "extra flags forwarded to `agentbox-ctl git pull`").option("--remote <name>", "remote name (default: origin)").option("--ff-only", "pass --ff-only to the in-box merge").allowExcessArguments(true).allowUnknownOption(true).action(
|
|
10338
10422
|
async (boxRef, branch, args, opts) => {
|
|
@@ -10354,7 +10438,7 @@ var pullCommand = new Command27("pull").description(
|
|
|
10354
10438
|
}
|
|
10355
10439
|
}
|
|
10356
10440
|
);
|
|
10357
|
-
var checkoutCommand = new
|
|
10441
|
+
var checkoutCommand = new Command28("checkout").description("Change the box's working branch (runs `git checkout <branch>` in /workspace)").argument("<box>", "box ref").argument("<branch>", "branch to check out inside the box").argument("[args...]", "extra flags forwarded to `git checkout`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, branch, args) => {
|
|
10358
10442
|
try {
|
|
10359
10443
|
const box = await resolveBoxOrExit(boxRef);
|
|
10360
10444
|
await exitWith(await runAndStream(box, ["git", "checkout", branch, ...args]));
|
|
@@ -10362,7 +10446,7 @@ var checkoutCommand = new Command27("checkout").description("Change the box's wo
|
|
|
10362
10446
|
handleLifecycleError(err);
|
|
10363
10447
|
}
|
|
10364
10448
|
});
|
|
10365
|
-
var statusCommand = new
|
|
10449
|
+
var statusCommand = new Command28("status").description("Run `git status` in the box's /workspace (read-only, no relay)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `git status`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args) => {
|
|
10366
10450
|
try {
|
|
10367
10451
|
const box = await resolveBoxOrExit(boxRef);
|
|
10368
10452
|
await exitWith(await runAndStream(box, ["git", "status", ...args]));
|
|
@@ -10388,7 +10472,7 @@ function injectPrCreateHead2(op, box, args) {
|
|
|
10388
10472
|
return injectPrCreateHead(op, rootWt?.branch, args);
|
|
10389
10473
|
}
|
|
10390
10474
|
function buildPrSubcommand(op) {
|
|
10391
|
-
return new
|
|
10475
|
+
return new Command28(op).description(PR_OP_DESCRIPTIONS[op]).argument("<box>", "box ref").argument(
|
|
10392
10476
|
"[args...]",
|
|
10393
10477
|
"extra flags forwarded to `gh pr <op>` (e.g. --title, --body, --label, --draft, --json)"
|
|
10394
10478
|
).allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args) => {
|
|
@@ -10404,18 +10488,18 @@ function buildPrSubcommand(op) {
|
|
|
10404
10488
|
}
|
|
10405
10489
|
});
|
|
10406
10490
|
}
|
|
10407
|
-
var prCommand = new
|
|
10491
|
+
var prCommand = new Command28("pr").description(
|
|
10408
10492
|
"PR operations against a box's branch via the host `gh` CLI"
|
|
10409
10493
|
);
|
|
10410
10494
|
for (const op of GH_PR_OPS) {
|
|
10411
10495
|
const sub = buildPrSubcommand(op);
|
|
10412
10496
|
prCommand.addCommand(sub, op === "create" ? { isDefault: true } : void 0);
|
|
10413
10497
|
}
|
|
10414
|
-
var gitCommand = new
|
|
10498
|
+
var gitCommand = new Command28("git").description("Run git / gh pr operations against a box from the host").addCommand(pushCommand).addCommand(fetchCommand).addCommand(pullCommand).addCommand(checkoutCommand).addCommand(statusCommand).addCommand(prCommand);
|
|
10415
10499
|
|
|
10416
10500
|
// src/commands/list.ts
|
|
10417
|
-
import { log as
|
|
10418
|
-
import { Command as
|
|
10501
|
+
import { log as log32 } from "@clack/prompts";
|
|
10502
|
+
import { Command as Command29 } from "commander";
|
|
10419
10503
|
import { pathToFileURL } from "url";
|
|
10420
10504
|
|
|
10421
10505
|
// src/hyperlink.ts
|
|
@@ -10469,13 +10553,56 @@ function parseIntervalMs(raw) {
|
|
|
10469
10553
|
if (!Number.isFinite(n) || n <= 0) return 2e3;
|
|
10470
10554
|
return Math.max(250, Math.round(n * 1e3));
|
|
10471
10555
|
}
|
|
10472
|
-
async function watchRender(produce, rawInterval) {
|
|
10556
|
+
async function watchRender(produce, rawInterval, opts = {}) {
|
|
10473
10557
|
const ms = parseIntervalMs(rawInterval);
|
|
10474
10558
|
const intervalLabel = `${String(ms / 1e3)}s`;
|
|
10475
10559
|
process.stdout.write("\x1B[?25l");
|
|
10476
|
-
|
|
10477
|
-
|
|
10478
|
-
const
|
|
10560
|
+
const stdin = process.stdin;
|
|
10561
|
+
const interactive = typeof opts.onKey === "function" && stdin.isTTY === true;
|
|
10562
|
+
const restore = () => {
|
|
10563
|
+
if (interactive && stdin.isTTY) stdin.setRawMode(false);
|
|
10564
|
+
process.stdout.write("\x1B[?25h");
|
|
10565
|
+
};
|
|
10566
|
+
process.once("exit", restore);
|
|
10567
|
+
let wake = null;
|
|
10568
|
+
let exiting = false;
|
|
10569
|
+
const exit = () => {
|
|
10570
|
+
exiting = true;
|
|
10571
|
+
wake?.();
|
|
10572
|
+
};
|
|
10573
|
+
if (interactive) {
|
|
10574
|
+
stdin.setRawMode(true);
|
|
10575
|
+
stdin.resume();
|
|
10576
|
+
stdin.setEncoding("utf8");
|
|
10577
|
+
stdin.on("data", (chunk) => {
|
|
10578
|
+
for (const key of chunk) {
|
|
10579
|
+
if (key === "" || key === "q") {
|
|
10580
|
+
exit();
|
|
10581
|
+
return;
|
|
10582
|
+
}
|
|
10583
|
+
const action = opts.onKey?.(key) ?? "ignore";
|
|
10584
|
+
if (action === "exit") {
|
|
10585
|
+
exit();
|
|
10586
|
+
return;
|
|
10587
|
+
}
|
|
10588
|
+
if (action === "redraw") wake?.();
|
|
10589
|
+
}
|
|
10590
|
+
});
|
|
10591
|
+
} else {
|
|
10592
|
+
process.once("SIGINT", () => process.exit(0));
|
|
10593
|
+
}
|
|
10594
|
+
const hint = interactive ? "q or Ctrl-C to exit" : "Ctrl-C to exit";
|
|
10595
|
+
const sleep5 = (d) => new Promise((r) => {
|
|
10596
|
+
const t = setTimeout(() => {
|
|
10597
|
+
wake = null;
|
|
10598
|
+
r();
|
|
10599
|
+
}, d);
|
|
10600
|
+
wake = () => {
|
|
10601
|
+
clearTimeout(t);
|
|
10602
|
+
wake = null;
|
|
10603
|
+
r();
|
|
10604
|
+
};
|
|
10605
|
+
});
|
|
10479
10606
|
for (; ; ) {
|
|
10480
10607
|
let body;
|
|
10481
10608
|
try {
|
|
@@ -10484,14 +10611,23 @@ async function watchRender(produce, rawInterval) {
|
|
|
10484
10611
|
body = `error: ${err instanceof Error ? err.message : String(err)}`;
|
|
10485
10612
|
}
|
|
10486
10613
|
const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10614
|
+
const trimmed = body.replace(/\n+$/, "");
|
|
10615
|
+
if (opts.hideStatusLine) {
|
|
10616
|
+
process.stdout.write(
|
|
10617
|
+
"\x1B[H" + trimmed.split("\n").map((l) => l + "\x1B[K").join("\n") + "\x1B[J"
|
|
10618
|
+
);
|
|
10619
|
+
} else {
|
|
10620
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
10621
|
+
process.stdout.write(`watching every ${intervalLabel} \u2014 ${ts} \u2014 ${hint}
|
|
10490
10622
|
|
|
10491
|
-
${
|
|
10492
|
-
`
|
|
10493
|
-
|
|
10623
|
+
${trimmed}
|
|
10624
|
+
`);
|
|
10625
|
+
}
|
|
10494
10626
|
await sleep5(ms);
|
|
10627
|
+
if (exiting) {
|
|
10628
|
+
restore();
|
|
10629
|
+
process.exit(0);
|
|
10630
|
+
}
|
|
10495
10631
|
}
|
|
10496
10632
|
}
|
|
10497
10633
|
|
|
@@ -10556,6 +10692,102 @@ function agentSummary(b) {
|
|
|
10556
10692
|
if (b.opencodeSession?.running) agents.push("opencode");
|
|
10557
10693
|
return agents.length > 0 ? agents.join(", ") : "-";
|
|
10558
10694
|
}
|
|
10695
|
+
var CMUX_COLOR = {
|
|
10696
|
+
blue: "38;5;39",
|
|
10697
|
+
amber: "38;5;214",
|
|
10698
|
+
red: "38;5;196",
|
|
10699
|
+
dim: "38;5;245"
|
|
10700
|
+
};
|
|
10701
|
+
function colorize(s, bucket) {
|
|
10702
|
+
return `\x1B[${CMUX_COLOR[bucket]}m${s}\x1B[0m`;
|
|
10703
|
+
}
|
|
10704
|
+
function tailKeep(s, max) {
|
|
10705
|
+
if (max <= 0) return "";
|
|
10706
|
+
if (s.length <= max) return s;
|
|
10707
|
+
if (max === 1) return "\u2026";
|
|
10708
|
+
return "\u2026" + s.slice(s.length - (max - 1));
|
|
10709
|
+
}
|
|
10710
|
+
function primaryAgent(b) {
|
|
10711
|
+
const real = (s) => !!s && s !== "unknown";
|
|
10712
|
+
if (real(b.claudeActivity) || b.claudeSessionTitle) {
|
|
10713
|
+
return { agent: "claude", activity: b.claudeActivity };
|
|
10714
|
+
}
|
|
10715
|
+
if (b.codexSession?.running || real(b.codexActivity)) {
|
|
10716
|
+
return { agent: "codex", activity: b.codexActivity };
|
|
10717
|
+
}
|
|
10718
|
+
if (b.opencodeSession?.running) return { agent: "opencode" };
|
|
10719
|
+
return { agent: "claude", activity: b.claudeActivity };
|
|
10720
|
+
}
|
|
10721
|
+
function activityView(a) {
|
|
10722
|
+
switch (a) {
|
|
10723
|
+
case "working":
|
|
10724
|
+
return { glyph: "\u25CF", label: "working", bucket: "blue" };
|
|
10725
|
+
case "compacting":
|
|
10726
|
+
return { glyph: "\u25CF", label: "compacting", bucket: "blue" };
|
|
10727
|
+
case "idle":
|
|
10728
|
+
return { glyph: "\u25CB", label: "idle", bucket: "dim" };
|
|
10729
|
+
case "waiting":
|
|
10730
|
+
case "question":
|
|
10731
|
+
return { glyph: "\u25D0", label: "needs input", bucket: "amber" };
|
|
10732
|
+
case "end-plan":
|
|
10733
|
+
return { glyph: "\u25D0", label: "plan ready", bucket: "amber" };
|
|
10734
|
+
case "error":
|
|
10735
|
+
return { glyph: "\u2716", label: "error", bucket: "red" };
|
|
10736
|
+
default:
|
|
10737
|
+
return { glyph: "\u25CB", label: "", bucket: "dim" };
|
|
10738
|
+
}
|
|
10739
|
+
}
|
|
10740
|
+
function cmuxStatusCell(b, color) {
|
|
10741
|
+
if (b.state !== "running") {
|
|
10742
|
+
const s = `[${b.state}]`;
|
|
10743
|
+
return color ? colorize(s, "dim") : s;
|
|
10744
|
+
}
|
|
10745
|
+
const { agent, activity } = primaryAgent(b);
|
|
10746
|
+
const v = activityView(activity);
|
|
10747
|
+
const text = `${v.glyph} ${agent ?? "agent"}${v.label ? " " + v.label : ""}`;
|
|
10748
|
+
return color ? colorize(text, v.bucket) : text;
|
|
10749
|
+
}
|
|
10750
|
+
function projectLabel(root) {
|
|
10751
|
+
if (!root) return "other";
|
|
10752
|
+
return root.split("/").filter(Boolean).pop() ?? root;
|
|
10753
|
+
}
|
|
10754
|
+
function projectHeader(label, color, width) {
|
|
10755
|
+
const max = Math.max(1, width - 6);
|
|
10756
|
+
const name = label.length > max ? label.slice(0, Math.max(1, max - 1)) + "\u2026" : label;
|
|
10757
|
+
const h = `\u2500\u2500 ${name} \u2500\u2500`;
|
|
10758
|
+
return color ? colorize(h, "dim") : h;
|
|
10759
|
+
}
|
|
10760
|
+
function renderCmuxRows(boxes, color, width) {
|
|
10761
|
+
const groups = /* @__PURE__ */ new Map();
|
|
10762
|
+
for (const b of boxes) {
|
|
10763
|
+
const key = b.projectRoot ?? "";
|
|
10764
|
+
const arr = groups.get(key);
|
|
10765
|
+
if (arr) arr.push(b);
|
|
10766
|
+
else groups.set(key, [b]);
|
|
10767
|
+
}
|
|
10768
|
+
const lines = [];
|
|
10769
|
+
let first = true;
|
|
10770
|
+
for (const [root, group] of groups) {
|
|
10771
|
+
if (!first) lines.push("");
|
|
10772
|
+
first = false;
|
|
10773
|
+
lines.push(projectHeader(projectLabel(root), color, width));
|
|
10774
|
+
for (const b of group) {
|
|
10775
|
+
const idx = b.projectIndex ? `${String(b.projectIndex)} ` : "";
|
|
10776
|
+
lines.push(`${idx}${tailKeep(b.name, Math.max(1, width - idx.length))}`);
|
|
10777
|
+
lines.push(" " + cmuxStatusCell(b, color));
|
|
10778
|
+
}
|
|
10779
|
+
}
|
|
10780
|
+
return lines.join("\n");
|
|
10781
|
+
}
|
|
10782
|
+
function cmuxEmptyMessage() {
|
|
10783
|
+
return "no boxes \xB7 agentbox create";
|
|
10784
|
+
}
|
|
10785
|
+
async function buildCmuxText(live, color) {
|
|
10786
|
+
const { boxes } = await scopedBoxes(true, live);
|
|
10787
|
+
if (boxes.length === 0) return cmuxEmptyMessage();
|
|
10788
|
+
const width = process.stdout.columns ?? 30;
|
|
10789
|
+
return renderCmuxRows(boxes, color, width);
|
|
10790
|
+
}
|
|
10559
10791
|
function renderTable(boxes, stream) {
|
|
10560
10792
|
const header = ["N", "NAME", "STATE", "AGENT", "SHELLS", "PROVIDER", "URL", "WORKSPACE"];
|
|
10561
10793
|
const wsCol = header.length - 1;
|
|
@@ -10623,19 +10855,43 @@ async function buildListText(all, live) {
|
|
|
10623
10855
|
${table}`;
|
|
10624
10856
|
}
|
|
10625
10857
|
var listCommand2 = withWatchOptions(
|
|
10626
|
-
new
|
|
10858
|
+
new Command29("list").alias("ls").description("List agent boxes in the current project (-g for all)").option("-j, --json", "machine-readable JSON output").option("-g, --global", "include boxes from all projects").option(
|
|
10627
10859
|
"--live",
|
|
10628
10860
|
"probe live cloud state via the provider SDK (slower; default: last host-known state)"
|
|
10629
|
-
)
|
|
10861
|
+
).option("--cmux", "compact output for the cmux dock sidebar (narrow, 2 lines per box)")
|
|
10630
10862
|
).action(async (opts) => {
|
|
10631
10863
|
if (opts.json && opts.watch) {
|
|
10632
|
-
|
|
10864
|
+
log32.error("cannot combine --json with --watch");
|
|
10633
10865
|
process.exit(2);
|
|
10634
10866
|
}
|
|
10635
10867
|
const all = opts.global ?? false;
|
|
10636
10868
|
const live = opts.live ?? false;
|
|
10869
|
+
if (opts.cmux) {
|
|
10870
|
+
const color = !!process.stdout.isTTY && !process.env.NO_COLOR;
|
|
10871
|
+
if (opts.watch) {
|
|
10872
|
+
await watchRender(() => buildCmuxText(live, color), opts.interval, { hideStatusLine: true });
|
|
10873
|
+
return;
|
|
10874
|
+
}
|
|
10875
|
+
process.stdout.write(await buildCmuxText(live, color) + "\n");
|
|
10876
|
+
return;
|
|
10877
|
+
}
|
|
10637
10878
|
if (opts.watch) {
|
|
10638
|
-
|
|
10879
|
+
let scoped2 = all;
|
|
10880
|
+
const checkbox = () => `[${scoped2 ? "x" : " "}] all projects \xB7 press g to toggle
|
|
10881
|
+
`;
|
|
10882
|
+
await watchRender(
|
|
10883
|
+
async () => checkbox() + await buildListText(scoped2, live),
|
|
10884
|
+
opts.interval,
|
|
10885
|
+
{
|
|
10886
|
+
onKey: (k) => {
|
|
10887
|
+
if (k === "g") {
|
|
10888
|
+
scoped2 = !scoped2;
|
|
10889
|
+
return "redraw";
|
|
10890
|
+
}
|
|
10891
|
+
return "ignore";
|
|
10892
|
+
}
|
|
10893
|
+
}
|
|
10894
|
+
);
|
|
10639
10895
|
return;
|
|
10640
10896
|
}
|
|
10641
10897
|
if (opts.json) {
|
|
@@ -10647,11 +10903,11 @@ var listCommand2 = withWatchOptions(
|
|
|
10647
10903
|
});
|
|
10648
10904
|
|
|
10649
10905
|
// src/commands/logs.ts
|
|
10650
|
-
import { log as
|
|
10651
|
-
import { Command as
|
|
10906
|
+
import { log as log33 } from "@clack/prompts";
|
|
10907
|
+
import { Command as Command30 } from "commander";
|
|
10652
10908
|
import { spawn as spawn3 } from "child_process";
|
|
10653
10909
|
var DAEMON_LOG_PATH = "/var/log/agentbox/ctl-daemon.log";
|
|
10654
|
-
var logsCommand = new
|
|
10910
|
+
var logsCommand = new Command30("logs").description("Print recent log lines from a box service; -f to stream").argument(
|
|
10655
10911
|
"[box]",
|
|
10656
10912
|
"box ref (optional when cwd has exactly 1 box): project index, id, id prefix, name, or container"
|
|
10657
10913
|
).argument("[service]", "service name from agentbox.yaml").option("-n, --tail <n>", "how many recent lines to print first", "200").option("-f, --follow", "keep the connection open and stream new lines").option(
|
|
@@ -10669,9 +10925,9 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
|
|
|
10669
10925
|
service = boxArg;
|
|
10670
10926
|
}
|
|
10671
10927
|
if (!service && !opts.daemon) {
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10928
|
+
log33.error("missing <service> argument");
|
|
10929
|
+
log33.info("usage: agentbox logs [box] <service> [-n N] [-f]");
|
|
10930
|
+
log33.info(" agentbox logs [box] --daemon [-n N] [-f]");
|
|
10675
10931
|
process.exit(2);
|
|
10676
10932
|
}
|
|
10677
10933
|
const box = await resolveBoxOrExit(idOrName);
|
|
@@ -10682,7 +10938,7 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
|
|
|
10682
10938
|
if (!opts.follow) {
|
|
10683
10939
|
const proc = await provider.exec(box, args, { user: "vscode" });
|
|
10684
10940
|
if (proc.exitCode !== 0) {
|
|
10685
|
-
|
|
10941
|
+
log33.error(
|
|
10686
10942
|
`${opts.daemon ? "daemon log" : "agentbox-ctl logs"} failed: ${proc.stderr || proc.stdout}`
|
|
10687
10943
|
);
|
|
10688
10944
|
process.exit(1);
|
|
@@ -10738,12 +10994,12 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
|
|
|
10738
10994
|
});
|
|
10739
10995
|
|
|
10740
10996
|
// src/commands/open.ts
|
|
10741
|
-
import { log as
|
|
10997
|
+
import { log as log34 } from "@clack/prompts";
|
|
10742
10998
|
import { execa as execa3 } from "execa";
|
|
10743
|
-
import { existsSync as
|
|
10744
|
-
import { homedir as
|
|
10745
|
-
import { join as
|
|
10746
|
-
import { Command as
|
|
10999
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7 } from "fs";
|
|
11000
|
+
import { homedir as homedir17 } from "os";
|
|
11001
|
+
import { join as join19 } from "path";
|
|
11002
|
+
import { Command as Command31 } from "commander";
|
|
10747
11003
|
|
|
10748
11004
|
// src/commands/path.ts
|
|
10749
11005
|
async function runPath(box, opts) {
|
|
@@ -10765,7 +11021,7 @@ async function runPath(box, opts) {
|
|
|
10765
11021
|
}
|
|
10766
11022
|
|
|
10767
11023
|
// src/commands/open.ts
|
|
10768
|
-
var openCommand = new
|
|
11024
|
+
var openCommand = new Command31("open").description("Open a box's /workspace in Finder (docker: rsync'd snapshot; cloud: sshfs mount)").argument(
|
|
10769
11025
|
"[box]",
|
|
10770
11026
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
10771
11027
|
).option("--no-refresh", "skip the rsync; open whatever's already on disk (docker only)").option(
|
|
@@ -10804,7 +11060,7 @@ var openCommand = new Command30("open").description("Open a box's /workspace in
|
|
|
10804
11060
|
}
|
|
10805
11061
|
});
|
|
10806
11062
|
async function runCloudOpen(box, provider, opts) {
|
|
10807
|
-
const mountRoot =
|
|
11063
|
+
const mountRoot = join19(homedir17(), ".agentbox", "mounts", box.name);
|
|
10808
11064
|
if (opts.unmount) {
|
|
10809
11065
|
const ok = await tryUnmount(mountRoot);
|
|
10810
11066
|
if (ok) process.stdout.write(`unmounted ${mountRoot}
|
|
@@ -10841,13 +11097,13 @@ async function runCloudOpen(box, provider, opts) {
|
|
|
10841
11097
|
user: target.user,
|
|
10842
11098
|
identityFile: target.identityFile
|
|
10843
11099
|
});
|
|
10844
|
-
if (!
|
|
10845
|
-
|
|
11100
|
+
if (!existsSync9(mountRoot)) {
|
|
11101
|
+
mkdirSync7(mountRoot, { recursive: true, mode: 493 });
|
|
10846
11102
|
} else if (await isMounted(mountRoot)) {
|
|
10847
|
-
|
|
11103
|
+
log34.info(`re-mounting (stale mount detected at ${mountRoot})`);
|
|
10848
11104
|
await tryUnmount(mountRoot);
|
|
10849
11105
|
}
|
|
10850
|
-
|
|
11106
|
+
log34.info(`mounting ${alias}:/workspace at ${mountRoot}`);
|
|
10851
11107
|
const mount = await execa3(
|
|
10852
11108
|
sshfsBin,
|
|
10853
11109
|
[
|
|
@@ -10894,8 +11150,8 @@ async function tryUnmount(path) {
|
|
|
10894
11150
|
}
|
|
10895
11151
|
|
|
10896
11152
|
// src/commands/pause.ts
|
|
10897
|
-
import { Command as
|
|
10898
|
-
var pauseCommand = new
|
|
11153
|
+
import { Command as Command32 } from "commander";
|
|
11154
|
+
var pauseCommand = new Command32("pause").description(
|
|
10899
11155
|
"Pause a box. Docker: `docker pause` (cgroup freeze \u2014 sub-second resume). Cloud: backend.pause (Daytona archive \u2014 cold storage; resume is slower but uses no quota while archived)."
|
|
10900
11156
|
).argument(
|
|
10901
11157
|
"[box]",
|
|
@@ -10918,8 +11174,8 @@ var pauseCommand = new Command31("pause").description(
|
|
|
10918
11174
|
});
|
|
10919
11175
|
|
|
10920
11176
|
// src/commands/prune.ts
|
|
10921
|
-
import { confirm as confirm15, isCancel as isCancel16, log as
|
|
10922
|
-
import { Command as
|
|
11177
|
+
import { confirm as confirm15, isCancel as isCancel16, log as log35 } from "@clack/prompts";
|
|
11178
|
+
import { Command as Command33 } from "commander";
|
|
10923
11179
|
function totalRemovals(r, projectConfigs) {
|
|
10924
11180
|
return r.removedRecords.length + r.removedContainers.length + r.removedVolumes.length + r.removedSnapshotDirs.length + r.removedBoxDirs.length + projectConfigs.length;
|
|
10925
11181
|
}
|
|
@@ -10965,7 +11221,7 @@ async function liveProjectRoots() {
|
|
|
10965
11221
|
return [];
|
|
10966
11222
|
}
|
|
10967
11223
|
}
|
|
10968
|
-
var pruneCommand = new
|
|
11224
|
+
var pruneCommand = new Command33("prune").description("Clean up orphan state.json records (and with --all, orphan docker resources)").option("--dry-run", "show what would be removed, don't change anything").option(
|
|
10969
11225
|
"--all",
|
|
10970
11226
|
"also remove orphan agentbox-* containers, volumes, snapshot dirs, and orphan per-project config dirs"
|
|
10971
11227
|
).option("-y, --yes", "skip the confirmation prompt").option(
|
|
@@ -10978,7 +11234,7 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
|
|
|
10978
11234
|
return;
|
|
10979
11235
|
}
|
|
10980
11236
|
if (opts.provider !== void 0 && opts.provider !== "docker") {
|
|
10981
|
-
|
|
11237
|
+
log35.error(`unknown provider '${opts.provider}'; expected docker, daytona, hetzner, or vercel`);
|
|
10982
11238
|
process.exit(2);
|
|
10983
11239
|
}
|
|
10984
11240
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -10991,13 +11247,13 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
|
|
|
10991
11247
|
process.stdout.write("nothing to prune\n");
|
|
10992
11248
|
return;
|
|
10993
11249
|
}
|
|
10994
|
-
|
|
11250
|
+
log35.info(`would remove:
|
|
10995
11251
|
${summary(preview, previewProjects)}`);
|
|
10996
11252
|
if (dryRun) return;
|
|
10997
11253
|
if (!opts.yes) {
|
|
10998
11254
|
const ok = await confirm15({ message: "Proceed with prune?", initialValue: true });
|
|
10999
11255
|
if (isCancel16(ok) || !ok) {
|
|
11000
|
-
|
|
11256
|
+
log35.info("cancelled");
|
|
11001
11257
|
return;
|
|
11002
11258
|
}
|
|
11003
11259
|
}
|
|
@@ -11018,7 +11274,7 @@ async function pruneCloud(provider, opts) {
|
|
|
11018
11274
|
const dryRun = opts.dryRun ?? false;
|
|
11019
11275
|
const backend = await cloudBackendForProvider(provider);
|
|
11020
11276
|
if (!backend.list) {
|
|
11021
|
-
|
|
11277
|
+
log35.error(`${provider} backend doesn't expose \`list()\`; cannot enumerate sandboxes for prune`);
|
|
11022
11278
|
process.exit(2);
|
|
11023
11279
|
}
|
|
11024
11280
|
const [remote, state] = await Promise.all([backend.list(), readState()]);
|
|
@@ -11038,7 +11294,7 @@ async function pruneCloud(provider, opts) {
|
|
|
11038
11294
|
`);
|
|
11039
11295
|
return;
|
|
11040
11296
|
}
|
|
11041
|
-
|
|
11297
|
+
log35.info(`found ${String(orphans.length)} ${provider} sandbox(es) not in this CLI's state:`);
|
|
11042
11298
|
for (const sb of orphans) {
|
|
11043
11299
|
const parts = [sb.sandboxId];
|
|
11044
11300
|
if (sb.name) parts.push(sb.name);
|
|
@@ -11054,7 +11310,7 @@ async function pruneCloud(provider, opts) {
|
|
|
11054
11310
|
initialValue: false
|
|
11055
11311
|
});
|
|
11056
11312
|
if (isCancel16(ok) || !ok) {
|
|
11057
|
-
|
|
11313
|
+
log35.info("cancelled");
|
|
11058
11314
|
return;
|
|
11059
11315
|
}
|
|
11060
11316
|
}
|
|
@@ -11066,7 +11322,7 @@ async function pruneCloud(provider, opts) {
|
|
|
11066
11322
|
deleted++;
|
|
11067
11323
|
} catch (err) {
|
|
11068
11324
|
failed++;
|
|
11069
|
-
|
|
11325
|
+
log35.warn(
|
|
11070
11326
|
`delete ${sb.sandboxId} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
11071
11327
|
);
|
|
11072
11328
|
}
|
|
@@ -11079,17 +11335,17 @@ async function pruneCloud(provider, opts) {
|
|
|
11079
11335
|
|
|
11080
11336
|
// src/commands/queue.ts
|
|
11081
11337
|
import { readFile as readFile5, stat as stat5 } from "fs/promises";
|
|
11082
|
-
import { intro as
|
|
11083
|
-
import { Command as
|
|
11338
|
+
import { intro as intro8, log as log36, outro as outro7 } from "@clack/prompts";
|
|
11339
|
+
import { Command as Command34 } from "commander";
|
|
11084
11340
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
|
|
11085
|
-
var queueCommand = new
|
|
11086
|
-
var queueListCommand = new
|
|
11341
|
+
var queueCommand = new Command34("queue").description("Inspect and manage background `agentbox claude|codex|opencode -i` jobs");
|
|
11342
|
+
var queueListCommand = new Command34("list").description("List queued, running, and (with --all) terminal background jobs").option("--all", "include done/failed/cancelled jobs (default: hide terminal)").action(async (opts) => {
|
|
11087
11343
|
const jobs = await loadQueue();
|
|
11088
11344
|
const cfg = await loadQueueConfig();
|
|
11089
11345
|
const visible = opts.all === true ? jobs : jobs.filter((j) => !TERMINAL_STATUSES.has(j.status));
|
|
11090
11346
|
if (visible.length === 0) {
|
|
11091
|
-
|
|
11092
|
-
|
|
11347
|
+
log36.info(opts.all ? "no queued jobs." : "no active queued jobs (--all to see terminal).");
|
|
11348
|
+
log36.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
|
|
11093
11349
|
return;
|
|
11094
11350
|
}
|
|
11095
11351
|
const rows = visible.map((j) => ({
|
|
@@ -11114,12 +11370,12 @@ var queueListCommand = new Command33("list").description("List queued, running,
|
|
|
11114
11370
|
headers.map((h, i) => pad4(String(r[h]), widths[i])).join(" ") + "\n"
|
|
11115
11371
|
);
|
|
11116
11372
|
}
|
|
11117
|
-
|
|
11373
|
+
log36.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
|
|
11118
11374
|
});
|
|
11119
|
-
var queueShowCommand = new
|
|
11375
|
+
var queueShowCommand = new Command34("show").description("Dump a job manifest and tail its log").argument("<id>", "queue job id (from `agentbox queue list`)").option("--tail <n>", "lines of log to print (default: 50)", "50").action(async (id, opts) => {
|
|
11120
11376
|
const job = await readJob(id);
|
|
11121
11377
|
if (!job) {
|
|
11122
|
-
|
|
11378
|
+
log36.error(`no job with id ${id}`);
|
|
11123
11379
|
process.exit(1);
|
|
11124
11380
|
}
|
|
11125
11381
|
process.stdout.write(JSON.stringify(job, null, 2) + "\n");
|
|
@@ -11135,18 +11391,18 @@ var queueShowCommand = new Command33("show").description("Dump a job manifest an
|
|
|
11135
11391
|
process.stdout.write(slice.join("\n"));
|
|
11136
11392
|
if (!slice.join("\n").endsWith("\n")) process.stdout.write("\n");
|
|
11137
11393
|
} catch {
|
|
11138
|
-
|
|
11394
|
+
log36.info(`(no log at ${job.logPath} yet)`);
|
|
11139
11395
|
}
|
|
11140
11396
|
});
|
|
11141
|
-
var queueCancelCommand = new
|
|
11142
|
-
|
|
11397
|
+
var queueCancelCommand = new Command34("cancel").description("Cancel a queued job; running jobs are NOT killed \u2014 use `agentbox destroy` instead").argument("<id>", "queue job id (from `agentbox queue list`)").action(async (id) => {
|
|
11398
|
+
intro8(`Cancelling queue job ${id}...`);
|
|
11143
11399
|
const job = await readJob(id);
|
|
11144
11400
|
if (!job) {
|
|
11145
|
-
|
|
11401
|
+
log36.error(`no job with id ${id}`);
|
|
11146
11402
|
process.exit(1);
|
|
11147
11403
|
}
|
|
11148
11404
|
if (job.status !== "queued") {
|
|
11149
|
-
|
|
11405
|
+
log36.error(
|
|
11150
11406
|
`job ${id} is ${job.status}; cancel only flips 'queued' \u2192 'cancelled'.` + (job.status === "running" ? ` Use 'agentbox destroy ${job.boxName || id}' to stop the box.` : "")
|
|
11151
11407
|
);
|
|
11152
11408
|
process.exit(1);
|
|
@@ -11158,15 +11414,15 @@ var queueCancelCommand = new Command33("cancel").description("Cancel a queued jo
|
|
|
11158
11414
|
reason: "cancelled by user"
|
|
11159
11415
|
};
|
|
11160
11416
|
await writeJob(cancelled);
|
|
11161
|
-
|
|
11417
|
+
outro7(`job ${id} cancelled`);
|
|
11162
11418
|
});
|
|
11163
|
-
var queueClearCommand = new
|
|
11419
|
+
var queueClearCommand = new Command34("clear").description("Sweep terminal-state manifests from ~/.agentbox/queue/").option("--done", "remove done jobs").option("--failed", "remove failed jobs").option("--cancelled", "remove cancelled jobs").option("--all", "remove every terminal-state job (done + failed + cancelled)").action(async (opts) => {
|
|
11164
11420
|
const targets = /* @__PURE__ */ new Set();
|
|
11165
11421
|
if (opts.all === true || opts.done === true) targets.add("done");
|
|
11166
11422
|
if (opts.all === true || opts.failed === true) targets.add("failed");
|
|
11167
11423
|
if (opts.all === true || opts.cancelled === true) targets.add("cancelled");
|
|
11168
11424
|
if (targets.size === 0) {
|
|
11169
|
-
|
|
11425
|
+
log36.error("pick at least one of: --done, --failed, --cancelled, --all");
|
|
11170
11426
|
process.exit(2);
|
|
11171
11427
|
}
|
|
11172
11428
|
const jobs = await loadQueue();
|
|
@@ -11176,7 +11432,7 @@ var queueClearCommand = new Command33("clear").description("Sweep terminal-state
|
|
|
11176
11432
|
await deleteJob(j.id);
|
|
11177
11433
|
removed += 1;
|
|
11178
11434
|
}
|
|
11179
|
-
|
|
11435
|
+
log36.success(`removed ${String(removed)} manifest${removed === 1 ? "" : "s"}`);
|
|
11180
11436
|
});
|
|
11181
11437
|
var QUEUE_WAIT_EVENTS = [
|
|
11182
11438
|
"new-box",
|
|
@@ -11189,11 +11445,11 @@ var QUEUE_WAIT_EVENTS = [
|
|
|
11189
11445
|
var ACTIVE_JOB_STATUSES = /* @__PURE__ */ new Set(["queued", "running"]);
|
|
11190
11446
|
var DEFAULT_QUEUE_WAIT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
11191
11447
|
var QUEUE_POLL_INTERVAL_MS = 500;
|
|
11192
|
-
var queueWaitForCommand = new
|
|
11448
|
+
var queueWaitForCommand = new Command34("wait-for").description(
|
|
11193
11449
|
`Block until a queue / box event fires. <event> one of: ${QUEUE_WAIT_EVENTS.join(" | ")}.`
|
|
11194
11450
|
).argument("<event>", `target event: ${QUEUE_WAIT_EVENTS.join(" | ")}`).option("--box <ref>", "box ref (required for box-paused / box-running / box-stopped)").option("--job <id>", "queue job id (required for job-done)").option("--timeout <ms>", `wall-clock cap (default: ${String(DEFAULT_QUEUE_WAIT_TIMEOUT_MS)})`).option("--json", "emit a JSON envelope { matched, elapsedMs, ... }").action(async (eventRaw, opts) => {
|
|
11195
11451
|
if (!QUEUE_WAIT_EVENTS.includes(eventRaw)) {
|
|
11196
|
-
|
|
11452
|
+
log36.error(`unknown event '${eventRaw}' (one of: ${QUEUE_WAIT_EVENTS.join(", ")})`);
|
|
11197
11453
|
process.exit(2);
|
|
11198
11454
|
}
|
|
11199
11455
|
const event = eventRaw;
|
|
@@ -11213,11 +11469,11 @@ var queueWaitForCommand = new Command33("wait-for").description(
|
|
|
11213
11469
|
if (opts.json === true) {
|
|
11214
11470
|
process.stdout.write(JSON.stringify({ matched: false, event, elapsedMs }) + "\n");
|
|
11215
11471
|
} else {
|
|
11216
|
-
|
|
11472
|
+
log36.error(`'${event}' did not occur within ${String(timeoutMs)}ms`);
|
|
11217
11473
|
}
|
|
11218
11474
|
process.exit(1);
|
|
11219
11475
|
}
|
|
11220
|
-
|
|
11476
|
+
log36.error(err instanceof Error ? err.message : String(err));
|
|
11221
11477
|
process.exit(1);
|
|
11222
11478
|
}
|
|
11223
11479
|
});
|
|
@@ -11314,8 +11570,8 @@ function truncate(s, max) {
|
|
|
11314
11570
|
}
|
|
11315
11571
|
|
|
11316
11572
|
// src/commands/relay.ts
|
|
11317
|
-
import { log as
|
|
11318
|
-
import { Command as
|
|
11573
|
+
import { log as log37, spinner as spinner9 } from "@clack/prompts";
|
|
11574
|
+
import { Command as Command35 } from "commander";
|
|
11319
11575
|
async function rehydrateFromState() {
|
|
11320
11576
|
const state = await readState();
|
|
11321
11577
|
await rehydrateRelayRegistry(
|
|
@@ -11357,7 +11613,7 @@ function renderStatus(s) {
|
|
|
11357
11613
|
}
|
|
11358
11614
|
return ["relay: not running", ` log: ${s.logFile}`].join("\n");
|
|
11359
11615
|
}
|
|
11360
|
-
var statusSub = new
|
|
11616
|
+
var statusSub = new Command35("status").description("Show whether the host relay is running, with pid / port / box count").option("--json", "emit RelayStatus as JSON").action(async (opts) => {
|
|
11361
11617
|
try {
|
|
11362
11618
|
const s = await getRelayStatus();
|
|
11363
11619
|
if (opts.json) {
|
|
@@ -11369,7 +11625,7 @@ var statusSub = new Command34("status").description("Show whether the host relay
|
|
|
11369
11625
|
handleLifecycleError(err);
|
|
11370
11626
|
}
|
|
11371
11627
|
});
|
|
11372
|
-
var stopSub = new
|
|
11628
|
+
var stopSub = new Command35("stop").description("Stop the host relay process (idempotent)").action(async () => {
|
|
11373
11629
|
try {
|
|
11374
11630
|
const s = spinner9();
|
|
11375
11631
|
s.start("stopping relay");
|
|
@@ -11381,7 +11637,7 @@ var stopSub = new Command34("stop").description("Stop the host relay process (id
|
|
|
11381
11637
|
handleLifecycleError(err);
|
|
11382
11638
|
}
|
|
11383
11639
|
});
|
|
11384
|
-
var startSub = new
|
|
11640
|
+
var startSub = new Command35("start").description("Start the host relay if not already running (idempotent)").action(async () => {
|
|
11385
11641
|
try {
|
|
11386
11642
|
const s = spinner9();
|
|
11387
11643
|
s.start("starting relay");
|
|
@@ -11392,7 +11648,7 @@ var startSub = new Command34("start").description("Start the host relay if not a
|
|
|
11392
11648
|
handleLifecycleError(err);
|
|
11393
11649
|
}
|
|
11394
11650
|
});
|
|
11395
|
-
var restartSub = new
|
|
11651
|
+
var restartSub = new Command35("restart").description("Stop then start the host relay").action(async () => {
|
|
11396
11652
|
try {
|
|
11397
11653
|
const s = spinner9();
|
|
11398
11654
|
s.start("stopping relay");
|
|
@@ -11408,35 +11664,35 @@ var restartSub = new Command34("restart").description("Stop then start the host
|
|
|
11408
11664
|
s2.stop(`relay running on ${ep.hostUrl}`);
|
|
11409
11665
|
} catch (err) {
|
|
11410
11666
|
s2.stop("relay start failed");
|
|
11411
|
-
|
|
11667
|
+
log37.warn(err instanceof Error ? err.message : String(err));
|
|
11412
11668
|
throw err;
|
|
11413
11669
|
}
|
|
11414
11670
|
} catch (err) {
|
|
11415
11671
|
handleLifecycleError(err);
|
|
11416
11672
|
}
|
|
11417
11673
|
});
|
|
11418
|
-
var relayCommand = new
|
|
11674
|
+
var relayCommand = new Command35("relay").description("Manage the host relay process (status / stop / start / restart)").addCommand(statusSub, { isDefault: true }).addCommand(stopSub).addCommand(startSub).addCommand(restartSub);
|
|
11419
11675
|
|
|
11420
11676
|
// src/commands/_run-queued-job.ts
|
|
11421
|
-
import { Command as
|
|
11422
|
-
var runQueuedJobCommand = new
|
|
11423
|
-
const
|
|
11424
|
-
|
|
11677
|
+
import { Command as Command36 } from "commander";
|
|
11678
|
+
var runQueuedJobCommand = new Command36("_run-queued-job").description("internal: run a queued background agent job (do not invoke directly)").argument("<id>", "queue job id (from ~/.agentbox/queue/<id>.json)").action(async (id) => {
|
|
11679
|
+
const log46 = openCommandLog(`queue-${id}`);
|
|
11680
|
+
log46.write(`worker pid=${String(process.pid)} starting for job ${id}`);
|
|
11425
11681
|
let job = null;
|
|
11426
11682
|
try {
|
|
11427
11683
|
job = await readJob(id);
|
|
11428
11684
|
if (!job) {
|
|
11429
|
-
|
|
11430
|
-
|
|
11685
|
+
log46.write(`FATAL: no manifest at id=${id}`);
|
|
11686
|
+
log46.close();
|
|
11431
11687
|
process.exit(64);
|
|
11432
11688
|
}
|
|
11433
11689
|
const onBoxCreated = (boxId) => {
|
|
11434
11690
|
if (job) job = { ...job, boxId };
|
|
11435
11691
|
};
|
|
11436
11692
|
if ((job.providerName || "docker") === "docker") {
|
|
11437
|
-
await runDockerJob(job,
|
|
11693
|
+
await runDockerJob(job, log46, onBoxCreated);
|
|
11438
11694
|
} else {
|
|
11439
|
-
await runCloudJob(job,
|
|
11695
|
+
await runCloudJob(job, log46, onBoxCreated);
|
|
11440
11696
|
}
|
|
11441
11697
|
const done = {
|
|
11442
11698
|
...job,
|
|
@@ -11445,12 +11701,12 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
|
|
|
11445
11701
|
exitCode: 0
|
|
11446
11702
|
};
|
|
11447
11703
|
await writeJob(done);
|
|
11448
|
-
|
|
11449
|
-
|
|
11704
|
+
log46.write(`done`);
|
|
11705
|
+
log46.close();
|
|
11450
11706
|
process.exit(0);
|
|
11451
11707
|
} catch (err) {
|
|
11452
11708
|
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
11453
|
-
|
|
11709
|
+
log46.write(`FAIL: ${msg}`);
|
|
11454
11710
|
if (job) {
|
|
11455
11711
|
try {
|
|
11456
11712
|
const failed = {
|
|
@@ -11464,11 +11720,11 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
|
|
|
11464
11720
|
} catch {
|
|
11465
11721
|
}
|
|
11466
11722
|
}
|
|
11467
|
-
|
|
11723
|
+
log46.close();
|
|
11468
11724
|
process.exit(1);
|
|
11469
11725
|
}
|
|
11470
11726
|
});
|
|
11471
|
-
async function runDockerJob(job,
|
|
11727
|
+
async function runDockerJob(job, log46, onBoxCreated) {
|
|
11472
11728
|
const opts = job.createOpts;
|
|
11473
11729
|
const cfg = await loadEffectiveConfig(opts.workspace, {
|
|
11474
11730
|
cliOverrides: buildOverridesFromJob(job)
|
|
@@ -11480,7 +11736,7 @@ async function runDockerJob(job, log45, onBoxCreated) {
|
|
|
11480
11736
|
const useSnapshot = opts.hostSnapshot === false ? false : opts.hostSnapshot === true ? true : cfg.effective.box.hostSnapshot ?? false;
|
|
11481
11737
|
const resolved = job.agent === "claude-code" ? await resolveClaudeAuth(process.env) : null;
|
|
11482
11738
|
const withPlaywright = cfg.effective.box.withPlaywright || cfg.effective.browser.default !== "agent-browser";
|
|
11483
|
-
|
|
11739
|
+
log46.write(`creating box for agent=${job.agent}`);
|
|
11484
11740
|
const result = await createBox({
|
|
11485
11741
|
workspacePath: opts.workspace,
|
|
11486
11742
|
name: opts.name && opts.name.length > 0 ? opts.name : void 0,
|
|
@@ -11506,22 +11762,22 @@ async function runDockerJob(job, log45, onBoxCreated) {
|
|
|
11506
11762
|
// at box-create time (the worker runs on the host, so it can read the files).
|
|
11507
11763
|
carry: opts.carry,
|
|
11508
11764
|
projectRoot,
|
|
11509
|
-
onLog: (line) =>
|
|
11765
|
+
onLog: (line) => log46.write(line)
|
|
11510
11766
|
});
|
|
11511
|
-
|
|
11767
|
+
log46.write(`box created: ${result.record.container}`);
|
|
11512
11768
|
onBoxCreated(result.record.id);
|
|
11513
11769
|
await writeJob({ ...job, boxId: result.record.id });
|
|
11514
11770
|
const resyncWarning = result.resync ? buildResyncWarning(result.resync) : null;
|
|
11515
|
-
if (resyncWarning)
|
|
11771
|
+
if (resyncWarning) log46.write(resyncWarning);
|
|
11516
11772
|
const prompt = prependResyncWarning(resyncWarning, job.prompt);
|
|
11517
11773
|
const promptedArgs = buildPromptArgs(job.agent, prompt, job.agentArgs);
|
|
11518
11774
|
if (job.agent === "claude-code") {
|
|
11519
|
-
|
|
11775
|
+
log46.write(`checking plugin native deps`);
|
|
11520
11776
|
await rebuildPluginNativeDeps(result.record.container, {
|
|
11521
11777
|
volume: result.record.claudeConfigVolume ?? SHARED_CLAUDE_VOLUME,
|
|
11522
|
-
onProgress: (line) =>
|
|
11778
|
+
onProgress: (line) => log46.write(line)
|
|
11523
11779
|
});
|
|
11524
|
-
|
|
11780
|
+
log46.write(`starting claude session`);
|
|
11525
11781
|
await startClaudeSession({
|
|
11526
11782
|
container: result.record.container,
|
|
11527
11783
|
claudeArgs: applyClaudeSkipPermissions(promptedArgs, cfg.effective),
|
|
@@ -11529,22 +11785,22 @@ async function runDockerJob(job, log45, onBoxCreated) {
|
|
|
11529
11785
|
boxName: result.record.name
|
|
11530
11786
|
});
|
|
11531
11787
|
} else if (job.agent === "codex") {
|
|
11532
|
-
|
|
11788
|
+
log46.write(`checking codex`);
|
|
11533
11789
|
await ensureCodexInstalled(result.record.container, {
|
|
11534
|
-
onProgress: (line) =>
|
|
11790
|
+
onProgress: (line) => log46.write(line)
|
|
11535
11791
|
});
|
|
11536
|
-
|
|
11792
|
+
log46.write(`starting codex session`);
|
|
11537
11793
|
await startCodexSession({
|
|
11538
11794
|
container: result.record.container,
|
|
11539
11795
|
codexArgs: applyCodexSkipPermissions(promptedArgs, cfg.effective),
|
|
11540
11796
|
sessionName: cfg.effective.codex.sessionName
|
|
11541
11797
|
});
|
|
11542
11798
|
} else if (job.agent === "opencode") {
|
|
11543
|
-
|
|
11799
|
+
log46.write(`checking opencode`);
|
|
11544
11800
|
await ensureOpencodeInstalled(result.record.container, {
|
|
11545
|
-
onProgress: (line) =>
|
|
11801
|
+
onProgress: (line) => log46.write(line)
|
|
11546
11802
|
});
|
|
11547
|
-
|
|
11803
|
+
log46.write(`starting opencode session`);
|
|
11548
11804
|
await startOpencodeSession({
|
|
11549
11805
|
container: result.record.container,
|
|
11550
11806
|
opencodeArgs: promptedArgs,
|
|
@@ -11554,7 +11810,7 @@ async function runDockerJob(job, log45, onBoxCreated) {
|
|
|
11554
11810
|
throw new Error(`unknown agent kind: ${String(job.agent)}`);
|
|
11555
11811
|
}
|
|
11556
11812
|
}
|
|
11557
|
-
async function runCloudJob(job,
|
|
11813
|
+
async function runCloudJob(job, log46, onBoxCreated) {
|
|
11558
11814
|
const opts = job.createOpts;
|
|
11559
11815
|
const cfg = await loadEffectiveConfig(opts.workspace, {
|
|
11560
11816
|
cliOverrides: buildOverridesFromJob(job)
|
|
@@ -11565,7 +11821,7 @@ async function runCloudJob(job, log45, onBoxCreated) {
|
|
|
11565
11821
|
const providerDefault = resolveDefaultCheckpoint(cfg.effective, providerName);
|
|
11566
11822
|
const checkpointRef = opts.snapshot && opts.snapshot.length > 0 ? opts.snapshot : providerDefault.length > 0 ? providerDefault : void 0;
|
|
11567
11823
|
const withPlaywright = cfg.effective.box.withPlaywright || cfg.effective.browser.default !== "agent-browser";
|
|
11568
|
-
|
|
11824
|
+
log46.write(`creating cloud box (${providerName}) for agent=${job.agent}`);
|
|
11569
11825
|
const result = await provider.create({
|
|
11570
11826
|
workspacePath: opts.workspace,
|
|
11571
11827
|
name: opts.name && opts.name.length > 0 ? opts.name : void 0,
|
|
@@ -11579,9 +11835,9 @@ async function runCloudJob(job, log45, onBoxCreated) {
|
|
|
11579
11835
|
// worker runs on the host too, so it reads the files and uploads them.
|
|
11580
11836
|
carry: opts.carry,
|
|
11581
11837
|
projectRoot,
|
|
11582
|
-
onLog: (line) =>
|
|
11838
|
+
onLog: (line) => log46.write(line)
|
|
11583
11839
|
});
|
|
11584
|
-
|
|
11840
|
+
log46.write(`box created: ${result.record.id}`);
|
|
11585
11841
|
onBoxCreated(result.record.id);
|
|
11586
11842
|
await writeJob({ ...job, boxId: result.record.id });
|
|
11587
11843
|
const promptedArgs = buildPromptArgs(job.agent, job.prompt, job.agentArgs);
|
|
@@ -11603,7 +11859,7 @@ async function runCloudJob(job, log45, onBoxCreated) {
|
|
|
11603
11859
|
} else {
|
|
11604
11860
|
throw new Error(`unknown agent kind: ${String(job.agent)}`);
|
|
11605
11861
|
}
|
|
11606
|
-
|
|
11862
|
+
log46.write(`starting detached ${job.agent} session`);
|
|
11607
11863
|
await cloudAgentStartDetached({
|
|
11608
11864
|
box: result.record,
|
|
11609
11865
|
binary,
|
|
@@ -11640,8 +11896,8 @@ function buildOverridesFromJob(job) {
|
|
|
11640
11896
|
|
|
11641
11897
|
// src/commands/screen.ts
|
|
11642
11898
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
11643
|
-
import { log as
|
|
11644
|
-
import { Command as
|
|
11899
|
+
import { log as log38 } from "@clack/prompts";
|
|
11900
|
+
import { Command as Command37 } from "commander";
|
|
11645
11901
|
var SIGNED_URL_TTL_MIN = 1;
|
|
11646
11902
|
var SIGNED_URL_TTL_MAX = 86400;
|
|
11647
11903
|
function parseTtlOrExit(raw) {
|
|
@@ -11654,7 +11910,7 @@ function parseTtlOrExit(raw) {
|
|
|
11654
11910
|
}
|
|
11655
11911
|
return n;
|
|
11656
11912
|
}
|
|
11657
|
-
var screenCommand = new
|
|
11913
|
+
var screenCommand = new Command37("screen").description("Open a box's VNC (noVNC) viewer in the browser (auto-unpause/start)").argument(
|
|
11658
11914
|
"[box]",
|
|
11659
11915
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
11660
11916
|
).option("--print", "print the URL to stdout instead of launching the browser").option("--loopback", "docker only: use the 127.0.0.1 URL instead of the OrbStack .orb.local URL").option(
|
|
@@ -11671,10 +11927,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
|
|
|
11671
11927
|
if (provider === "docker") {
|
|
11672
11928
|
const insp = await inspectBox(box.id);
|
|
11673
11929
|
if (insp.state === "paused") {
|
|
11674
|
-
|
|
11930
|
+
log38.info("box is paused; unpausing");
|
|
11675
11931
|
await unpauseBox(box.id);
|
|
11676
11932
|
} else if (insp.state === "stopped") {
|
|
11677
|
-
|
|
11933
|
+
log38.info("box is stopped; starting");
|
|
11678
11934
|
await startBox(box.id);
|
|
11679
11935
|
} else if (insp.state === "missing") {
|
|
11680
11936
|
throw new Error(`box ${box.name} has no container; was it destroyed?`);
|
|
@@ -11684,13 +11940,13 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
|
|
|
11684
11940
|
const inBoxUrl = exposePort !== void 0 ? box.portlessUrl ?? `http://localhost:${String(exposePort)}` : "about:blank";
|
|
11685
11941
|
const br = await ensureBoxBrowser(box.container, void 0, inBoxUrl);
|
|
11686
11942
|
if (br.up && !br.alreadyRunning) {
|
|
11687
|
-
|
|
11943
|
+
log38.info(
|
|
11688
11944
|
exposePort !== void 0 ? `opened ${inBoxUrl} in the in-box browser (visible in the VNC view)` : "started in-box browser"
|
|
11689
11945
|
);
|
|
11690
11946
|
} else if (br.alreadyRunning) {
|
|
11691
|
-
|
|
11947
|
+
log38.info("in-box browser already running; left it untouched");
|
|
11692
11948
|
} else {
|
|
11693
|
-
|
|
11949
|
+
log38.warn(`could not start in-box browser: ${br.reason ?? "unknown"}`);
|
|
11694
11950
|
}
|
|
11695
11951
|
const engine = await detectEngine();
|
|
11696
11952
|
const urls = buildVncUrls(box, engine);
|
|
@@ -11711,10 +11967,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
|
|
|
11711
11967
|
const p = await providerForBox(box);
|
|
11712
11968
|
const state = await p.probeState(box);
|
|
11713
11969
|
if (state === "paused") {
|
|
11714
|
-
|
|
11970
|
+
log38.info("box is paused; resuming");
|
|
11715
11971
|
await p.resume(box);
|
|
11716
11972
|
} else if (state === "stopped") {
|
|
11717
|
-
|
|
11973
|
+
log38.info("box is stopped; starting");
|
|
11718
11974
|
await p.start(box);
|
|
11719
11975
|
} else if (state === "missing") {
|
|
11720
11976
|
throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
|
|
@@ -11729,14 +11985,14 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
|
|
|
11729
11985
|
user: "vscode"
|
|
11730
11986
|
});
|
|
11731
11987
|
if (br.exitCode === 0) {
|
|
11732
|
-
|
|
11988
|
+
log38.info(`opened ${webUrl} in the in-box browser (visible in the VNC view)`);
|
|
11733
11989
|
} else {
|
|
11734
|
-
|
|
11990
|
+
log38.warn(
|
|
11735
11991
|
`could not open in-box browser (continuing): ${br.stderr.trim() || br.stdout.trim() || `exit ${String(br.exitCode)}`}`
|
|
11736
11992
|
);
|
|
11737
11993
|
}
|
|
11738
11994
|
} catch (err) {
|
|
11739
|
-
|
|
11995
|
+
log38.warn(
|
|
11740
11996
|
`in-box browser skipped: ${err instanceof Error ? err.message : String(err)}`
|
|
11741
11997
|
);
|
|
11742
11998
|
}
|
|
@@ -11762,18 +12018,18 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
|
|
|
11762
12018
|
|
|
11763
12019
|
// src/commands/shell.ts
|
|
11764
12020
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
11765
|
-
import { log as
|
|
11766
|
-
import { Command as
|
|
12021
|
+
import { log as log40 } from "@clack/prompts";
|
|
12022
|
+
import { Command as Command38 } from "commander";
|
|
11767
12023
|
|
|
11768
12024
|
// src/commands/_provider-guard.ts
|
|
11769
|
-
import { log as
|
|
12025
|
+
import { log as log39 } from "@clack/prompts";
|
|
11770
12026
|
function requireDockerProvider(box, commandName) {
|
|
11771
12027
|
const provider = box.provider ?? "docker";
|
|
11772
12028
|
if (provider === "docker") return;
|
|
11773
|
-
|
|
12029
|
+
log39.error(
|
|
11774
12030
|
`\`agentbox ${commandName}\` doesn't yet support cloud boxes (this box's provider is '${provider}').`
|
|
11775
12031
|
);
|
|
11776
|
-
|
|
12032
|
+
log39.info(
|
|
11777
12033
|
"Cloud-provider routing for this command is on the Phase 3 backlog. For now: use `agentbox url` for web access, `agentbox-ctl git push` from inside the sandbox via SSH/web terminal, or fall back to the cloud provider's own console."
|
|
11778
12034
|
);
|
|
11779
12035
|
process.exit(2);
|
|
@@ -11813,10 +12069,10 @@ function fmtAgo2(iso) {
|
|
|
11813
12069
|
async function ensureBoxRunning(box) {
|
|
11814
12070
|
const insp = await inspectBox(box.id);
|
|
11815
12071
|
if (insp.state === "paused") {
|
|
11816
|
-
|
|
12072
|
+
log40.info("box is paused; unpausing");
|
|
11817
12073
|
await unpauseBox(box.id);
|
|
11818
12074
|
} else if (insp.state === "stopped") {
|
|
11819
|
-
|
|
12075
|
+
log40.info("box is stopped; starting");
|
|
11820
12076
|
await startBox(box.id);
|
|
11821
12077
|
} else if (insp.state === "missing") {
|
|
11822
12078
|
throw new Error(`box ${box.name} has no container; was it destroyed?`);
|
|
@@ -11855,7 +12111,7 @@ async function startOrAttachShell(box, cfg) {
|
|
|
11855
12111
|
const label = shellLabel(cfg.sessionName);
|
|
11856
12112
|
const info = await shellSessionInfo(box.container, cfg.sessionName, cfg.user);
|
|
11857
12113
|
if (info.running) {
|
|
11858
|
-
|
|
12114
|
+
log40.info(`reattaching to shell "${label}" \u2014 Control+a d to detach`);
|
|
11859
12115
|
} else {
|
|
11860
12116
|
await startShellSession({
|
|
11861
12117
|
container: box.container,
|
|
@@ -11863,7 +12119,7 @@ async function startOrAttachShell(box, cfg) {
|
|
|
11863
12119
|
user: cfg.user,
|
|
11864
12120
|
login: cfg.login
|
|
11865
12121
|
});
|
|
11866
|
-
|
|
12122
|
+
log40.info(`shell "${label}" \u2014 Control+a d to detach, leaves it running`);
|
|
11867
12123
|
}
|
|
11868
12124
|
const code = await runWrappedAttach({
|
|
11869
12125
|
container: box.container,
|
|
@@ -11878,7 +12134,7 @@ async function startOrAttachShell(box, cfg) {
|
|
|
11878
12134
|
});
|
|
11879
12135
|
process.exit(code);
|
|
11880
12136
|
}
|
|
11881
|
-
var shellCommand = new
|
|
12137
|
+
var shellCommand = new Command38("shell").description(
|
|
11882
12138
|
"Open an interactive shell in a box, in a detachable tmux session (auto-unpause/start)"
|
|
11883
12139
|
).argument(
|
|
11884
12140
|
"[box]",
|
|
@@ -11969,7 +12225,7 @@ var shellCommand = new Command37("shell").description(
|
|
|
11969
12225
|
handleLifecycleError(err);
|
|
11970
12226
|
}
|
|
11971
12227
|
});
|
|
11972
|
-
var shellAttachCommand = new
|
|
12228
|
+
var shellAttachCommand = new Command38("attach").description(
|
|
11973
12229
|
"Attach to a shell tmux session in a box, starting one if none is running (auto-unpause/start)"
|
|
11974
12230
|
).argument(
|
|
11975
12231
|
"[box]",
|
|
@@ -12007,7 +12263,7 @@ function renderShellTable(sessions) {
|
|
|
12007
12263
|
for (const r of rows) process.stdout.write(`${fmt(r)}
|
|
12008
12264
|
`);
|
|
12009
12265
|
}
|
|
12010
|
-
var shellLsCommand = new
|
|
12266
|
+
var shellLsCommand = new Command38("ls").description("List the shell tmux sessions running in a box").argument(
|
|
12011
12267
|
"[box]",
|
|
12012
12268
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
12013
12269
|
).action(async (idOrName) => {
|
|
@@ -12016,11 +12272,11 @@ var shellLsCommand = new Command37("ls").description("List the shell tmux sessio
|
|
|
12016
12272
|
requireDockerProvider(box, "shell");
|
|
12017
12273
|
const insp = await inspectBox(box.id);
|
|
12018
12274
|
if (insp.state !== "running") {
|
|
12019
|
-
|
|
12275
|
+
log40.info(`box ${box.name} is ${insp.state} \u2014 no live shell sessions`);
|
|
12020
12276
|
return;
|
|
12021
12277
|
}
|
|
12022
12278
|
if (insp.shellSessions.length === 0) {
|
|
12023
|
-
|
|
12279
|
+
log40.info(
|
|
12024
12280
|
`no shell sessions in ${box.name} \u2014 start one with: agentbox shell ${reattachRef4(box)}`
|
|
12025
12281
|
);
|
|
12026
12282
|
return;
|
|
@@ -12030,7 +12286,7 @@ var shellLsCommand = new Command37("ls").description("List the shell tmux sessio
|
|
|
12030
12286
|
handleLifecycleError(err);
|
|
12031
12287
|
}
|
|
12032
12288
|
});
|
|
12033
|
-
var shellKillCommand = new
|
|
12289
|
+
var shellKillCommand = new Command38("kill").description("Kill a shell tmux session in a box (the shell and anything running in it)").argument(
|
|
12034
12290
|
"[box]",
|
|
12035
12291
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
12036
12292
|
).option("-n, --name <label>", "shell label to kill (default: the box default shell)").option("--all", "kill every shell session in the box").action(async function(idOrName) {
|
|
@@ -12040,25 +12296,25 @@ var shellKillCommand = new Command37("kill").description("Kill a shell tmux sess
|
|
|
12040
12296
|
requireDockerProvider(box, "shell");
|
|
12041
12297
|
const insp = await inspectBox(box.id);
|
|
12042
12298
|
if (insp.state !== "running") {
|
|
12043
|
-
|
|
12299
|
+
log40.info(`box ${box.name} is ${insp.state} \u2014 no shell sessions to kill`);
|
|
12044
12300
|
return;
|
|
12045
12301
|
}
|
|
12046
12302
|
if (opts.all) {
|
|
12047
12303
|
if (insp.shellSessions.length === 0) {
|
|
12048
|
-
|
|
12304
|
+
log40.info(`no shell sessions in ${box.name}`);
|
|
12049
12305
|
return;
|
|
12050
12306
|
}
|
|
12051
12307
|
let killed = 0;
|
|
12052
12308
|
for (const s of insp.shellSessions) {
|
|
12053
12309
|
if (await killShellSession(box.container, s.sessionName)) killed++;
|
|
12054
12310
|
}
|
|
12055
|
-
|
|
12311
|
+
log40.success(`killed ${String(killed)} shell session${killed === 1 ? "" : "s"} in ${box.name}`);
|
|
12056
12312
|
return;
|
|
12057
12313
|
}
|
|
12058
12314
|
const target = shellSessionName(opts.name);
|
|
12059
12315
|
const ok = await killShellSession(box.container, target);
|
|
12060
|
-
if (ok)
|
|
12061
|
-
else
|
|
12316
|
+
if (ok) log40.success(`killed shell "${shellLabel(target)}" in ${box.name}`);
|
|
12317
|
+
else log40.warn(`no shell "${shellLabel(target)}" in ${box.name} (already gone?)`);
|
|
12062
12318
|
} catch (err) {
|
|
12063
12319
|
handleLifecycleError(err);
|
|
12064
12320
|
}
|
|
@@ -12068,8 +12324,8 @@ shellCommand.addCommand(shellLsCommand);
|
|
|
12068
12324
|
shellCommand.addCommand(shellKillCommand);
|
|
12069
12325
|
|
|
12070
12326
|
// src/commands/start.ts
|
|
12071
|
-
import { Command as
|
|
12072
|
-
var startCommand = new
|
|
12327
|
+
import { Command as Command39 } from "commander";
|
|
12328
|
+
var startCommand = new Command39("start").description(
|
|
12073
12329
|
"Start a stopped box. Docker: docker start + relaunch ctl/dockerd/vnc daemons. Cloud: backend.start, then re-resolve preview URLs/tokens, re-launch in-sandbox ctl/dockerd daemons, and re-register with the host relay (so the CloudBoxPoller resumes)."
|
|
12074
12330
|
).argument(
|
|
12075
12331
|
"[box]",
|
|
@@ -12092,8 +12348,8 @@ var startCommand = new Command38("start").description(
|
|
|
12092
12348
|
});
|
|
12093
12349
|
|
|
12094
12350
|
// src/commands/status.ts
|
|
12095
|
-
import { log as
|
|
12096
|
-
import { Command as
|
|
12351
|
+
import { log as log42 } from "@clack/prompts";
|
|
12352
|
+
import { Command as Command40 } from "commander";
|
|
12097
12353
|
|
|
12098
12354
|
// src/endpoints-render.ts
|
|
12099
12355
|
function renderEndpointLines(endpoints, stream) {
|
|
@@ -12123,7 +12379,7 @@ function renderEndpointLines(endpoints, stream) {
|
|
|
12123
12379
|
}
|
|
12124
12380
|
|
|
12125
12381
|
// src/commands/inspect.ts
|
|
12126
|
-
import { log as
|
|
12382
|
+
import { log as log41 } from "@clack/prompts";
|
|
12127
12383
|
function fmtLimit(n, unit) {
|
|
12128
12384
|
return n && n > 0 ? `${String(n)}${unit}` : "unlimited";
|
|
12129
12385
|
}
|
|
@@ -12268,7 +12524,7 @@ function renderCodexActivityCloud(persisted) {
|
|
|
12268
12524
|
async function runInspect(box, opts) {
|
|
12269
12525
|
try {
|
|
12270
12526
|
if (opts.json && opts.watch) {
|
|
12271
|
-
|
|
12527
|
+
log41.error("cannot combine --json with --watch");
|
|
12272
12528
|
process.exit(2);
|
|
12273
12529
|
}
|
|
12274
12530
|
const isCloud = (box.provider ?? "docker") !== "docker";
|
|
@@ -12305,14 +12561,14 @@ async function runInspect(box, opts) {
|
|
|
12305
12561
|
|
|
12306
12562
|
// src/commands/status.ts
|
|
12307
12563
|
var statusCommand2 = withWatchOptions(
|
|
12308
|
-
new
|
|
12564
|
+
new Command40("status").description("Show service + task status from a box's agentbox-ctl daemon").argument(
|
|
12309
12565
|
"[box]",
|
|
12310
12566
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
12311
12567
|
).option("-j, --json", "machine-readable JSON output").option("--inspect", "show detailed box info (volumes, limits, paths) instead of service/task status")
|
|
12312
12568
|
).action(async (idOrName, opts) => {
|
|
12313
12569
|
try {
|
|
12314
12570
|
if (opts.json && opts.watch) {
|
|
12315
|
-
|
|
12571
|
+
log42.error("cannot combine --json with --watch");
|
|
12316
12572
|
process.exit(2);
|
|
12317
12573
|
}
|
|
12318
12574
|
const box = await resolveBoxOrExit(idOrName);
|
|
@@ -12479,8 +12735,8 @@ function renderPersisted2(s, state) {
|
|
|
12479
12735
|
}
|
|
12480
12736
|
|
|
12481
12737
|
// src/commands/stop.ts
|
|
12482
|
-
import { Command as
|
|
12483
|
-
var stopCommand = new
|
|
12738
|
+
import { Command as Command41 } from "commander";
|
|
12739
|
+
var stopCommand = new Command41("stop").description(
|
|
12484
12740
|
"Stop a box (Docker: docker stop; preserves upper + node_modules volumes. Cloud: backend.stop \u2014 sandbox stays in your account, disk preserved)."
|
|
12485
12741
|
).argument(
|
|
12486
12742
|
"[box]",
|
|
@@ -12509,7 +12765,7 @@ restart with: agentbox start ${box.name}
|
|
|
12509
12765
|
});
|
|
12510
12766
|
|
|
12511
12767
|
// src/commands/top.ts
|
|
12512
|
-
import { Command as
|
|
12768
|
+
import { Command as Command42 } from "commander";
|
|
12513
12769
|
var COLS = ["BOX", "STATE", "CPU%", "MEM USAGE / LIMIT", "MEM%", "PIDS", "DISK", "NET I/O"];
|
|
12514
12770
|
function row(name, state, s) {
|
|
12515
12771
|
const mem = `${fmtBytes(s.memUsedBytes)} / ${fmtBytes(s.memLimitBytes)}`;
|
|
@@ -12583,7 +12839,7 @@ async function renderProjectFooters() {
|
|
|
12583
12839
|
|
|
12584
12840
|
SYSTEM: ${parts.join(" - ")}` : "";
|
|
12585
12841
|
}
|
|
12586
|
-
var topCommand = new
|
|
12842
|
+
var topCommand = new Command42("top").description("Live resource monitor (cpu/mem/pids/disk) for a box, the project, or every box").argument(
|
|
12587
12843
|
"[box]",
|
|
12588
12844
|
"box ref (default: every box on the host; --project narrows to the cwd's project)"
|
|
12589
12845
|
).option("-p, --project", "show only boxes in the cwd's project").option("--once", "print a single snapshot instead of watching").option("-j, --json", "machine-readable JSON (implies --once)").option("--interval <seconds>", "refresh interval", "2").option("--live", "probe live cloud state via the provider SDK (slower; default: last host-known)").action(async (idOrName, opts) => {
|
|
@@ -12616,8 +12872,8 @@ var topCommand = new Command41("top").description("Live resource monitor (cpu/me
|
|
|
12616
12872
|
});
|
|
12617
12873
|
|
|
12618
12874
|
// src/commands/unpause.ts
|
|
12619
|
-
import { Command as
|
|
12620
|
-
var unpauseCommand = new
|
|
12875
|
+
import { Command as Command43 } from "commander";
|
|
12876
|
+
var unpauseCommand = new Command43("unpause").description(
|
|
12621
12877
|
"Resume a paused box. Docker: `docker unpause` (sub-second). Cloud: backend.resume (re-hydrates from archive \u2014 slower first time)."
|
|
12622
12878
|
).argument(
|
|
12623
12879
|
"[box]",
|
|
@@ -12641,8 +12897,8 @@ var unpauseCommand = new Command42("unpause").description(
|
|
|
12641
12897
|
|
|
12642
12898
|
// src/commands/update.ts
|
|
12643
12899
|
import { spawn as spawn4 } from "child_process";
|
|
12644
|
-
import { confirm as confirm16, intro as
|
|
12645
|
-
import { Command as
|
|
12900
|
+
import { confirm as confirm16, intro as intro9, isCancel as isCancel17, log as log43, outro as outro8, spinner as spinner10 } from "@clack/prompts";
|
|
12901
|
+
import { Command as Command44 } from "commander";
|
|
12646
12902
|
|
|
12647
12903
|
// src/exec-method.ts
|
|
12648
12904
|
function detectExecutionMethod(input) {
|
|
@@ -12686,7 +12942,7 @@ function runInherit(cmd, args) {
|
|
|
12686
12942
|
child.on("close", (code) => resolveP(code ?? 0));
|
|
12687
12943
|
});
|
|
12688
12944
|
}
|
|
12689
|
-
var updateCommand = new
|
|
12945
|
+
var updateCommand = new Command44("self-update").description(
|
|
12690
12946
|
"Update agentbox: self-update via npm/pnpm (unless run via npx), refresh the host skills, wipe the box image so it rebuilds, and reload the relay"
|
|
12691
12947
|
).option("-y, --yes", "skip the confirmation prompt").option("--dry-run", "show what would happen, don't change anything").option("--skip-self", "skip the package self-update; only refresh the skills + image + relay").option("--skip-skills", "skip refreshing the host skill files in ~/.claude, ~/.codex, ~/.config/opencode").action(async (opts) => {
|
|
12692
12948
|
try {
|
|
@@ -12694,10 +12950,10 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12694
12950
|
userAgent: process.env.npm_config_user_agent,
|
|
12695
12951
|
argv1: process.argv[1]
|
|
12696
12952
|
});
|
|
12697
|
-
|
|
12953
|
+
intro9("agentbox self-update");
|
|
12698
12954
|
const selfStep = opts.skipSelf ? "self-update: skipped (--skip-self)" : describeSelfUpdate(method);
|
|
12699
12955
|
const skillsStep = opts.skipSkills ? "skills: skipped (--skip-skills)" : "skills: refresh agentbox-managed host skill files in ~/.claude (and Codex/OpenCode)";
|
|
12700
|
-
|
|
12956
|
+
log43.info(
|
|
12701
12957
|
[
|
|
12702
12958
|
"plan:",
|
|
12703
12959
|
` ${selfStep}`,
|
|
@@ -12707,41 +12963,41 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12707
12963
|
].join("\n")
|
|
12708
12964
|
);
|
|
12709
12965
|
if (opts.dryRun) {
|
|
12710
|
-
|
|
12966
|
+
outro8("dry run \u2014 nothing changed");
|
|
12711
12967
|
return;
|
|
12712
12968
|
}
|
|
12713
12969
|
if (!opts.yes) {
|
|
12714
12970
|
const ok = await confirm16({ message: "Proceed with update?", initialValue: true });
|
|
12715
12971
|
if (isCancel17(ok) || !ok) {
|
|
12716
|
-
|
|
12972
|
+
log43.info("cancelled");
|
|
12717
12973
|
return;
|
|
12718
12974
|
}
|
|
12719
12975
|
}
|
|
12720
12976
|
let selfUpdated = false;
|
|
12721
12977
|
if (opts.skipSelf) {
|
|
12722
|
-
|
|
12978
|
+
log43.info("skipping self-update (--skip-self)");
|
|
12723
12979
|
} else {
|
|
12724
12980
|
const cmd = selfUpdateCommand(method);
|
|
12725
12981
|
if (cmd === null) {
|
|
12726
|
-
|
|
12982
|
+
log43.info(describeSelfUpdate(method));
|
|
12727
12983
|
} else {
|
|
12728
|
-
|
|
12984
|
+
log43.info(`running: ${cmd.cmd} ${cmd.args.join(" ")}`);
|
|
12729
12985
|
const code = await runInherit(cmd.cmd, cmd.args);
|
|
12730
12986
|
if (code !== 0) {
|
|
12731
12987
|
throw new Error(`${cmd.cmd} exited with code ${String(code)}`);
|
|
12732
12988
|
}
|
|
12733
12989
|
selfUpdated = true;
|
|
12734
|
-
|
|
12990
|
+
log43.success(`updated ${PKG} via ${cmd.cmd}`);
|
|
12735
12991
|
}
|
|
12736
12992
|
}
|
|
12737
12993
|
if (opts.skipSkills) {
|
|
12738
|
-
|
|
12994
|
+
log43.info("skipping skills refresh (--skip-skills)");
|
|
12739
12995
|
} else if (selfUpdated) {
|
|
12740
12996
|
const code = await runInherit("agentbox", ["install", "--skills-only"]);
|
|
12741
12997
|
if (code === 0) {
|
|
12742
|
-
|
|
12998
|
+
log43.success("refreshed host skills (via updated build)");
|
|
12743
12999
|
} else {
|
|
12744
|
-
|
|
13000
|
+
log43.warn(
|
|
12745
13001
|
`host skills not refreshed (agentbox install --skills-only exited ${String(code)}) \u2014 run it manually to pick up the new versions`
|
|
12746
13002
|
);
|
|
12747
13003
|
}
|
|
@@ -12749,17 +13005,17 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12749
13005
|
try {
|
|
12750
13006
|
const res = installHostSkills({ quiet: true });
|
|
12751
13007
|
if (res.written.length > 0) {
|
|
12752
|
-
|
|
13008
|
+
log43.success(`refreshed host skills (${String(res.written.length)} file(s))`);
|
|
12753
13009
|
} else {
|
|
12754
|
-
|
|
13010
|
+
log43.info(`host skills already current (${String(res.skipped)} skipped)`);
|
|
12755
13011
|
}
|
|
12756
13012
|
if (res.blocked.length > 0) {
|
|
12757
|
-
|
|
13013
|
+
log43.warn(
|
|
12758
13014
|
`user-modified skill file(s) left in place: ${res.blocked.join(", ")} \u2014 run \`agentbox install --skills-only --force\` to overwrite`
|
|
12759
13015
|
);
|
|
12760
13016
|
}
|
|
12761
13017
|
} catch (err) {
|
|
12762
|
-
|
|
13018
|
+
log43.warn(
|
|
12763
13019
|
`host skills not refreshed (${err instanceof Error ? err.message : String(err)})`
|
|
12764
13020
|
);
|
|
12765
13021
|
}
|
|
@@ -12777,7 +13033,7 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12777
13033
|
stop.stopped ? `stopped relay (pid ${String(stop.pid)})` : "relay was not running"
|
|
12778
13034
|
);
|
|
12779
13035
|
if (selfUpdated) {
|
|
12780
|
-
|
|
13036
|
+
log43.info(
|
|
12781
13037
|
"relay will restart automatically (with the updated build) on your next `agentbox create` / `agentbox claude`"
|
|
12782
13038
|
);
|
|
12783
13039
|
} else {
|
|
@@ -12788,12 +13044,12 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12788
13044
|
sr2.stop(`relay back up on ${ep.hostUrl}`);
|
|
12789
13045
|
} catch (err) {
|
|
12790
13046
|
sr2.stop("relay restart failed");
|
|
12791
|
-
|
|
13047
|
+
log43.warn(
|
|
12792
13048
|
`${err instanceof Error ? err.message : String(err)} \u2014 it will retry on the next box command`
|
|
12793
13049
|
);
|
|
12794
13050
|
}
|
|
12795
13051
|
}
|
|
12796
|
-
|
|
13052
|
+
outro8("update complete");
|
|
12797
13053
|
} catch (err) {
|
|
12798
13054
|
handleLifecycleError(err);
|
|
12799
13055
|
}
|
|
@@ -12801,8 +13057,8 @@ var updateCommand = new Command43("self-update").description(
|
|
|
12801
13057
|
|
|
12802
13058
|
// src/commands/url.ts
|
|
12803
13059
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
12804
|
-
import { log as
|
|
12805
|
-
import { Command as
|
|
13060
|
+
import { log as log44 } from "@clack/prompts";
|
|
13061
|
+
import { Command as Command45 } from "commander";
|
|
12806
13062
|
var SIGNED_URL_TTL_MIN2 = 1;
|
|
12807
13063
|
var SIGNED_URL_TTL_MAX2 = 86400;
|
|
12808
13064
|
function parseTtlOrExit2(raw) {
|
|
@@ -12815,7 +13071,7 @@ function parseTtlOrExit2(raw) {
|
|
|
12815
13071
|
}
|
|
12816
13072
|
return n;
|
|
12817
13073
|
}
|
|
12818
|
-
var urlCommand = new
|
|
13074
|
+
var urlCommand = new Command45("url").description(
|
|
12819
13075
|
"Open a box's web app URL in the browser, even when no service declares `expose:` (auto-unpause/start)"
|
|
12820
13076
|
).argument(
|
|
12821
13077
|
"[box]",
|
|
@@ -12834,10 +13090,10 @@ var urlCommand = new Command44("url").description(
|
|
|
12834
13090
|
if (provider === "docker") {
|
|
12835
13091
|
const insp = await inspectBox(box.id);
|
|
12836
13092
|
if (insp.state === "paused") {
|
|
12837
|
-
|
|
13093
|
+
log44.info("box is paused; unpausing");
|
|
12838
13094
|
await unpauseBox(box.id);
|
|
12839
13095
|
} else if (insp.state === "stopped") {
|
|
12840
|
-
|
|
13096
|
+
log44.info("box is stopped; starting");
|
|
12841
13097
|
await startBox(box.id);
|
|
12842
13098
|
} else if (insp.state === "missing") {
|
|
12843
13099
|
throw new Error(`box ${box.name} has no container; was it destroyed?`);
|
|
@@ -12866,10 +13122,10 @@ var urlCommand = new Command44("url").description(
|
|
|
12866
13122
|
const p = await providerForBox(box);
|
|
12867
13123
|
const state = await p.probeState(box);
|
|
12868
13124
|
if (state === "paused") {
|
|
12869
|
-
|
|
13125
|
+
log44.info("box is paused; resuming");
|
|
12870
13126
|
await p.resume(box);
|
|
12871
13127
|
} else if (state === "stopped") {
|
|
12872
|
-
|
|
13128
|
+
log44.info("box is stopped; starting");
|
|
12873
13129
|
await p.start(box);
|
|
12874
13130
|
} else if (state === "missing") {
|
|
12875
13131
|
throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
|
|
@@ -12893,9 +13149,9 @@ var urlCommand = new Command44("url").description(
|
|
|
12893
13149
|
});
|
|
12894
13150
|
|
|
12895
13151
|
// src/commands/wait.ts
|
|
12896
|
-
import { log as
|
|
12897
|
-
import { Command as
|
|
12898
|
-
var waitCommand = new
|
|
13152
|
+
import { log as log45 } from "@clack/prompts";
|
|
13153
|
+
import { Command as Command46 } from "commander";
|
|
13154
|
+
var waitCommand = new Command46("wait").description("Block until the box reports all autostart units ready").argument(
|
|
12899
13155
|
"[box]",
|
|
12900
13156
|
"box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
|
|
12901
13157
|
).option("--timeout <ms>", "overall timeout in milliseconds", "120000").option("--units <names...>", "restrict to the named units").option("-j, --json", "machine-readable JSON output").action(async (idOrName, opts) => {
|
|
@@ -12911,7 +13167,7 @@ var waitCommand = new Command45("wait").description("Block until the box reports
|
|
|
12911
13167
|
try {
|
|
12912
13168
|
parsed = JSON.parse(proc.stdout);
|
|
12913
13169
|
} catch {
|
|
12914
|
-
|
|
13170
|
+
log45.error(`agentbox-ctl wait-ready failed: ${proc.stderr || proc.stdout}`);
|
|
12915
13171
|
process.exit(1);
|
|
12916
13172
|
}
|
|
12917
13173
|
if (opts.json) {
|
|
@@ -12950,7 +13206,7 @@ function rewriteProviderPrefix(argv2) {
|
|
|
12950
13206
|
process.env.DOCKER_CLI_HINTS ??= "false";
|
|
12951
13207
|
process.env.AGENTBOX_CLI_VERSION = AGENTBOX_VERSION;
|
|
12952
13208
|
process.env.AGENTBOX_CLI_COMMIT = AGENTBOX_COMMIT;
|
|
12953
|
-
var program = new
|
|
13209
|
+
var program = new Command47();
|
|
12954
13210
|
program.name("agentbox").description("Launch coding agents in isolated sandboxes").version(AGENTBOX_VERSION);
|
|
12955
13211
|
program.enablePositionalOptions();
|
|
12956
13212
|
program.addCommand(createCommand);
|