@kvbox/cli 0.5.11 → 0.5.13
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 +221 -94
- 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 Command45 } 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.13" : void 0);
|
|
166
166
|
|
|
167
167
|
// src/commands/vm/index.ts
|
|
168
|
-
import { Command as
|
|
168
|
+
import { Command as Command21 } from "commander";
|
|
169
169
|
|
|
170
170
|
// src/commands/vm/connect.ts
|
|
171
171
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
@@ -384,6 +384,18 @@ function parseMib(text) {
|
|
|
384
384
|
var SizeSchema = z2.enum(SIZE_NAMES);
|
|
385
385
|
var BOX_SSH_USER = "kvbox";
|
|
386
386
|
var BoxStatusSchema = z2.enum(["running", "standby", "hibernated", "stopped", "unknown"]);
|
|
387
|
+
var PortProtoSchema = z2.enum(["tcp", "udp"]);
|
|
388
|
+
var MAX_BOX_PORTS = 16;
|
|
389
|
+
var PortForwardSchema = z2.object({
|
|
390
|
+
guestPort: z2.number().int().min(1).max(65535),
|
|
391
|
+
hostPort: z2.number().int(),
|
|
392
|
+
proto: PortProtoSchema,
|
|
393
|
+
/** The host's public address; only the control plane fills it in, as for `ssh`. */
|
|
394
|
+
address: z2.string().optional()
|
|
395
|
+
});
|
|
396
|
+
var PortsRequest = z2.object({
|
|
397
|
+
ports: z2.array(z2.object({ guestPort: z2.number().int().min(1).max(65535), proto: PortProtoSchema.optional() })).min(1).max(MAX_BOX_PORTS)
|
|
398
|
+
});
|
|
387
399
|
var MachineSchema = z2.object({
|
|
388
400
|
/** Host-unique short id (the tap is `kv-<id>`). Missing only on a box made before ids that has not restarted since. */
|
|
389
401
|
id: z2.string(),
|
|
@@ -416,6 +428,8 @@ var MachineSchema = z2.object({
|
|
|
416
428
|
* whose host reported no port or did not answer.
|
|
417
429
|
*/
|
|
418
430
|
ssh: z2.object({ host: z2.string(), port: z2.number().int(), user: z2.string() }).optional(),
|
|
431
|
+
/** Box ports published on the host (#30). Absent: none. */
|
|
432
|
+
ports: z2.array(PortForwardSchema).optional(),
|
|
419
433
|
/** Whether the owner slug is a user or an org. Only the control plane knows; it fills it in on `GET /machines`. */
|
|
420
434
|
ownerKind: z2.enum(["user", "org"]).optional(),
|
|
421
435
|
/** Seconds without network traffic before the host hibernates the box (#47). Absent: never. */
|
|
@@ -820,6 +834,7 @@ async function resolveTarget(opts, p = paths()) {
|
|
|
820
834
|
}
|
|
821
835
|
return { kind: "local", socketPath: p.serverSock };
|
|
822
836
|
}
|
|
837
|
+
var allQuery = (opts) => opts.all ? "?all=1" : "";
|
|
823
838
|
var ServerClient = class {
|
|
824
839
|
constructor(target, opts = {}) {
|
|
825
840
|
this.target = target;
|
|
@@ -886,9 +901,12 @@ var ServerClient = class {
|
|
|
886
901
|
capacity() {
|
|
887
902
|
return this.call("GET", "/capacity", CapacitySchema);
|
|
888
903
|
}
|
|
889
|
-
/**
|
|
890
|
-
|
|
891
|
-
|
|
904
|
+
/**
|
|
905
|
+
* Through a control plane: the user's boxes and their orgs', the `--org` org's, or `org`'s;
|
|
906
|
+
* `all`: every box on the platform (platform admins only, #78).
|
|
907
|
+
*/
|
|
908
|
+
listMachines(opts = {}) {
|
|
909
|
+
return this.call("GET", `/machines${allQuery(opts)}`, z3.array(MachineSchema), void 0, opts.org);
|
|
892
910
|
}
|
|
893
911
|
createMachine(req) {
|
|
894
912
|
return this.call("POST", "/machines", MachineSchema, req);
|
|
@@ -920,6 +938,14 @@ var ServerClient = class {
|
|
|
920
938
|
setMachine(name, req) {
|
|
921
939
|
return this.call("POST", `/machines/${encodeURIComponent(name)}/set`, MachineSchema, req);
|
|
922
940
|
}
|
|
941
|
+
/** Publish box ports on the host (#30); the answer is the box with every port it publishes. */
|
|
942
|
+
addPorts(name, req) {
|
|
943
|
+
return this.call("POST", `/machines/${encodeURIComponent(name)}/ports`, MachineSchema, req);
|
|
944
|
+
}
|
|
945
|
+
/** Stop publishing them (#30). */
|
|
946
|
+
removePorts(name, req) {
|
|
947
|
+
return this.call("DELETE", `/machines/${encodeURIComponent(name)}/ports`, MachineSchema, req);
|
|
948
|
+
}
|
|
923
949
|
/** A running box's own load, memory and disk, asked of its guest (#67). */
|
|
924
950
|
machineStats(name) {
|
|
925
951
|
return this.call("GET", `/machines/${encodeURIComponent(name)}/stats`, MachineStatsSchema);
|
|
@@ -930,8 +956,9 @@ var ServerClient = class {
|
|
|
930
956
|
return this.call("GET", `/machines/${encodeURIComponent(name)}/usage${query}`, MachineUsageSchema);
|
|
931
957
|
}
|
|
932
958
|
/** Every box of the caller over the window (#41 on a host, #42 through a control plane); dates as the user wrote them. */
|
|
933
|
-
usageReport(since, until) {
|
|
959
|
+
usageReport(since, until, all = false) {
|
|
934
960
|
const q = new URLSearchParams();
|
|
961
|
+
if (all) q.set("all", "1");
|
|
935
962
|
if (since !== void 0) q.set("since", since);
|
|
936
963
|
if (until !== void 0) q.set("until", until);
|
|
937
964
|
const query = q.size === 0 ? "" : `?${q.toString()}`;
|
|
@@ -944,8 +971,9 @@ var ServerClient = class {
|
|
|
944
971
|
deleteMachine(name) {
|
|
945
972
|
return this.call("DELETE", `/machines/${encodeURIComponent(name)}`, z3.undefined());
|
|
946
973
|
}
|
|
947
|
-
|
|
948
|
-
|
|
974
|
+
/** Like `listMachines`, for snapshots. */
|
|
975
|
+
listSnapshots(opts = {}) {
|
|
976
|
+
return this.call("GET", `/snapshots${allQuery(opts)}`, z3.array(SnapshotSchema), void 0, opts.org);
|
|
949
977
|
}
|
|
950
978
|
createSnapshot(req) {
|
|
951
979
|
return this.call("POST", "/snapshots", SnapshotSchema, req);
|
|
@@ -1031,6 +1059,11 @@ async function wakeUp(client, box, name) {
|
|
|
1031
1059
|
return box;
|
|
1032
1060
|
}
|
|
1033
1061
|
}
|
|
1062
|
+
function boxesFor(client, text) {
|
|
1063
|
+
const slash = text.indexOf("/");
|
|
1064
|
+
if (slash === -1 || client.target.kind !== "cloud") return client.listMachines();
|
|
1065
|
+
return client.listMachines({ org: text.slice(0, slash).split("@")[0] });
|
|
1066
|
+
}
|
|
1034
1067
|
var me = (client) => client.target.kind === "cloud" ? client.target.user : void 0;
|
|
1035
1068
|
async function clientFor(opts, client = {}) {
|
|
1036
1069
|
return new ServerClient(await resolveTarget(opts), client);
|
|
@@ -1200,7 +1233,7 @@ var connectCommand = new Command2("connect").alias("cn").description("open a she
|
|
|
1200
1233
|
let cert;
|
|
1201
1234
|
let owner;
|
|
1202
1235
|
try {
|
|
1203
|
-
let box = pickRef(await client
|
|
1236
|
+
let box = pickRef(await boxesFor(client, name), name, me(client));
|
|
1204
1237
|
if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1205
1238
|
cert = await ensureCert(client, void 0, void 0, { owner: box.owner });
|
|
1206
1239
|
owner = box.owner;
|
|
@@ -1278,7 +1311,7 @@ var execCommand = new Command3("exec").description("run a command in a box and e
|
|
|
1278
1311
|
let cert;
|
|
1279
1312
|
let owner;
|
|
1280
1313
|
try {
|
|
1281
|
-
let box = pickRef(await client
|
|
1314
|
+
let box = pickRef(await boxesFor(client, name), name, me(client));
|
|
1282
1315
|
if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1283
1316
|
if (box.status === "stopped") throw new KvboxError(`box ${name} is stopped (kvbox start ${name})`);
|
|
1284
1317
|
cert = await ensureCert(client, void 0, void 0, { owner: box.owner });
|
|
@@ -1334,7 +1367,7 @@ var hibernateCommand = new Command4("hibernate").description("save a box's memor
|
|
|
1334
1367
|
});
|
|
1335
1368
|
|
|
1336
1369
|
// src/commands/vm/ls.ts
|
|
1337
|
-
import { Command as Command5
|
|
1370
|
+
import { Command as Command5 } from "commander";
|
|
1338
1371
|
function ownerCell(b, me2) {
|
|
1339
1372
|
const slug = slugOf(b.owner);
|
|
1340
1373
|
if (slug === me2) return "private";
|
|
@@ -1344,10 +1377,10 @@ function addressOf(b) {
|
|
|
1344
1377
|
if (b.ssh !== void 0) return `${b.ssh.host}:${b.ssh.port}`;
|
|
1345
1378
|
return b.ip === "" ? "-" : b.ip;
|
|
1346
1379
|
}
|
|
1347
|
-
var lsCommand = new Command5("ls").description("list boxes with status and address (yours and your orgs'; --org <slug> for one org)").
|
|
1380
|
+
var lsCommand = new Command5("ls").description("list boxes with status and address (yours and your orgs'; --org <slug> for one org)").option("-a, --all", "every box on the platform (platform admins only)").option("--json", "print as JSON").action(async (opts, cmd) => {
|
|
1348
1381
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1349
1382
|
try {
|
|
1350
|
-
const boxes = await client.listMachines();
|
|
1383
|
+
const boxes = await client.listMachines({ all: opts.all });
|
|
1351
1384
|
if (opts.json) {
|
|
1352
1385
|
json(boxes);
|
|
1353
1386
|
return;
|
|
@@ -1387,9 +1420,103 @@ var pauseCommand = new Command6("pause").description("freeze a box in place (mem
|
|
|
1387
1420
|
}
|
|
1388
1421
|
});
|
|
1389
1422
|
|
|
1423
|
+
// src/commands/vm/proxy/index.ts
|
|
1424
|
+
import { Command as Command10 } from "commander";
|
|
1425
|
+
|
|
1426
|
+
// src/commands/vm/proxy/add.ts
|
|
1427
|
+
import { Command as Command7 } from "commander";
|
|
1428
|
+
|
|
1429
|
+
// src/commands/vm/proxy/shared.ts
|
|
1430
|
+
function rowsOf(box, user, only) {
|
|
1431
|
+
return (box.ports ?? []).filter(only ?? (() => true)).map((f) => ({ box: displayName(box, user), ...f }));
|
|
1432
|
+
}
|
|
1433
|
+
function reaches(row, short = false) {
|
|
1434
|
+
if (row.address !== void 0) return `${row.address}:${row.hostPort}`;
|
|
1435
|
+
return short ? `:${row.hostPort}` : `port ${row.hostPort} of this host's public address`;
|
|
1436
|
+
}
|
|
1437
|
+
function parsePorts(texts) {
|
|
1438
|
+
return texts.map((t) => {
|
|
1439
|
+
const n = Number(t);
|
|
1440
|
+
if (!/^\d+$/.test(t) || n < 1 || n > 65535) throw new KvboxError(`"${t}" is not a port (1-65535)`);
|
|
1441
|
+
return n;
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
async function findBox(client, text) {
|
|
1445
|
+
const found = pickRef(await boxesFor(client, text), text, me(client));
|
|
1446
|
+
if (!found) throw new KvboxError(`box ${text}: not found (kvbox ls)`);
|
|
1447
|
+
return found;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// src/commands/vm/proxy/add.ts
|
|
1451
|
+
var addCommand = new Command7("add").description("publish box ports on the internet; each gets a random public port").argument("<box>", "box name").argument("<port...>", "ports inside the box, e.g. 3000 8080").option("--udp", "UDP instead of TCP").option("--json", "print the new forwards as JSON").action(async (name, portTexts, opts, cmd) => {
|
|
1452
|
+
const guestPorts = parsePorts(portTexts);
|
|
1453
|
+
const proto = opts.udp ? "udp" : "tcp";
|
|
1454
|
+
const client = await clientFor(cmd.optsWithGlobals());
|
|
1455
|
+
try {
|
|
1456
|
+
const user = me(client);
|
|
1457
|
+
const found = await findBox(client, name);
|
|
1458
|
+
const box = await spin(`publishing ${guestPorts.join(", ")} on ${name}\u2026`, client.addPorts(displayName(found, user), { ports: guestPorts.map((guestPort) => ({ guestPort, proto })) }));
|
|
1459
|
+
const rows = rowsOf(box, user, (f) => f.proto === proto && guestPorts.includes(f.guestPort));
|
|
1460
|
+
if (opts.json) {
|
|
1461
|
+
json(rows);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
for (const row of rows) info(`${color.green("\u2713")} box ${color.bold(row.box)} port ${row.guestPort} is reachable at ${reaches(row)} (${row.proto})`);
|
|
1465
|
+
if (box.status !== "running") info(` box ${name} is ${box.status}: the ports open when it runs`);
|
|
1466
|
+
} finally {
|
|
1467
|
+
await client.close();
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
// src/commands/vm/proxy/ls.ts
|
|
1472
|
+
import { Command as Command8 } from "commander";
|
|
1473
|
+
var lsCommand2 = new Command8("ls").description("list the box ports published on the internet").argument("[box]", "only this box").option("--json", "print as JSON").action(async (name, opts, cmd) => {
|
|
1474
|
+
const client = await clientFor(cmd.optsWithGlobals());
|
|
1475
|
+
try {
|
|
1476
|
+
const user = me(client);
|
|
1477
|
+
const boxes = name === void 0 ? await client.listMachines() : [await findBox(client, name)];
|
|
1478
|
+
const rows = boxes.flatMap((b) => rowsOf(b, user)).sort((a, b) => a.box.localeCompare(b.box) || a.guestPort - b.guestPort);
|
|
1479
|
+
if (opts.json) {
|
|
1480
|
+
json(rows);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (rows.length === 0) {
|
|
1484
|
+
info(name === void 0 ? "no published ports (kvbox vm proxy add <box> <port>)" : `box ${name} publishes no ports (kvbox vm proxy add ${name} <port>)`);
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
table(rows.map((r) => ({ box: r.box, port: r.guestPort, reaches: reaches(r, true), proto: r.proto })));
|
|
1488
|
+
} finally {
|
|
1489
|
+
await client.close();
|
|
1490
|
+
}
|
|
1491
|
+
});
|
|
1492
|
+
|
|
1493
|
+
// src/commands/vm/proxy/rm.ts
|
|
1494
|
+
import { Command as Command9 } from "commander";
|
|
1495
|
+
var rmCommand = new Command9("rm").description("stop publishing box ports").argument("<box>", "box name").argument("<port...>", "ports inside the box, as given to add").option("--udp", "the UDP forwards of those ports").option("-y, --yes", "do not ask for confirmation").action(async (name, portTexts, opts, cmd) => {
|
|
1496
|
+
const guestPorts = parsePorts(portTexts);
|
|
1497
|
+
const proto = opts.udp ? "udp" : "tcp";
|
|
1498
|
+
if (!await confirm(`Stop publishing port${guestPorts.length > 1 ? "s" : ""} ${guestPorts.join(", ")} of box ${name}?`, opts.yes ?? false)) {
|
|
1499
|
+
info("cancelled");
|
|
1500
|
+
process.exitCode = 1;
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
const client = await clientFor(cmd.optsWithGlobals());
|
|
1504
|
+
try {
|
|
1505
|
+
const found = await findBox(client, name);
|
|
1506
|
+
await spin(`closing ${guestPorts.join(", ")} on ${name}\u2026`, client.removePorts(displayName(found, me(client)), { ports: guestPorts.map((guestPort) => ({ guestPort, proto })) }));
|
|
1507
|
+
info(`${color.green("\u2713")} box ${color.bold(name)} no longer publishes ${guestPorts.join(", ")} (${proto})`);
|
|
1508
|
+
} finally {
|
|
1509
|
+
await client.close();
|
|
1510
|
+
}
|
|
1511
|
+
});
|
|
1512
|
+
|
|
1513
|
+
// src/commands/vm/proxy/index.ts
|
|
1514
|
+
var proxyCommand = new Command10("proxy").description("publish box ports on the internet").addCommand(addCommand).addCommand(lsCommand2).addCommand(rmCommand);
|
|
1515
|
+
for (const cmd of proxyCommand.commands) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
|
|
1516
|
+
|
|
1390
1517
|
// src/commands/vm/rescale.ts
|
|
1391
|
-
import { Command as
|
|
1392
|
-
var rescaleCommand = new
|
|
1518
|
+
import { Command as Command11, Option as Option2 } from "commander";
|
|
1519
|
+
var rescaleCommand = new Command11("rescale").description("change a box's vCPUs, memory or disk (e.g. --vcpu 4 --mem 16GB); a running box restarts").argument("<name>", "box name").addOption(new Option2("-s, --size <size>", "a preset to start from").choices(SIZE_NAMES)).option("--vcpu <n>", "number of vCPUs").option("--mem <size>", "memory, e.g. 16GB or 4096MB").option("--disk <size>", "disk size, e.g. 32GB (grow only)").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
|
|
1393
1520
|
const req = {
|
|
1394
1521
|
...opts.size !== void 0 ? { size: opts.size } : {},
|
|
1395
1522
|
...opts.vcpu !== void 0 ? { vcpu: parseCount(opts.vcpu) } : {},
|
|
@@ -1399,7 +1526,7 @@ var rescaleCommand = new Command7("rescale").description("change a box's vCPUs,
|
|
|
1399
1526
|
if (Object.keys(req).length === 0) throw new KvboxError("nothing to change: give --size, --vcpu, --mem or --disk");
|
|
1400
1527
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1401
1528
|
try {
|
|
1402
|
-
const before = pickRef(await client
|
|
1529
|
+
const before = pickRef(await boxesFor(client, name), name, me(client));
|
|
1403
1530
|
if (!before) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1404
1531
|
const box = await spin(`rescaling ${name}\u2026`, client.rescaleMachine(displayName(before, me(client)), req));
|
|
1405
1532
|
if (opts.json) {
|
|
@@ -1434,8 +1561,8 @@ function parseGib(flag, text) {
|
|
|
1434
1561
|
}
|
|
1435
1562
|
|
|
1436
1563
|
// src/commands/vm/resume.ts
|
|
1437
|
-
import { Command as
|
|
1438
|
-
var resumeCommand = new
|
|
1564
|
+
import { Command as Command12 } from "commander";
|
|
1565
|
+
var resumeCommand = new Command12("resume").description("continue a box that is in standby (kvbox pause)").argument("<name>", "box name").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
|
|
1439
1566
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1440
1567
|
try {
|
|
1441
1568
|
const box = await spin(`resuming ${name}\u2026`, client.resumeMachine(name));
|
|
@@ -1447,11 +1574,11 @@ var resumeCommand = new Command8("resume").description("continue a box that is i
|
|
|
1447
1574
|
});
|
|
1448
1575
|
|
|
1449
1576
|
// src/commands/vm/rm.ts
|
|
1450
|
-
import { Command as
|
|
1451
|
-
var
|
|
1577
|
+
import { Command as Command13 } from "commander";
|
|
1578
|
+
var rmCommand2 = new Command13("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) => {
|
|
1452
1579
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1453
1580
|
try {
|
|
1454
|
-
const box = pickRef(await client
|
|
1581
|
+
const box = pickRef(await boxesFor(client, name), name, me(client));
|
|
1455
1582
|
if (!box) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1456
1583
|
const ref = displayName(box, me(client));
|
|
1457
1584
|
if (!await confirm(`Destroy box ${ref} and its disk?`, opts.yes ?? false)) {
|
|
@@ -1467,13 +1594,13 @@ var rmCommand = new Command9("rm").description("destroy a box (its disk is delet
|
|
|
1467
1594
|
});
|
|
1468
1595
|
|
|
1469
1596
|
// src/commands/vm/set.ts
|
|
1470
|
-
import { Command as
|
|
1471
|
-
var setCommand = new
|
|
1597
|
+
import { Command as Command14 } from "commander";
|
|
1598
|
+
var setCommand = new Command14("set").description("change a box's settings, e.g. --auto-hibernate 30m (off: never)").argument("<name>", "box name").option("--auto-hibernate <duration>", "hibernate the box after this long without network traffic (30m, 4h, 1d; off: never)").option("--json", "print the box as JSON").action(async (name, opts, cmd) => {
|
|
1472
1599
|
if (opts.autoHibernate === void 0) throw new KvboxError("nothing to change: give --auto-hibernate");
|
|
1473
1600
|
const autoHibernateSec = parseIdleTimeout(opts.autoHibernate);
|
|
1474
1601
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1475
1602
|
try {
|
|
1476
|
-
const found = pickRef(await client
|
|
1603
|
+
const found = pickRef(await boxesFor(client, name), name, me(client));
|
|
1477
1604
|
if (!found) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1478
1605
|
const box = await spin(`updating ${name}\u2026`, client.setMachine(displayName(found, me(client)), { autoHibernateSec }));
|
|
1479
1606
|
if (opts.json) {
|
|
@@ -1487,8 +1614,8 @@ var setCommand = new Command10("set").description("change a box's settings, e.g.
|
|
|
1487
1614
|
});
|
|
1488
1615
|
|
|
1489
1616
|
// src/commands/vm/start.ts
|
|
1490
|
-
import { Command as
|
|
1491
|
-
var startCommand = new
|
|
1617
|
+
import { Command as Command15 } from "commander";
|
|
1618
|
+
var startCommand = new Command15("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) => {
|
|
1492
1619
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1493
1620
|
try {
|
|
1494
1621
|
const box = await spin(`booting ${name}\u2026`, client.startMachine(name));
|
|
@@ -1500,8 +1627,8 @@ var startCommand = new Command11("start").description("boot a stopped box again
|
|
|
1500
1627
|
});
|
|
1501
1628
|
|
|
1502
1629
|
// src/commands/vm/stop.ts
|
|
1503
|
-
import { Command as
|
|
1504
|
-
var stopCommand = new
|
|
1630
|
+
import { Command as Command16 } from "commander";
|
|
1631
|
+
var stopCommand = new Command16("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) => {
|
|
1505
1632
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1506
1633
|
try {
|
|
1507
1634
|
const box = await spin(`shutting ${name} down\u2026`, client.stopMachine(name));
|
|
@@ -1513,11 +1640,11 @@ var stopCommand = new Command12("stop").description("shut a box down (its disk i
|
|
|
1513
1640
|
});
|
|
1514
1641
|
|
|
1515
1642
|
// src/commands/vm/top.ts
|
|
1516
|
-
import { Command as
|
|
1517
|
-
var topCommand = new
|
|
1643
|
+
import { Command as Command17 } from "commander";
|
|
1644
|
+
var topCommand = new Command17("top").description("load, memory and disk of each running box, as the box itself sees them").option("-a, --all", "every running box on the platform (platform admins only)").option("--json", "print as JSON").action(async (opts, cmd) => {
|
|
1518
1645
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1519
1646
|
try {
|
|
1520
|
-
const running = (await client.listMachines()).filter((b) => b.status === "running");
|
|
1647
|
+
const running = (await client.listMachines({ all: opts.all })).filter((b) => b.status === "running");
|
|
1521
1648
|
const entries = await mapLimit(running, ASK_AT_ONCE, async (b) => {
|
|
1522
1649
|
const who = { name: b.name, owner: b.owner, ...b.ownerKind === void 0 ? {} : { ownerKind: b.ownerKind } };
|
|
1523
1650
|
try {
|
|
@@ -1574,11 +1701,11 @@ function topRows(entries, cloud) {
|
|
|
1574
1701
|
}
|
|
1575
1702
|
|
|
1576
1703
|
// src/commands/vm/update.ts
|
|
1577
|
-
import { Command as
|
|
1578
|
-
var updateCommand = new
|
|
1704
|
+
import { Command as Command18 } from "commander";
|
|
1705
|
+
var updateCommand = new Command18("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) => {
|
|
1579
1706
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1580
1707
|
try {
|
|
1581
|
-
const before = pickRef(await client
|
|
1708
|
+
const before = pickRef(await boxesFor(client, name), name, me(client));
|
|
1582
1709
|
if (!before) throw new KvboxError(`box ${name}: not found (kvbox ls)`);
|
|
1583
1710
|
const box = await spin(`updating ${name}\u2026`, client.updateMachine(displayName(before, me(client))));
|
|
1584
1711
|
if (opts.json) {
|
|
@@ -1597,8 +1724,8 @@ var updateCommand = new Command14("update").description("move a box onto the cur
|
|
|
1597
1724
|
});
|
|
1598
1725
|
|
|
1599
1726
|
// src/commands/vm/usage.ts
|
|
1600
|
-
import { Command as
|
|
1601
|
-
var usageCommand = new
|
|
1727
|
+
import { Command as Command19 } from "commander";
|
|
1728
|
+
var usageCommand = new Command19("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) => {
|
|
1602
1729
|
let since;
|
|
1603
1730
|
if (opts.since !== void 0) {
|
|
1604
1731
|
const t = Date.parse(opts.since);
|
|
@@ -1645,8 +1772,8 @@ function block(u) {
|
|
|
1645
1772
|
}
|
|
1646
1773
|
|
|
1647
1774
|
// src/commands/vm/wake.ts
|
|
1648
|
-
import { Command as
|
|
1649
|
-
var wakeCommand = new
|
|
1775
|
+
import { Command as Command20 } from "commander";
|
|
1776
|
+
var wakeCommand = new Command20("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) => {
|
|
1650
1777
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
1651
1778
|
try {
|
|
1652
1779
|
const box = await spin(`waking ${name} (loading its memory from disk)\u2026`, client.wakeMachine(name));
|
|
@@ -1658,15 +1785,15 @@ var wakeCommand = new Command16("wake").description("continue a hibernated box w
|
|
|
1658
1785
|
});
|
|
1659
1786
|
|
|
1660
1787
|
// src/commands/vm/index.ts
|
|
1661
|
-
var vmCommand = new
|
|
1662
|
-
for (const cmd of vmCommand.commands) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
|
|
1663
|
-
var vmAliases = [newCommand, lsCommand, connectCommand, execCommand, stopCommand, startCommand, pauseCommand, resumeCommand, hibernateCommand, wakeCommand,
|
|
1788
|
+
var vmCommand = new Command21("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(proxyCommand).addCommand(rmCommand2);
|
|
1789
|
+
for (const cmd of vmCommand.commands) if (cmd !== proxyCommand) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
|
|
1790
|
+
var vmAliases = [newCommand, lsCommand, connectCommand, execCommand, stopCommand, startCommand, pauseCommand, resumeCommand, hibernateCommand, wakeCommand, rmCommand2];
|
|
1664
1791
|
|
|
1665
1792
|
// src/commands/server/index.ts
|
|
1666
|
-
import { Command as
|
|
1793
|
+
import { Command as Command29 } from "commander";
|
|
1667
1794
|
|
|
1668
1795
|
// src/commands/server/join.ts
|
|
1669
|
-
import { Command as
|
|
1796
|
+
import { Command as Command22 } from "commander";
|
|
1670
1797
|
|
|
1671
1798
|
// src/commands/server/daemon.ts
|
|
1672
1799
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -1720,7 +1847,7 @@ function runKvboxServer(args) {
|
|
|
1720
1847
|
}
|
|
1721
1848
|
|
|
1722
1849
|
// src/commands/server/join.ts
|
|
1723
|
-
var joinCommand = new
|
|
1850
|
+
var joinCommand = new Command22("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) => {
|
|
1724
1851
|
const args = ["join", url, "--token", opts.token];
|
|
1725
1852
|
if (opts.advertise !== void 0) args.push("--advertise", opts.advertise);
|
|
1726
1853
|
if (opts.name !== void 0) args.push("--name", opts.name);
|
|
@@ -1730,8 +1857,8 @@ var joinCommand = new Command18("join").description("put this machine behind a c
|
|
|
1730
1857
|
});
|
|
1731
1858
|
|
|
1732
1859
|
// src/commands/server/leave.ts
|
|
1733
|
-
import { Command as
|
|
1734
|
-
var leaveCommand = new
|
|
1860
|
+
import { Command as Command23 } from "commander";
|
|
1861
|
+
var leaveCommand = new Command23("leave").description("take this machine out from behind its control plane and restart its server").action(async () => {
|
|
1735
1862
|
const p = paths();
|
|
1736
1863
|
for (const line of (await runKvboxServer(["leave"])).split("\n")) info(line);
|
|
1737
1864
|
if (await runningPid(p) === null) return;
|
|
@@ -1740,14 +1867,14 @@ var leaveCommand = new Command19("leave").description("take this machine out fro
|
|
|
1740
1867
|
});
|
|
1741
1868
|
|
|
1742
1869
|
// src/commands/server/relay.ts
|
|
1743
|
-
import { Command as
|
|
1744
|
-
var relayCommand = new
|
|
1870
|
+
import { Command as Command24 } from "commander";
|
|
1871
|
+
var relayCommand = new Command24("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) => {
|
|
1745
1872
|
for (const line of (await runKvboxServer(["relay", joinString])).split("\n")) info(line);
|
|
1746
1873
|
});
|
|
1747
1874
|
|
|
1748
1875
|
// src/commands/server/start.ts
|
|
1749
|
-
import { Command as
|
|
1750
|
-
var startCommand2 = new
|
|
1876
|
+
import { Command as Command25 } from "commander";
|
|
1877
|
+
var startCommand2 = new Command25("start").description("start the local kvbox-server in the background").action(async (_opts, cmd) => {
|
|
1751
1878
|
const client = await clientFor({ ...cmd.optsWithGlobals(), local: true }, { autoStart: false });
|
|
1752
1879
|
try {
|
|
1753
1880
|
const health = await client.health();
|
|
@@ -1763,8 +1890,8 @@ var startCommand2 = new Command21("start").description("start the local kvbox-se
|
|
|
1763
1890
|
});
|
|
1764
1891
|
|
|
1765
1892
|
// src/commands/server/status.ts
|
|
1766
|
-
import { Command as
|
|
1767
|
-
var statusCommand = new
|
|
1893
|
+
import { Command as Command26 } from "commander";
|
|
1894
|
+
var statusCommand = new Command26("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) => {
|
|
1768
1895
|
const client = await clientFor({ ...cmd.optsWithGlobals(), local: true });
|
|
1769
1896
|
try {
|
|
1770
1897
|
const health = await client.health();
|
|
@@ -1796,8 +1923,8 @@ var statusCommand = new Command22("status").description("show whether this machi
|
|
|
1796
1923
|
});
|
|
1797
1924
|
|
|
1798
1925
|
// src/commands/server/stop.ts
|
|
1799
|
-
import { Command as
|
|
1800
|
-
var stopCommand2 = new
|
|
1926
|
+
import { Command as Command27 } from "commander";
|
|
1927
|
+
var stopCommand2 = new Command27("stop").description("stop the local server (running boxes are not affected)").action(async () => {
|
|
1801
1928
|
const pid = await runningPid(paths());
|
|
1802
1929
|
if (pid === null) throw new KvboxError("kvbox-server is not running");
|
|
1803
1930
|
await stopLocalServer(pid);
|
|
@@ -1805,8 +1932,8 @@ var stopCommand2 = new Command23("stop").description("stop the local server (run
|
|
|
1805
1932
|
});
|
|
1806
1933
|
|
|
1807
1934
|
// src/commands/server/trust-ca.ts
|
|
1808
|
-
import { Command as
|
|
1809
|
-
var trustCaCommand = new
|
|
1935
|
+
import { Command as Command28 } from "commander";
|
|
1936
|
+
var trustCaCommand = new Command28("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) => {
|
|
1810
1937
|
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");
|
|
1811
1938
|
if (publicKey !== void 0 && opts.fromCloud) throw new KvboxError("either a public key or --from-cloud, not both");
|
|
1812
1939
|
const client = await clientFor({ ...cmd.optsWithGlobals(), local: true });
|
|
@@ -1844,7 +1971,7 @@ function describeReport(report) {
|
|
|
1844
1971
|
}
|
|
1845
1972
|
|
|
1846
1973
|
// src/commands/server/index.ts
|
|
1847
|
-
var serverCommand = new
|
|
1974
|
+
var serverCommand = new Command29("server").description("run or manage the kvbox server").addCommand(startCommand2).addCommand(statusCommand).addCommand(stopCommand2).addCommand(joinCommand).addCommand(leaveCommand).addCommand(relayCommand).addCommand(trustCaCommand);
|
|
1848
1975
|
|
|
1849
1976
|
// src/commands/login.ts
|
|
1850
1977
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
@@ -1852,8 +1979,8 @@ import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from
|
|
|
1852
1979
|
import { hostname as osHostname } from "os";
|
|
1853
1980
|
import { createInterface } from "readline/promises";
|
|
1854
1981
|
import { Writable } from "stream";
|
|
1855
|
-
import { Command as
|
|
1856
|
-
var loginCommand = new
|
|
1982
|
+
import { Command as Command30 } from "commander";
|
|
1983
|
+
var loginCommand = new Command30("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) => {
|
|
1857
1984
|
const url = normalizeUrl(urlArg ?? DEFAULT_CLOUD_URL);
|
|
1858
1985
|
const creds = await readCredentials(opts);
|
|
1859
1986
|
const session = await runLogin(url, creds, paths());
|
|
@@ -1951,8 +2078,8 @@ async function firstLine(stream) {
|
|
|
1951
2078
|
}
|
|
1952
2079
|
|
|
1953
2080
|
// src/commands/logout.ts
|
|
1954
|
-
import { Command as
|
|
1955
|
-
var logoutCommand = new
|
|
2081
|
+
import { Command as Command31 } from "commander";
|
|
2082
|
+
var logoutCommand = new Command31("logout").description("log out of the control plane; commands target this machine's kvbox-server again").action(async () => {
|
|
1956
2083
|
const p = paths();
|
|
1957
2084
|
const session = await readSession(p).catch(() => null);
|
|
1958
2085
|
switch (await runLogout(p)) {
|
|
@@ -1989,8 +2116,8 @@ async function runLogout(p = paths()) {
|
|
|
1989
2116
|
}
|
|
1990
2117
|
|
|
1991
2118
|
// src/commands/whoami.ts
|
|
1992
|
-
import { Command as
|
|
1993
|
-
var whoamiCommand = new
|
|
2119
|
+
import { Command as Command32 } from "commander";
|
|
2120
|
+
var whoamiCommand = new Command32("whoami").description("show which account and control plane commands target (or local mode)").option("--json", "print as JSON").action(async (opts) => {
|
|
1994
2121
|
const session = await readSession();
|
|
1995
2122
|
if (opts.json) {
|
|
1996
2123
|
json(session ? { user: session.user, url: session.url, sshCertExpires: session.sshCertExpires ?? null } : null);
|
|
@@ -2006,15 +2133,15 @@ function describeSession(session) {
|
|
|
2006
2133
|
}
|
|
2007
2134
|
|
|
2008
2135
|
// src/commands/snapshots/index.ts
|
|
2009
|
-
import { Command as
|
|
2136
|
+
import { Command as Command36 } from "commander";
|
|
2010
2137
|
|
|
2011
2138
|
// src/commands/snapshots/ls.ts
|
|
2012
|
-
import { Command as
|
|
2013
|
-
var
|
|
2139
|
+
import { Command as Command33 } from "commander";
|
|
2140
|
+
var lsCommand3 = new Command33("ls").description("list snapshots (yours and your orgs'; --org <slug> for one org)").option("-a, --all", "every snapshot on the platform (platform admins only)").option("--json", "print as JSON").action(async (opts, cmd) => {
|
|
2014
2141
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
2015
2142
|
try {
|
|
2016
2143
|
const cloud = client.target.kind === "cloud";
|
|
2017
|
-
const snaps = await client.listSnapshots();
|
|
2144
|
+
const snaps = await client.listSnapshots({ all: opts.all });
|
|
2018
2145
|
if (opts.json) {
|
|
2019
2146
|
json(snaps);
|
|
2020
2147
|
return;
|
|
@@ -2041,8 +2168,8 @@ var lsCommand2 = new Command29("ls").description("list snapshots (yours and your
|
|
|
2041
2168
|
});
|
|
2042
2169
|
|
|
2043
2170
|
// src/commands/snapshots/new.ts
|
|
2044
|
-
import { Command as
|
|
2045
|
-
var newCommand2 = new
|
|
2171
|
+
import { Command as Command34 } from "commander";
|
|
2172
|
+
var newCommand2 = new Command34("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) => {
|
|
2046
2173
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
2047
2174
|
try {
|
|
2048
2175
|
const snap = await spin(`saving snapshot ${name} from box ${box} (memory + disk)\u2026`, client.createSnapshot({ box, name }));
|
|
@@ -2054,8 +2181,8 @@ var newCommand2 = new Command30("new").description("freeze a running box (memory
|
|
|
2054
2181
|
});
|
|
2055
2182
|
|
|
2056
2183
|
// src/commands/snapshots/rm.ts
|
|
2057
|
-
import { Command as
|
|
2058
|
-
var
|
|
2184
|
+
import { Command as Command35 } from "commander";
|
|
2185
|
+
var rmCommand3 = new Command35("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) => {
|
|
2059
2186
|
if (!await confirm(`Delete snapshot ${name}?`, opts.yes ?? false)) {
|
|
2060
2187
|
info("cancelled");
|
|
2061
2188
|
process.exitCode = 1;
|
|
@@ -2071,14 +2198,14 @@ var rmCommand2 = new Command31("rm").description("delete a snapshot (boxes made
|
|
|
2071
2198
|
});
|
|
2072
2199
|
|
|
2073
2200
|
// src/commands/snapshots/index.ts
|
|
2074
|
-
var snapshotsCommand = new
|
|
2201
|
+
var snapshotsCommand = new Command36("snapshots").aliases(["snapshot", "snap"]).description("freeze running boxes into snapshots and manage them").addCommand(newCommand2).addCommand(lsCommand3).addCommand(rmCommand3);
|
|
2075
2202
|
for (const cmd of snapshotsCommand.commands) cmd.option("--org <slug>", "act in this org (- for your personal boxes)");
|
|
2076
2203
|
|
|
2077
2204
|
// src/commands/org/index.ts
|
|
2078
|
-
import { Command as
|
|
2205
|
+
import { Command as Command42 } from "commander";
|
|
2079
2206
|
|
|
2080
2207
|
// src/commands/org/ls.ts
|
|
2081
|
-
import { Command as
|
|
2208
|
+
import { Command as Command37 } from "commander";
|
|
2082
2209
|
|
|
2083
2210
|
// src/commands/org/context.ts
|
|
2084
2211
|
var NOT_LOGGED_IN = "orgs live on the control plane: kvbox login first";
|
|
@@ -2098,7 +2225,7 @@ function orgFor(opts, target) {
|
|
|
2098
2225
|
}
|
|
2099
2226
|
|
|
2100
2227
|
// src/commands/org/ls.ts
|
|
2101
|
-
var
|
|
2228
|
+
var lsCommand4 = new Command37("ls").description("list the orgs you belong to and your role in each").option("--json", "print as JSON").action(async (opts, cmd) => {
|
|
2102
2229
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2103
2230
|
try {
|
|
2104
2231
|
const orgs = await client.listOrgs();
|
|
@@ -2120,8 +2247,8 @@ function orgRows(orgs) {
|
|
|
2120
2247
|
}
|
|
2121
2248
|
|
|
2122
2249
|
// src/commands/org/members.ts
|
|
2123
|
-
import { Command as
|
|
2124
|
-
var
|
|
2250
|
+
import { Command as Command38, Option as Option3 } from "commander";
|
|
2251
|
+
var lsCommand5 = new Command38("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) => {
|
|
2125
2252
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2126
2253
|
try {
|
|
2127
2254
|
const org = await client.getOrg(orgFor(opts, client.target));
|
|
@@ -2135,7 +2262,7 @@ var lsCommand4 = new Command34("ls").description("list an org's members and thei
|
|
|
2135
2262
|
await client.close();
|
|
2136
2263
|
}
|
|
2137
2264
|
});
|
|
2138
|
-
var
|
|
2265
|
+
var addCommand2 = new Command38("add").description("add a user to an org (admins and owners; only an owner can add an owner)").argument("<user>", "their username").addOption(new Option3("-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) => {
|
|
2139
2266
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2140
2267
|
try {
|
|
2141
2268
|
const slug = orgFor(opts, client.target);
|
|
@@ -2145,7 +2272,7 @@ var addCommand = new Command34("add").description("add a user to an org (admins
|
|
|
2145
2272
|
await client.close();
|
|
2146
2273
|
}
|
|
2147
2274
|
});
|
|
2148
|
-
var
|
|
2275
|
+
var rmCommand4 = new Command38("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) => {
|
|
2149
2276
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2150
2277
|
try {
|
|
2151
2278
|
const slug = orgFor(opts, client.target);
|
|
@@ -2161,11 +2288,11 @@ var rmCommand3 = new Command34("rm").description("remove a member (or leave: rem
|
|
|
2161
2288
|
await client.close();
|
|
2162
2289
|
}
|
|
2163
2290
|
});
|
|
2164
|
-
var membersCommand = new
|
|
2291
|
+
var membersCommand = new Command38("members").description("who is in an org and what they may do").addCommand(lsCommand5).addCommand(addCommand2).addCommand(rmCommand4);
|
|
2165
2292
|
|
|
2166
2293
|
// src/commands/org/new.ts
|
|
2167
|
-
import { Command as
|
|
2168
|
-
var newCommand3 = new
|
|
2294
|
+
import { Command as Command39 } from "commander";
|
|
2295
|
+
var newCommand3 = new Command39("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) => {
|
|
2169
2296
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2170
2297
|
try {
|
|
2171
2298
|
const org = await client.createOrg({ slug, name: opts.name ?? slug });
|
|
@@ -2181,8 +2308,8 @@ var newCommand3 = new Command35("new").description("create an org; you become it
|
|
|
2181
2308
|
});
|
|
2182
2309
|
|
|
2183
2310
|
// src/commands/org/rm.ts
|
|
2184
|
-
import { Command as
|
|
2185
|
-
var
|
|
2311
|
+
import { Command as Command40 } from "commander";
|
|
2312
|
+
var rmCommand5 = new Command40("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) => {
|
|
2186
2313
|
if (!await confirm(`Delete org ${slug}? Its members lose access; its slug stays taken.`, opts.yes ?? false)) {
|
|
2187
2314
|
info("cancelled");
|
|
2188
2315
|
process.exitCode = 1;
|
|
@@ -2198,8 +2325,8 @@ var rmCommand4 = new Command36("rm").description("delete an org (owners only; re
|
|
|
2198
2325
|
});
|
|
2199
2326
|
|
|
2200
2327
|
// src/commands/org/role.ts
|
|
2201
|
-
import { Argument, Command as
|
|
2202
|
-
var roleCommand = new
|
|
2328
|
+
import { Argument, Command as Command41 } from "commander";
|
|
2329
|
+
var roleCommand = new Command41("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) => {
|
|
2203
2330
|
const client = await cloudClientFor(cmd.optsWithGlobals());
|
|
2204
2331
|
try {
|
|
2205
2332
|
const slug = orgFor(opts, client.target);
|
|
@@ -2211,11 +2338,11 @@ var roleCommand = new Command37("role").description("change a member's role (own
|
|
|
2211
2338
|
});
|
|
2212
2339
|
|
|
2213
2340
|
// src/commands/org/index.ts
|
|
2214
|
-
var orgCommand = new
|
|
2341
|
+
var orgCommand = new Command42("org").description("orgs: shared slugs that own boxes, with owners, admins and members").addCommand(lsCommand4).addCommand(newCommand3).addCommand(membersCommand).addCommand(roleCommand).addCommand(rmCommand5);
|
|
2215
2342
|
|
|
2216
2343
|
// src/commands/usage.ts
|
|
2217
|
-
import { Command as
|
|
2218
|
-
var usageCommand2 = new
|
|
2344
|
+
import { Command as Command43 } from "commander";
|
|
2345
|
+
var usageCommand2 = new Command43("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("-a, --all", "every box on the platform (platform admins only)").option("--json", "print as JSON").action(async (opts, cmd) => {
|
|
2219
2346
|
for (const [name, value] of [
|
|
2220
2347
|
["since", opts.since],
|
|
2221
2348
|
["until", opts.until]
|
|
@@ -2225,7 +2352,7 @@ var usageCommand2 = new Command39("usage").description("what your boxes used thi
|
|
|
2225
2352
|
const client = await clientFor(cmd.optsWithGlobals());
|
|
2226
2353
|
try {
|
|
2227
2354
|
if (client.target.kind === "local" && cmd.optsWithGlobals().org) throw new KvboxError("--org needs a control plane: kvbox login, or drop --org");
|
|
2228
|
-
const report = await client.usageReport(opts.since, opts.until);
|
|
2355
|
+
const report = await client.usageReport(opts.since, opts.until, opts.all);
|
|
2229
2356
|
if (opts.json) {
|
|
2230
2357
|
json(report);
|
|
2231
2358
|
return;
|
|
@@ -2288,8 +2415,8 @@ function usageRows(report, cloud) {
|
|
|
2288
2415
|
}
|
|
2289
2416
|
|
|
2290
2417
|
// src/commands/credit.ts
|
|
2291
|
-
import { Command as
|
|
2292
|
-
var creditCommand = new
|
|
2418
|
+
import { Command as Command44 } from "commander";
|
|
2419
|
+
var creditCommand = new Command44("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) => {
|
|
2293
2420
|
const client = await clientFor(cmd.optsWithGlobals(), { autoStart: false });
|
|
2294
2421
|
try {
|
|
2295
2422
|
if (client.target.kind === "local") throw new KvboxError("credit lives on the control plane: kvbox login first");
|
|
@@ -2318,7 +2445,7 @@ function creditRow(b, me2) {
|
|
|
2318
2445
|
|
|
2319
2446
|
// src/program.ts
|
|
2320
2447
|
function buildProgram() {
|
|
2321
|
-
const program = new
|
|
2448
|
+
const program = new Command45("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();
|
|
2322
2449
|
program.addCommand(vmCommand);
|
|
2323
2450
|
program.addCommand(snapshotsCommand);
|
|
2324
2451
|
program.addCommand(serverCommand);
|