@ghalex/kvbox 0.0.5 → 0.0.7

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/kvbox.js CHANGED
@@ -48,7 +48,7 @@ function gb(bytes) {
48
48
  }
49
49
 
50
50
  // src/program.ts
51
- import { Command as Command16 } from "commander";
51
+ import { Command as Command17 } from "commander";
52
52
 
53
53
  // ../shared/src/version.ts
54
54
  import { createRequire } from "module";
@@ -63,10 +63,10 @@ function versionOf(srcFileUrl, injected) {
63
63
  }
64
64
 
65
65
  // src/version.ts
66
- var VERSION = versionOf(import.meta.url, true ? "0.0.5" : void 0);
66
+ var VERSION = versionOf(import.meta.url, true ? "0.0.7" : void 0);
67
67
 
68
68
  // src/commands/vm/index.ts
69
- import { Command as Command7 } from "commander";
69
+ import { Command as Command8 } from "commander";
70
70
 
71
71
  // src/commands/vm/connect.ts
72
72
  import { spawnSync } from "child_process";
@@ -95,9 +95,9 @@ import { z } from "zod";
95
95
 
96
96
  // ../shared/src/sizes.ts
97
97
  var SIZES = {
98
- s: { vcpu: 2, memMib: 4096 },
99
- m: { vcpu: 4, memMib: 8192 },
100
- l: { vcpu: 8, memMib: 16384 }
98
+ s: { vcpu: 2, memMib: 4096, diskGib: 8 },
99
+ m: { vcpu: 4, memMib: 8192, diskGib: 16 },
100
+ l: { vcpu: 8, memMib: 16384, diskGib: 32 }
101
101
  };
102
102
  var SIZE_NAMES = Object.keys(SIZES);
103
103
 
