@abuaboud/box 0.7.10 → 0.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cbox.mjs +23 -13
- package/package.json +1 -1
package/dist/cbox.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import { join } from "node:path";
|
|
|
20
20
|
import ssh2 from "ssh2";
|
|
21
21
|
var CONFIG_DIR = join(homedir(), ".config", "box");
|
|
22
22
|
var BOXES = join(homedir(), ".box");
|
|
23
|
+
var MAX_SETUP_MB = 70;
|
|
23
24
|
var SERVICES = { 5432: "Postgres", 6379: "Redis", 3306: "MySQL", 27017: "MongoDB", 8123: "ClickHouse" };
|
|
24
25
|
function localMcp() {
|
|
25
26
|
const claudeJson = join(homedir(), ".claude.json");
|
|
@@ -351,14 +352,14 @@ async function setUpEnvironment(repo, dir, envs) {
|
|
|
351
352
|
const detected = detectSetup(dir), sized = detectSize(dir), names = secretNames(dir);
|
|
352
353
|
let name = repo.split("/")[1].toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+/, "").slice(0, 28) || "env";
|
|
353
354
|
for (let i = 2, base = name; envs.some((e) => e.name === name); i++) name = `${base}-${i}`;
|
|
354
|
-
let
|
|
355
|
+
let setup2 = detected?.setup ?? "", size = sized.size, secrets = "";
|
|
355
356
|
const sizes = { small: "2 vCPU, 4 GB", medium: "4 vCPU, 8 GB", large: "8 vCPU, 16 GB" };
|
|
356
357
|
for (; ; ) {
|
|
357
358
|
console.log();
|
|
358
359
|
console.log(` ${dim("Name ")} ${name}`);
|
|
359
360
|
console.log(` ${dim("Repo ")} ${repo}`);
|
|
360
361
|
console.log(` ${dim("Machine ")} ${size[0].toUpperCase() + size.slice(1)} ${dim(`\xB7 ${sizes[size]}${size === sized.size ? ` (${sized.why})` : ""}`)}`);
|
|
361
|
-
console.log(` ${dim("Setup ")} ${
|
|
362
|
+
console.log(` ${dim("Setup ")} ${setup2 ? styleText3("cyan", setup2) : dim("none")} ${dim(detected && setup2 === detected.setup ? `\xB7 from ${detected.from}` : setup2 ? "" : "\xB7 boxes start from a plain clone")}`);
|
|
362
363
|
if (names.length) console.log(` ${dim("Secrets ")} ${names.join(", ")} ${dim(secrets ? "\xB7 values copied from .env" : "\xB7 names from .env.example, values empty")}`);
|
|
363
364
|
console.log();
|
|
364
365
|
const choice = await select({ message: "Create it?", choices: [
|
|
@@ -377,13 +378,13 @@ async function setUpEnvironment(repo, dir, envs) {
|
|
|
377
378
|
if (choice === "edit") {
|
|
378
379
|
name = await input({ message: "Name", default: name, validate: (v) => /^[a-z0-9][a-z0-9-]{0,30}$/.test(v) || "Lowercase letters, digits and dashes" });
|
|
379
380
|
size = await select({ message: "Machine", default: size, choices: Object.entries(sizes).map(([value, spec]) => ({ name: `${value.padEnd(8)}${dim(spec)}`, value })) });
|
|
380
|
-
|
|
381
|
+
setup2 = (await input({ message: "Setup script (runs once in the snapshot; empty for none)", default: setup2 })).trim();
|
|
381
382
|
continue;
|
|
382
383
|
}
|
|
383
384
|
break;
|
|
384
385
|
}
|
|
385
386
|
await ensureGitHub(repo);
|
|
386
|
-
const { id } = await api("/api/environments", { method: "POST", body: JSON.stringify({ name, repo, size, setup, secrets }) });
|
|
387
|
+
const { id } = await api("/api/environments", { method: "POST", body: JSON.stringify({ name, repo, size, setup: setup2, secrets }) });
|
|
387
388
|
ok(`Environment ${styleText3("cyan", name)} created`);
|
|
388
389
|
return { id, name, repo, status: "building", size, progress: "Starting a build machine" };
|
|
389
390
|
}
|
|
@@ -782,7 +783,7 @@ async function openLocal({ name, env, here, branch, fresh = false }) {
|
|
|
782
783
|
api("/api/environments")
|
|
783
784
|
]).finally(() => stop());
|
|
784
785
|
const environment = envs.find((e) => e.name === env) ?? fail(`No environment named ${env}.`);
|
|
785
|
-
void sendSetup();
|
|
786
|
+
void sendSetup().catch(() => void 0);
|
|
786
787
|
const folder = prepareFolder(name, env, here, got.mcp);
|
|
787
788
|
try {
|
|
788
789
|
writeFileSync4(join5(BOXES, "llms.txt"), await fetch(new URL("/llms.txt", load().server)).then((r) => r.ok ? r.text() : Promise.reject()));
|
|
@@ -805,14 +806,12 @@ async function openLocal({ name, env, here, branch, fresh = false }) {
|
|
|
805
806
|
process.exit(code2);
|
|
806
807
|
}
|
|
807
808
|
async function sendSetup() {
|
|
808
|
-
const { tar, ...home2 } = localClaudeHome();
|
|
809
|
+
const { tar, skills, enabled, memory, ...home2 } = localClaudeHome();
|
|
809
810
|
const buf = await tar;
|
|
810
|
-
const sha = buf && buf.length <=
|
|
811
|
-
const put = (body) => api("/api/laptop-setup", { method: "PUT", body: JSON.stringify({ home: home2, sha, ...body }) });
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
} catch {
|
|
815
|
-
}
|
|
811
|
+
const sha = buf && buf.length <= MAX_SETUP_MB << 20 ? createHash("sha256").update(buf).digest("hex") : void 0;
|
|
812
|
+
const put = (body) => api("/api/laptop-setup", { method: "PUT", body: JSON.stringify({ home: { ...home2, memory }, sha, ...body }) });
|
|
813
|
+
if ((await put({})).need && buf) await put({ tgz: buf.toString("base64") });
|
|
814
|
+
return { skills, plugins: enabled.length, memory: !!memory.trim(), tooBig: !!buf && !sha };
|
|
816
815
|
}
|
|
817
816
|
var claude = (folder, args) => new Promise((done) => spawn3("claude", args, { cwd: folder, stdio: "inherit", env: { ...process.env, ...process.getuid?.() === 0 && { IS_SANDBOX: "1" } } }).on("error", () => fail("Claude Code is not installed on this laptop. npm i -g @anthropic-ai/claude-code, or use box --remote.")).on("close", (c) => done(c ?? 0)));
|
|
818
817
|
function trustFolder(folder) {
|
|
@@ -996,7 +995,7 @@ async function newRemoteBox(env, branch, name, o) {
|
|
|
996
995
|
}
|
|
997
996
|
async function sendHome(name, tar) {
|
|
998
997
|
const buf = await tar;
|
|
999
|
-
if (!buf || buf.length >
|
|
998
|
+
if (!buf || buf.length > MAX_SETUP_MB << 20) return api(`/api/boxes/${name}/home`, { method: "POST", body: "{}" }).catch(() => void 0);
|
|
1000
999
|
const sha = createHash2("sha256").update(buf).digest("hex");
|
|
1001
1000
|
const post = (body) => api(`/api/boxes/${name}/home`, { method: "POST", body: JSON.stringify(body) });
|
|
1002
1001
|
if ((await post({ sha }).catch(() => ({ need: false }))).need) await post({ sha, tgz: buf.toString("base64") }).catch(() => void 0);
|
|
@@ -1294,6 +1293,16 @@ async function ls() {
|
|
|
1294
1293
|
console.log(`${b.name.padEnd(width)}${l}${" ".repeat(Math.max(1, 20 - l.replace(/\x1b\[[0-9;]*m/g, "").length))}${dim(b.agent === "local" ? "laptop" : "remote")}`);
|
|
1295
1294
|
}
|
|
1296
1295
|
}
|
|
1296
|
+
async function setup() {
|
|
1297
|
+
const sent = await sendSetup();
|
|
1298
|
+
const n = (k, word) => `${k} ${word}${k === 1 ? "" : "s"}`;
|
|
1299
|
+
ok(`Sent ${[n(sent.skills, "skill"), n(sent.plugins, "plugin"), ...sent.memory ? ["CLAUDE.md"] : []].join(", ")} ${dim("\xB7 @Box and webhooks start boxes with these")}`);
|
|
1300
|
+
if (sent.tooBig) miss(`Your skills and plugins are over ${MAX_SETUP_MB} MB, so only CLAUDE.md and the plugin list were sent.`);
|
|
1301
|
+
const { data } = await api("/api/accounts");
|
|
1302
|
+
const missing = ["claude", "github"].filter((id) => data.find((a) => a.id === id)?.status !== "ready").map((id) => id === "claude" ? "sign in to Claude" : "connect GitHub");
|
|
1303
|
+
if (missing.length) miss(`Before @Box can start boxes as you, ${missing.join(" and ")}: ${new URL("/boxes?new", load().server)}`);
|
|
1304
|
+
else ok("Claude and GitHub are connected");
|
|
1305
|
+
}
|
|
1297
1306
|
var quiet = ["proxy", "sync"].includes(process.argv[2] ?? "");
|
|
1298
1307
|
if (quiet) console.log = console.error;
|
|
1299
1308
|
if (!quiet && !process.env.CBOX_UPDATED && !process.argv.slice(2).some((a) => ["-V", "--version", "-h", "--help", "help"].includes(a))) console.log(dim(`box ${VERSION}`));
|
|
@@ -1307,6 +1316,7 @@ boxOptions(cli.command("new").description("always make a fresh box")).action((o)
|
|
|
1307
1316
|
cli.command("ls").description("list your boxes").action(ls);
|
|
1308
1317
|
cli.command("code [env]").description("open an environment's boxes in one VS Code window, each a git worktree, and sync your saves").action((env) => code(env));
|
|
1309
1318
|
cli.command("rm <box>").option("-f, --force", "delete even while someone is attached or Claude is working").description("delete a box, pushing unpushed work to cb/<box>").action(rm);
|
|
1319
|
+
cli.command("setup").description("send your skills, plugins and CLAUDE.md for @Box and webhooks, and check Claude and GitHub").action(setup);
|
|
1310
1320
|
cli.command("login").option("--server <url>", "box server").description("sign in from the browser").action((o) => login(o.server));
|
|
1311
1321
|
cli.command("upgrade").description("update box to the latest version now").action(upgrade);
|
|
1312
1322
|
cli.command("attach [box]", { hidden: true }).action((name) => name ? openBox(name) : home(void 0, {}));
|
package/package.json
CHANGED