@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 +142 -60
- package/dist/kvbox.js.map +1 -1
- package/package.json +1 -1
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
|
|
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.
|
|
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
|
|
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/
|
|
1515
|
+
// src/commands/vm/top.ts
|
|
1495
1516
|
import { Command as Command13 } from "commander";
|
|
1496
|
-
var
|
|
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
|
|
1519
|
-
var usageCommand = new
|
|
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
|
|
1567
|
-
var wakeCommand = new
|
|
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
|
|
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
|
|
1666
|
+
import { Command as Command25 } from "commander";
|
|
1585
1667
|
|
|
1586
1668
|
// src/commands/server/join.ts
|
|
1587
|
-
import { Command as
|
|
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
|
|
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
|
|
1652
|
-
var leaveCommand = new
|
|
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
|
|
1662
|
-
var relayCommand = new
|
|
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
|
|
1668
|
-
var startCommand2 = new
|
|
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
|
|
1685
|
-
var statusCommand = new
|
|
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
|
|
1718
|
-
var stopCommand2 = new
|
|
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
|
|
1727
|
-
var trustCaCommand = new
|
|
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
|
|
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
|
|
1774
|
-
var loginCommand = new
|
|
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
|
|
1873
|
-
var logoutCommand = new
|
|
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
|
|
1911
|
-
var whoamiCommand = new
|
|
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
|
|
2009
|
+
import { Command as Command32 } from "commander";
|
|
1928
2010
|
|
|
1929
2011
|
// src/commands/snapshots/ls.ts
|
|
1930
|
-
import { Command as
|
|
1931
|
-
var lsCommand2 = new
|
|
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
|
|
1963
|
-
var newCommand2 = new
|
|
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
|
|
1976
|
-
var rmCommand2 = new
|
|
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
|
|
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
|
|
2078
|
+
import { Command as Command38 } from "commander";
|
|
1997
2079
|
|
|
1998
2080
|
// src/commands/org/ls.ts
|
|
1999
|
-
import { Command as
|
|
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
|
|
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
|
|
2042
|
-
var lsCommand4 = new
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2086
|
-
var newCommand3 = new
|
|
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
|
|
2103
|
-
var rmCommand4 = new
|
|
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
|
|
2120
|
-
var roleCommand = new
|
|
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
|
|
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
|
|
2136
|
-
var usageCommand2 = new
|
|
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
|
|
2210
|
-
var creditCommand = new
|
|
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
|
|
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);
|