@abuaboud/box 0.7.9 → 0.7.11
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 +27 -6
- package/package.json +1 -1
package/dist/cbox.mjs
CHANGED
|
@@ -351,14 +351,14 @@ async function setUpEnvironment(repo, dir, envs) {
|
|
|
351
351
|
const detected = detectSetup(dir), sized = detectSize(dir), names = secretNames(dir);
|
|
352
352
|
let name = repo.split("/")[1].toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+/, "").slice(0, 28) || "env";
|
|
353
353
|
for (let i = 2, base = name; envs.some((e) => e.name === name); i++) name = `${base}-${i}`;
|
|
354
|
-
let
|
|
354
|
+
let setup2 = detected?.setup ?? "", size = sized.size, secrets = "";
|
|
355
355
|
const sizes = { small: "2 vCPU, 4 GB", medium: "4 vCPU, 8 GB", large: "8 vCPU, 16 GB" };
|
|
356
356
|
for (; ; ) {
|
|
357
357
|
console.log();
|
|
358
358
|
console.log(` ${dim("Name ")} ${name}`);
|
|
359
359
|
console.log(` ${dim("Repo ")} ${repo}`);
|
|
360
360
|
console.log(` ${dim("Machine ")} ${size[0].toUpperCase() + size.slice(1)} ${dim(`\xB7 ${sizes[size]}${size === sized.size ? ` (${sized.why})` : ""}`)}`);
|
|
361
|
-
console.log(` ${dim("Setup ")} ${
|
|
361
|
+
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
362
|
if (names.length) console.log(` ${dim("Secrets ")} ${names.join(", ")} ${dim(secrets ? "\xB7 values copied from .env" : "\xB7 names from .env.example, values empty")}`);
|
|
363
363
|
console.log();
|
|
364
364
|
const choice = await select({ message: "Create it?", choices: [
|
|
@@ -377,13 +377,13 @@ async function setUpEnvironment(repo, dir, envs) {
|
|
|
377
377
|
if (choice === "edit") {
|
|
378
378
|
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
379
|
size = await select({ message: "Machine", default: size, choices: Object.entries(sizes).map(([value, spec]) => ({ name: `${value.padEnd(8)}${dim(spec)}`, value })) });
|
|
380
|
-
|
|
380
|
+
setup2 = (await input({ message: "Setup script (runs once in the snapshot; empty for none)", default: setup2 })).trim();
|
|
381
381
|
continue;
|
|
382
382
|
}
|
|
383
383
|
break;
|
|
384
384
|
}
|
|
385
385
|
await ensureGitHub(repo);
|
|
386
|
-
const { id } = await api("/api/environments", { method: "POST", body: JSON.stringify({ name, repo, size, setup, secrets }) });
|
|
386
|
+
const { id } = await api("/api/environments", { method: "POST", body: JSON.stringify({ name, repo, size, setup: setup2, secrets }) });
|
|
387
387
|
ok(`Environment ${styleText3("cyan", name)} created`);
|
|
388
388
|
return { id, name, repo, status: "building", size, progress: "Starting a build machine" };
|
|
389
389
|
}
|
|
@@ -417,6 +417,7 @@ ${styleText3("yellow", "!")} Connect GitHub so Box can clone ${repo} and your bo
|
|
|
417
417
|
|
|
418
418
|
// src/local.ts
|
|
419
419
|
import { execFileSync as execFileSync3, spawn as spawn3 } from "node:child_process";
|
|
420
|
+
import { createHash } from "node:crypto";
|
|
420
421
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync5, renameSync, rmSync, statSync, watch, writeFileSync as writeFileSync4 } from "node:fs";
|
|
421
422
|
import { homedir as homedir4 } from "node:os";
|
|
422
423
|
import { basename, dirname, join as join5 } from "node:path";
|
|
@@ -781,6 +782,7 @@ async function openLocal({ name, env, here, branch, fresh = false }) {
|
|
|
781
782
|
api("/api/environments")
|
|
782
783
|
]).finally(() => stop());
|
|
783
784
|
const environment = envs.find((e) => e.name === env) ?? fail(`No environment named ${env}.`);
|
|
785
|
+
void sendSetup().catch(() => void 0);
|
|
784
786
|
const folder = prepareFolder(name, env, here, got.mcp);
|
|
785
787
|
try {
|
|
786
788
|
writeFileSync4(join5(BOXES, "llms.txt"), await fetch(new URL("/llms.txt", load().server)).then((r) => r.ok ? r.text() : Promise.reject()));
|
|
@@ -802,6 +804,14 @@ async function openLocal({ name, env, here, branch, fresh = false }) {
|
|
|
802
804
|
ok(`Claude closed \xB7 repo synced \xB7 ${name} sleeps once it's quiet ${dim(`\xB7 come back with: box ${name}`)}`);
|
|
803
805
|
process.exit(code2);
|
|
804
806
|
}
|
|
807
|
+
async function sendSetup() {
|
|
808
|
+
const { tar, skills, enabled, memory, ...home2 } = localClaudeHome();
|
|
809
|
+
const buf = await tar;
|
|
810
|
+
const sha = buf && buf.length <= 30 << 20 ? createHash("sha256").update(buf).digest("hex") : void 0;
|
|
811
|
+
const put = (body) => api("/api/laptop-setup", { method: "PUT", body: JSON.stringify({ home: { ...home2, memory }, sha, ...body }) });
|
|
812
|
+
if ((await put({})).need && buf) await put({ tgz: buf.toString("base64") });
|
|
813
|
+
return { skills, plugins: enabled.length, memory: !!memory.trim(), tooBig: !!buf && !sha };
|
|
814
|
+
}
|
|
805
815
|
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)));
|
|
806
816
|
function trustFolder(folder) {
|
|
807
817
|
const file2 = join5(homedir4(), ".claude.json");
|
|
@@ -862,7 +872,7 @@ async function rm(name, opts = {}) {
|
|
|
862
872
|
}
|
|
863
873
|
|
|
864
874
|
// src/remote.ts
|
|
865
|
-
import { createHash } from "node:crypto";
|
|
875
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
866
876
|
import { styleText as styleText4 } from "node:util";
|
|
867
877
|
import { select as select3 } from "@inquirer/prompts";
|
|
868
878
|
import ssh22 from "ssh2";
|
|
@@ -985,7 +995,7 @@ async function newRemoteBox(env, branch, name, o) {
|
|
|
985
995
|
async function sendHome(name, tar) {
|
|
986
996
|
const buf = await tar;
|
|
987
997
|
if (!buf || buf.length > 30 << 20) return api(`/api/boxes/${name}/home`, { method: "POST", body: "{}" }).catch(() => void 0);
|
|
988
|
-
const sha =
|
|
998
|
+
const sha = createHash2("sha256").update(buf).digest("hex");
|
|
989
999
|
const post = (body) => api(`/api/boxes/${name}/home`, { method: "POST", body: JSON.stringify(body) });
|
|
990
1000
|
if ((await post({ sha }).catch(() => ({ need: false }))).need) await post({ sha, tgz: buf.toString("base64") }).catch(() => void 0);
|
|
991
1001
|
}
|
|
@@ -1282,6 +1292,16 @@ async function ls() {
|
|
|
1282
1292
|
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")}`);
|
|
1283
1293
|
}
|
|
1284
1294
|
}
|
|
1295
|
+
async function setup() {
|
|
1296
|
+
const sent = await sendSetup();
|
|
1297
|
+
const n = (k, word) => `${k} ${word}${k === 1 ? "" : "s"}`;
|
|
1298
|
+
ok(`Sent ${[n(sent.skills, "skill"), n(sent.plugins, "plugin"), ...sent.memory ? ["CLAUDE.md"] : []].join(", ")} ${dim("\xB7 @Box and webhooks start boxes with these")}`);
|
|
1299
|
+
if (sent.tooBig) miss("Your skills and plugins are over 30 MB, so only CLAUDE.md and the plugin list were sent.");
|
|
1300
|
+
const { data } = await api("/api/accounts");
|
|
1301
|
+
const missing = ["claude", "github"].filter((id) => data.find((a) => a.id === id)?.status !== "ready").map((id) => id === "claude" ? "sign in to Claude" : "connect GitHub");
|
|
1302
|
+
if (missing.length) miss(`Before @Box can start boxes as you, ${missing.join(" and ")}: ${new URL("/boxes?new", load().server)}`);
|
|
1303
|
+
else ok("Claude and GitHub are connected");
|
|
1304
|
+
}
|
|
1285
1305
|
var quiet = ["proxy", "sync"].includes(process.argv[2] ?? "");
|
|
1286
1306
|
if (quiet) console.log = console.error;
|
|
1287
1307
|
if (!quiet && !process.env.CBOX_UPDATED && !process.argv.slice(2).some((a) => ["-V", "--version", "-h", "--help", "help"].includes(a))) console.log(dim(`box ${VERSION}`));
|
|
@@ -1295,6 +1315,7 @@ boxOptions(cli.command("new").description("always make a fresh box")).action((o)
|
|
|
1295
1315
|
cli.command("ls").description("list your boxes").action(ls);
|
|
1296
1316
|
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));
|
|
1297
1317
|
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);
|
|
1318
|
+
cli.command("setup").description("send your skills, plugins and CLAUDE.md for @Box and webhooks, and check Claude and GitHub").action(setup);
|
|
1298
1319
|
cli.command("login").option("--server <url>", "box server").description("sign in from the browser").action((o) => login(o.server));
|
|
1299
1320
|
cli.command("upgrade").description("update box to the latest version now").action(upgrade);
|
|
1300
1321
|
cli.command("attach [box]", { hidden: true }).action((name) => name ? openBox(name) : home(void 0, {}));
|
package/package.json
CHANGED