@@ -111,9 +111,11 @@ var MachineSchema = z.object({
111
111
  vcpu: z.number().int(),
112
112
  memMib: z.number().int(),
113
113
  diskBytes: z.number().int(),
114
- // size of the disk as the guest sees it
114
+ // the box's own writable disk, as the guest sees it
115
115
  diskUsedBytes: z.number().int(),
116
- // what the sparse disk file really occupies on the host
116
+ // what that sparse file really occupies on the host
117
+ base: z.string().nullable(),
118
+ // base image version the box runs on (null: pre-overlay box with its own copy)
117
119
  createdAt: z.string(),
118
120
  source: z.string(),
119
121
  // "base" or "snapshot:<name>"
@@ -172,12 +174,17 @@ function paths(home = kvboxHome()) {
172
174
  firecracker: join(home, "bin", "firecracker"),
173
175
  assets: join(home, "assets"),
174
176
  kernel: join(home, "assets", "vmlinux"),
177
+ /** Symlink to the current base image, assets/rootfs-<version>.ext4; boxes keep using the version they were made from. */
175
178
  rootfs: join(home, "assets", "rootfs.ext4"),
179
+ baseImage: (version) => join(home, "assets", `rootfs-${version}.ext4`),
176
180
  machines: join(home, "machines"),
177
181
  snapshots: join(home, "snapshots"),
178
182
  machine: (name) => ({
179
183
  dir: join(home, "machines", name),
180
184
  meta: join(home, "machines", name, "meta.json"),
185
+ /** The box's writable layer, stacked on the read-only base image inside the guest. */
186
+ overlay: join(home, "machines", name, "overlay.ext4"),
187
+ /** Boxes made before overlays: a full copy of the base image. Kept bootable, never created anymore. */
181
188
  disk: join(home, "machines", name, "disk.ext4"),
182
189
  sock: join(home, "machines", name, "fc.sock"),
183
190
  log: join(home, "machines", name, "fc.log")
@@ -350,9 +357,85 @@ var connectCommand = new Command("connect").description("open a shell in a box o
350
357
  process.exit(res.status ?? 1);
351
358
  });
352
359
 
360
+ // src/commands/vm/exec.ts
361
+ import { spawn as spawn2 } from "child_process";
362
+ import { Command as Command2, InvalidArgumentError } from "commander";
363
+ function shellQuote(s) {
364
+ return `'${s.replace(/'/g, `'\\''`)}'`;
365
+ }
366
+ function remoteCommand(cmdArgs, env) {
367
+ const cmd = cmdArgs.join(" ");
368
+ if (env.length === 0) return cmd;
369
+ const assignments = env.map((entry) => {
370
+ const eq = entry.indexOf("=");
371
+ const key = eq > 0 ? entry.slice(0, eq) : "";
372
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) throw new KvboxError(`--env ${entry}: expected KEY=VALUE`);
373
+ return `${key}=${shellQuote(entry.slice(eq + 1))}`;
374
+ });
375
+ return `export ${assignments.join(" ")}; ${cmd}`;
376
+ }
377
+ var TIMEOUT_EXIT = 124;
378
+ var SSH_FAILED = 255;
379
+ function collect(value, previous) {
380
+ return [...previous ?? [], value];
381
+ }
382
+ function positiveSeconds(value) {
383
+ const n = Number(value);
384
+ if (!Number.isFinite(n) || n <= 0) throw new InvalidArgumentError("expected a number of seconds > 0");
385
+ return n;
386
+ }
387
+ var execCommand = new Command2("exec").description("run a command in a box and exit with its status (kvbox exec <name> -- <cmd>)").argument("<name>", "box name").argument("<cmd...>", "command, passed to the box's shell as one string (pipes, &&, cd work)").option("-e, --env <KEY=VALUE>", "set an environment variable for the command (repeatable)", collect).option("--timeout <seconds>", "kill the command after N seconds and exit 124", positiveSeconds).option("--tty", "allocate a pseudo-terminal (for interactive tools like htop)").option("--json", 'capture output and print {"output": "...", "exit_code": N}').action(async (name, cmdArgs, opts, cmd) => {
388
+ const client = clientFor(cmd.optsWithGlobals());
389
+ let ip;
390
+ try {
391
+ const box = (await client.listMachines()).find((b) => b.name === name);
392
+ if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
393
+ if (box.status !== "running") throw new KvboxError(`box ${name} is ${box.status}`);
394
+ ip = box.ip;
395
+ } finally {
396
+ await client.close();
397
+ }
398
+ const remote = remoteCommand(cmdArgs, opts.env ?? []);
399
+ const stdinIsTty = process.stdin.isTTY === true;
400
+ const ssh = [
401
+ ...opts.tty ? ["-t"] : [],
402
+ // With a terminal on stdin nothing is sent (the command would otherwise wait on it);
403
+ // from a pipe or file, stdin is forwarded and its EOF reaches the command.
404
+ ...stdinIsTty && !opts.tty ? ["-n"] : [],
405
+ ...sshArgs(ip),
406
+ // ssh joins everything after the host into the remote command line.
407
+ remote
408
+ ];
409
+ const child = spawn2("ssh", ssh, { stdio: ["inherit", opts.json ? "pipe" : "inherit", opts.json ? "pipe" : "inherit"] });
410
+ const chunks = [];
411
+ child.stdout?.on("data", (c) => chunks.push(c));
412
+ child.stderr?.on("data", (c) => chunks.push(c));
413
+ let timedOut = false;
414
+ const timer = opts.timeout === void 0 ? void 0 : setTimeout(() => {
415
+ timedOut = true;
416
+ child.kill("SIGTERM");
417
+ }, opts.timeout * 1e3);
418
+ const status = await new Promise((resolve, reject) => {
419
+ child.once("error", (err) => reject(new KvboxError(`could not run ssh: ${err.message}`)));
420
+ child.once("close", (code, signal) => {
421
+ if (timedOut) resolve(TIMEOUT_EXIT);
422
+ else if (code !== null) resolve(code);
423
+ else resolve(signal === "SIGINT" ? 130 : 1);
424
+ });
425
+ }).finally(() => clearTimeout(timer));
426
+ if (status === SSH_FAILED && !timedOut) {
427
+ if (opts.json) process.stderr.write(Buffer.concat(chunks));
428
+ throw new KvboxError(`box ${name}: could not run the command over SSH (box still booting?)`, SSH_FAILED);
429
+ }
430
+ if (opts.json) {
431
+ process.stdout.write(JSON.stringify({ output: Buffer.concat(chunks).toString("utf8"), exit_code: status }) + "\n");
432
+ }
433
+ process.exit(status);
434
+ });
435
+
353
436
  // src/commands/vm/ls.ts
354
- import { Command as Command2 } from "commander";
355
- var lsCommand = new Command2("ls").description("list boxes with status and IP").option("--json", "print as JSON").action(async (opts, cmd) => {
437
+ import { Command as Command3 } from "commander";
438
+ var lsCommand = new Command3("ls").description("list boxes with status and IP").option("--json", "print as JSON").action(async (opts, cmd) => {
356
439
  const client = clientFor(cmd.optsWithGlobals());
357
440
  try {
358
441
  const boxes = await client.listMachines();
@@ -372,7 +455,7 @@ var lsCommand = new Command2("ls").description("list boxes with status and IP").
372
455
  cpu: `${b.vcpu} vCPU`,
373
456
  ram: gb(b.memMib * 1024 ** 2),
374
457
  disk: `${gb(b.diskBytes)} (${gb(b.diskUsedBytes)} used)`,
375
- source: b.source,
458
+ source: b.base !== null && b.source === "base" ? `base ${b.base}` : b.source,
376
459
  created: b.createdAt.replace("T", " ").slice(0, 16)
377
460
  }))
378
461
  );
@@ -382,8 +465,8 @@ var lsCommand = new Command2("ls").description("list boxes with status and IP").
382
465
  });
383
466
 
384
467
  // src/commands/vm/new.ts
385
- import { Command as Command3, Option } from "commander";
386
- var newCommand = new Command3("new").description("boot a new box from the base image or a snapshot").argument("[name]", "box name (box1, box2, \u2026 when omitted)").addOption(new Option("-s, --size <size>", "box size (default: server config, s)").choices(SIZE_NAMES)).option("-f, --from <snapshot>", "start from a snapshot instead of the base image").option("--force", "skip the capacity guard").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
468
+ import { Command as Command4, Option } from "commander";
469
+ var newCommand = new Command4("new").description("boot a new box from the base image or a snapshot").argument("[name]", "box name (box1, box2, \u2026 when omitted)").addOption(new Option("-s, --size <size>", "box size (default: server config, s)").choices(SIZE_NAMES)).option("-f, --from <snapshot>", "start from a snapshot instead of the base image").option("--force", "skip the capacity guard").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
387
470
  const client = clientFor(cmd.optsWithGlobals());
388
471
  try {
389
472
  const box = await client.createMachine({
@@ -409,8 +492,8 @@ function describe(box) {
409
492
  }
410
493
 
411
494
  // src/commands/vm/rm.ts
412
- import { Command as Command4 } from "commander";
413
- var rmCommand = new Command4("rm").description("destroy a box (its disk is deleted; snapshots are kept)").argument("<name>", "box name").option("-y, --yes", "do not ask for confirmation").action(async (name, opts, cmd) => {
495
+ import { Command as Command5 } from "commander";
496
+ var rmCommand = new Command5("rm").description("destroy a box (its disk is deleted; snapshots are kept)").argument("<name>", "box name").option("-y, --yes", "do not ask for confirmation").action(async (name, opts, cmd) => {
414
497
  if (!await confirm(`Destroy box ${name} and its disk?`, opts.yes ?? false)) {
415
498
  info("cancelled");
416
499
  process.exitCode = 1;
@@ -426,8 +509,8 @@ var rmCommand = new Command4("rm").description("destroy a box (its disk is delet
426
509
  });
427
510
 
428
511
  // src/commands/vm/start.ts
429
- import { Command as Command5 } from "commander";
430
- var startCommand = new Command5("start").description("boot a stopped box again (same name, IP and disk)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
512
+ import { Command as Command6 } from "commander";
513
+ var startCommand = new Command6("start").description("boot a stopped box again (same name, IP and disk)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
431
514
  const client = clientFor(cmd.optsWithGlobals());
432
515
  try {
433
516
  const box = await client.startMachine(name);
@@ -439,8 +522,8 @@ var startCommand = new Command5("start").description("boot a stopped box again (
439
522
  });
440
523
 
441
524
  // src/commands/vm/stop.ts
442
- import { Command as Command6 } from "commander";
443
- var stopCommand = new Command6("stop").description("shut a box down (its disk is kept; start it again with kvbox start)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
525
+ import { Command as Command7 } from "commander";
526
+ var stopCommand = new Command7("stop").description("shut a box down (its disk is kept; start it again with kvbox start)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
444
527
  const client = clientFor(cmd.optsWithGlobals());
445
528
  try {
446
529
  const box = await client.stopMachine(name);
@@ -452,15 +535,15 @@ var stopCommand = new Command6("stop").description("shut a box down (its disk is
452
535
  });
453
536
 
454
537
  // src/commands/vm/index.ts
455
- var vmCommand = new Command7("vm").enablePositionalOptions().description("manage boxes (each one is a Firecracker microVM)").addCommand(newCommand).addCommand(lsCommand).addCommand(connectCommand).addCommand(stopCommand).addCommand(startCommand).addCommand(rmCommand);
456
- var vmAliases = [newCommand, lsCommand, connectCommand, stopCommand, startCommand, rmCommand];
538
+ var vmCommand = new Command8("vm").enablePositionalOptions().description("manage boxes (each one is a Firecracker microVM)").addCommand(newCommand).addCommand(lsCommand).addCommand(connectCommand).addCommand(execCommand).addCommand(stopCommand).addCommand(startCommand).addCommand(rmCommand);
539
+ var vmAliases = [newCommand, lsCommand, connectCommand, execCommand, stopCommand, startCommand, rmCommand];
457
540
 
458
541
  // src/commands/server/index.ts
459
- import { Command as Command11 } from "commander";
542
+ import { Command as Command12 } from "commander";
460
543
 
461
544
  // src/commands/server/start.ts
462
- import { Command as Command8 } from "commander";
463
- var startCommand2 = new Command8("start").description("start the local kvbox-server in the background").action(async (_opts, cmd) => {
545
+ import { Command as Command9 } from "commander";
546
+ var startCommand2 = new Command9("start").description("start the local kvbox-server in the background").action(async (_opts, cmd) => {
464
547
  const client = clientFor(cmd.optsWithGlobals(), { autoStart: false });
465
548
  try {
466
549
  const health = await client.health();
@@ -475,8 +558,8 @@ var startCommand2 = new Command8("start").description("start the local kvbox-ser
475
558
  });
476
559
 
477
560
  // src/commands/server/status.ts
478
- import { Command as Command9 } from "commander";
479
- var statusCommand = new Command9("status").description("show whether the server is running").option("--json", "print as JSON").action(async (opts, cmd) => {
561
+ import { Command as Command10 } from "commander";
562
+ var statusCommand = new Command10("status").description("show whether the server is running").option("--json", "print as JSON").action(async (opts, cmd) => {
480
563
  const client = clientFor(cmd.optsWithGlobals());
481
564
  try {
482
565
  const health = await client.health();
@@ -489,8 +572,8 @@ var statusCommand = new Command9("status").description("show whether the server
489
572
 
490
573
  // src/commands/server/stop.ts
491
574
  import { readFile } from "fs/promises";
492
- import { Command as Command10 } from "commander";
493
- var stopCommand2 = new Command10("stop").description("stop the local server (running boxes are not affected)").action(async () => {
575
+ import { Command as Command11 } from "commander";
576
+ var stopCommand2 = new Command11("stop").description("stop the local server (running boxes are not affected)").action(async () => {
494
577
  const p = paths();
495
578
  let pid;
496
579
  try {
@@ -507,29 +590,29 @@ var stopCommand2 = new Command10("stop").description("stop the local server (run
507
590
  });
508
591
 
509
592
  // src/commands/server/index.ts
510
- var serverCommand = new Command11("server").description("run or manage the kvbox server").addCommand(startCommand2).addCommand(statusCommand).addCommand(stopCommand2);
593
+ var serverCommand = new Command12("server").description("run or manage the kvbox server").addCommand(startCommand2).addCommand(statusCommand).addCommand(stopCommand2);
511
594
 
512
595
  // src/commands/snapshot/index.ts
513
- import { Command as Command15 } from "commander";
596
+ import { Command as Command16 } from "commander";
514
597
 
515
598
  // src/commands/snapshot/ls.ts
516
- import { Command as Command12 } from "commander";
517
- var lsCommand2 = new Command12("ls").description("list snapshots").option("--json", "print as JSON").action(() => notImplemented("snapshot ls"));
599
+ import { Command as Command13 } from "commander";
600
+ var lsCommand2 = new Command13("ls").description("list snapshots").option("--json", "print as JSON").action(() => notImplemented("snapshot ls"));
518
601
 
519
602
  // src/commands/snapshot/rm.ts
520
- import { Command as Command13 } from "commander";
521
- var rmCommand2 = new Command13("rm").description("delete a snapshot").argument("<name>", "snapshot name").option("-y, --yes", "do not ask for confirmation").action(() => notImplemented("snapshot rm"));
603
+ import { Command as Command14 } from "commander";
604
+ var rmCommand2 = new Command14("rm").description("delete a snapshot").argument("<name>", "snapshot name").option("-y, --yes", "do not ask for confirmation").action(() => notImplemented("snapshot rm"));
522
605
 
523
606
  // src/commands/snapshot/save.ts
524
- import { Command as Command14 } from "commander";
525
- var saveCommand = new Command14("save").description("freeze a running box (memory + disk) into a snapshot").argument("<box>", "box name").argument("<name>", "snapshot name").option("--json", "print the snapshot as JSON").action(() => notImplemented("snapshot save"));
607
+ import { Command as Command15 } from "commander";
608
+ var saveCommand = new Command15("save").description("freeze a running box (memory + disk) into a snapshot").argument("<box>", "box name").argument("<name>", "snapshot name").option("--json", "print the snapshot as JSON").action(() => notImplemented("snapshot save"));
526
609
 
527
610
  // src/commands/snapshot/index.ts
528
- var snapshotCommand = new Command15("snapshot").alias("snap").description("manage snapshots").addCommand(saveCommand).addCommand(lsCommand2).addCommand(rmCommand2);
611
+ var snapshotCommand = new Command16("snapshot").alias("snap").description("manage snapshots").addCommand(saveCommand).addCommand(lsCommand2).addCommand(rmCommand2);
529
612
 
530
613
  // src/program.ts
531
614
  function buildProgram() {
532
- const program = new Command16("kvbox").description("self-hosted Firecracker microVMs with Docker-like ergonomics").version(VERSION, "-v, --version").option("--host <name>", "target a configured remote host (M2)").showHelpAfterError().enablePositionalOptions();
615
+ const program = new Command17("kvbox").description("self-hosted Firecracker microVMs with Docker-like ergonomics").version(VERSION, "-v, --version").option("--host <name>", "target a configured remote host (M2)").showHelpAfterError().enablePositionalOptions();
533
616
  program.addCommand(vmCommand);
534
617
  program.addCommand(snapshotCommand);
535
618
  program.addCommand(serverCommand);
package/dist/kvbox.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/output.ts","../src/program.ts","../../shared/src/version.ts","../src/version.ts","../src/commands/vm/index.ts","../src/commands/vm/connect.ts","../../shared/src/errors.ts","../src/client.ts","../../shared/src/api.ts","../../shared/src/sizes.ts","../../shared/src/paths.ts","../src/commands/vm/ls.ts","../src/commands/vm/new.ts","../src/commands/vm/rm.ts","../src/commands/vm/start.ts","../src/commands/vm/stop.ts","../src/commands/server/index.ts","../src/commands/server/start.ts","../src/commands/server/status.ts","../src/commands/server/stop.ts","../src/commands/snapshot/index.ts","../src/commands/snapshot/ls.ts","../src/commands/snapshot/rm.ts","../src/commands/snapshot/save.ts","../src/index.ts"],"sourcesContent":["/** Printing: tables for humans, `--json` for agents, colors only on a TTY. */\nimport pc from \"picocolors\";\n\nexport const color = pc.createColors(process.stdout.isTTY === true && !process.env[\"NO_COLOR\"]);\n\nexport function json(value: unknown): void {\n process.stdout.write(JSON.stringify(value, null, 2) + \"\\n\");\n}\n\nexport function table(rows: Record<string, string | number | null | undefined>[], columns?: string[]): void {\n if (rows.length === 0) return;\n const cols = columns ?? Object.keys(rows[0]!);\n const cells = rows.map((r) => cols.map((c) => String(r[c] ?? \"\")));\n const widths = cols.map((c, i) => Math.max(c.length, ...cells.map((r) => r[i]!.length)));\n const line = (parts: string[]) => parts.map((p, i) => p.padEnd(widths[i]!)).join(\" \").trimEnd();\n process.stdout.write(color.dim(line(cols.map((c) => c.toUpperCase()))) + \"\\n\");\n for (const row of cells) process.stdout.write(line(row) + \"\\n\");\n}\n\nexport function info(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nexport function warn(msg: string): void {\n process.stderr.write(color.yellow(msg) + \"\\n\");\n}\n\nexport function notImplemented(command: string): never {\n process.stderr.write(color.yellow(`kvbox ${command}: not implemented yet\\n`));\n process.exit(2);\n}\n\n/** y/N prompt on a TTY; requires `-y` otherwise (boxd's rule for destructive commands). */\nexport async function confirm(question: string, yes: boolean): Promise<boolean> {\n if (yes) return true;\n if (!process.stdin.isTTY) {\n warn(\"refusing without -y when stdin is not a terminal\");\n return false;\n }\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();\n return answer === \"y\" || answer === \"yes\";\n } finally {\n rl.close();\n }\n}\n\n/** Bytes for humans: 4 GiB -> \"4 GB\", 3.4 GiB -> \"3.4 GB\", under 1 GiB -> \"640 MB\". */\nexport function gb(bytes: number): string {\n const g = bytes / 1024 ** 3;\n if (g >= 1) return `${Number.isInteger(g) ? g : g.toFixed(1)} GB`;\n return `${Math.round(bytes / 1024 ** 2)} MB`;\n}\n","/** Builds the commander tree. Importable without side effects (tests); src/index.ts runs it. */\nimport { Command } from \"commander\";\nimport { VERSION } from \"./version.js\";\nimport { vmAliases, vmCommand } from \"./commands/vm/index.js\";\nimport { serverCommand } from \"./commands/server/index.js\";\nimport { snapshotCommand } from \"./commands/snapshot/index.js\";\n\nexport function buildProgram(): Command {\n const program = new Command(\"kvbox\")\n .description(\"self-hosted Firecracker microVMs with Docker-like ergonomics\")\n .version(VERSION, \"-v, --version\")\n .option(\"--host <name>\", \"target a configured remote host (M2)\")\n .showHelpAfterError()\n .enablePositionalOptions();\n\n program.addCommand(vmCommand);\n program.addCommand(snapshotCommand);\n program.addCommand(serverCommand);\n // Top-level shortcuts: the same Command objects as under `vm`.\n for (const cmd of vmAliases) program.addCommand(cmd);\n\n return program;\n}\n","/**\n * Each binary's version comes from its own package.json: tsup injects\n * `__KVBOX_VERSION__` at build time; the dev path (tsx) reads the file.\n * Usage in a package: `versionOf(import.meta.url)` from its `src/version.ts`.\n */\nimport { createRequire } from \"node:module\";\n\nexport function versionOf(srcFileUrl: string, injected?: string): string {\n if (typeof injected === \"string\") return injected;\n try {\n const require = createRequire(srcFileUrl);\n return (require(\"../package.json\") as { version: string }).version;\n } catch {\n return \"0.0.0-dev\";\n }\n}\n","import { versionOf } from \"@kvbox/shared/version\";\n\ndeclare const __KVBOX_VERSION__: string | undefined;\n\nexport const VERSION: string = versionOf(import.meta.url, typeof __KVBOX_VERSION__ === \"string\" ? __KVBOX_VERSION__ : undefined);\n","import { Command } from \"commander\";\nimport { connectCommand } from \"./connect.js\";\nimport { lsCommand } from \"./ls.js\";\nimport { newCommand } from \"./new.js\";\nimport { rmCommand } from \"./rm.js\";\nimport { startCommand } from \"./start.js\";\nimport { stopCommand } from \"./stop.js\";\n\nexport const vmCommand = new Command(\"vm\")\n .enablePositionalOptions()\n .description(\"manage boxes (each one is a Firecracker microVM)\")\n .addCommand(newCommand)\n .addCommand(lsCommand)\n .addCommand(connectCommand)\n .addCommand(stopCommand)\n .addCommand(startCommand)\n .addCommand(rmCommand);\n\n/** The same Command objects, added again at the top level so they cannot drift. */\nexport const vmAliases = [newCommand, lsCommand, connectCommand, stopCommand, startCommand, rmCommand];\n","import { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { clientFor, sshArgs } from \"../../client.js\";\n\n/** kvbox vm connect <name> [-- cmd...] — ssh kvbox@<ip> with the kvbox key; a shell, or run a command */\nexport const connectCommand = new Command(\"connect\")\n .description(\"open a shell in a box over SSH (or run a command: kvbox connect <name> -- <cmd>)\")\n .argument(\"<name>\", \"box name\")\n .argument(\"[cmd...]\", \"command to run instead of a shell\")\n .passThroughOptions()\n .action(async (name: string, cmdArgs: string[], _opts: unknown, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n let ip: string;\n try {\n const box = (await client.listMachines()).find((b) => b.name === name);\n if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);\n if (box.status !== \"running\") throw new KvboxError(`box ${name} is ${box.status}`);\n ip = box.ip;\n } finally {\n await client.close();\n }\n const res = spawnSync(\"ssh\", [...sshArgs(ip), ...cmdArgs], { stdio: \"inherit\" });\n if (res.error) throw new KvboxError(`could not run ssh: ${res.error.message}`);\n process.exit(res.status ?? 1);\n });\n","/** Errors with an exit code; the entry point prints `message` and exits with `exitCode`. */\nexport class KvboxError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"KvboxError\";\n }\n}\n\nexport class NotImplementedError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not implemented yet`, 2);\n this.name = \"NotImplementedError\";\n }\n}\n\n/** The named box/snapshot/host does not exist: HTTP 404, exit 1. */\nexport class NotFoundError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not found`, 1);\n this.name = \"NotFoundError\";\n }\n}\n","/**\n * ServerClient: one method per route of the kvbox API, over undici.\n * Target resolution: `--host` -> configured hosts (M2) -> local Unix socket.\n * Auto-starting the local server from every command when nothing listens is #17;\n * `startLocalServer` below is the piece it will reuse.\n */\nimport { spawn } from \"node:child_process\";\nimport { openSync } from \"node:fs\";\nimport { mkdir, stat } from \"node:fs/promises\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { Agent, request, type Dispatcher } from \"undici\";\nimport { z } from \"zod\";\nimport {\n ApiErrorSchema,\n CapacitySchema,\n HealthSchema,\n MachineSchema,\n SnapshotSchema,\n type CreateMachineRequest,\n type CreateSnapshotRequest,\n} from \"@kvbox/shared/api\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\n\nexport type Target = { kind: \"local\"; socketPath: string } | { kind: \"remote\"; name: string; url: string };\n\nexport function resolveTarget(hostFlag?: string): Target {\n if (hostFlag) {\n throw new KvboxError(`--host ${hostFlag}: remote hosts arrive in M2`);\n }\n return { kind: \"local\", socketPath: paths().serverSock };\n}\n\nexport interface ClientOptions {\n /** Spawn `kvbox-server` when the local socket does not answer (default true; the start probe turns it off). */\n autoStart?: boolean;\n}\n\nexport class ServerClient {\n private readonly dispatcher: Dispatcher;\n private readonly base: string;\n private readonly autoStart: boolean;\n private startedOnce = false;\n\n constructor(\n readonly target: Target,\n opts: ClientOptions = {},\n ) {\n this.autoStart = opts.autoStart ?? true;\n if (target.kind === \"local\") {\n this.dispatcher = new Agent({ connect: { socketPath: target.socketPath } });\n this.base = \"http://kvbox\";\n } else {\n this.dispatcher = new Agent();\n this.base = target.url;\n }\n }\n\n private async call<T>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n schema: z.ZodType<T>,\n body?: unknown,\n ): Promise<T> {\n let res;\n try {\n res = await request(this.base + path, {\n dispatcher: this.dispatcher,\n method,\n headers: body === undefined ? {} : { \"content-type\": \"application/json\" },\n body: body === undefined ? null : JSON.stringify(body),\n });\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code ?? (err as Error).cause;\n if (this.target.kind === \"local\") {\n // Nothing listens locally: start the daemon once and retry (architecture: \"auto-start\").\n if (this.autoStart && !this.startedOnce) {\n this.startedOnce = true;\n await startLocalServer(paths(), 5000);\n return this.call(method, path, schema, body);\n }\n throw new KvboxError(`kvbox-server is not running (${String(code)}); start it with: kvbox server start`);\n }\n throw new KvboxError(`cannot reach ${this.target.name}: ${String(code)}`);\n }\n const text = await res.body.text();\n if (res.statusCode >= 300) {\n const parsed = ApiErrorSchema.safeParse(text ? JSON.parse(text) : {});\n const msg = parsed.success ? parsed.data.error : `${res.statusCode} ${text}`;\n throw new KvboxError(msg, res.statusCode === 501 ? 2 : 1);\n }\n return schema.parse(text ? JSON.parse(text) : undefined);\n }\n\n health() {\n return this.call(\"GET\", \"/health\", HealthSchema);\n }\n\n capacity() {\n return this.call(\"GET\", \"/capacity\", CapacitySchema);\n }\n\n listMachines() {\n return this.call(\"GET\", \"/machines\", z.array(MachineSchema));\n }\n\n createMachine(req: CreateMachineRequest) {\n return this.call(\"POST\", \"/machines\", MachineSchema, req);\n }\n\n stopMachine(name: string) {\n return this.call(\"POST\", `/machines/${encodeURIComponent(name)}/stop`, MachineSchema);\n }\n\n startMachine(name: string) {\n return this.call(\"POST\", `/machines/${encodeURIComponent(name)}/start`, MachineSchema);\n }\n\n deleteMachine(name: string) {\n return this.call(\"DELETE\", `/machines/${encodeURIComponent(name)}`, z.undefined());\n }\n\n listSnapshots() {\n return this.call(\"GET\", \"/snapshots\", z.array(SnapshotSchema));\n }\n\n createSnapshot(req: CreateSnapshotRequest) {\n return this.call(\"POST\", \"/snapshots\", SnapshotSchema, req);\n }\n\n deleteSnapshot(name: string) {\n return this.call(\"DELETE\", `/snapshots/${encodeURIComponent(name)}`, z.undefined());\n }\n\n async close() {\n await this.dispatcher.close();\n }\n}\n\n/** Build a client from the global `--host` option of the root command. */\nexport function clientFor(opts: { host?: string }, client: ClientOptions = {}): ServerClient {\n return new ServerClient(resolveTarget(opts.host), client);\n}\n\n/**\n * `ssh` argv for a box. Host keys are per box and IPs get reused, so no known_hosts;\n * SetEnv pins the locale because the image only ships C.UTF-8 (#24).\n */\nexport function sshArgs(ip: string, keyPath: string = paths().sshKey): string[] {\n return [\n \"-i\", keyPath,\n \"-o\", \"StrictHostKeyChecking=no\",\n \"-o\", \"UserKnownHostsFile=/dev/null\",\n \"-o\", \"LogLevel=ERROR\",\n \"-o\", \"SetEnv=LC_ALL=C.UTF-8\",\n `kvbox@${ip}`,\n ];\n}\n\nexport const NOT_A_HOST_HINT =\n \"kvbox-server is not installed, so this machine is not a kvbox host. \" +\n \"Set it up with install-server.sh, or point the CLI at a remote host (M2: kvbox host add).\";\n\n/**\n * Spawn `kvbox-server start` from PATH, detached, stdio to ~/.kvbox/server.log,\n * and resolve once its socket accepts a /health call (or reject after `timeoutMs`).\n */\nexport async function startLocalServer(p: Paths = paths(), timeoutMs = 5000): Promise<{ pid: number; socketPath: string }> {\n await mkdir(p.home, { recursive: true });\n const log = openSync(p.serverLog, \"a\");\n const child = spawn(\"kvbox-server\", [\"start\"], { detached: true, stdio: [\"ignore\", log, log] });\n\n const failed = new Promise<never>((_, reject) => {\n child.once(\"error\", (err: NodeJS.ErrnoException) => {\n reject(new KvboxError(err.code === \"ENOENT\" ? NOT_A_HOST_HINT : `could not start kvbox-server: ${err.message}`));\n });\n child.once(\"exit\", (code) => {\n reject(new KvboxError(`kvbox-server exited with code ${String(code)} before listening; see ${p.serverLog}`));\n });\n });\n\n const ready = (async () => {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await stat(p.serverSock).then(() => true, () => false)) {\n const probe = new ServerClient({ kind: \"local\", socketPath: p.serverSock }, { autoStart: false });\n try {\n await probe.health();\n return;\n } catch {\n // socket exists but not serving yet\n } finally {\n await probe.close();\n }\n }\n await sleep(100);\n }\n throw new KvboxError(`kvbox-server did not start within ${timeoutMs / 1000}s; see ${p.serverLog}`);\n })();\n\n await Promise.race([ready, failed]);\n child.removeAllListeners(\"exit\");\n child.unref();\n return { pid: child.pid ?? -1, socketPath: p.serverSock };\n}\n","/**\n * Wire shapes of the kvbox HTTP API, shared by the client (src/cli) and the\n * server (src/server). Validated with zod on both sides because the client\n * may be talking to an older or newer server.\n */\nimport { z } from \"zod\";\nimport { SIZE_NAMES } from \"./sizes.js\";\n\nexport const SizeSchema = z.enum(SIZE_NAMES as [string, ...string[]]);\n\nexport const MachineSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n diskBytes: z.number().int(), // size of the disk as the guest sees it\n diskUsedBytes: z.number().int(), // what the sparse disk file really occupies on the host\n createdAt: z.string(),\n source: z.string(), // \"base\" or \"snapshot:<name>\"\n status: z.enum([\"running\", \"stopped\"]),\n});\nexport type Machine = z.infer<typeof MachineSchema>;\n\nexport const CreateMachineRequest = z.object({\n name: z.string().optional(),\n size: SizeSchema.optional(),\n from: z.string().optional(),\n force: z.boolean().optional(),\n});\nexport type CreateMachineRequest = z.infer<typeof CreateMachineRequest>;\n\nexport const SnapshotSchema = z.object({\n name: z.string(),\n source: z.string(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n createdAt: z.string(),\n});\nexport type Snapshot = z.infer<typeof SnapshotSchema>;\n\nexport const CreateSnapshotRequest = z.object({\n box: z.string(),\n name: z.string(),\n});\nexport type CreateSnapshotRequest = z.infer<typeof CreateSnapshotRequest>;\n\nexport const CapacitySchema = z.object({\n hostMemMib: z.number().int(),\n hostCores: z.number().int(),\n reservedMemMib: z.number().int(),\n reservedVcpu: z.number().int(),\n running: z.number().int(),\n});\nexport type Capacity = z.infer<typeof CapacitySchema>;\n\nexport const HealthSchema = z.object({\n ok: z.literal(true),\n version: z.string(),\n pid: z.number().int(),\n});\nexport type Health = z.infer<typeof HealthSchema>;\n\nexport const ApiErrorSchema = z.object({\n error: z.string(),\n});\n","/** Fixed box sizes. Firecracker backs guest memory lazily, so a box only costs what the guest touches. */\nexport const SIZES = {\n s: { vcpu: 2, memMib: 4096 },\n m: { vcpu: 4, memMib: 8192 },\n l: { vcpu: 8, memMib: 16384 },\n} as const;\n\nexport type SizeName = keyof typeof SIZES;\nexport const SIZE_NAMES = Object.keys(SIZES) as SizeName[];\nexport const DEFAULT_SIZE: SizeName = \"s\";\n\nexport function isSizeName(value: string): value is SizeName {\n return value in SIZES;\n}\n","/**\n * Host state layout. The filesystem is the database and `~/.kvbox` is its root.\n * This module is dependency-free so both the CLI (socket path, hosts.json)\n * and core (everything else) can use it without crossing the layer boundary.\n *\n * `KVBOX_HOME` overrides the root, mainly for tests.\n */\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function kvboxHome(): string {\n return process.env[\"KVBOX_HOME\"] ?? join(homedir(), \".kvbox\");\n}\n\nexport function paths(home: string = kvboxHome()) {\n return {\n home,\n config: join(home, \"config.json\"),\n serverSock: join(home, \"server.sock\"),\n serverPid: join(home, \"server.pid\"),\n serverLog: join(home, \"server.log\"),\n hosts: join(home, \"hosts.json\"),\n ssh: join(home, \"ssh\"),\n sshKey: join(home, \"ssh\", \"id_ed25519\"),\n bin: join(home, \"bin\"),\n firecracker: join(home, \"bin\", \"firecracker\"),\n assets: join(home, \"assets\"),\n kernel: join(home, \"assets\", \"vmlinux\"),\n rootfs: join(home, \"assets\", \"rootfs.ext4\"),\n machines: join(home, \"machines\"),\n snapshots: join(home, \"snapshots\"),\n machine: (name: string) => ({\n dir: join(home, \"machines\", name),\n meta: join(home, \"machines\", name, \"meta.json\"),\n disk: join(home, \"machines\", name, \"disk.ext4\"),\n sock: join(home, \"machines\", name, \"fc.sock\"),\n log: join(home, \"machines\", name, \"fc.log\"),\n }),\n snapshot: (name: string) => ({\n dir: join(home, \"snapshots\", name),\n meta: join(home, \"snapshots\", name, \"meta.json\"),\n vmstate: join(home, \"snapshots\", name, \"vmstate\"),\n mem: join(home, \"snapshots\", name, \"mem\"),\n disk: join(home, \"snapshots\", name, \"disk.ext4\"),\n }),\n } as const;\n}\n\nexport type Paths = ReturnType<typeof paths>;\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { gb, info, json, table } from \"../../output.js\";\n\n/** kvbox vm ls [--json] — --json output: Machine[] */\nexport const lsCommand = new Command(\"ls\")\n .description(\"list boxes with status and IP\")\n .option(\"--json\", \"print as JSON\")\n .action(async (opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const boxes = await client.listMachines();\n if (opts.json) {\n json(boxes);\n return;\n }\n if (boxes.length === 0) {\n info(\"no boxes yet; create one with: kvbox new\");\n return;\n }\n table(\n boxes.map((b) => ({\n name: b.name,\n status: b.status,\n ip: b.ip,\n cpu: `${b.vcpu} vCPU`,\n ram: gb(b.memMib * 1024 ** 2),\n disk: `${gb(b.diskBytes)} (${gb(b.diskUsedBytes)} used)`,\n source: b.source,\n created: b.createdAt.replace(\"T\", \" \").slice(0, 16),\n })),\n );\n } finally {\n await client.close();\n }\n });\n","import { Command, Option } from \"commander\";\nimport type { Machine } from \"@kvbox/shared/api\";\nimport { SIZE_NAMES } from \"@kvbox/shared/sizes\";\nimport { clientFor } from \"../../client.js\";\nimport { color, gb, info, json } from \"../../output.js\";\n\n/**\n * kvbox vm new [name] [--size s|m|l] [--from <snapshot>] [--force] [--json]\n * --json output: the Machine object (see packages/shared/src/api.ts).\n */\nexport const newCommand = new Command(\"new\")\n .description(\"boot a new box from the base image or a snapshot\")\n .argument(\"[name]\", \"box name (box1, box2, … when omitted)\")\n .addOption(new Option(\"-s, --size <size>\", \"box size (default: server config, s)\").choices(SIZE_NAMES))\n .option(\"-f, --from <snapshot>\", \"start from a snapshot instead of the base image\")\n .option(\"--force\", \"skip the capacity guard\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string | undefined, opts: { size?: string; from?: string; force?: boolean; json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.createMachine({\n ...(name !== undefined ? { name } : {}),\n ...(opts.size !== undefined ? { size: opts.size } : {}),\n ...(opts.from !== undefined ? { from: opts.from } : {}),\n ...(opts.force ? { force: true } : {}),\n });\n if (opts.json) {\n json(box);\n return;\n }\n process.stdout.write(`${box.name}\\n`);\n info(`${color.green(\"✓\")} ${describe(box)}`);\n info(` connect with: kvbox connect ${box.name} (SSH is up a couple of seconds after boot)`);\n } finally {\n await client.close();\n }\n });\n\nexport function describe(box: Machine): string {\n return `box ${color.bold(box.name)} is ${box.status} at ${box.ip}: ${box.vcpu} vCPU, ${gb(box.memMib * 1024 ** 2)} RAM, ${gb(box.diskBytes)} disk`;\n}\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, confirm, info } from \"../../output.js\";\n\n/** kvbox vm rm <name> [-y] — destructive: asks y/N on a TTY, needs -y otherwise */\nexport const rmCommand = new Command(\"rm\")\n .description(\"destroy a box (its disk is deleted; snapshots are kept)\")\n .argument(\"<name>\", \"box name\")\n .option(\"-y, --yes\", \"do not ask for confirmation\")\n .action(async (name: string, opts: { yes?: boolean }, cmd: Command) => {\n if (!(await confirm(`Destroy box ${name} and its disk?`, opts.yes ?? false))) {\n info(\"cancelled\");\n process.exitCode = 1;\n return;\n }\n const client = clientFor(cmd.optsWithGlobals());\n try {\n await client.deleteMachine(name);\n info(`${color.green(\"✓\")} box ${name} destroyed`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, info, json } from \"../../output.js\";\nimport { describe } from \"./new.js\";\n\n/** kvbox vm start <name> [--json] — boot a stopped box from its own disk; --json output: the Machine object */\nexport const startCommand = new Command(\"start\")\n .description(\"boot a stopped box again (same name, IP and disk)\")\n .argument(\"<name>\", \"box name\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string, opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.startMachine(name);\n if (opts.json) json(box);\n else info(`${color.green(\"✓\")} ${describe(box)}`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, info, json } from \"../../output.js\";\n\n/** kvbox vm stop <name> [--json] — clean shutdown, disk kept; --json output: the Machine object */\nexport const stopCommand = new Command(\"stop\")\n .description(\"shut a box down (its disk is kept; start it again with kvbox start)\")\n .argument(\"<name>\", \"box name\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string, opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.stopMachine(name);\n if (opts.json) json(box);\n else info(`${color.green(\"✓\")} box ${name} stopped (disk kept; kvbox start ${name} boots it again)`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { startCommand } from \"./start.js\";\nimport { statusCommand } from \"./status.js\";\nimport { stopCommand } from \"./stop.js\";\n\nexport const serverCommand = new Command(\"server\")\n .description(\"run or manage the kvbox server\")\n .addCommand(startCommand)\n .addCommand(statusCommand)\n .addCommand(stopCommand);\n","/**\n * kvbox server start\n * Starts the local `kvbox-server` (a separate package) detached, logging to\n * ~/.kvbox/server.log, and waits for its socket. The CLI never imports server code.\n */\nimport { Command } from \"commander\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { clientFor, startLocalServer } from \"../../client.js\";\nimport { info } from \"../../output.js\";\n\nexport const startCommand = new Command(\"start\")\n .description(\"start the local kvbox-server in the background\")\n .action(async (_opts: Record<string, never>, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals(), { autoStart: false });\n try {\n const health = await client.health();\n info(`kvbox-server ${health.version} is already running (pid ${health.pid})`);\n return;\n } catch {\n // not running: start it\n } finally {\n await client.close();\n }\n const { pid, socketPath } = await startLocalServer(paths());\n info(`kvbox-server started (pid ${pid}), listening on ${socketPath}`);\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { info, json } from \"../../output.js\";\n\n/** kvbox server status [--json] — --json output: Health */\nexport const statusCommand = new Command(\"status\")\n .description(\"show whether the server is running\")\n .option(\"--json\", \"print as JSON\")\n .action(async (opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const health = await client.health();\n if (opts.json) json(health);\n else info(`kvbox-server ${health.version} running, pid ${health.pid}`);\n } finally {\n await client.close();\n }\n });\n","import { readFile } from \"node:fs/promises\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { info } from \"../../output.js\";\n\n/** kvbox server stop — SIGTERM the pid in server.pid. Boxes keep running. */\nexport const stopCommand = new Command(\"stop\")\n .description(\"stop the local server (running boxes are not affected)\")\n .action(async () => {\n const p = paths();\n let pid: number;\n try {\n pid = Number.parseInt(await readFile(p.serverPid, \"utf8\"), 10);\n } catch {\n throw new KvboxError(\"kvbox-server is not running (no pid file)\");\n }\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n throw new KvboxError(`kvbox-server pid ${pid} is not running; remove ${p.serverPid}`);\n }\n info(`sent SIGTERM to kvbox-server (pid ${pid})`);\n });\n","import { Command } from \"commander\";\nimport { lsCommand } from \"./ls.js\";\nimport { rmCommand } from \"./rm.js\";\nimport { saveCommand } from \"./save.js\";\n\nexport const snapshotCommand = new Command(\"snapshot\")\n .alias(\"snap\")\n .description(\"manage snapshots\")\n .addCommand(saveCommand)\n .addCommand(lsCommand)\n .addCommand(rmCommand);\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot ls [--json] — --json output: Snapshot[] */\nexport const lsCommand = new Command(\"ls\")\n .description(\"list snapshots\")\n .option(\"--json\", \"print as JSON\")\n .action(() => notImplemented(\"snapshot ls\"));\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot rm <name> [-y] — destructive: asks y/N on a TTY, needs -y otherwise */\nexport const rmCommand = new Command(\"rm\")\n .description(\"delete a snapshot\")\n .argument(\"<name>\", \"snapshot name\")\n .option(\"-y, --yes\", \"do not ask for confirmation\")\n .action(() => notImplemented(\"snapshot rm\"));\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot save <box> <name> [--json] — --json output: Snapshot */\nexport const saveCommand = new Command(\"save\")\n .description(\"freeze a running box (memory + disk) into a snapshot\")\n .argument(\"<box>\", \"box name\")\n .argument(\"<name>\", \"snapshot name\")\n .option(\"--json\", \"print the snapshot as JSON\")\n .action(() => notImplemented(\"snapshot save\"));\n","/** Entry point: parse argv, map KvboxError to an exit code. */\nimport { color } from \"./output.js\";\nimport { buildProgram } from \"./program.js\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\ntry {\n await buildProgram().parseAsync(process.argv);\n} catch (err) {\n if (err instanceof KvboxError) {\n process.stderr.write(color.red(`error: ${err.message}`) + \"\\n\");\n process.exit(err.exitCode);\n }\n throw err;\n}\n"],"mappings":"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","names":["Command","require","Command","z","z","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","startCommand","Command","Command","Command","Command","stopCommand","Command","Command","startCommand","stopCommand","Command","Command","lsCommand","Command","Command","rmCommand","Command","Command","Command","Command","lsCommand","rmCommand","Command"]}
1
+ {"version":3,"sources":["../src/output.ts","../src/program.ts","../../shared/src/version.ts","../src/version.ts","../src/commands/vm/index.ts","../src/commands/vm/connect.ts","../../shared/src/errors.ts","../src/client.ts","../../shared/src/api.ts","../../shared/src/sizes.ts","../../shared/src/paths.ts","../src/commands/vm/exec.ts","../src/commands/vm/ls.ts","../src/commands/vm/new.ts","../src/commands/vm/rm.ts","../src/commands/vm/start.ts","../src/commands/vm/stop.ts","../src/commands/server/index.ts","../src/commands/server/start.ts","../src/commands/server/status.ts","../src/commands/server/stop.ts","../src/commands/snapshot/index.ts","../src/commands/snapshot/ls.ts","../src/commands/snapshot/rm.ts","../src/commands/snapshot/save.ts","../src/index.ts"],"sourcesContent":["/** Printing: tables for humans, `--json` for agents, colors only on a TTY. */\nimport pc from \"picocolors\";\n\nexport const color = pc.createColors(process.stdout.isTTY === true && !process.env[\"NO_COLOR\"]);\n\nexport function json(value: unknown): void {\n process.stdout.write(JSON.stringify(value, null, 2) + \"\\n\");\n}\n\nexport function table(rows: Record<string, string | number | null | undefined>[], columns?: string[]): void {\n if (rows.length === 0) return;\n const cols = columns ?? Object.keys(rows[0]!);\n const cells = rows.map((r) => cols.map((c) => String(r[c] ?? \"\")));\n const widths = cols.map((c, i) => Math.max(c.length, ...cells.map((r) => r[i]!.length)));\n const line = (parts: string[]) => parts.map((p, i) => p.padEnd(widths[i]!)).join(\" \").trimEnd();\n process.stdout.write(color.dim(line(cols.map((c) => c.toUpperCase()))) + \"\\n\");\n for (const row of cells) process.stdout.write(line(row) + \"\\n\");\n}\n\nexport function info(msg: string): void {\n process.stderr.write(msg + \"\\n\");\n}\n\nexport function warn(msg: string): void {\n process.stderr.write(color.yellow(msg) + \"\\n\");\n}\n\nexport function notImplemented(command: string): never {\n process.stderr.write(color.yellow(`kvbox ${command}: not implemented yet\\n`));\n process.exit(2);\n}\n\n/** y/N prompt on a TTY; requires `-y` otherwise (boxd's rule for destructive commands). */\nexport async function confirm(question: string, yes: boolean): Promise<boolean> {\n if (yes) return true;\n if (!process.stdin.isTTY) {\n warn(\"refusing without -y when stdin is not a terminal\");\n return false;\n }\n const { createInterface } = await import(\"node:readline/promises\");\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n try {\n const answer = (await rl.question(`${question} [y/N] `)).trim().toLowerCase();\n return answer === \"y\" || answer === \"yes\";\n } finally {\n rl.close();\n }\n}\n\n/** Bytes for humans: 4 GiB -> \"4 GB\", 3.4 GiB -> \"3.4 GB\", under 1 GiB -> \"640 MB\". */\nexport function gb(bytes: number): string {\n const g = bytes / 1024 ** 3;\n if (g >= 1) return `${Number.isInteger(g) ? g : g.toFixed(1)} GB`;\n return `${Math.round(bytes / 1024 ** 2)} MB`;\n}\n","/** Builds the commander tree. Importable without side effects (tests); src/index.ts runs it. */\nimport { Command } from \"commander\";\nimport { VERSION } from \"./version.js\";\nimport { vmAliases, vmCommand } from \"./commands/vm/index.js\";\nimport { serverCommand } from \"./commands/server/index.js\";\nimport { snapshotCommand } from \"./commands/snapshot/index.js\";\n\nexport function buildProgram(): Command {\n const program = new Command(\"kvbox\")\n .description(\"self-hosted Firecracker microVMs with Docker-like ergonomics\")\n .version(VERSION, \"-v, --version\")\n .option(\"--host <name>\", \"target a configured remote host (M2)\")\n .showHelpAfterError()\n .enablePositionalOptions();\n\n program.addCommand(vmCommand);\n program.addCommand(snapshotCommand);\n program.addCommand(serverCommand);\n // Top-level shortcuts: the same Command objects as under `vm`.\n for (const cmd of vmAliases) program.addCommand(cmd);\n\n return program;\n}\n","/**\n * Each binary's version comes from its own package.json: tsup injects\n * `__KVBOX_VERSION__` at build time; the dev path (tsx) reads the file.\n * Usage in a package: `versionOf(import.meta.url)` from its `src/version.ts`.\n */\nimport { createRequire } from \"node:module\";\n\nexport function versionOf(srcFileUrl: string, injected?: string): string {\n if (typeof injected === \"string\") return injected;\n try {\n const require = createRequire(srcFileUrl);\n return (require(\"../package.json\") as { version: string }).version;\n } catch {\n return \"0.0.0-dev\";\n }\n}\n","import { versionOf } from \"@kvbox/shared/version\";\n\ndeclare const __KVBOX_VERSION__: string | undefined;\n\nexport const VERSION: string = versionOf(import.meta.url, typeof __KVBOX_VERSION__ === \"string\" ? __KVBOX_VERSION__ : undefined);\n","import { Command } from \"commander\";\nimport { connectCommand } from \"./connect.js\";\nimport { execCommand } from \"./exec.js\";\nimport { lsCommand } from \"./ls.js\";\nimport { newCommand } from \"./new.js\";\nimport { rmCommand } from \"./rm.js\";\nimport { startCommand } from \"./start.js\";\nimport { stopCommand } from \"./stop.js\";\n\nexport const vmCommand = new Command(\"vm\")\n .enablePositionalOptions()\n .description(\"manage boxes (each one is a Firecracker microVM)\")\n .addCommand(newCommand)\n .addCommand(lsCommand)\n .addCommand(connectCommand)\n .addCommand(execCommand)\n .addCommand(stopCommand)\n .addCommand(startCommand)\n .addCommand(rmCommand);\n\n/** The same Command objects, added again at the top level so they cannot drift. */\nexport const vmAliases = [newCommand, lsCommand, connectCommand, execCommand, stopCommand, startCommand, rmCommand];\n","import { spawnSync } from \"node:child_process\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { clientFor, sshArgs } from \"../../client.js\";\n\n/** kvbox vm connect <name> [-- cmd...] — ssh kvbox@<ip> with the kvbox key; a shell, or run a command */\nexport const connectCommand = new Command(\"connect\")\n .description(\"open a shell in a box over SSH (or run a command: kvbox connect <name> -- <cmd>)\")\n .argument(\"<name>\", \"box name\")\n .argument(\"[cmd...]\", \"command to run instead of a shell\")\n .passThroughOptions()\n .action(async (name: string, cmdArgs: string[], _opts: unknown, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n let ip: string;\n try {\n const box = (await client.listMachines()).find((b) => b.name === name);\n if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);\n if (box.status !== \"running\") throw new KvboxError(`box ${name} is ${box.status}`);\n ip = box.ip;\n } finally {\n await client.close();\n }\n const res = spawnSync(\"ssh\", [...sshArgs(ip), ...cmdArgs], { stdio: \"inherit\" });\n if (res.error) throw new KvboxError(`could not run ssh: ${res.error.message}`);\n process.exit(res.status ?? 1);\n });\n","/** Errors with an exit code; the entry point prints `message` and exits with `exitCode`. */\nexport class KvboxError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number = 1,\n ) {\n super(message);\n this.name = \"KvboxError\";\n }\n}\n\nexport class NotImplementedError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not implemented yet`, 2);\n this.name = \"NotImplementedError\";\n }\n}\n\n/** The named box/snapshot/host does not exist: HTTP 404, exit 1. */\nexport class NotFoundError extends KvboxError {\n constructor(what: string) {\n super(`${what}: not found`, 1);\n this.name = \"NotFoundError\";\n }\n}\n","/**\n * ServerClient: one method per route of the kvbox API, over undici.\n * Target resolution: `--host` -> configured hosts (M2) -> local Unix socket.\n * Auto-starting the local server from every command when nothing listens is #17;\n * `startLocalServer` below is the piece it will reuse.\n */\nimport { spawn } from \"node:child_process\";\nimport { openSync } from \"node:fs\";\nimport { mkdir, stat } from \"node:fs/promises\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\nimport { Agent, request, type Dispatcher } from \"undici\";\nimport { z } from \"zod\";\nimport {\n ApiErrorSchema,\n CapacitySchema,\n HealthSchema,\n MachineSchema,\n SnapshotSchema,\n type CreateMachineRequest,\n type CreateSnapshotRequest,\n} from \"@kvbox/shared/api\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths, type Paths } from \"@kvbox/shared/paths\";\n\nexport type Target = { kind: \"local\"; socketPath: string } | { kind: \"remote\"; name: string; url: string };\n\nexport function resolveTarget(hostFlag?: string): Target {\n if (hostFlag) {\n throw new KvboxError(`--host ${hostFlag}: remote hosts arrive in M2`);\n }\n return { kind: \"local\", socketPath: paths().serverSock };\n}\n\nexport interface ClientOptions {\n /** Spawn `kvbox-server` when the local socket does not answer (default true; the start probe turns it off). */\n autoStart?: boolean;\n}\n\nexport class ServerClient {\n private readonly dispatcher: Dispatcher;\n private readonly base: string;\n private readonly autoStart: boolean;\n private startedOnce = false;\n\n constructor(\n readonly target: Target,\n opts: ClientOptions = {},\n ) {\n this.autoStart = opts.autoStart ?? true;\n if (target.kind === \"local\") {\n this.dispatcher = new Agent({ connect: { socketPath: target.socketPath } });\n this.base = \"http://kvbox\";\n } else {\n this.dispatcher = new Agent();\n this.base = target.url;\n }\n }\n\n private async call<T>(\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n schema: z.ZodType<T>,\n body?: unknown,\n ): Promise<T> {\n let res;\n try {\n res = await request(this.base + path, {\n dispatcher: this.dispatcher,\n method,\n headers: body === undefined ? {} : { \"content-type\": \"application/json\" },\n body: body === undefined ? null : JSON.stringify(body),\n });\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code ?? (err as Error).cause;\n if (this.target.kind === \"local\") {\n // Nothing listens locally: start the daemon once and retry (architecture: \"auto-start\").\n if (this.autoStart && !this.startedOnce) {\n this.startedOnce = true;\n await startLocalServer(paths(), 5000);\n return this.call(method, path, schema, body);\n }\n throw new KvboxError(`kvbox-server is not running (${String(code)}); start it with: kvbox server start`);\n }\n throw new KvboxError(`cannot reach ${this.target.name}: ${String(code)}`);\n }\n const text = await res.body.text();\n if (res.statusCode >= 300) {\n const parsed = ApiErrorSchema.safeParse(text ? JSON.parse(text) : {});\n const msg = parsed.success ? parsed.data.error : `${res.statusCode} ${text}`;\n throw new KvboxError(msg, res.statusCode === 501 ? 2 : 1);\n }\n return schema.parse(text ? JSON.parse(text) : undefined);\n }\n\n health() {\n return this.call(\"GET\", \"/health\", HealthSchema);\n }\n\n capacity() {\n return this.call(\"GET\", \"/capacity\", CapacitySchema);\n }\n\n listMachines() {\n return this.call(\"GET\", \"/machines\", z.array(MachineSchema));\n }\n\n createMachine(req: CreateMachineRequest) {\n return this.call(\"POST\", \"/machines\", MachineSchema, req);\n }\n\n stopMachine(name: string) {\n return this.call(\"POST\", `/machines/${encodeURIComponent(name)}/stop`, MachineSchema);\n }\n\n startMachine(name: string) {\n return this.call(\"POST\", `/machines/${encodeURIComponent(name)}/start`, MachineSchema);\n }\n\n deleteMachine(name: string) {\n return this.call(\"DELETE\", `/machines/${encodeURIComponent(name)}`, z.undefined());\n }\n\n listSnapshots() {\n return this.call(\"GET\", \"/snapshots\", z.array(SnapshotSchema));\n }\n\n createSnapshot(req: CreateSnapshotRequest) {\n return this.call(\"POST\", \"/snapshots\", SnapshotSchema, req);\n }\n\n deleteSnapshot(name: string) {\n return this.call(\"DELETE\", `/snapshots/${encodeURIComponent(name)}`, z.undefined());\n }\n\n async close() {\n await this.dispatcher.close();\n }\n}\n\n/** Build a client from the global `--host` option of the root command. */\nexport function clientFor(opts: { host?: string }, client: ClientOptions = {}): ServerClient {\n return new ServerClient(resolveTarget(opts.host), client);\n}\n\n/**\n * `ssh` argv for a box. Host keys are per box and IPs get reused, so no known_hosts;\n * SetEnv pins the locale because the image only ships C.UTF-8 (#24).\n */\nexport function sshArgs(ip: string, keyPath: string = paths().sshKey): string[] {\n return [\n \"-i\", keyPath,\n \"-o\", \"StrictHostKeyChecking=no\",\n \"-o\", \"UserKnownHostsFile=/dev/null\",\n \"-o\", \"LogLevel=ERROR\",\n \"-o\", \"SetEnv=LC_ALL=C.UTF-8\",\n `kvbox@${ip}`,\n ];\n}\n\nexport const NOT_A_HOST_HINT =\n \"kvbox-server is not installed, so this machine is not a kvbox host. \" +\n \"Set it up with install-server.sh, or point the CLI at a remote host (M2: kvbox host add).\";\n\n/**\n * Spawn `kvbox-server start` from PATH, detached, stdio to ~/.kvbox/server.log,\n * and resolve once its socket accepts a /health call (or reject after `timeoutMs`).\n */\nexport async function startLocalServer(p: Paths = paths(), timeoutMs = 5000): Promise<{ pid: number; socketPath: string }> {\n await mkdir(p.home, { recursive: true });\n const log = openSync(p.serverLog, \"a\");\n const child = spawn(\"kvbox-server\", [\"start\"], { detached: true, stdio: [\"ignore\", log, log] });\n\n const failed = new Promise<never>((_, reject) => {\n child.once(\"error\", (err: NodeJS.ErrnoException) => {\n reject(new KvboxError(err.code === \"ENOENT\" ? NOT_A_HOST_HINT : `could not start kvbox-server: ${err.message}`));\n });\n child.once(\"exit\", (code) => {\n reject(new KvboxError(`kvbox-server exited with code ${String(code)} before listening; see ${p.serverLog}`));\n });\n });\n\n const ready = (async () => {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await stat(p.serverSock).then(() => true, () => false)) {\n const probe = new ServerClient({ kind: \"local\", socketPath: p.serverSock }, { autoStart: false });\n try {\n await probe.health();\n return;\n } catch {\n // socket exists but not serving yet\n } finally {\n await probe.close();\n }\n }\n await sleep(100);\n }\n throw new KvboxError(`kvbox-server did not start within ${timeoutMs / 1000}s; see ${p.serverLog}`);\n })();\n\n await Promise.race([ready, failed]);\n child.removeAllListeners(\"exit\");\n child.unref();\n return { pid: child.pid ?? -1, socketPath: p.serverSock };\n}\n","/**\n * Wire shapes of the kvbox HTTP API, shared by the client (src/cli) and the\n * server (src/server). Validated with zod on both sides because the client\n * may be talking to an older or newer server.\n */\nimport { z } from \"zod\";\nimport { SIZE_NAMES } from \"./sizes.js\";\n\nexport const SizeSchema = z.enum(SIZE_NAMES as [string, ...string[]]);\n\nexport const MachineSchema = z.object({\n name: z.string(),\n ip: z.string(),\n mac: z.string(),\n pid: z.number().int().nullable(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n diskBytes: z.number().int(), // the box's own writable disk, as the guest sees it\n diskUsedBytes: z.number().int(), // what that sparse file really occupies on the host\n base: z.string().nullable(), // base image version the box runs on (null: pre-overlay box with its own copy)\n createdAt: z.string(),\n source: z.string(), // \"base\" or \"snapshot:<name>\"\n status: z.enum([\"running\", \"stopped\"]),\n});\nexport type Machine = z.infer<typeof MachineSchema>;\n\nexport const CreateMachineRequest = z.object({\n name: z.string().optional(),\n size: SizeSchema.optional(),\n from: z.string().optional(),\n force: z.boolean().optional(),\n});\nexport type CreateMachineRequest = z.infer<typeof CreateMachineRequest>;\n\nexport const SnapshotSchema = z.object({\n name: z.string(),\n source: z.string(),\n vcpu: z.number().int(),\n memMib: z.number().int(),\n createdAt: z.string(),\n});\nexport type Snapshot = z.infer<typeof SnapshotSchema>;\n\nexport const CreateSnapshotRequest = z.object({\n box: z.string(),\n name: z.string(),\n});\nexport type CreateSnapshotRequest = z.infer<typeof CreateSnapshotRequest>;\n\nexport const CapacitySchema = z.object({\n hostMemMib: z.number().int(),\n hostCores: z.number().int(),\n reservedMemMib: z.number().int(),\n reservedVcpu: z.number().int(),\n running: z.number().int(),\n});\nexport type Capacity = z.infer<typeof CapacitySchema>;\n\nexport const HealthSchema = z.object({\n ok: z.literal(true),\n version: z.string(),\n pid: z.number().int(),\n});\nexport type Health = z.infer<typeof HealthSchema>;\n\nexport const ApiErrorSchema = z.object({\n error: z.string(),\n});\n","/**\n * Fixed box sizes. Firecracker backs guest memory lazily and the disk is a sparse overlay on the\n * shared base image, so a box only costs what the guest actually touches.\n */\nexport const SIZES = {\n s: { vcpu: 2, memMib: 4096, diskGib: 8 },\n m: { vcpu: 4, memMib: 8192, diskGib: 16 },\n l: { vcpu: 8, memMib: 16384, diskGib: 32 },\n} as const;\n\nexport type SizeName = keyof typeof SIZES;\nexport const SIZE_NAMES = Object.keys(SIZES) as SizeName[];\nexport const DEFAULT_SIZE: SizeName = \"s\";\n\nexport function isSizeName(value: string): value is SizeName {\n return value in SIZES;\n}\n","/**\n * Host state layout. The filesystem is the database and `~/.kvbox` is its root.\n * This module is dependency-free so both the CLI (socket path, hosts.json)\n * and core (everything else) can use it without crossing the layer boundary.\n *\n * `KVBOX_HOME` overrides the root, mainly for tests.\n */\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function kvboxHome(): string {\n return process.env[\"KVBOX_HOME\"] ?? join(homedir(), \".kvbox\");\n}\n\nexport function paths(home: string = kvboxHome()) {\n return {\n home,\n config: join(home, \"config.json\"),\n serverSock: join(home, \"server.sock\"),\n serverPid: join(home, \"server.pid\"),\n serverLog: join(home, \"server.log\"),\n hosts: join(home, \"hosts.json\"),\n ssh: join(home, \"ssh\"),\n sshKey: join(home, \"ssh\", \"id_ed25519\"),\n bin: join(home, \"bin\"),\n firecracker: join(home, \"bin\", \"firecracker\"),\n assets: join(home, \"assets\"),\n kernel: join(home, \"assets\", \"vmlinux\"),\n /** Symlink to the current base image, assets/rootfs-<version>.ext4; boxes keep using the version they were made from. */\n rootfs: join(home, \"assets\", \"rootfs.ext4\"),\n baseImage: (version: string) => join(home, \"assets\", `rootfs-${version}.ext4`),\n machines: join(home, \"machines\"),\n snapshots: join(home, \"snapshots\"),\n machine: (name: string) => ({\n dir: join(home, \"machines\", name),\n meta: join(home, \"machines\", name, \"meta.json\"),\n /** The box's writable layer, stacked on the read-only base image inside the guest. */\n overlay: join(home, \"machines\", name, \"overlay.ext4\"),\n /** Boxes made before overlays: a full copy of the base image. Kept bootable, never created anymore. */\n disk: join(home, \"machines\", name, \"disk.ext4\"),\n sock: join(home, \"machines\", name, \"fc.sock\"),\n log: join(home, \"machines\", name, \"fc.log\"),\n }),\n snapshot: (name: string) => ({\n dir: join(home, \"snapshots\", name),\n meta: join(home, \"snapshots\", name, \"meta.json\"),\n vmstate: join(home, \"snapshots\", name, \"vmstate\"),\n mem: join(home, \"snapshots\", name, \"mem\"),\n disk: join(home, \"snapshots\", name, \"disk.ext4\"),\n }),\n } as const;\n}\n\nexport type Paths = ReturnType<typeof paths>;\n","import { spawn } from \"node:child_process\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { clientFor, sshArgs } from \"../../client.js\";\n\n/** POSIX single-quote a string for the guest's shell. */\nexport function shellQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * The one string handed to the guest's login shell: the words after `--` joined with spaces\n * (so `'cd /app && npm test'` and `cd /app '&&' npm test` both work), preceded by `export`s\n * for `--env` so the shell itself expands `$VAR` in the command. SSH SetEnv is not an option:\n * the image's sshd does not AcceptEnv (#24).\n */\nexport function remoteCommand(cmdArgs: string[], env: string[]): string {\n const cmd = cmdArgs.join(\" \");\n if (env.length === 0) return cmd;\n const assignments = env.map((entry) => {\n const eq = entry.indexOf(\"=\");\n const key = eq > 0 ? entry.slice(0, eq) : \"\";\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) throw new KvboxError(`--env ${entry}: expected KEY=VALUE`);\n return `${key}=${shellQuote(entry.slice(eq + 1))}`;\n });\n return `export ${assignments.join(\" \")}; ${cmd}`;\n}\n\n/** `timeout(1)`'s exit status when the command was killed. */\nconst TIMEOUT_EXIT = 124;\n/** ssh's own status when it could not connect or the session broke. */\nconst SSH_FAILED = 255;\n\nfunction collect(value: string, previous: string[] | undefined): string[] {\n return [...(previous ?? []), value];\n}\n\nfunction positiveSeconds(value: string): number {\n const n = Number(value);\n if (!Number.isFinite(n) || n <= 0) throw new InvalidArgumentError(\"expected a number of seconds > 0\");\n return n;\n}\n\ninterface ExecOptions {\n env?: string[];\n timeout?: number;\n tty?: boolean;\n json?: boolean;\n}\n\n/** kvbox vm exec <name> [-e K=V]... [--timeout N] [--tty] [--json] -- <cmd...> */\nexport const execCommand = new Command(\"exec\")\n .description(\"run a command in a box and exit with its status (kvbox exec <name> -- <cmd>)\")\n .argument(\"<name>\", \"box name\")\n .argument(\"<cmd...>\", \"command, passed to the box's shell as one string (pipes, &&, cd work)\")\n .option(\"-e, --env <KEY=VALUE>\", \"set an environment variable for the command (repeatable)\", collect)\n .option(\"--timeout <seconds>\", \"kill the command after N seconds and exit 124\", positiveSeconds)\n .option(\"--tty\", \"allocate a pseudo-terminal (for interactive tools like htop)\")\n .option(\"--json\", 'capture output and print {\"output\": \"...\", \"exit_code\": N}')\n // No passThroughOptions: flags come after the box name, `--` ends them, the rest is the command.\n .action(async (name: string, cmdArgs: string[], opts: ExecOptions, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n let ip: string;\n try {\n const box = (await client.listMachines()).find((b) => b.name === name);\n if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);\n if (box.status !== \"running\") throw new KvboxError(`box ${name} is ${box.status}`);\n ip = box.ip;\n } finally {\n await client.close();\n }\n\n const remote = remoteCommand(cmdArgs, opts.env ?? []);\n const stdinIsTty = process.stdin.isTTY === true;\n const ssh = [\n ...(opts.tty ? [\"-t\"] : []),\n // With a terminal on stdin nothing is sent (the command would otherwise wait on it);\n // from a pipe or file, stdin is forwarded and its EOF reaches the command.\n ...(stdinIsTty && !opts.tty ? [\"-n\"] : []),\n ...sshArgs(ip),\n // ssh joins everything after the host into the remote command line.\n remote,\n ];\n\n const child = spawn(\"ssh\", ssh, { stdio: [\"inherit\", opts.json ? \"pipe\" : \"inherit\", opts.json ? \"pipe\" : \"inherit\"] });\n const chunks: Buffer[] = [];\n child.stdout?.on(\"data\", (c: Buffer) => chunks.push(c));\n child.stderr?.on(\"data\", (c: Buffer) => chunks.push(c));\n\n let timedOut = false;\n const timer =\n opts.timeout === undefined\n ? undefined\n : setTimeout(() => {\n timedOut = true;\n child.kill(\"SIGTERM\");\n }, opts.timeout * 1000);\n\n const status = await new Promise<number>((resolve, reject) => {\n child.once(\"error\", (err) => reject(new KvboxError(`could not run ssh: ${err.message}`)));\n child.once(\"close\", (code, signal) => {\n if (timedOut) resolve(TIMEOUT_EXIT);\n else if (code !== null) resolve(code);\n else resolve(signal === \"SIGINT\" ? 130 : 1);\n });\n }).finally(() => clearTimeout(timer));\n\n if (status === SSH_FAILED && !timedOut) {\n if (opts.json) process.stderr.write(Buffer.concat(chunks));\n throw new KvboxError(`box ${name}: could not run the command over SSH (box still booting?)`, SSH_FAILED);\n }\n if (opts.json) {\n process.stdout.write(JSON.stringify({ output: Buffer.concat(chunks).toString(\"utf8\"), exit_code: status }) + \"\\n\");\n }\n process.exit(status);\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { gb, info, json, table } from \"../../output.js\";\n\n/** kvbox vm ls [--json] — --json output: Machine[] */\nexport const lsCommand = new Command(\"ls\")\n .description(\"list boxes with status and IP\")\n .option(\"--json\", \"print as JSON\")\n .action(async (opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const boxes = await client.listMachines();\n if (opts.json) {\n json(boxes);\n return;\n }\n if (boxes.length === 0) {\n info(\"no boxes yet; create one with: kvbox new\");\n return;\n }\n table(\n boxes.map((b) => ({\n name: b.name,\n status: b.status,\n ip: b.ip,\n cpu: `${b.vcpu} vCPU`,\n ram: gb(b.memMib * 1024 ** 2),\n disk: `${gb(b.diskBytes)} (${gb(b.diskUsedBytes)} used)`,\n source: b.base !== null && b.source === \"base\" ? `base ${b.base}` : b.source,\n created: b.createdAt.replace(\"T\", \" \").slice(0, 16),\n })),\n );\n } finally {\n await client.close();\n }\n });\n","import { Command, Option } from \"commander\";\nimport type { Machine } from \"@kvbox/shared/api\";\nimport { SIZE_NAMES } from \"@kvbox/shared/sizes\";\nimport { clientFor } from \"../../client.js\";\nimport { color, gb, info, json } from \"../../output.js\";\n\n/**\n * kvbox vm new [name] [--size s|m|l] [--from <snapshot>] [--force] [--json]\n * --json output: the Machine object (see packages/shared/src/api.ts).\n */\nexport const newCommand = new Command(\"new\")\n .description(\"boot a new box from the base image or a snapshot\")\n .argument(\"[name]\", \"box name (box1, box2, … when omitted)\")\n .addOption(new Option(\"-s, --size <size>\", \"box size (default: server config, s)\").choices(SIZE_NAMES))\n .option(\"-f, --from <snapshot>\", \"start from a snapshot instead of the base image\")\n .option(\"--force\", \"skip the capacity guard\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string | undefined, opts: { size?: string; from?: string; force?: boolean; json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.createMachine({\n ...(name !== undefined ? { name } : {}),\n ...(opts.size !== undefined ? { size: opts.size } : {}),\n ...(opts.from !== undefined ? { from: opts.from } : {}),\n ...(opts.force ? { force: true } : {}),\n });\n if (opts.json) {\n json(box);\n return;\n }\n process.stdout.write(`${box.name}\\n`);\n info(`${color.green(\"✓\")} ${describe(box)}`);\n info(` connect with: kvbox connect ${box.name} (SSH is up a couple of seconds after boot)`);\n } finally {\n await client.close();\n }\n });\n\nexport function describe(box: Machine): string {\n return `box ${color.bold(box.name)} is ${box.status} at ${box.ip}: ${box.vcpu} vCPU, ${gb(box.memMib * 1024 ** 2)} RAM, ${gb(box.diskBytes)} disk`;\n}\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, confirm, info } from \"../../output.js\";\n\n/** kvbox vm rm <name> [-y] — destructive: asks y/N on a TTY, needs -y otherwise */\nexport const rmCommand = new Command(\"rm\")\n .description(\"destroy a box (its disk is deleted; snapshots are kept)\")\n .argument(\"<name>\", \"box name\")\n .option(\"-y, --yes\", \"do not ask for confirmation\")\n .action(async (name: string, opts: { yes?: boolean }, cmd: Command) => {\n if (!(await confirm(`Destroy box ${name} and its disk?`, opts.yes ?? false))) {\n info(\"cancelled\");\n process.exitCode = 1;\n return;\n }\n const client = clientFor(cmd.optsWithGlobals());\n try {\n await client.deleteMachine(name);\n info(`${color.green(\"✓\")} box ${name} destroyed`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, info, json } from \"../../output.js\";\nimport { describe } from \"./new.js\";\n\n/** kvbox vm start <name> [--json] — boot a stopped box from its own disk; --json output: the Machine object */\nexport const startCommand = new Command(\"start\")\n .description(\"boot a stopped box again (same name, IP and disk)\")\n .argument(\"<name>\", \"box name\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string, opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.startMachine(name);\n if (opts.json) json(box);\n else info(`${color.green(\"✓\")} ${describe(box)}`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { color, info, json } from \"../../output.js\";\n\n/** kvbox vm stop <name> [--json] — clean shutdown, disk kept; --json output: the Machine object */\nexport const stopCommand = new Command(\"stop\")\n .description(\"shut a box down (its disk is kept; start it again with kvbox start)\")\n .argument(\"<name>\", \"box name\")\n .option(\"--json\", \"print the box as JSON\")\n .action(async (name: string, opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const box = await client.stopMachine(name);\n if (opts.json) json(box);\n else info(`${color.green(\"✓\")} box ${name} stopped (disk kept; kvbox start ${name} boots it again)`);\n } finally {\n await client.close();\n }\n });\n","import { Command } from \"commander\";\nimport { startCommand } from \"./start.js\";\nimport { statusCommand } from \"./status.js\";\nimport { stopCommand } from \"./stop.js\";\n\nexport const serverCommand = new Command(\"server\")\n .description(\"run or manage the kvbox server\")\n .addCommand(startCommand)\n .addCommand(statusCommand)\n .addCommand(stopCommand);\n","/**\n * kvbox server start\n * Starts the local `kvbox-server` (a separate package) detached, logging to\n * ~/.kvbox/server.log, and waits for its socket. The CLI never imports server code.\n */\nimport { Command } from \"commander\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { clientFor, startLocalServer } from \"../../client.js\";\nimport { info } from \"../../output.js\";\n\nexport const startCommand = new Command(\"start\")\n .description(\"start the local kvbox-server in the background\")\n .action(async (_opts: Record<string, never>, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals(), { autoStart: false });\n try {\n const health = await client.health();\n info(`kvbox-server ${health.version} is already running (pid ${health.pid})`);\n return;\n } catch {\n // not running: start it\n } finally {\n await client.close();\n }\n const { pid, socketPath } = await startLocalServer(paths());\n info(`kvbox-server started (pid ${pid}), listening on ${socketPath}`);\n });\n","import { Command } from \"commander\";\nimport { clientFor } from \"../../client.js\";\nimport { info, json } from \"../../output.js\";\n\n/** kvbox server status [--json] — --json output: Health */\nexport const statusCommand = new Command(\"status\")\n .description(\"show whether the server is running\")\n .option(\"--json\", \"print as JSON\")\n .action(async (opts: { json?: boolean }, cmd: Command) => {\n const client = clientFor(cmd.optsWithGlobals());\n try {\n const health = await client.health();\n if (opts.json) json(health);\n else info(`kvbox-server ${health.version} running, pid ${health.pid}`);\n } finally {\n await client.close();\n }\n });\n","import { readFile } from \"node:fs/promises\";\nimport { Command } from \"commander\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\nimport { paths } from \"@kvbox/shared/paths\";\nimport { info } from \"../../output.js\";\n\n/** kvbox server stop — SIGTERM the pid in server.pid. Boxes keep running. */\nexport const stopCommand = new Command(\"stop\")\n .description(\"stop the local server (running boxes are not affected)\")\n .action(async () => {\n const p = paths();\n let pid: number;\n try {\n pid = Number.parseInt(await readFile(p.serverPid, \"utf8\"), 10);\n } catch {\n throw new KvboxError(\"kvbox-server is not running (no pid file)\");\n }\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {\n throw new KvboxError(`kvbox-server pid ${pid} is not running; remove ${p.serverPid}`);\n }\n info(`sent SIGTERM to kvbox-server (pid ${pid})`);\n });\n","import { Command } from \"commander\";\nimport { lsCommand } from \"./ls.js\";\nimport { rmCommand } from \"./rm.js\";\nimport { saveCommand } from \"./save.js\";\n\nexport const snapshotCommand = new Command(\"snapshot\")\n .alias(\"snap\")\n .description(\"manage snapshots\")\n .addCommand(saveCommand)\n .addCommand(lsCommand)\n .addCommand(rmCommand);\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot ls [--json] — --json output: Snapshot[] */\nexport const lsCommand = new Command(\"ls\")\n .description(\"list snapshots\")\n .option(\"--json\", \"print as JSON\")\n .action(() => notImplemented(\"snapshot ls\"));\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot rm <name> [-y] — destructive: asks y/N on a TTY, needs -y otherwise */\nexport const rmCommand = new Command(\"rm\")\n .description(\"delete a snapshot\")\n .argument(\"<name>\", \"snapshot name\")\n .option(\"-y, --yes\", \"do not ask for confirmation\")\n .action(() => notImplemented(\"snapshot rm\"));\n","import { Command } from \"commander\";\nimport { notImplemented } from \"../../output.js\";\n\n/** kvbox snapshot save <box> <name> [--json] — --json output: Snapshot */\nexport const saveCommand = new Command(\"save\")\n .description(\"freeze a running box (memory + disk) into a snapshot\")\n .argument(\"<box>\", \"box name\")\n .argument(\"<name>\", \"snapshot name\")\n .option(\"--json\", \"print the snapshot as JSON\")\n .action(() => notImplemented(\"snapshot save\"));\n","/** Entry point: parse argv, map KvboxError to an exit code. */\nimport { color } from \"./output.js\";\nimport { buildProgram } from \"./program.js\";\nimport { KvboxError } from \"@kvbox/shared/errors\";\n\ntry {\n await buildProgram().parseAsync(process.argv);\n} catch (err) {\n if (err instanceof KvboxError) {\n process.stderr.write(color.red(`error: ${err.message}`) + \"\\n\");\n process.exit(err.exitCode);\n }\n throw err;\n}\n"],"mappings":"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","names":["Command","require","Command","z","z","spawn","Command","Command","spawn","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","startCommand","Command","Command","Command","Command","stopCommand","Command","Command","startCommand","stopCommand","Command","Command","lsCommand","Command","Command","rmCommand","Command","Command","Command","Command","lsCommand","rmCommand","Command"]}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@ghalex/kvbox",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "kvbox CLI: manage Firecracker microVM hosts with Docker-like commands. Thin client; the host runs @ghalex/kvbox-server.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "bin": {
8
- "kvbox": "./dist/kvbox.js"
8
+ "kvbox": "dist/kvbox.js"
9
9
  },
10
10
  "files": [
11
11
  "dist"
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "https://github.com/ghalex/kvbox",
18
+ "url": "git+https://github.com/ghalex/kvbox.git",
19
19
  "directory": "packages/cli"
20
20
  },
21
21
  "homepage": "https://kvbox.sh",