@kvbox/cli 0.5.10 → 0.5.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/kvbox.js CHANGED
@@ -147,7 +147,7 @@ async function spin(message, work, opts = {}) {
147
147
  }
148
148
 
149
149
  // src/program.ts
150
- import { Command as Command40 } from "commander";
150
+ import { Command as Command41 } from "commander";
151
151
 
152
152
  // ../shared/src/version.ts
153
153
  import { createRequire } from "module";
@@ -162,10 +162,10 @@ function versionOf(srcFileUrl, injected) {
162
162
  }
163
163
 
164
164
  // src/version.ts
165
- var VERSION = versionOf(import.meta.url, true ? "0.5.10" : void 0);
165
+ var VERSION = versionOf(import.meta.url, true ? "0.5.11" : void 0);
166
166
 
167
167
  // src/commands/vm/index.ts
168
- import { Command as Command16 } from "commander";
168
+ import { Command as Command17 } from "commander";
169
169
 
170
170
  // src/commands/vm/connect.ts
171
171
  import { spawnSync as spawnSync2 } from "child_process";
@@ -529,6 +529,23 @@ var MachineUsageSchema = z2.object({
529
529
  estimatedStops: z2.number().int(),
530
530
  historyFrom: z2.string().nullable()
531
531
  });
532
+ var GuestStatsSchema = z2.object({
533
+ /** Load average over 1, 5 and 15 minutes. */
534
+ load: z2.tuple([z2.number(), z2.number(), z2.number()]),
535
+ cpus: z2.number().int(),
536
+ memTotalMib: z2.number().int(),
537
+ /** Total minus available: page cache counts as free. */
538
+ memUsedMib: z2.number().int(),
539
+ /** The box's root, which is its overlay disk: the box's own writes, not the shared base. */
540
+ diskTotalBytes: z2.number().int(),
541
+ diskUsedBytes: z2.number().int(),
542
+ uptimeSec: z2.number().int()
543
+ });
544
+ var MachineStatsSchema = z2.object({
545
+ name: z2.string(),
546
+ owner: z2.string(),
547
+ stats: GuestStatsSchema.nullable()
548
+ });
532
549
  var UsageStatusSchema = z2.enum([...BoxStatusSchema.options, "removed"]);
