@madarco/agentbox 0.12.0 → 0.14.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 +96 -0
- package/README.md +21 -7
- package/dist/{_cloud-attach-XKO4SHR3.js → _cloud-attach-GUBB5RH2.js} +4 -4
- package/dist/{chunk-R5XIDQFR.js → chunk-BKU34KYY.js} +170 -6
- package/dist/chunk-BKU34KYY.js.map +1 -0
- package/dist/{chunk-HFV6THYG.js → chunk-BYCLD6D6.js} +308 -36
- package/dist/chunk-BYCLD6D6.js.map +1 -0
- package/dist/chunk-LDMYHWUS.js +346 -0
- package/dist/chunk-LDMYHWUS.js.map +1 -0
- package/dist/{chunk-2LF5YILI.js → chunk-RSKG7AFU.js} +80 -6
- package/dist/chunk-RSKG7AFU.js.map +1 -0
- package/dist/{chunk-DHJ7OMIP.js → chunk-TBSIJVSN.js} +149 -47
- package/dist/chunk-TBSIJVSN.js.map +1 -0
- package/dist/{chunk-IZXPJPPV.js → chunk-TCS5HXJX.js} +389 -176
- package/dist/chunk-TCS5HXJX.js.map +1 -0
- package/dist/{chunk-ECLLV5JH.js → chunk-VATTS2MR.js} +156 -5
- package/dist/chunk-VATTS2MR.js.map +1 -0
- package/dist/{chunk-SNTHHWKY.js → chunk-XKH7NTT7.js} +80 -22
- package/dist/chunk-XKH7NTT7.js.map +1 -0
- package/dist/dist-34RKQ74M.js +662 -0
- package/dist/dist-34RKQ74M.js.map +1 -0
- package/dist/{dist-47LVLYUV.js → dist-3IMQNTTV.js} +14 -69
- package/dist/dist-3IMQNTTV.js.map +1 -0
- package/dist/{dist-RZZSSUNB.js → dist-4DPOL5A7.js} +5 -3
- package/dist/{dist-24PY2ZMO.js → dist-57M6ZA7H.js} +25 -177
- package/dist/dist-57M6ZA7H.js.map +1 -0
- package/dist/{dist-SWUOU34W.js → dist-J2IHD5T7.js} +37 -226
- package/dist/dist-J2IHD5T7.js.map +1 -0
- package/dist/index.js +1524 -921
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js → prepared-state-MQHD3M5F-Q27AZU53.js} +2 -2
- package/package.json +9 -7
- package/runtime/docker/Dockerfile.box +21 -26
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +37 -1
- package/runtime/docker/packages/ctl/dist/bin.cjs +46 -17
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +17 -6
- package/runtime/docker/packages/sandbox-docker/scripts/chromium-resolver +57 -0
- package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +2 -1
- package/runtime/e2b/agentbox-checkpoint-cleanup +52 -0
- package/runtime/e2b/agentbox-codex-hooks.json +68 -0
- package/runtime/e2b/agentbox-open +28 -0
- package/runtime/e2b/agentbox-setup-skill.md +233 -0
- package/runtime/e2b/agentbox-vnc-start +102 -0
- package/runtime/e2b/attach-helper.cjs +167 -0
- package/runtime/e2b/claude-managed-settings.json +116 -0
- package/runtime/e2b/ctl.cjs +23864 -0
- package/runtime/e2b/custom-system-CLAUDE.md +46 -0
- package/runtime/e2b/gh-shim +344 -0
- package/runtime/e2b/git-shim +131 -0
- package/runtime/e2b/scripts/build-template.sh +295 -0
- package/runtime/hetzner/agentbox-setup-skill.md +37 -1
- package/runtime/hetzner/agentbox-vnc-start +17 -6
- package/runtime/hetzner/claude-managed-settings.json +2 -1
- package/runtime/hetzner/ctl.cjs +46 -17
- package/runtime/relay/bin.cjs +305 -230
- package/runtime/vercel/agentbox-setup-skill.md +37 -1
- package/runtime/vercel/agentbox-vnc-start +17 -6
- package/runtime/vercel/claude-managed-settings.json +2 -1
- package/runtime/vercel/ctl.cjs +46 -17
- package/share/agentbox-setup/SKILL.md +37 -1
- package/share/host-skills/agentbox-info/SKILL.md +26 -34
- package/dist/chunk-2LF5YILI.js.map +0 -1
- package/dist/chunk-DHJ7OMIP.js.map +0 -1
- package/dist/chunk-ECLLV5JH.js.map +0 -1
- package/dist/chunk-HFV6THYG.js.map +0 -1
- package/dist/chunk-IZXPJPPV.js.map +0 -1
- package/dist/chunk-R5XIDQFR.js.map +0 -1
- package/dist/chunk-SNTHHWKY.js.map +0 -1
- package/dist/dist-24PY2ZMO.js.map +0 -1
- package/dist/dist-47LVLYUV.js.map +0 -1
- package/dist/dist-SWUOU34W.js.map +0 -1
- /package/dist/{_cloud-attach-XKO4SHR3.js.map → _cloud-attach-GUBB5RH2.js.map} +0 -0
- /package/dist/{dist-RZZSSUNB.js.map → dist-4DPOL5A7.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js.map → prepared-state-MQHD3M5F-Q27AZU53.js.map} +0 -0
|
@@ -1,42 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_RELAY_PORT,
|
|
4
|
+
loadEffectiveConfig,
|
|
4
5
|
readBoxStatus
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TCS5HXJX.js";
|
|
6
7
|
|
|
7
8
|
// src/commands/_cloud-attach.ts
|
|
8
|
-
import { spawn as
|
|
9
|
+
import { spawn as spawn4 } from "child_process";
|
|
9
10
|
import { appendFileSync } from "fs";
|
|
10
11
|
import { homedir } from "os";
|
|
11
12
|
import { join as join2 } from "path";
|
|
12
13
|
import { spinner } from "@clack/prompts";
|
|
13
14
|
|
|
14
15
|
// src/provider/registry.ts
|
|
15
|
-
var KNOWN = ["docker", "daytona", "hetzner", "vercel"];
|
|
16
|
+
var KNOWN = ["docker", "daytona", "hetzner", "vercel", "e2b"];
|
|
16
17
|
function isKnownProvider(name) {
|
|
17
18
|
return KNOWN.includes(name);
|
|
18
19
|
}
|
|
19
20
|
async function getProvider(name) {
|
|
20
21
|
switch (name) {
|
|
21
22
|
case "docker": {
|
|
22
|
-
const mod = await import("./dist-
|
|
23
|
+
const mod = await import("./dist-4DPOL5A7.js");
|
|
23
24
|
return mod.dockerProvider;
|
|
24
25
|
}
|
|
25
26
|
case "daytona": {
|
|
26
|
-
const mod = await import("./dist-
|
|
27
|
+
const mod = await import("./dist-3IMQNTTV.js");
|
|
27
28
|
await mod.ensureDaytonaCredentials();
|
|
28
29
|
return mod.daytonaProvider;
|
|
29
30
|
}
|
|
30
31
|
case "hetzner": {
|
|
31
|
-
const mod = await import("./dist-
|
|
32
|
+
const mod = await import("./dist-J2IHD5T7.js");
|
|
32
33
|
await mod.ensureHetznerCredentials();
|
|
33
34
|
return mod.hetznerProvider;
|
|
34
35
|
}
|
|
35
36
|
case "vercel": {
|
|
36
|
-
const mod = await import("./dist-
|
|
37
|
+
const mod = await import("./dist-57M6ZA7H.js");
|
|
37
38
|
await mod.ensureVercelCredentials();
|
|
38
39
|
return mod.vercelProvider;
|
|
39
40
|
}
|
|
41
|
+
case "e2b": {
|
|
42
|
+
const mod = await import("./dist-34RKQ74M.js");
|
|
43
|
+
await mod.ensureE2bCredentials();
|
|
44
|
+
return mod.e2bProvider;
|
|
45
|
+
}
|
|
40
46
|
default:
|
|
41
47
|
throw new Error(`unknown sandbox provider: ${String(name)}`);
|
|
42
48
|
}
|
|
@@ -56,20 +62,20 @@ async function providerForCreate(choice) {
|
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
// src/wrapped-pty/run.ts
|
|
59
|
-
import { spawn as
|
|
65
|
+
import { spawn as spawn3, spawnSync as spawnSync2 } from "child_process";
|
|
60
66
|
|
|
61
67
|
// src/pty/pty-backend.ts
|
|
62
68
|
async function loadPtyBackend() {
|
|
63
69
|
try {
|
|
64
70
|
const ptyMod = await import("@homebridge/node-pty-prebuilt-multiarch");
|
|
65
71
|
const xtermMod = await import("@xterm/headless");
|
|
66
|
-
const
|
|
72
|
+
const spawn5 = ptyMod["spawn"] ?? ptyMod["default"]?.["spawn"];
|
|
67
73
|
const Terminal = xtermMod["Terminal"] ?? xtermMod["default"]?.["Terminal"];
|
|
68
|
-
if (typeof
|
|
74
|
+
if (typeof spawn5 !== "function" || typeof Terminal !== "function") {
|
|
69
75
|
return null;
|
|
70
76
|
}
|
|
71
77
|
return {
|
|
72
|
-
ptySpawn:
|
|
78
|
+
ptySpawn: spawn5,
|
|
73
79
|
termCtor: Terminal
|
|
74
80
|
};
|
|
75
81
|
} catch {
|
|
@@ -82,10 +88,16 @@ import { spawn } from "child_process";
|
|
|
82
88
|
function detectHostTerminal(env = process.env) {
|
|
83
89
|
const tmux = env["TMUX"];
|
|
84
90
|
if (tmux && tmux.length > 0) return "tmux";
|
|
91
|
+
const cmuxSocket = env["CMUX_SOCKET_PATH"];
|
|
92
|
+
if (cmuxSocket && cmuxSocket.length > 0) return "cmux";
|
|
85
93
|
const termProgram = env["TERM_PROGRAM"];
|
|
86
94
|
if (termProgram === "iTerm.app") return "iterm2";
|
|
87
95
|
return "unknown";
|
|
88
96
|
}
|
|
97
|
+
function cmuxBinary(env = process.env) {
|
|
98
|
+
const bundled = env["CMUX_BUNDLED_CLI_PATH"];
|
|
99
|
+
return bundled && bundled.length > 0 ? bundled : "cmux";
|
|
100
|
+
}
|
|
89
101
|
function shellQuote(s) {
|
|
90
102
|
if (s.length === 0) return "''";
|
|
91
103
|
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
@@ -98,6 +110,7 @@ function shellJoin(argv) {
|
|
|
98
110
|
}
|
|
99
111
|
async function spawnInNewTerminal(args) {
|
|
100
112
|
if (args.host === "tmux") return spawnInTmux(args);
|
|
113
|
+
if (args.host === "cmux") return spawnInCmux(args);
|
|
101
114
|
return spawnInITerm2(args);
|
|
102
115
|
}
|
|
103
116
|
async function spawnInTmux(args) {
|
|
@@ -124,6 +137,63 @@ async function spawnInTmux(args) {
|
|
|
124
137
|
note: `Attached in new ${noteKind}.`
|
|
125
138
|
};
|
|
126
139
|
}
|
|
140
|
+
async function spawnInCmux(args) {
|
|
141
|
+
const bin = cmuxBinary();
|
|
142
|
+
if (args.mode === "window") {
|
|
143
|
+
const r = await runQuiet(bin, [
|
|
144
|
+
"new-workspace",
|
|
145
|
+
"--name",
|
|
146
|
+
args.title,
|
|
147
|
+
"--cwd",
|
|
148
|
+
args.cwd,
|
|
149
|
+
"--command",
|
|
150
|
+
shellJoin(args.argv),
|
|
151
|
+
"--focus",
|
|
152
|
+
"true"
|
|
153
|
+
]);
|
|
154
|
+
if (r.code !== 0) {
|
|
155
|
+
return {
|
|
156
|
+
launched: false,
|
|
157
|
+
note: "",
|
|
158
|
+
error: `cmux new-workspace exited ${String(r.code)}: ${r.stderr.trim()}`
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return { launched: true, note: "Attached in new cmux workspace." };
|
|
162
|
+
}
|
|
163
|
+
const createArgv = args.mode === "split" ? ["new-split", "right", "--focus", "true"] : ["new-surface", "--focus", "true"];
|
|
164
|
+
const noteKind = args.mode === "split" ? "cmux split" : "cmux tab";
|
|
165
|
+
const created = await runQuiet(bin, createArgv);
|
|
166
|
+
if (created.code !== 0) {
|
|
167
|
+
return {
|
|
168
|
+
launched: false,
|
|
169
|
+
note: "",
|
|
170
|
+
error: `cmux ${createArgv[0]} exited ${String(created.code)}: ${created.stderr.trim()}`
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const surfaceRef = parseCmuxRef(created.stdout);
|
|
174
|
+
if (!surfaceRef) {
|
|
175
|
+
return {
|
|
176
|
+
launched: false,
|
|
177
|
+
note: "",
|
|
178
|
+
error: `cmux ${createArgv[0]} gave no surface ref: ${created.stdout.trim()}`
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const cmdLine = `cd ${shellQuote(args.cwd)} && exec ${shellJoin(args.argv)}`;
|
|
182
|
+
const sent = await runQuiet(bin, ["send", "--surface", surfaceRef, `${cmdLine}
|
|
183
|
+
`]);
|
|
184
|
+
if (sent.code !== 0) {
|
|
185
|
+
return {
|
|
186
|
+
launched: false,
|
|
187
|
+
note: "",
|
|
188
|
+
error: `cmux send exited ${String(sent.code)}: ${sent.stderr.trim()}`
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return { launched: true, note: `Attached in new ${noteKind}.` };
|
|
192
|
+
}
|
|
193
|
+
function parseCmuxRef(stdout) {
|
|
194
|
+
const m = stdout.match(/\b(?:surface|pane):\d+\b/);
|
|
195
|
+
return m ? m[0] : void 0;
|
|
196
|
+
}
|
|
127
197
|
async function spawnInITerm2(args) {
|
|
128
198
|
const inner = shellJoin(args.argv);
|
|
129
199
|
const cmdLine = `cd ${shellQuote(args.cwd)} && exec ${inner}`;
|
|
@@ -174,20 +244,139 @@ async function spawnInITerm2(args) {
|
|
|
174
244
|
}
|
|
175
245
|
function runQuiet(cmd, argv) {
|
|
176
246
|
return new Promise((resolve) => {
|
|
177
|
-
const child = spawn(cmd, argv, { stdio: ["ignore", "
|
|
247
|
+
const child = spawn(cmd, argv, { stdio: ["ignore", "pipe", "pipe"] });
|
|
248
|
+
let stdout = "";
|
|
178
249
|
let stderr = "";
|
|
250
|
+
child.stdout?.on("data", (chunk) => {
|
|
251
|
+
stdout += chunk.toString("utf8");
|
|
252
|
+
});
|
|
179
253
|
child.stderr?.on("data", (chunk) => {
|
|
180
254
|
stderr += chunk.toString("utf8");
|
|
181
255
|
});
|
|
182
256
|
child.on("error", (err) => {
|
|
183
|
-
resolve({ code: 127, stderr: err.message });
|
|
257
|
+
resolve({ code: 127, stdout, stderr: err.message });
|
|
184
258
|
});
|
|
185
259
|
child.on("exit", (code) => {
|
|
186
|
-
resolve({ code: typeof code === "number" ? code : 1, stderr });
|
|
260
|
+
resolve({ code: typeof code === "number" ? code : 1, stdout, stderr });
|
|
187
261
|
});
|
|
188
262
|
});
|
|
189
263
|
}
|
|
190
264
|
|
|
265
|
+
// src/terminal/cmux-status.ts
|
|
266
|
+
import { spawn as spawn2, spawnSync } from "child_process";
|
|
267
|
+
var AGENT_LABEL = {
|
|
268
|
+
claude: "claude",
|
|
269
|
+
codex: "codex",
|
|
270
|
+
opencode: "opencode"
|
|
271
|
+
};
|
|
272
|
+
function mapActivityToWorkspace(mode, activity) {
|
|
273
|
+
if (mode === "shell") return null;
|
|
274
|
+
const label = AGENT_LABEL[mode];
|
|
275
|
+
switch (activity) {
|
|
276
|
+
case "working":
|
|
277
|
+
case "compacting":
|
|
278
|
+
return { description: `${label} \xB7 working`, color: "Blue" };
|
|
279
|
+
case "question":
|
|
280
|
+
case "waiting":
|
|
281
|
+
return { description: `${label} \xB7 needs input`, color: "Amber" };
|
|
282
|
+
case "end-plan":
|
|
283
|
+
return { description: `${label} \xB7 plan ready`, color: "Amber" };
|
|
284
|
+
case "error":
|
|
285
|
+
return { description: `${label} \xB7 error`, color: "Red" };
|
|
286
|
+
case "idle":
|
|
287
|
+
return { description: `${label} \xB7 idle`, color: "" };
|
|
288
|
+
case "unknown":
|
|
289
|
+
case void 0:
|
|
290
|
+
default:
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function isAttentionState(activity) {
|
|
295
|
+
return activity === "question" || activity === "waiting" || activity === "end-plan" || activity === "error";
|
|
296
|
+
}
|
|
297
|
+
function attentionReason(activity) {
|
|
298
|
+
switch (activity) {
|
|
299
|
+
case "end-plan":
|
|
300
|
+
return "plan ready";
|
|
301
|
+
case "error":
|
|
302
|
+
return "error";
|
|
303
|
+
case "question":
|
|
304
|
+
case "waiting":
|
|
305
|
+
default:
|
|
306
|
+
return "needs input";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function cmuxStatusActive(env = process.env) {
|
|
310
|
+
const sock = env["CMUX_SOCKET_PATH"];
|
|
311
|
+
return typeof sock === "string" && sock.length > 0;
|
|
312
|
+
}
|
|
313
|
+
async function cmuxStatusEnabled(env = process.env) {
|
|
314
|
+
if (!cmuxStatusActive(env)) return false;
|
|
315
|
+
try {
|
|
316
|
+
const cfg = await loadEffectiveConfig(process.cwd());
|
|
317
|
+
return cfg.effective.attach.cmuxStatus;
|
|
318
|
+
} catch {
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function runCmux(argv) {
|
|
323
|
+
try {
|
|
324
|
+
const child = spawn2(cmuxBinary(), argv, { stdio: "ignore" });
|
|
325
|
+
child.on("error", () => {
|
|
326
|
+
});
|
|
327
|
+
child.unref();
|
|
328
|
+
} catch {
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function captureCmuxWorkspace(env = process.env) {
|
|
332
|
+
const wsId = env["CMUX_WORKSPACE_ID"];
|
|
333
|
+
if (!wsId) return null;
|
|
334
|
+
try {
|
|
335
|
+
const r = spawnSync(cmuxBinary(), ["list-workspaces", "--json", "--id-format", "both"], {
|
|
336
|
+
encoding: "utf8"
|
|
337
|
+
});
|
|
338
|
+
if (r.status !== 0 || !r.stdout) return null;
|
|
339
|
+
const data = JSON.parse(r.stdout);
|
|
340
|
+
for (const w of data.workspaces ?? []) {
|
|
341
|
+
if (!JSON.stringify(w).includes(wsId)) continue;
|
|
342
|
+
const description = typeof w["description"] === "string" ? w["description"] : "";
|
|
343
|
+
const color = typeof w["custom_color"] === "string" ? w["custom_color"] : "";
|
|
344
|
+
return { description, color };
|
|
345
|
+
}
|
|
346
|
+
} catch {
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
function applyCmuxAgentState(mode, activity) {
|
|
351
|
+
const view = mapActivityToWorkspace(mode, activity);
|
|
352
|
+
if (!view) return;
|
|
353
|
+
runCmux(["workspace-action", "--action", "set-description", "--description", view.description]);
|
|
354
|
+
if (view.color) {
|
|
355
|
+
runCmux(["workspace-action", "--action", "set-color", "--color", view.color]);
|
|
356
|
+
} else {
|
|
357
|
+
runCmux(["workspace-action", "--action", "clear-color"]);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
function markCmuxTabAttention(mode, boxName, activity, env = process.env) {
|
|
361
|
+
const label = mode === "shell" ? "shell" : AGENT_LABEL[mode];
|
|
362
|
+
const argv = ["notify", "--title", boxName, "--body", `${label} \xB7 ${attentionReason(activity)}`];
|
|
363
|
+
const surface = env["CMUX_SURFACE_ID"];
|
|
364
|
+
if (surface && surface.length > 0) argv.push("--surface", surface);
|
|
365
|
+
runCmux(argv);
|
|
366
|
+
}
|
|
367
|
+
function restoreCmuxWorkspace(orig) {
|
|
368
|
+
if (orig && orig.description) {
|
|
369
|
+
runCmux(["workspace-action", "--action", "set-description", "--description", orig.description]);
|
|
370
|
+
} else {
|
|
371
|
+
runCmux(["workspace-action", "--action", "clear-description"]);
|
|
372
|
+
}
|
|
373
|
+
if (orig && orig.color) {
|
|
374
|
+
runCmux(["workspace-action", "--action", "set-color", "--color", orig.color]);
|
|
375
|
+
} else {
|
|
376
|
+
runCmux(["workspace-action", "--action", "clear-color"]);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
191
380
|
// src/terminal/title.ts
|
|
192
381
|
var ESC = "\x1B";
|
|
193
382
|
var BEL = "\x07";
|
|
@@ -665,7 +854,7 @@ var ADVANCED_HINT_GROUPS = [
|
|
|
665
854
|
["u", "url"],
|
|
666
855
|
["t", "stop"],
|
|
667
856
|
["p", "pause"],
|
|
668
|
-
["
|
|
857
|
+
["k", "destroy"],
|
|
669
858
|
["q", "quit"]
|
|
670
859
|
];
|
|
671
860
|
function statusLine(box, w, stateLabel, groups = HINT_GROUPS, fallbackGroups) {
|
|
@@ -728,12 +917,16 @@ var DETACHABLE_LEADER_HINTS = [
|
|
|
728
917
|
["c", "code"],
|
|
729
918
|
["s", "screen"],
|
|
730
919
|
["u", "url"],
|
|
920
|
+
["t", "shell"],
|
|
921
|
+
["k", "destroy"],
|
|
731
922
|
["d", "detach"]
|
|
732
923
|
];
|
|
733
924
|
var PLAIN_LEADER_HINTS = [
|
|
734
925
|
["c", "code"],
|
|
735
926
|
["s", "screen"],
|
|
736
|
-
["u", "url"]
|
|
927
|
+
["u", "url"],
|
|
928
|
+
["t", "shell"],
|
|
929
|
+
["k", "destroy"]
|
|
737
930
|
];
|
|
738
931
|
function padTo(visible, width) {
|
|
739
932
|
if (visible.length === width) return visible;
|
|
@@ -1062,7 +1255,8 @@ var CHECKPOINT_DROP_GRACE_MS = 4e3;
|
|
|
1062
1255
|
var ACTION_FLASH = {
|
|
1063
1256
|
screen: "Opening noVNC viewer\u2026",
|
|
1064
1257
|
code: "Launching VS Code / Cursor\u2026",
|
|
1065
|
-
url: "Opening box URL\u2026"
|
|
1258
|
+
url: "Opening box URL\u2026",
|
|
1259
|
+
shell: "Opening shell in box\u2026"
|
|
1066
1260
|
};
|
|
1067
1261
|
var ACTION_CMD = {
|
|
1068
1262
|
screen: { sub: "screen", flags: [] },
|
|
@@ -1154,6 +1348,7 @@ async function runWrappedAttach(opts) {
|
|
|
1154
1348
|
let reconnecting = false;
|
|
1155
1349
|
let reconnectAbort = null;
|
|
1156
1350
|
let userDetached = false;
|
|
1351
|
+
let userKilled = false;
|
|
1157
1352
|
let checkpointNoticeAt = 0;
|
|
1158
1353
|
let checkpointNoticeClearedAt = 0;
|
|
1159
1354
|
const reservedRows = () => FOOTER_ROWS + bandReservedRows;
|
|
@@ -1249,7 +1444,7 @@ async function runWrappedAttach(opts) {
|
|
|
1249
1444
|
});
|
|
1250
1445
|
};
|
|
1251
1446
|
wireOutput();
|
|
1252
|
-
const leaderChords = detachable ? { c: "code", s: "screen", u: "url", d: "detach" } : { c: "code", s: "screen", u: "url" };
|
|
1447
|
+
const leaderChords = detachable ? { c: "code", s: "screen", u: "url", t: "shell", k: "kill", d: "detach" } : { c: "code", s: "screen", u: "url", t: "shell", k: "kill" };
|
|
1253
1448
|
const runAction = (name) => {
|
|
1254
1449
|
if (name === "detach") {
|
|
1255
1450
|
if (!reconnecting) {
|
|
@@ -1258,20 +1453,76 @@ async function runWrappedAttach(opts) {
|
|
|
1258
1453
|
}
|
|
1259
1454
|
return;
|
|
1260
1455
|
}
|
|
1456
|
+
if (name === "kill") {
|
|
1457
|
+
if (capturingPrompt) return;
|
|
1458
|
+
const ev = {
|
|
1459
|
+
id: "local:kill",
|
|
1460
|
+
kind: "confirm",
|
|
1461
|
+
message: `Destroy ${opts.boxName}? This wipes the box and all its data.`,
|
|
1462
|
+
detail: "This cannot be undone.",
|
|
1463
|
+
defaultAnswer: "n",
|
|
1464
|
+
context: { command: "destroy box" }
|
|
1465
|
+
};
|
|
1466
|
+
capturingPrompt = ev;
|
|
1467
|
+
applyBandChange();
|
|
1468
|
+
void router.capture(ev).then((body) => {
|
|
1469
|
+
if (body.answer !== "y" || body.cancelled) return;
|
|
1470
|
+
userDetached = true;
|
|
1471
|
+
userKilled = true;
|
|
1472
|
+
flashMessage = `Destroying ${opts.boxName}\u2026`;
|
|
1473
|
+
recomputeFooter();
|
|
1474
|
+
redrawChrome();
|
|
1475
|
+
const cli = process.argv[1];
|
|
1476
|
+
if (typeof cli === "string" && cli.length > 0) {
|
|
1477
|
+
try {
|
|
1478
|
+
spawn3(process.execPath, [cli, "destroy", opts.boxId, "-y"], {
|
|
1479
|
+
detached: true,
|
|
1480
|
+
stdio: "ignore"
|
|
1481
|
+
}).unref();
|
|
1482
|
+
} catch (e) {
|
|
1483
|
+
logErr(`leader-action kill spawn failed: ${e.message}`);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}).catch((e) => {
|
|
1487
|
+
if (capturingPrompt === ev) {
|
|
1488
|
+
capturingPrompt = null;
|
|
1489
|
+
applyBandChange();
|
|
1490
|
+
}
|
|
1491
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1492
|
+
if (msg !== "resolved-elsewhere") logErr(`kill confirm rejected: ${msg}`);
|
|
1493
|
+
});
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1261
1496
|
const cliEntry = process.argv[1];
|
|
1262
|
-
if (
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1497
|
+
if (name === "shell") {
|
|
1498
|
+
const host = detectHostTerminal();
|
|
1499
|
+
if (typeof cliEntry === "string" && cliEntry.length > 0 && host !== "unknown") {
|
|
1500
|
+
void spawnInNewTerminal({
|
|
1501
|
+
host,
|
|
1502
|
+
mode: "tab",
|
|
1503
|
+
argv: [process.execPath, cliEntry, "shell", opts.boxId, "--new"],
|
|
1504
|
+
cwd: process.cwd(),
|
|
1505
|
+
title: `${opts.boxName} shell`
|
|
1506
|
+
}).then((r) => {
|
|
1507
|
+
if (!r.launched && r.error) logErr(`leader-action shell: ${r.error}`);
|
|
1508
|
+
}).catch((e) => logErr(`leader-action shell failed: ${e.message}`));
|
|
1509
|
+
}
|
|
1510
|
+
flashMessage = host === "unknown" ? `Run: agentbox shell ${opts.boxId} --new` : ACTION_FLASH.shell;
|
|
1511
|
+
} else {
|
|
1512
|
+
if (typeof cliEntry === "string" && cliEntry.length > 0) {
|
|
1513
|
+
const cmd = ACTION_CMD[name];
|
|
1514
|
+
try {
|
|
1515
|
+
spawn3(
|
|
1516
|
+
process.execPath,
|
|
1517
|
+
[cliEntry, cmd.sub, opts.boxId, ...cmd.flags],
|
|
1518
|
+
{ detached: true, stdio: "ignore" }
|
|
1519
|
+
).unref();
|
|
1520
|
+
} catch (e) {
|
|
1521
|
+
logErr(`leader-action spawn (${name}) failed: ${e.message}`);
|
|
1522
|
+
}
|
|
1272
1523
|
}
|
|
1524
|
+
flashMessage = ACTION_FLASH[name];
|
|
1273
1525
|
}
|
|
1274
|
-
flashMessage = ACTION_FLASH[name];
|
|
1275
1526
|
if (flashTimer) clearTimeout(flashTimer);
|
|
1276
1527
|
flashTimer = setTimeout(() => {
|
|
1277
1528
|
flashTimer = null;
|
|
@@ -1318,7 +1569,9 @@ async function runWrappedAttach(opts) {
|
|
|
1318
1569
|
pty.write(b.toString("utf8"));
|
|
1319
1570
|
},
|
|
1320
1571
|
onAnswer: (body) => {
|
|
1321
|
-
|
|
1572
|
+
if (!body.id.startsWith("local:")) {
|
|
1573
|
+
void postAnswer({ relayBaseUrl: opts.relayBaseUrl, body });
|
|
1574
|
+
}
|
|
1322
1575
|
capturingPrompt = null;
|
|
1323
1576
|
applyBandChange();
|
|
1324
1577
|
},
|
|
@@ -1385,6 +1638,8 @@ async function runWrappedAttach(opts) {
|
|
|
1385
1638
|
}
|
|
1386
1639
|
}
|
|
1387
1640
|
});
|
|
1641
|
+
let cmuxOn = false;
|
|
1642
|
+
let cmuxOrig = null;
|
|
1388
1643
|
const pollStatus = async () => {
|
|
1389
1644
|
try {
|
|
1390
1645
|
const status = await readBoxStatus({
|
|
@@ -1395,6 +1650,12 @@ async function runWrappedAttach(opts) {
|
|
|
1395
1650
|
const body = opts.mode === "codex" ? status?.codex : opts.mode === "opencode" ? status?.opencode : opts.mode === "shell" ? void 0 : status?.claude;
|
|
1396
1651
|
const nextTitle = body?.sessionTitle?.trim() || void 0;
|
|
1397
1652
|
const nextActivity = body?.state || void 0;
|
|
1653
|
+
if (cmuxOn && nextActivity !== lastActivity) {
|
|
1654
|
+
applyCmuxAgentState(opts.mode, nextActivity);
|
|
1655
|
+
if (isAttentionState(nextActivity) && !isAttentionState(lastActivity)) {
|
|
1656
|
+
markCmuxTabAttention(opts.mode, opts.boxName, nextActivity);
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1398
1659
|
const desiredTitle = nextTitle ?? opts.boxName;
|
|
1399
1660
|
if (desiredTitle !== lastEmittedTitle) {
|
|
1400
1661
|
lastEmittedTitle = desiredTitle;
|
|
@@ -1417,6 +1678,10 @@ async function runWrappedAttach(opts) {
|
|
|
1417
1678
|
logErr(`status poll failed: ${e.message}`);
|
|
1418
1679
|
}
|
|
1419
1680
|
};
|
|
1681
|
+
if (opts.mode !== "shell") {
|
|
1682
|
+
cmuxOn = await cmuxStatusEnabled();
|
|
1683
|
+
if (cmuxOn) cmuxOrig = captureCmuxWorkspace();
|
|
1684
|
+
}
|
|
1420
1685
|
void pollStatus();
|
|
1421
1686
|
const statusTimer = setInterval(() => {
|
|
1422
1687
|
void pollStatus();
|
|
@@ -1505,6 +1770,7 @@ async function runWrappedAttach(opts) {
|
|
|
1505
1770
|
process.stdin.off("data", onStdinData);
|
|
1506
1771
|
process.stdout.off("resize", onResize);
|
|
1507
1772
|
clearInterval(statusTimer);
|
|
1773
|
+
if (cmuxOn) restoreCmuxWorkspace(cmuxOrig);
|
|
1508
1774
|
stopSpinner();
|
|
1509
1775
|
if (flashTimer) clearTimeout(flashTimer);
|
|
1510
1776
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
@@ -1520,13 +1786,16 @@ async function runWrappedAttach(opts) {
|
|
|
1520
1786
|
teardownPaint += cursorMoveTo(rsFinal, csFinal);
|
|
1521
1787
|
process.stdout.write(teardownPaint);
|
|
1522
1788
|
popTerminalTitle();
|
|
1523
|
-
if (
|
|
1789
|
+
if (userKilled) {
|
|
1790
|
+
process.stdout.write(`\x1B[1A\x1B[2K\rbox ${opts.boxName} destroyed
|
|
1791
|
+
`);
|
|
1792
|
+
} else if (exitCode === 0 && opts.detachNotice) {
|
|
1524
1793
|
process.stdout.write("\x1B[1A\x1B[2K\r" + opts.detachNotice + "\n");
|
|
1525
1794
|
}
|
|
1526
1795
|
return exitCode;
|
|
1527
1796
|
}
|
|
1528
1797
|
function runFallback(command, argv, env) {
|
|
1529
|
-
const child =
|
|
1798
|
+
const child = spawnSync2(command, argv, {
|
|
1530
1799
|
stdio: "inherit",
|
|
1531
1800
|
env: env ? { ...process.env, ...env } : process.env
|
|
1532
1801
|
});
|
|
@@ -1698,12 +1967,15 @@ function abortableSleep(ms, signal) {
|
|
|
1698
1967
|
);
|
|
1699
1968
|
});
|
|
1700
1969
|
}
|
|
1970
|
+
function agentStartBanner(binary) {
|
|
1971
|
+
return `printf " agentbox: starting ${binary} (first paint may take a few seconds)...\\r\\n"; `;
|
|
1972
|
+
}
|
|
1701
1973
|
function buildCloudAttachInnerCommand(binary, extraArgs) {
|
|
1702
1974
|
if (!extraArgs || extraArgs.length === 0) {
|
|
1703
|
-
return `bash -lc exec
|
|
1975
|
+
return `bash -lc '${agentStartBanner(binary)}exec ${binary}'`;
|
|
1704
1976
|
}
|
|
1705
1977
|
const blob = Buffer.from(extraArgs.join("\n"), "utf8").toString("base64");
|
|
1706
|
-
return `bash -lc 'mapfile -t A <<< "$(echo ${blob} | base64 -d)"; exec ${binary} "\${A[@]}"'`;
|
|
1978
|
+
return `bash -lc '${agentStartBanner(binary)}mapfile -t A <<< "$(echo ${blob} | base64 -d)"; exec ${binary} "\${A[@]}"'`;
|
|
1707
1979
|
}
|
|
1708
1980
|
async function cloudAgentAttach(args) {
|
|
1709
1981
|
const provider = await providerForBox(args.box);
|
|
@@ -1817,7 +2089,7 @@ async function cloudAgentStartDetached(args) {
|
|
|
1817
2089
|
}
|
|
1818
2090
|
function runDetached(argv, env) {
|
|
1819
2091
|
return new Promise((resolve) => {
|
|
1820
|
-
const child =
|
|
2092
|
+
const child = spawn4(argv[0], argv.slice(1), {
|
|
1821
2093
|
stdio: "ignore",
|
|
1822
2094
|
env: env ? { ...process.env, ...env } : process.env
|
|
1823
2095
|
});
|
|
@@ -1857,4 +2129,4 @@ export {
|
|
|
1857
2129
|
cloudAgentAttach,
|
|
1858
2130
|
cloudAgentStartDetached
|
|
1859
2131
|
};
|
|
1860
|
-
//# sourceMappingURL=chunk-
|
|
2132
|
+
//# sourceMappingURL=chunk-BYCLD6D6.js.map
|