533
550
  var BoxUsageSchema = MachineUsageSchema.omit({ window: true, status: true }).extend({
534
551
  /** The host's box id; a name removed and recreated appears twice, with two ids. */
@@ -903,6 +920,10 @@ var ServerClient = class {
903
920
  setMachine(name, req) {
904
921
  return this.call("POST", `/machines/${encodeURIComponent(name)}/set`, MachineSchema, req);
905
922
  }
923
+ /** A running box's own load, memory and disk, asked of its guest (#67). */
924
+ machineStats(name) {
925
+ return this.call("GET", `/machines/${encodeURIComponent(name)}/stats`, MachineStatsSchema);
926
+ }
906
927
  /** `since`: an ISO date, already validated; the server counts from the box's creation without it. */
907
928
  machineUsage(name, since) {
908
929
  const query = since === void 0 ? "" : `?since=${encodeURIComponent(since)}`;
@@ -1491,9 +1512,70 @@ var stopCommand = new Command12("stop").description("shut a box down (its disk i
1491
1512
  }
1492
1513
  });
1493
1514
 
1494
- // src/commands/vm/update.ts
1515
+ // src/commands/vm/top.ts
1495
1516
  import { Command as Command13 } from "commander";
1496
- var updateCommand = new Command13("update").description("move a box onto the current base image (its files stay; a running box restarts)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
1517
+ var topCommand = new Command13("top").description("load, memory and disk of each running box, as the box itself sees them").option("--json", "print as JSON").action(async (opts, cmd) => {
1518
+ const client = await clientFor(cmd.optsWithGlobals());
1519
+ try {
1520
+ const running = (await client.listMachines()).filter((b) => b.status === "running");
1521
+ const entries = await mapLimit(running, ASK_AT_ONCE, async (b) => {
1522
+ const who = { name: b.name, owner: b.owner, ...b.ownerKind === void 0 ? {} : { ownerKind: b.ownerKind } };
1523
+ try {
1524
+ return { ...who, stats: (await client.machineStats(`${slugOf(b.owner)}/${b.name}`)).stats };
1525
+ } catch (err) {
1526
+ return { ...who, stats: null, error: err.message };
1527
+ }
1528
+ });
1529
+ if (entries.length > 0 && entries.every((e) => e.error !== void 0)) process.exitCode = 1;
1530
+ if (opts.json) {
1531
+ json(entries);
1532
+ return;
1533
+ }
1534
+ if (entries.length === 0) {
1535
+ info("no running boxes");
1536
+ return;
1537
+ }
1538
+ table(topRows(entries, client.target.kind === "cloud" ? { me: client.target.user } : void 0));
1539
+ for (const e of entries) if (e.error !== void 0) info(color.dim(`${e.name}: ${e.error}`));
1540
+ if (entries.some((e) => e.stats === null && e.error === void 0)) {
1541
+ info(color.dim("-: the box's image is older than base v0.7.0; kvbox vm update <box> moves it onto the current one"));
1542
+ }
1543
+ } finally {
1544
+ await client.close();
1545
+ }
1546
+ });
1547
+ var ASK_AT_ONCE = 8;
1548
+ async function mapLimit(items, limit, fn) {
1549
+ const out = new Array(items.length);
1550
+ let next = 0;
1551
+ const worker = async () => {
1552
+ while (next < items.length) {
1553
+ const i = next++;
1554
+ out[i] = await fn(items[i]);
1555
+ }
1556
+ };
1557
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
1558
+ return out;
1559
+ }
1560
+ var pct = (used, total) => total > 0 ? color.dim(` ${Math.round(used / total * 100)}%`) : "";
1561
+ function topRows(entries, cloud) {
1562
+ return entries.map((e) => {
1563
+ const s = e.stats;
1564
+ return {
1565
+ ...cloud ? { owner: ownerCell(e, cloud.me) } : {},
1566
+ name: boxName(e.name),
1567
+ load: s ? `${s.load[0].toFixed(2)} ${s.load[1].toFixed(2)} ${color.dim(`/${s.cpus}`)}` : "-",
1568
+ mem: s ? `${gbShort(s.memUsedMib * 1024 ** 2)}/${gbShort(s.memTotalMib * 1024 ** 2)}${pct(s.memUsedMib, s.memTotalMib)}` : "-",
1569
+ disk: s ? `${gbShort(s.diskUsedBytes)}/${gbShort(s.diskTotalBytes)}${pct(s.diskUsedBytes, s.diskTotalBytes)}` : "-",
1570
+ // duration() writes "-" for 0, which here would read as "no numbers".
1571
+ uptime: s ? s.uptimeSec >= 1 ? duration(s.uptimeSec) : "0s" : "-"
1572
+ };
1573
+ });
1574
+ }
1575
+
1576
+ // src/commands/vm/update.ts
1577
+ import { Command as Command14 } from "commander";
1578
+ var updateCommand = new Command14("update").description("move a box onto the current base image (its files stay; a running box restarts)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
1497
1579
  const client = await clientFor(cmd.optsWithGlobals());
1498
1580
  try {
1499
1581
  const before = pickRef(await client.listMachines(), name, me(client));
@@ -1515,8 +1597,8 @@ var updateCommand = new Command13("update").description("move a box onto the cur
1515
1597
  });
1516
1598
 
1517
1599
  // src/commands/vm/usage.ts
1518
- import { Command as Command14 } from "commander";
1519
- var usageCommand = new Command14("usage").description("how long a box ran, slept and sat stopped, as vCPU-hours, RAM and disk GiB-hours (and cost, when the host prices them)").argument("<name>", "box name").option("--since <date>", "count from this date instead of the box's creation, e.g. 2026-10-01").option("--json", "print as JSON").action(async (name, opts, cmd) => {
1600
+ import { Command as Command15 } from "commander";
1601
+ var usageCommand = new Command15("usage").description("how long a box ran, slept and sat stopped, as vCPU-hours, RAM and disk GiB-hours (and cost, when the host prices them)").argument("<name>", "box name").option("--since <date>", "count from this date instead of the box's creation, e.g. 2026-10-01").option("--json", "print as JSON").action(async (name, opts, cmd) => {
1520
1602
  let since;
1521
1603
  if (opts.since !== void 0) {
1522
1604
  const t = Date.parse(opts.since);
@@ -1563,8 +1645,8 @@ function block(u) {
1563
1645
  }
1564
1646
 
1565
1647
  // src/commands/vm/wake.ts
1566
- import { Command as Command15 } from "commander";
1567
- var wakeCommand = new Command15("wake").description("continue a hibernated box where it left off (same name, IP and disk)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
1648
+ import { Command as Command16 } from "commander";
1649
+ var wakeCommand = new Command16("wake").description("continue a hibernated box where it left off (same name, IP and disk)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
1568
1650
  const client = await clientFor(cmd.optsWithGlobals());
1569
1651
  try {
1570
1652
  const box = await spin(`waking ${name} (loading its memory from disk)\u2026`, client.wakeMachine(name));
@@ -1576,15 +1658,15 @@ var wakeCommand = new Command15("wake").description("continue a hibernated box w
1576
1658
  });
1577
1659
 
1578
1660
  // src/commands/vm/index.ts
1579
- var vmCommand = new Command16("vm").enablePositionalOptions().description("manage boxes (each one is a Firecracker microVM)").addCommand(newCommand).addCommand(lsCommand).addCommand(connectCommand).addCommand(execCommand).addCommand(stopCommand).addCommand(startCommand).addCommand(pauseCommand).addCommand(resumeCommand).addCommand(hibernateCommand).addCommand(wakeCommand).addCommand(updateCommand).addCommand(rescaleCommand).addCommand(setCommand).addCommand(usageCommand).addCommand(rmCommand);
1661
+ var vmCommand = new Command17("vm").enablePositionalOptions().description("manage boxes (each one is a Firecracker microVM)").addCommand(newCommand).addCommand(lsCommand).addCommand(connectCommand).addCommand(execCommand).addCommand(stopCommand).addCommand(startCommand).addCommand(pauseCommand).addCommand(resumeCommand).addCommand(hibernateCommand).addCommand(wakeCommand).addCommand(updateCommand).addCommand(rescaleCommand).addCommand(setCommand).addCommand(usageCommand).addCommand(topCommand).addCommand(rmCommand);
1580
1662
  for (const cmd of vmCommand.commands) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
1581
1663
  var vmAliases = [newCommand, lsCommand, connectCommand, execCommand, stopCommand, startCommand, pauseCommand, resumeCommand, hibernateCommand, wakeCommand, rmCommand];
1582
1664
 
1583
1665
  // src/commands/server/index.ts
1584
- import { Command as Command24 } from "commander";
1666
+ import { Command as Command25 } from "commander";
1585
1667
 
1586
1668
  // src/commands/server/join.ts
1587
- import { Command as Command17 } from "commander";
1669
+ import { Command as Command18 } from "commander";
1588
1670
 
1589
1671
  // src/commands/server/daemon.ts
1590
1672
  import { spawn as spawn3 } from "child_process";
@@ -1638,7 +1720,7 @@ function runKvboxServer(args) {
1638
1720
  }
1639
1721
 
1640
1722
  // src/commands/server/join.ts
1641
- var joinCommand = new Command17("join").description("put this machine behind a control plane (needs a one-time token minted there) and restart its server").argument("<control-plane-url>", "the control plane, e.g. https://api.kvbox.sh").requiredOption("--token <token>", "one-time join token from the control plane").option("--advertise <host-or-ip>", "address the control plane reaches this machine at (default: its default-route address)").option("--name <name>", "how the control plane lists this machine (default: hostname)").action(async (url, opts) => {
1723
+ var joinCommand = new Command18("join").description("put this machine behind a control plane (needs a one-time token minted there) and restart its server").argument("<control-plane-url>", "the control plane, e.g. https://api.kvbox.sh").requiredOption("--token <token>", "one-time join token from the control plane").option("--advertise <host-or-ip>", "address the control plane reaches this machine at (default: its default-route address)").option("--name <name>", "how the control plane lists this machine (default: hostname)").action(async (url, opts) => {
1642
1724
  const args = ["join", url, "--token", opts.token];
1643
1725
  if (opts.advertise !== void 0) args.push("--advertise", opts.advertise);
1644
1726
  if (opts.name !== void 0) args.push("--name", opts.name);
@@ -1648,8 +1730,8 @@ var joinCommand = new Command17("join").description("put this machine behind a c
1648
1730
  });
1649
1731
 
1650
1732
  // src/commands/server/leave.ts
1651
- import { Command as Command18 } from "commander";
1652
- var leaveCommand = new Command18("leave").description("take this machine out from behind its control plane and restart its server").action(async () => {
1733
+ import { Command as Command19 } from "commander";
1734
+ var leaveCommand = new Command19("leave").description("take this machine out from behind its control plane and restart its server").action(async () => {
1653
1735
  const p = paths();
1654
1736
  for (const line of (await runKvboxServer(["leave"])).split("\n")) info(line);
1655
1737
  if (await runningPid(p) === null) return;
@@ -1658,14 +1740,14 @@ var leaveCommand = new Command18("leave").description("take this machine out fro
1658
1740
  });
1659
1741
 
1660
1742
  // src/commands/server/relay.ts
1661
- import { Command as Command19 } from "commander";
1662
- var relayCommand = new Command19("relay").description("reach the internet through a relay (paste what `kvbox-relay add` printed on the relay VM); `off` takes the tunnel down").argument("<join-string>", "the line `kvbox-relay add` printed, or `off`").action(async (joinString) => {
1743
+ import { Command as Command20 } from "commander";
1744
+ var relayCommand = new Command20("relay").description("reach the internet through a relay (paste what `kvbox-relay add` printed on the relay VM); `off` takes the tunnel down").argument("<join-string>", "the line `kvbox-relay add` printed, or `off`").action(async (joinString) => {
1663
1745
  for (const line of (await runKvboxServer(["relay", joinString])).split("\n")) info(line);
1664
1746
  });
1665
1747
 
1666
1748
  // src/commands/server/start.ts
1667
- import { Command as Command20 } from "commander";
1668
- var startCommand2 = new Command20("start").description("start the local kvbox-server in the background").action(async (_opts, cmd) => {
1749
+ import { Command as Command21 } from "commander";
1750
+ var startCommand2 = new Command21("start").description("start the local kvbox-server in the background").action(async (_opts, cmd) => {
1669
1751
  const client = await clientFor({ ...cmd.optsWithGlobals(), local: true }, { autoStart: false });
1670
1752
  try {
1671
1753
  const health = await client.health();
@@ -1681,8 +1763,8 @@ var startCommand2 = new Command20("start").description("start the local kvbox-se
1681
1763
  });
1682
1764
 
1683
1765
  // src/commands/server/status.ts
1684
- import { Command as Command21 } from "commander";
1685
- var statusCommand = new Command21("status").description("show whether this machine's server is running, its control plane and which base image new boxes get").option("--json", "print as JSON").action(async (opts, cmd) => {
1766
+ import { Command as Command22 } from "commander";
1767
+ var statusCommand = new Command22("status").description("show whether this machine's server is running, its control plane and which base image new boxes get").option("--json", "print as JSON").action(async (opts, cmd) => {
1686
1768
  const client = await clientFor({ ...cmd.optsWithGlobals(), local: true });
1687
1769
  try {
1688
1770
  const health = await client.health();
@@ -1714,8 +1796,8 @@ var statusCommand = new Command21("status").description("show whether this machi
1714
1796
  });
1715
1797
 
1716
1798
  // src/commands/server/stop.ts
1717
- import { Command as Command22 } from "commander";
1718
- var stopCommand2 = new Command22("stop").description("stop the local server (running boxes are not affected)").action(async () => {
1799
+ import { Command as Command23 } from "commander";
1800
+ var stopCommand2 = new Command23("stop").description("stop the local server (running boxes are not affected)").action(async () => {
1719
1801
  const pid = await runningPid(paths());
1720
1802
  if (pid === null) throw new KvboxError("kvbox-server is not running");
1721
1803
  await stopLocalServer(pid);
@@ -1723,8 +1805,8 @@ var stopCommand2 = new Command22("stop").description("stop the local server (run
1723
1805
  });
1724
1806
 
1725
1807
  // src/commands/server/trust-ca.ts
1726
- import { Command as Command23 } from "commander";
1727
- var trustCaCommand = new Command23("trust-ca").description("make every cloud box on this machine trust a new SSH CA (after `ca rotate` on the control plane)").argument("[public-key]", "the CA public key (or its cert-authority line); or --from-cloud").option("--from-cloud", "ask the control plane this host joined for its current CA, show the fingerprint, then ask").option("-y, --yes", "do not ask for confirmation").option("--json", "print the report as JSON").action(async (publicKey, opts, cmd) => {
1808
+ import { Command as Command24 } from "commander";
1809
+ var trustCaCommand = new Command24("trust-ca").description("make every cloud box on this machine trust a new SSH CA (after `ca rotate` on the control plane)").argument("[public-key]", "the CA public key (or its cert-authority line); or --from-cloud").option("--from-cloud", "ask the control plane this host joined for its current CA, show the fingerprint, then ask").option("-y, --yes", "do not ask for confirmation").option("--json", "print the report as JSON").action(async (publicKey, opts, cmd) => {
1728
1810
  if (publicKey === void 0 && !opts.fromCloud) throw new KvboxError("give the CA public key, or --from-cloud to fetch it from the control plane this host joined");
1729
1811
  if (publicKey !== void 0 && opts.fromCloud) throw new KvboxError("either a public key or --from-cloud, not both");
1730
1812
  const client = await clientFor({ ...cmd.optsWithGlobals(), local: true });
@@ -1762,7 +1844,7 @@ function describeReport(report) {
1762
1844
  }
1763
1845
 
1764
1846
  // src/commands/server/index.ts
1765
- var serverCommand = new Command24("server").description("run or manage the kvbox server").addCommand(startCommand2).addCommand(statusCommand).addCommand(stopCommand2).addCommand(joinCommand).addCommand(leaveCommand).addCommand(relayCommand).addCommand(trustCaCommand);
1847
+ var serverCommand = new Command25("server").description("run or manage the kvbox server").addCommand(startCommand2).addCommand(statusCommand).addCommand(stopCommand2).addCommand(joinCommand).addCommand(leaveCommand).addCommand(relayCommand).addCommand(trustCaCommand);
1766
1848
 
1767
1849
  // src/commands/login.ts
1768
1850
  import { spawnSync as spawnSync3 } from "child_process";
@@ -1770,8 +1852,8 @@ import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from
1770
1852
  import { hostname as osHostname } from "os";
1771
1853
  import { createInterface } from "readline/promises";
1772
1854
  import { Writable } from "stream";
1773
- import { Command as Command25 } from "commander";
1774
- var loginCommand = new Command25("login").description("log in to the kvbox cloud (or your own control plane) and target it from now on").argument("[url]", `control plane URL (default: ${DEFAULT_CLOUD_URL})`).option("-e, --email <email>", "account email (prompted otherwise)").option("--password-stdin", "read the password from the first line of stdin (for scripts)").action(async (urlArg, opts) => {
1855
+ import { Command as Command26 } from "commander";
1856
+ var loginCommand = new Command26("login").description("log in to the kvbox cloud (or your own control plane) and target it from now on").argument("[url]", `control plane URL (default: ${DEFAULT_CLOUD_URL})`).option("-e, --email <email>", "account email (prompted otherwise)").option("--password-stdin", "read the password from the first line of stdin (for scripts)").action(async (urlArg, opts) => {
1775
1857
  const url = normalizeUrl(urlArg ?? DEFAULT_CLOUD_URL);
1776
1858
  const creds = await readCredentials(opts);
1777
1859
  const session = await runLogin(url, creds, paths());
@@ -1869,8 +1951,8 @@ async function firstLine(stream) {
1869
1951
  }
1870
1952
 
1871
1953
  // src/commands/logout.ts
1872
- import { Command as Command26 } from "commander";
1873
- var logoutCommand = new Command26("logout").description("log out of the control plane; commands target this machine's kvbox-server again").action(async () => {
1954
+ import { Command as Command27 } from "commander";
1955
+ var logoutCommand = new Command27("logout").description("log out of the control plane; commands target this machine's kvbox-server again").action(async () => {
1874
1956
  const p = paths();
1875
1957
  const session = await readSession(p).catch(() => null);
1876
1958
  switch (await runLogout(p)) {
@@ -1907,8 +1989,8 @@ async function runLogout(p = paths()) {
1907
1989
  }
1908
1990
 
1909
1991
  // src/commands/whoami.ts
1910
- import { Command as Command27 } from "commander";
1911
- var whoamiCommand = new Command27("whoami").description("show which account and control plane commands target (or local mode)").option("--json", "print as JSON").action(async (opts) => {
1992
+ import { Command as Command28 } from "commander";
1993
+ var whoamiCommand = new Command28("whoami").description("show which account and control plane commands target (or local mode)").option("--json", "print as JSON").action(async (opts) => {
1912
1994
  const session = await readSession();
1913
1995
  if (opts.json) {
1914
1996
  json(session ? { user: session.user, url: session.url, sshCertExpires: session.sshCertExpires ?? null } : null);
@@ -1924,11 +2006,11 @@ function describeSession(session) {
1924
2006
  }
1925
2007
 
1926
2008
  // src/commands/snapshots/index.ts
1927
- import { Command as Command31 } from "commander";
2009
+ import { Command as Command32 } from "commander";
1928
2010
 
1929
2011
  // src/commands/snapshots/ls.ts
1930
- import { Command as Command28, Option as Option4 } from "commander";
1931
- var lsCommand2 = new Command28("ls").description("list snapshots (yours and your orgs'; --org <slug> for one org)").addOption(new Option4("-a, --all", "kept for older scripts: the listing covers everything you can see anyway").hideHelp()).option("--json", "print as JSON").action(async (opts, cmd) => {
2012
+ import { Command as Command29, Option as Option4 } from "commander";
2013
+ var lsCommand2 = new Command29("ls").description("list snapshots (yours and your orgs'; --org <slug> for one org)").addOption(new Option4("-a, --all", "kept for older scripts: the listing covers everything you can see anyway").hideHelp()).option("--json", "print as JSON").action(async (opts, cmd) => {
1932
2014
  const client = await clientFor(cmd.optsWithGlobals());
1933
2015
  try {
1934
2016
  const cloud = client.target.kind === "cloud";
@@ -1959,8 +2041,8 @@ var lsCommand2 = new Command28("ls").description("list snapshots (yours and your
1959
2041
  });
1960
2042
 
1961
2043
  // src/commands/snapshots/new.ts
1962
- import { Command as Command29 } from "commander";
1963
- var newCommand2 = new Command29("new").description("freeze a running box (memory + disk) into a snapshot; the box keeps running").argument("<box>", "box name").argument("<name>", "snapshot name").option("--json", "print the snapshot as JSON").action(async (box, name, opts, cmd) => {
2044
+ import { Command as Command30 } from "commander";
2045
+ var newCommand2 = new Command30("new").description("freeze a running box (memory + disk) into a snapshot; the box keeps running").argument("<box>", "box name").argument("<name>", "snapshot name").option("--json", "print the snapshot as JSON").action(async (box, name, opts, cmd) => {
1964
2046
  const client = await clientFor(cmd.optsWithGlobals());
1965
2047
  try {
1966
2048
  const snap = await spin(`saving snapshot ${name} from box ${box} (memory + disk)\u2026`, client.createSnapshot({ box, name }));
@@ -1972,8 +2054,8 @@ var newCommand2 = new Command29("new").description("freeze a running box (memory
1972
2054
  });
1973
2055
 
1974
2056
  // src/commands/snapshots/rm.ts
1975
- import { Command as Command30 } from "commander";
1976
- var rmCommand2 = new Command30("rm").description("delete a snapshot (boxes made from it are not affected)").argument("<name>", "snapshot name").option("-y, --yes", "do not ask for confirmation").action(async (name, opts, cmd) => {
2057
+ import { Command as Command31 } from "commander";
2058
+ var rmCommand2 = new Command31("rm").description("delete a snapshot (boxes made from it are not affected)").argument("<name>", "snapshot name").option("-y, --yes", "do not ask for confirmation").action(async (name, opts, cmd) => {
1977
2059
  if (!await confirm(`Delete snapshot ${name}?`, opts.yes ?? false)) {
1978
2060
  info("cancelled");
1979
2061
  process.exitCode = 1;
@@ -1989,14 +2071,14 @@ var rmCommand2 = new Command30("rm").description("delete a snapshot (boxes made
1989
2071
  });
1990
2072
 
1991
2073
  // src/commands/snapshots/index.ts
1992
- var snapshotsCommand = new Command31("snapshots").aliases(["snapshot", "snap"]).description("freeze running boxes into snapshots and manage them").addCommand(newCommand2).addCommand(lsCommand2).addCommand(rmCommand2);
2074
+ var snapshotsCommand = new Command32("snapshots").aliases(["snapshot", "snap"]).description("freeze running boxes into snapshots and manage them").addCommand(newCommand2).addCommand(lsCommand2).addCommand(rmCommand2);
1993
2075
  for (const cmd of snapshotsCommand.commands) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
1994
2076
 
1995
2077
  // src/commands/org/index.ts
1996
- import { Command as Command37 } from "commander";
2078
+ import { Command as Command38 } from "commander";
1997
2079
 
1998
2080
  // src/commands/org/ls.ts
1999
- import { Command as Command32 } from "commander";
2081
+ import { Command as Command33 } from "commander";
2000
2082
 
2001
2083
  // src/commands/org/context.ts
2002
2084
  var NOT_LOGGED_IN = "orgs live on the control plane: kvbox login first";
@@ -2016,7 +2098,7 @@ function orgFor(opts, target) {
2016
2098
  }
2017
2099
 
2018
2100
  // src/commands/org/ls.ts
2019
- var lsCommand3 = new Command32("ls").description("list the orgs you belong to and your role in each").option("--json", "print as JSON").action(async (opts, cmd) => {
2101
+ var lsCommand3 = new Command33("ls").description("list the orgs you belong to and your role in each").option("--json", "print as JSON").action(async (opts, cmd) => {
2020
2102
  const client = await cloudClientFor(cmd.optsWithGlobals());
2021
2103
  try {
2022
2104
  const orgs = await client.listOrgs();
@@ -2038,8 +2120,8 @@ function orgRows(orgs) {
2038
2120
  }
2039
2121
 
2040
2122
  // src/commands/org/members.ts
2041
- import { Command as Command33, Option as Option5 } from "commander";
2042
- var lsCommand4 = new Command33("ls").description("list an org's members and their roles").option("-o, --org <slug>", "the org (or --org before the command)").option("--json", "print as JSON").action(async (opts, cmd) => {
2123
+ import { Command as Command34, Option as Option5 } from "commander";
2124
+ var lsCommand4 = new Command34("ls").description("list an org's members and their roles").option("-o, --org <slug>", "the org (or --org before the command)").option("--json", "print as JSON").action(async (opts, cmd) => {
2043
2125
  const client = await cloudClientFor(cmd.optsWithGlobals());
2044
2126
  try {
2045
2127
  const org = await client.getOrg(orgFor(opts, client.target));
@@ -2053,7 +2135,7 @@ var lsCommand4 = new Command33("ls").description("list an org's members and thei
2053
2135
  await client.close();
2054
2136
  }
2055
2137
  });
2056
- var addCommand = new Command33("add").description("add a user to an org (admins and owners; only an owner can add an owner)").argument("<user>", "their username").addOption(new Option5("-r, --role <role>", "their role").choices(ORG_ROLES).default("member")).option("-o, --org <slug>", "the org (or --org before the command)").action(async (user, opts, cmd) => {
2138
+ var addCommand = new Command34("add").description("add a user to an org (admins and owners; only an owner can add an owner)").argument("<user>", "their username").addOption(new Option5("-r, --role <role>", "their role").choices(ORG_ROLES).default("member")).option("-o, --org <slug>", "the org (or --org before the command)").action(async (user, opts, cmd) => {
2057
2139
  const client = await cloudClientFor(cmd.optsWithGlobals());
2058
2140
  try {
2059
2141
  const slug = orgFor(opts, client.target);
@@ -2063,7 +2145,7 @@ var addCommand = new Command33("add").description("add a user to an org (admins
2063
2145
  await client.close();
2064
2146
  }
2065
2147
  });
2066
- var rmCommand3 = new Command33("rm").description("remove a member (or leave: remove yourself)").argument("<user>", "their username").option("-o, --org <slug>", "the org (or --org before the command)").option("-y, --yes", "do not ask for confirmation").action(async (user, opts, cmd) => {
2148
+ var rmCommand3 = new Command34("rm").description("remove a member (or leave: remove yourself)").argument("<user>", "their username").option("-o, --org <slug>", "the org (or --org before the command)").option("-y, --yes", "do not ask for confirmation").action(async (user, opts, cmd) => {
2067
2149
  const client = await cloudClientFor(cmd.optsWithGlobals());
2068
2150
  try {
2069
2151
  const slug = orgFor(opts, client.target);
@@ -2079,11 +2161,11 @@ var rmCommand3 = new Command33("rm").description("remove a member (or leave: rem
2079
2161
  await client.close();
2080
2162
  }
2081
2163
  });
2082
- var membersCommand = new Command33("members").description("who is in an org and what they may do").addCommand(lsCommand4).addCommand(addCommand).addCommand(rmCommand3);
2164
+ var membersCommand = new Command34("members").description("who is in an org and what they may do").addCommand(lsCommand4).addCommand(addCommand).addCommand(rmCommand3);
2083
2165
 
2084
2166
  // src/commands/org/new.ts
2085
- import { Command as Command34 } from "commander";
2086
- var newCommand3 = new Command34("new").description("create an org; you become its owner (the slug is permanent, the name is not)").argument("<slug>", "the org's slug: lowercase, like a username (acme)").option("-n, --name <name>", "display name (default: the slug)").option("--json", "print the org as JSON").action(async (slug, opts, cmd) => {
2167
+ import { Command as Command35 } from "commander";
2168
+ var newCommand3 = new Command35("new").description("create an org; you become its owner (the slug is permanent, the name is not)").argument("<slug>", "the org's slug: lowercase, like a username (acme)").option("-n, --name <name>", "display name (default: the slug)").option("--json", "print the org as JSON").action(async (slug, opts, cmd) => {
2087
2169
  const client = await cloudClientFor(cmd.optsWithGlobals());
2088
2170
  try {
2089
2171
  const org = await client.createOrg({ slug, name: opts.name ?? slug });
@@ -2099,8 +2181,8 @@ var newCommand3 = new Command34("new").description("create an org; you become it
2099
2181
  });
2100
2182
 
2101
2183
  // src/commands/org/rm.ts
2102
- import { Command as Command35 } from "commander";
2103
- var rmCommand4 = new Command35("rm").description("delete an org (owners only; remove its boxes and snapshots first)").argument("<slug>", "the org").option("-y, --yes", "do not ask for confirmation").action(async (slug, opts, cmd) => {
2184
+ import { Command as Command36 } from "commander";
2185
+ var rmCommand4 = new Command36("rm").description("delete an org (owners only; remove its boxes and snapshots first)").argument("<slug>", "the org").option("-y, --yes", "do not ask for confirmation").action(async (slug, opts, cmd) => {
2104
2186
  if (!await confirm(`Delete org ${slug}? Its members lose access; its slug stays taken.`, opts.yes ?? false)) {
2105
2187
  info("cancelled");
2106
2188
  process.exitCode = 1;
@@ -2116,8 +2198,8 @@ var rmCommand4 = new Command35("rm").description("delete an org (owners only; re
2116
2198
  });
2117
2199
 
2118
2200
  // src/commands/org/role.ts
2119
- import { Argument, Command as Command36 } from "commander";
2120
- var roleCommand = new Command36("role").description("change a member's role (owners only)").argument("<user>", "their username").addArgument(new Argument("<role>", "owner, admin or member").choices(ORG_ROLES)).option("-o, --org <slug>", "the org (default: the current context)").action(async (user, role, opts, cmd) => {
2201
+ import { Argument, Command as Command37 } from "commander";
2202
+ var roleCommand = new Command37("role").description("change a member's role (owners only)").argument("<user>", "their username").addArgument(new Argument("<role>", "owner, admin or member").choices(ORG_ROLES)).option("-o, --org <slug>", "the org (default: the current context)").action(async (user, role, opts, cmd) => {
2121
2203
  const client = await cloudClientFor(cmd.optsWithGlobals());
2122
2204
  try {
2123
2205
  const slug = orgFor(opts, client.target);
@@ -2129,11 +2211,11 @@ var roleCommand = new Command36("role").description("change a member's role (own
2129
2211
  });
2130
2212
 
2131
2213
  // src/commands/org/index.ts
2132
- var orgCommand = new Command37("org").description("orgs: shared slugs that own boxes, with owners, admins and members").addCommand(lsCommand3).addCommand(newCommand3).addCommand(membersCommand).addCommand(roleCommand).addCommand(rmCommand4);
2214
+ var orgCommand = new Command38("org").description("orgs: shared slugs that own boxes, with owners, admins and members").addCommand(lsCommand3).addCommand(newCommand3).addCommand(membersCommand).addCommand(roleCommand).addCommand(rmCommand4);
2133
2215
 
2134
2216
  // src/commands/usage.ts
2135
- import { Command as Command38 } from "commander";
2136
- var usageCommand2 = new Command38("usage").description("what your boxes used this month (or --since/--until): running time, vCPU-h, RAM and disk GiB-h, cost").option("--since <date>", "count from this date, e.g. 2026-10-01 (default: the 1st of this month)").option("--until <date>", "count up to this date (default: now)").option("--org <slug>", "one org's boxes only").option("--json", "print as JSON").action(async (opts, cmd) => {
2217
+ import { Command as Command39 } from "commander";
2218
+ var usageCommand2 = new Command39("usage").description("what your boxes used this month (or --since/--until): running time, vCPU-h, RAM and disk GiB-h, cost").option("--since <date>", "count from this date, e.g. 2026-10-01 (default: the 1st of this month)").option("--until <date>", "count up to this date (default: now)").option("--org <slug>", "one org's boxes only").option("--json", "print as JSON").action(async (opts, cmd) => {
2137
2219
  for (const [name, value] of [
2138
2220
  ["since", opts.since],
2139
2221
  ["until", opts.until]
@@ -2206,8 +2288,8 @@ function usageRows(report, cloud) {
2206
2288
  }
2207
2289
 
2208
2290
  // src/commands/credit.ts
2209
- import { Command as Command39 } from "commander";
2210
- var creditCommand = new Command39("credit").description("the prepaid credit left on your account and on each of your orgs").option("--org <slug>", "one org only").option("--json", "print as JSON").action(async (opts, cmd) => {
2291
+ import { Command as Command40 } from "commander";
2292
+ var creditCommand = new Command40("credit").description("the prepaid credit left on your account and on each of your orgs").option("--org <slug>", "one org only").option("--json", "print as JSON").action(async (opts, cmd) => {
2211
2293
  const client = await clientFor(cmd.optsWithGlobals(), { autoStart: false });
2212
2294
  try {
2213
2295
  if (client.target.kind === "local") throw new KvboxError("credit lives on the control plane: kvbox login first");
@@ -2236,7 +2318,7 @@ function creditRow(b, me2) {
2236
2318
 
2237
2319
  // src/program.ts
2238
2320
  function buildProgram() {
2239
- const program = new Command40("kvbox").description("self-hosted Firecracker microVMs with Docker-like ergonomics").version(VERSION, "-v, --version").option("--local", "use this machine's kvbox-server over its socket, ignoring kvbox login").option("--org <slug>", "the org: where kvbox new creates, and which box a name means when it is not one of yours; before the command here, or after it").showHelpAfterError().enablePositionalOptions();
2321
+ const program = new Command41("kvbox").description("self-hosted Firecracker microVMs with Docker-like ergonomics").version(VERSION, "-v, --version").option("--local", "use this machine's kvbox-server over its socket, ignoring kvbox login").option("--org <slug>", "the org: where kvbox new creates, and which box a name means when it is not one of yours; before the command here, or after it").showHelpAfterError().enablePositionalOptions();
2240
2322
  program.addCommand(vmCommand);
2241
2323
  program.addCommand(snapshotsCommand);
2242
2324
  program.addCommand(serverCommand);