@krovacloud/cli 0.4.2 → 0.5.0
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/CHANGELOG.md +32 -0
- package/README.md +24 -1
- package/dist/index.js +204 -16
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@krovacloud/cli` are documented here.
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 0.5.0
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `krova domains` (list / add / rm) — manage a Cube's custom domains.
|
|
12
|
+
- `krova snapshots` (list / create / restore / rm) — snapshot and restore a
|
|
13
|
+
Cube's disk.
|
|
14
|
+
- `krova tcp` (list / add / rm) — manage a Cube's TCP port mappings, with an
|
|
15
|
+
optional `--whitelist` IP allow-list.
|
|
16
|
+
## 0.4.3
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- `webhooks listen --addr` now correctly parses a bare hostname (e.g.
|
|
21
|
+
`localhost`), a bare port, and IPv6 (`[::1]:4666`, `::1`). A bare host was
|
|
22
|
+
previously replaced with `127.0.0.1`.
|
|
23
|
+
|
|
24
|
+
## 0.4.2
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- `krova pricing` now shows the per-resource hourly **rates** — it previously
|
|
29
|
+
printed only the volume-tier multipliers and dropped `rates`/`currency`/`note`.
|
|
30
|
+
- A one-off `--base-url` / `KROVA_BASE_URL` is no longer persisted into the
|
|
31
|
+
stored context.
|
|
32
|
+
- `auth login --space` is honored instead of being overwritten by the resolved
|
|
33
|
+
space.
|
|
34
|
+
- `cubes create` validates `--vcpu/--ram/--disk` are positive integers instead
|
|
35
|
+
of forwarding `null`.
|
|
36
|
+
|
|
5
37
|
## 0.4.1
|
|
6
38
|
|
|
7
39
|
### Changed
|
package/README.md
CHANGED
|
@@ -64,6 +64,29 @@ checking (no trust-on-first-use window). The destination is always passed after
|
|
|
64
64
|
a `--` separator, with host/user validated against option-injection — a hostile
|
|
65
65
|
value aborts before `ssh` ever runs.
|
|
66
66
|
|
|
67
|
+
## Domains, snapshots & TCP mappings
|
|
68
|
+
|
|
69
|
+
Manage a Cube's attached resources. All take a `<cube>` name or ID and support
|
|
70
|
+
`--json`.
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
# Custom domains
|
|
74
|
+
krova domains list <cube>
|
|
75
|
+
krova domains add <cube> --domain app.example.com --port 8080
|
|
76
|
+
krova domains rm <cube> <domain-id>
|
|
77
|
+
|
|
78
|
+
# Snapshots + restore
|
|
79
|
+
krova snapshots list <cube>
|
|
80
|
+
krova snapshots create <cube> --name nightly
|
|
81
|
+
krova snapshots restore <cube> <snapshot-id> # replaces the Cube's disk
|
|
82
|
+
krova snapshots rm <cube> <snapshot-id>
|
|
83
|
+
|
|
84
|
+
# TCP port mappings (expose a Cube port on the host)
|
|
85
|
+
krova tcp list <cube>
|
|
86
|
+
krova tcp add <cube> --port 5432 --whitelist 203.0.113.4/32
|
|
87
|
+
krova tcp rm <cube> <mapping-id>
|
|
88
|
+
```
|
|
89
|
+
|
|
67
90
|
## Catalog
|
|
68
91
|
|
|
69
92
|
```sh
|
|
@@ -90,7 +113,7 @@ Available on every command (flag > env var > context):
|
|
|
90
113
|
| `--base-url <url>` | `KROVA_BASE_URL` | override the API base URL |
|
|
91
114
|
| `--context <name>` | `KROVA_CONTEXT` | select a named context |
|
|
92
115
|
| `--json` | | machine-readable JSON output |
|
|
93
|
-
| `--timeout <dur>` | | per-request timeout (e.g. `30s`) |
|
|
116
|
+
| `--timeout <dur>` | | per-request timeout (e.g. `30s`); defaults to `30s` |
|
|
94
117
|
|
|
95
118
|
## License
|
|
96
119
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command13 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -670,9 +670,52 @@ function cubesCommand() {
|
|
|
670
670
|
var rootListCommand = listCmd;
|
|
671
671
|
var rootGetCommand = getCmd;
|
|
672
672
|
|
|
673
|
+
// src/commands/domains.ts
|
|
674
|
+
import { Command as Command5 } from "commander";
|
|
675
|
+
function domainsCommand() {
|
|
676
|
+
const cmd = new Command5("domains").description("manage a Cube's custom domains");
|
|
677
|
+
cmd.command("list").argument("<cube>", "cube name or ID").description("list the custom domains attached to a Cube").action(async (cubeRef, _opts, c) => {
|
|
678
|
+
const rt = getRuntime(c);
|
|
679
|
+
const client = makeClient(rt.res);
|
|
680
|
+
const space = await resolveSpace(rt);
|
|
681
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
682
|
+
const domains = await client.domains.list(space, id);
|
|
683
|
+
if (rt.json) return printJSON(domains);
|
|
684
|
+
printTable(
|
|
685
|
+
["ID", "DOMAIN", "PORT", "STATUS"],
|
|
686
|
+
domains.map((d) => [d.id, d.domain, String(d.port ?? ""), d.status])
|
|
687
|
+
);
|
|
688
|
+
});
|
|
689
|
+
cmd.command("add").argument("<cube>", "cube name or ID").requiredOption("--domain <domain>", "the domain name to attach").requiredOption("--port <n>", "the in-Cube port to route to").description("attach a custom domain to a Cube").action(async (cubeRef, opts, c) => {
|
|
690
|
+
const rt = getRuntime(c);
|
|
691
|
+
const client = makeClient(rt.res);
|
|
692
|
+
const space = await resolveSpace(rt);
|
|
693
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
694
|
+
const port = Number(opts.port);
|
|
695
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
696
|
+
throw new Error(`--port must be a valid port (got "${opts.port}").`);
|
|
697
|
+
}
|
|
698
|
+
const domain = await client.domains.create(space, id, { domain: opts.domain, port });
|
|
699
|
+
if (rt.json) return printJSON(domain);
|
|
700
|
+
process.stdout.write(`Attached ${domain.domain} (${domain.id}) \u2014 status ${domain.status}
|
|
701
|
+
`);
|
|
702
|
+
});
|
|
703
|
+
cmd.command("rm").argument("<cube>", "cube name or ID").argument("<domain-id>", "the domain mapping ID (see `krova domains list`)").description("detach a custom domain from a Cube").action(async (cubeRef, mappingId, _opts, c) => {
|
|
704
|
+
const rt = getRuntime(c);
|
|
705
|
+
const client = makeClient(rt.res);
|
|
706
|
+
const space = await resolveSpace(rt);
|
|
707
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
708
|
+
await client.domains.delete(space, id, mappingId);
|
|
709
|
+
if (rt.json) return printJSON({ id: mappingId, result: "detached" });
|
|
710
|
+
process.stdout.write(`Detached domain ${mappingId}
|
|
711
|
+
`);
|
|
712
|
+
});
|
|
713
|
+
return cmd;
|
|
714
|
+
}
|
|
715
|
+
|
|
673
716
|
// src/commands/login.ts
|
|
674
717
|
import { spawn } from "child_process";
|
|
675
|
-
import { Command as
|
|
718
|
+
import { Command as Command6 } from "commander";
|
|
676
719
|
var BROWSER_UNAVAILABLE = "Browser login isn't enabled on this server yet \u2014 run `krova auth login` to paste an API key from https://krova.cloud";
|
|
677
720
|
function safeBrowserURL(raw) {
|
|
678
721
|
let u;
|
|
@@ -697,7 +740,7 @@ function openBrowser(url) {
|
|
|
697
740
|
}
|
|
698
741
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
699
742
|
function loginCommand() {
|
|
700
|
-
return new
|
|
743
|
+
return new Command6("login").description("log in through your browser (device authorization)").option("--no-browser", "don't open a browser; just print the URL").option("--context <name>", "name for the saved context").action(async (opts, cmd) => {
|
|
701
744
|
const rt = getRuntime(cmd);
|
|
702
745
|
const baseUrl = rt.res.baseUrl;
|
|
703
746
|
const start = await rawRequest({
|
|
@@ -766,8 +809,64 @@ function loginCommand() {
|
|
|
766
809
|
});
|
|
767
810
|
}
|
|
768
811
|
|
|
812
|
+
// src/commands/snapshots.ts
|
|
813
|
+
import { Command as Command7 } from "commander";
|
|
814
|
+
function snapshotsCommand() {
|
|
815
|
+
const cmd = new Command7("snapshots").description("snapshot and restore a Cube's disk");
|
|
816
|
+
cmd.command("list").argument("<cube>", "cube name or ID").description("list a Cube's snapshots").action(async (cubeRef, _opts, c) => {
|
|
817
|
+
const rt = getRuntime(c);
|
|
818
|
+
const client = makeClient(rt.res);
|
|
819
|
+
const space = await resolveSpace(rt);
|
|
820
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
821
|
+
const snaps = await client.snapshots.list(space, id);
|
|
822
|
+
if (rt.json) return printJSON(snaps);
|
|
823
|
+
printTable(
|
|
824
|
+
["ID", "NAME", "STATUS", "KIND", "SIZE (BYTES)", "CREATED"],
|
|
825
|
+
snaps.map((s) => [
|
|
826
|
+
s.id,
|
|
827
|
+
s.name,
|
|
828
|
+
s.status,
|
|
829
|
+
s.kind,
|
|
830
|
+
s.sizeBytes == null ? "" : String(s.sizeBytes),
|
|
831
|
+
s.createdAt
|
|
832
|
+
])
|
|
833
|
+
);
|
|
834
|
+
});
|
|
835
|
+
cmd.command("create").argument("<cube>", "cube name or ID").option("--name <name>", "a name for the snapshot").description("create a snapshot of a Cube's disk").action(async (cubeRef, opts, c) => {
|
|
836
|
+
const rt = getRuntime(c);
|
|
837
|
+
const client = makeClient(rt.res);
|
|
838
|
+
const space = await resolveSpace(rt);
|
|
839
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
840
|
+
const snap = await client.snapshots.create(space, id, opts.name ? { name: opts.name } : {});
|
|
841
|
+
if (rt.json) return printJSON(snap);
|
|
842
|
+
process.stdout.write(`Created snapshot ${snap.id} (${snap.status})
|
|
843
|
+
`);
|
|
844
|
+
});
|
|
845
|
+
cmd.command("rm").argument("<cube>", "cube name or ID").argument("<snapshot-id>", "the snapshot ID (see `krova snapshots list`)").description("delete a snapshot").action(async (cubeRef, snapshotId, _opts, c) => {
|
|
846
|
+
const rt = getRuntime(c);
|
|
847
|
+
const client = makeClient(rt.res);
|
|
848
|
+
const space = await resolveSpace(rt);
|
|
849
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
850
|
+
await client.snapshots.delete(space, id, snapshotId);
|
|
851
|
+
if (rt.json) return printJSON({ id: snapshotId, result: "deleted" });
|
|
852
|
+
process.stdout.write(`Deleted snapshot ${snapshotId}
|
|
853
|
+
`);
|
|
854
|
+
});
|
|
855
|
+
cmd.command("restore").argument("<cube>", "cube name or ID").argument("<snapshot-id>", "the snapshot to restore the Cube's disk from").description("restore a Cube's disk from one of its snapshots (replaces the disk)").action(async (cubeRef, snapshotId, _opts, c) => {
|
|
856
|
+
const rt = getRuntime(c);
|
|
857
|
+
const client = makeClient(rt.res);
|
|
858
|
+
const space = await resolveSpace(rt);
|
|
859
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
860
|
+
await client.cubes.restore(space, id, snapshotId);
|
|
861
|
+
if (rt.json) return printJSON({ id, snapshotId, result: "restore enqueued" });
|
|
862
|
+
process.stdout.write(`Restore of cube ${id} from ${snapshotId} enqueued
|
|
863
|
+
`);
|
|
864
|
+
});
|
|
865
|
+
return cmd;
|
|
866
|
+
}
|
|
867
|
+
|
|
769
868
|
// src/commands/ssh.ts
|
|
770
|
-
import { Command as
|
|
869
|
+
import { Command as Command8 } from "commander";
|
|
771
870
|
|
|
772
871
|
// src/lib/ssh.ts
|
|
773
872
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -864,7 +963,7 @@ var collect = (v, acc) => {
|
|
|
864
963
|
return acc;
|
|
865
964
|
};
|
|
866
965
|
function sshCommand() {
|
|
867
|
-
return new
|
|
966
|
+
return new Command8("ssh").argument("<cube>", "cube name or ID").argument("[command...]", "command to run non-interactively (after --)").description("open an SSH session to a Cube (by name or ID)").option("-i, --identity <file>", "SSH identity (private key) file, passed to ssh -i").option("-L, --local-forward <spec>", "local port forward, passed to ssh -L (repeatable)", collect, []).option("-R, --remote-forward <spec>", "remote port forward, passed to ssh -R (repeatable)", collect, []).action(async (cubeRef, command, opts, cmd) => {
|
|
868
967
|
const rt = getRuntime(cmd);
|
|
869
968
|
const client = makeClient(rt.res);
|
|
870
969
|
const space = await resolveSpace(rt);
|
|
@@ -915,14 +1014,78 @@ function sshCommand() {
|
|
|
915
1014
|
});
|
|
916
1015
|
}
|
|
917
1016
|
|
|
1017
|
+
// src/commands/tcp.ts
|
|
1018
|
+
import { Command as Command9 } from "commander";
|
|
1019
|
+
function tcpCommand() {
|
|
1020
|
+
const cmd = new Command9("tcp").description("manage a Cube's TCP port mappings");
|
|
1021
|
+
cmd.command("list").argument("<cube>", "cube name or ID").description("list a Cube's TCP port mappings").action(async (cubeRef, _opts, c) => {
|
|
1022
|
+
const rt = getRuntime(c);
|
|
1023
|
+
const client = makeClient(rt.res);
|
|
1024
|
+
const space = await resolveSpace(rt);
|
|
1025
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
1026
|
+
const maps = await client.tcpMappings.list(space, id);
|
|
1027
|
+
if (rt.json) return printJSON(maps);
|
|
1028
|
+
printTable(
|
|
1029
|
+
["ID", "CUBE PORT", "HOST PORT", "LABEL", "STATUS", "SSH"],
|
|
1030
|
+
maps.map((m) => [
|
|
1031
|
+
m.id,
|
|
1032
|
+
String(m.cubePort),
|
|
1033
|
+
String(m.hostPort),
|
|
1034
|
+
m.label ?? "",
|
|
1035
|
+
m.status,
|
|
1036
|
+
m.isSsh ? "yes" : "no"
|
|
1037
|
+
])
|
|
1038
|
+
);
|
|
1039
|
+
});
|
|
1040
|
+
cmd.command("add").argument("<cube>", "cube name or ID").requiredOption("--port <n>", "the in-Cube port to expose").option(
|
|
1041
|
+
"--whitelist <cidr>",
|
|
1042
|
+
"restrict access to this IP/CIDR (repeatable)",
|
|
1043
|
+
(val, acc) => {
|
|
1044
|
+
acc.push(val);
|
|
1045
|
+
return acc;
|
|
1046
|
+
},
|
|
1047
|
+
[]
|
|
1048
|
+
).description("expose a Cube TCP port on the host, optionally IP-restricted").action(async (cubeRef, opts, c) => {
|
|
1049
|
+
const rt = getRuntime(c);
|
|
1050
|
+
const client = makeClient(rt.res);
|
|
1051
|
+
const space = await resolveSpace(rt);
|
|
1052
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
1053
|
+
const cubePort = Number(opts.port);
|
|
1054
|
+
if (!Number.isInteger(cubePort) || cubePort <= 0 || cubePort > 65535) {
|
|
1055
|
+
throw new Error(`--port must be a valid port (got "${opts.port}").`);
|
|
1056
|
+
}
|
|
1057
|
+
const whitelist = opts.whitelist;
|
|
1058
|
+
const mapping = await client.tcpMappings.create(space, id, {
|
|
1059
|
+
cubePort,
|
|
1060
|
+
...whitelist.length ? { whitelistIps: whitelist } : {}
|
|
1061
|
+
});
|
|
1062
|
+
if (rt.json) return printJSON(mapping);
|
|
1063
|
+
process.stdout.write(
|
|
1064
|
+
`Mapped cube port ${mapping.cubePort} \u2192 host port ${mapping.hostPort} (${mapping.id})
|
|
1065
|
+
`
|
|
1066
|
+
);
|
|
1067
|
+
});
|
|
1068
|
+
cmd.command("rm").argument("<cube>", "cube name or ID").argument("<mapping-id>", "the mapping ID (see `krova tcp list`)").description("remove a TCP port mapping").action(async (cubeRef, mappingId, _opts, c) => {
|
|
1069
|
+
const rt = getRuntime(c);
|
|
1070
|
+
const client = makeClient(rt.res);
|
|
1071
|
+
const space = await resolveSpace(rt);
|
|
1072
|
+
const id = await resolveCube(client, space, cubeRef);
|
|
1073
|
+
await client.tcpMappings.delete(space, id, mappingId);
|
|
1074
|
+
if (rt.json) return printJSON({ id: mappingId, result: "removed" });
|
|
1075
|
+
process.stdout.write(`Removed TCP mapping ${mappingId}
|
|
1076
|
+
`);
|
|
1077
|
+
});
|
|
1078
|
+
return cmd;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
918
1081
|
// src/commands/version.ts
|
|
919
1082
|
import { createRequire } from "module";
|
|
920
|
-
import { Command as
|
|
1083
|
+
import { Command as Command10 } from "commander";
|
|
921
1084
|
var require2 = createRequire(import.meta.url);
|
|
922
1085
|
var pkg = require2("../package.json");
|
|
923
1086
|
var CLI_VERSION = pkg.version;
|
|
924
1087
|
function versionCommand() {
|
|
925
|
-
return new
|
|
1088
|
+
return new Command10("version").description("print the krova CLI version").action((_opts, cmd) => {
|
|
926
1089
|
const rt = getRuntime(cmd);
|
|
927
1090
|
const info = {
|
|
928
1091
|
version: CLI_VERSION,
|
|
@@ -938,9 +1101,34 @@ function versionCommand() {
|
|
|
938
1101
|
// src/commands/webhooks.ts
|
|
939
1102
|
import { createServer } from "http";
|
|
940
1103
|
import { verifyKrovaWebhookOrThrow } from "@krovacloud/webhook";
|
|
941
|
-
import { Command as
|
|
1104
|
+
import { Command as Command11 } from "commander";
|
|
1105
|
+
var DEFAULT_LISTEN_HOST = "127.0.0.1";
|
|
1106
|
+
var DEFAULT_LISTEN_PORT = 4666;
|
|
1107
|
+
function parseListenAddr(addr) {
|
|
1108
|
+
const s = (addr ?? "").trim();
|
|
1109
|
+
const bracket = s.match(/^\[([^\]]+)\](?::(\d+))?$/);
|
|
1110
|
+
if (bracket) {
|
|
1111
|
+
return { host: bracket[1], port: bracket[2] ? Number(bracket[2]) : DEFAULT_LISTEN_PORT };
|
|
1112
|
+
}
|
|
1113
|
+
if ((s.match(/:/g)?.length ?? 0) >= 2) {
|
|
1114
|
+
return { host: s, port: DEFAULT_LISTEN_PORT };
|
|
1115
|
+
}
|
|
1116
|
+
const i = s.lastIndexOf(":");
|
|
1117
|
+
if (i > 0) {
|
|
1118
|
+
const port = Number(s.slice(i + 1));
|
|
1119
|
+
return {
|
|
1120
|
+
host: s.slice(0, i),
|
|
1121
|
+
port: Number.isInteger(port) && port > 0 && port <= 65535 ? port : DEFAULT_LISTEN_PORT
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
if (/^\d+$/.test(s)) {
|
|
1125
|
+
const port = Number(s);
|
|
1126
|
+
return { host: DEFAULT_LISTEN_HOST, port: port > 0 && port <= 65535 ? port : DEFAULT_LISTEN_PORT };
|
|
1127
|
+
}
|
|
1128
|
+
return { host: s || DEFAULT_LISTEN_HOST, port: DEFAULT_LISTEN_PORT };
|
|
1129
|
+
}
|
|
942
1130
|
function webhooksCommand() {
|
|
943
|
-
const wh = new
|
|
1131
|
+
const wh = new Command11("webhooks").description("developer tools for Krova Cloud webhooks");
|
|
944
1132
|
wh.command("listen").description("run a local server that verifies + prints incoming webhook deliveries").option("--addr <host:port>", "address to listen on", "127.0.0.1:4666").option("--path <path>", "path to accept POSTs on", "/").option("--secret <secret>", "signing secret (or the KROVA_WEBHOOK_SECRET env var)").action((opts, cmd) => {
|
|
945
1133
|
const rt = getRuntime(cmd);
|
|
946
1134
|
const secret = opts.secret || process.env.KROVA_WEBHOOK_SECRET || "";
|
|
@@ -949,10 +1137,7 @@ function webhooksCommand() {
|
|
|
949
1137
|
"a signing secret is required: pass --secret or set KROVA_WEBHOOK_SECRET"
|
|
950
1138
|
);
|
|
951
1139
|
}
|
|
952
|
-
const
|
|
953
|
-
const lastColon = addr.lastIndexOf(":");
|
|
954
|
-
const host = lastColon > 0 ? addr.slice(0, lastColon) : "127.0.0.1";
|
|
955
|
-
const port = Number(lastColon > 0 ? addr.slice(lastColon + 1) : addr) || 4666;
|
|
1140
|
+
const { host, port } = parseListenAddr(String(opts.addr));
|
|
956
1141
|
const wantPath = String(opts.path);
|
|
957
1142
|
const server = createServer((req, res) => {
|
|
958
1143
|
const reqPath = (req.url ?? "/").split("?")[0];
|
|
@@ -1004,9 +1189,9 @@ function webhooksCommand() {
|
|
|
1004
1189
|
}
|
|
1005
1190
|
|
|
1006
1191
|
// src/commands/whoami.ts
|
|
1007
|
-
import { Command as
|
|
1192
|
+
import { Command as Command12 } from "commander";
|
|
1008
1193
|
function whoamiCommand() {
|
|
1009
|
-
return new
|
|
1194
|
+
return new Command12("whoami").description("show the current context, space, and base URL").action(async (_opts, cmd) => {
|
|
1010
1195
|
const rt = getRuntime(cmd);
|
|
1011
1196
|
const ctx = find(rt.cfg, rt.res.contextName);
|
|
1012
1197
|
let spaceId = rt.res.spaceId;
|
|
@@ -1055,7 +1240,7 @@ function addGlobalOptions(cmd) {
|
|
|
1055
1240
|
add("--json", "output machine-readable JSON instead of a table");
|
|
1056
1241
|
add("--timeout <duration>", "per-request timeout", "30s");
|
|
1057
1242
|
}
|
|
1058
|
-
var program = new
|
|
1243
|
+
var program = new Command13();
|
|
1059
1244
|
program.name("krova").description(
|
|
1060
1245
|
"krova is the command-line interface for Krova Cloud \u2014 manage Cubes (Firecracker microVMs), browse the catalog, and receive webhooks."
|
|
1061
1246
|
).version(CLI_VERSION, "-v, --version", "print the krova CLI version").showHelpAfterError();
|
|
@@ -1064,6 +1249,9 @@ program.addCommand(authCommand());
|
|
|
1064
1249
|
program.addCommand(contextCommand());
|
|
1065
1250
|
program.addCommand(whoamiCommand());
|
|
1066
1251
|
program.addCommand(cubesCommand());
|
|
1252
|
+
program.addCommand(domainsCommand());
|
|
1253
|
+
program.addCommand(snapshotsCommand());
|
|
1254
|
+
program.addCommand(tcpCommand());
|
|
1067
1255
|
program.addCommand(sshCommand());
|
|
1068
1256
|
program.addCommand(rootListCommand());
|
|
1069
1257
|
program.addCommand(rootGetCommand());
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/auth.ts","../src/lib/config.ts","../src/lib/output.ts","../src/lib/client.ts","../src/lib/runtime.ts","../src/lib/persist.ts","../src/commands/catalog.ts","../src/commands/context.ts","../src/commands/cubes.ts","../src/lib/resolve.ts","../src/commands/login.ts","../src/commands/ssh.ts","../src/lib/ssh.ts","../src/commands/version.ts","../src/commands/webhooks.ts","../src/commands/whoami.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { authCommand } from \"./commands/auth.js\";\nimport { imagesCommand, pricingCommand, regionsCommand } from \"./commands/catalog.js\";\nimport { contextCommand } from \"./commands/context.js\";\nimport { cubesCommand, rootGetCommand, rootListCommand } from \"./commands/cubes.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { sshCommand } from \"./commands/ssh.js\";\nimport { CLI_VERSION, versionCommand } from \"./commands/version.js\";\nimport { webhooksCommand } from \"./commands/webhooks.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\n\n/** cobra-style persistent flags: usable on any command, before or after it.\n * Skips a flag a command already defines locally (e.g. login's own --context). */\nfunction addGlobalOptions(cmd: Command): void {\n const have = new Set(cmd.options.map((o) => o.long));\n const add = (flags: string, desc: string, def?: string) => {\n const long = flags.split(/[ ,<[]/).find((f) => f.startsWith(\"--\"));\n if (long && !have.has(long)) cmd.option(flags, desc, def);\n };\n add(\"--api-key <key>\", \"Krova Cloud API key (overrides env and context)\");\n add(\"--space <id>\", \"Space ID (overrides KROVA_SPACE_ID and context)\");\n add(\"--base-url <url>\", \"override the API base URL\");\n add(\"--context <name>\", \"use a named context (overrides KROVA_CONTEXT)\");\n add(\"--json\", \"output machine-readable JSON instead of a table\");\n add(\"--timeout <duration>\", \"per-request timeout\", \"30s\");\n}\n\nconst program = new Command();\nprogram\n .name(\"krova\")\n .description(\n \"krova is the command-line interface for Krova Cloud — manage Cubes (Firecracker microVMs), browse the catalog, and receive webhooks.\"\n )\n .version(CLI_VERSION, \"-v, --version\", \"print the krova CLI version\")\n .showHelpAfterError();\n\nprogram.addCommand(loginCommand());\nprogram.addCommand(authCommand());\nprogram.addCommand(contextCommand());\nprogram.addCommand(whoamiCommand());\nprogram.addCommand(cubesCommand());\nprogram.addCommand(sshCommand());\nprogram.addCommand(rootListCommand()); // `krova list` (alias `ls`)\nprogram.addCommand(rootGetCommand()); // `krova get`\nprogram.addCommand(regionsCommand());\nprogram.addCommand(imagesCommand());\nprogram.addCommand(pricingCommand());\nprogram.addCommand(webhooksCommand());\nprogram.addCommand(versionCommand());\n\n// Apply the global flags to the root and every (sub)command.\nconst applyAll = (cmd: Command): void => {\n addGlobalOptions(cmd);\n for (const c of cmd.commands) applyAll(c);\n};\napplyAll(program);\n\nasync function main(): Promise<void> {\n try {\n await program.parseAsync(process.argv);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`Error: ${msg}\\n`);\n process.exitCode = 1;\n }\n}\n\nvoid main();\n","import { Command } from \"commander\";\n\nimport { configPath, maskKey } from \"../lib/config.js\";\nimport { printJSON, printKeyValue } from \"../lib/output.js\";\nimport { persistLogin } from \"../lib/persist.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\n/** Prompt for an API key. Hidden echo when stdin is a TTY. */\nfunction promptAPIKey(): Promise<string> {\n return new Promise((resolve, reject) => {\n process.stdout.write(\"Krova API key: \");\n const stdin = process.stdin;\n const tty = Boolean(stdin.isTTY);\n let buf = \"\";\n if (tty) stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding(\"utf8\");\n const finish = (fn: () => void) => {\n if (tty) stdin.setRawMode(false);\n stdin.pause();\n stdin.removeListener(\"data\", onData);\n fn();\n };\n const onData = (ch: string) => {\n for (const c of ch) {\n const code = c.charCodeAt(0);\n if (code === 10 || code === 13) {\n finish(() => {\n process.stdout.write(\"\\n\");\n resolve(buf.trim());\n });\n return;\n }\n if (code === 3) {\n finish(() => reject(new Error(\"cancelled\")));\n return;\n }\n if (code === 127 || code === 8) {\n buf = buf.slice(0, -1);\n } else if (code >= 32) {\n buf += c;\n }\n }\n };\n stdin.on(\"data\", onData);\n });\n}\n\nexport function authCommand(): Command {\n const auth = new Command(\"auth\").description(\"manage Krova Cloud credentials\");\n\n auth\n .command(\"login\")\n .description(\"log in by pasting an API key\")\n .option(\"--api-key <key>\", \"API key (else you'll be prompted)\")\n .option(\"--space <id>\", \"Space ID to store with the key\")\n .option(\"--context <name>\", \"name for the saved context\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n let key = (opts.apiKey as string) || rt.flags.apiKey || \"\";\n if (!key.trim()) key = await promptAPIKey();\n if (!key.trim()) throw new Error(\"no API key provided\");\n const { ctxName, spaceName } = await persistLogin({\n apiKey: key.trim(),\n baseUrl: rt.res.baseUrl,\n spaceId: opts.space as string | undefined,\n ctxName: opts.context as string | undefined,\n timeoutMs: rt.timeoutMs,\n });\n process.stdout.write(`Logged in. Saved context \"${ctxName}\" to ${configPath()}\\n`);\n if (spaceName) process.stdout.write(`Space: ${spaceName}\\n`);\n });\n\n auth\n .command(\"status\")\n .description(\"show the resolved credentials\")\n .action((_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const authenticated = Boolean(rt.res.apiKey);\n if (rt.json) {\n return printJSON({\n authenticated,\n context: rt.res.contextName,\n apiKeySource: rt.res.apiKeySource,\n apiKeyMasked: maskKey(rt.res.apiKey),\n spaceId: rt.res.spaceId,\n spaceSource: rt.res.spaceIdSource,\n baseUrl: rt.res.baseUrl,\n configPath: configPath(),\n });\n }\n printKeyValue([\n [\"Authenticated\", authenticated ? \"yes\" : \"no\"],\n [\"Context\", rt.res.contextName || \"—\"],\n [\"API key\", rt.res.apiKey ? `${maskKey(rt.res.apiKey)} (${rt.res.apiKeySource})` : \"—\"],\n [\"Space ID\", rt.res.spaceId ? `${rt.res.spaceId} (${rt.res.spaceIdSource})` : \"—\"],\n [\"Base URL\", rt.res.baseUrl],\n [\"Config\", configPath()],\n ]);\n });\n\n return auth;\n}\n","// Reads/writes ~/.config/krova/config.json in the EXACT shape the Go CLI used,\n// so existing configs keep working. Multi-context, with legacy single-key\n// migration. The file is always tightened to 0600 on save.\n\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\nexport const DEFAULT_CONTEXT_NAME = \"default\";\n\nexport const ENV = {\n apiKey: \"KROVA_API_KEY\",\n spaceId: \"KROVA_SPACE_ID\",\n baseUrl: \"KROVA_BASE_URL\",\n context: \"KROVA_CONTEXT\",\n} as const;\n\nexport interface Context {\n name: string;\n apiKey?: string;\n spaceId?: string;\n spaceName?: string;\n baseUrl?: string;\n}\n\nexport interface Config {\n currentContext?: string;\n contexts?: Context[];\n // legacy (pre-context) fields — parsed then migrated into a \"default\" context\n apiKey?: string;\n spaceId?: string;\n baseUrl?: string;\n}\n\nexport function configDir(): string {\n const xdg = (process.env.XDG_CONFIG_HOME ?? \"\").trim();\n if (xdg) return join(xdg, \"krova\");\n return join(homedir(), \".config\", \"krova\");\n}\n\nexport function configPath(): string {\n return join(configDir(), \"config.json\");\n}\n\nexport function load(): Config {\n let cfg: Config = {};\n try {\n cfg = JSON.parse(readFileSync(configPath(), \"utf8\")) as Config;\n } catch {\n cfg = {};\n }\n return migrate(cfg);\n}\n\n// If only legacy fields are set, synthesize a \"default\" context from them.\nfunction migrate(cfg: Config): Config {\n if ((cfg.apiKey ?? \"\").trim() && (!cfg.contexts || cfg.contexts.length === 0)) {\n cfg.contexts = [\n {\n name: DEFAULT_CONTEXT_NAME,\n apiKey: cfg.apiKey,\n spaceId: cfg.spaceId,\n baseUrl: cfg.baseUrl,\n },\n ];\n cfg.currentContext = DEFAULT_CONTEXT_NAME;\n }\n cfg.apiKey = undefined;\n cfg.spaceId = undefined;\n cfg.baseUrl = undefined;\n return cfg;\n}\n\nexport function save(cfg: Config): void {\n const path = configPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n // clear legacy fields; only serialize non-empty keys (matches Go omitempty)\n const clean: Config = {};\n if (cfg.currentContext) clean.currentContext = cfg.currentContext;\n if (cfg.contexts && cfg.contexts.length) {\n clean.contexts = cfg.contexts.map((c) => {\n const o: Context = { name: c.name };\n if (c.apiKey) o.apiKey = c.apiKey;\n if (c.spaceId) o.spaceId = c.spaceId;\n if (c.spaceName) o.spaceName = c.spaceName;\n if (c.baseUrl) o.baseUrl = c.baseUrl;\n return o;\n });\n }\n writeFileSync(path, `${JSON.stringify(clean, null, 2)}\\n`, { mode: 0o600 });\n // writeFileSync only applies mode on creation — re-tighten an existing file.\n chmodSync(path, 0o600);\n}\n\nexport function find(cfg: Config, name: string): Context | undefined {\n return (cfg.contexts ?? []).find((c) => c.name === name);\n}\n\n/** The active context: `override` (e.g. --context) wins, else currentContext. */\nexport function current(cfg: Config, override?: string): Context | undefined {\n const name = (override ?? \"\").trim() || (cfg.currentContext ?? \"\").trim();\n if (!name) return undefined;\n return find(cfg, name);\n}\n\n/** Merge-in a context: only NON-EMPTY apiKey/spaceId/spaceName/baseUrl\n * overwrite an existing value. This keeps a transient per-command override\n * (e.g. a one-off `--base-url`) from being silently persisted over the\n * context's real base URL. First-ever context becomes current. Returns it. */\nexport function upsert(cfg: Config, incoming: Context): Context {\n cfg.contexts ??= [];\n let ctx = cfg.contexts.find((c) => c.name === incoming.name);\n if (!ctx) {\n ctx = { name: incoming.name };\n cfg.contexts.push(ctx);\n if (!cfg.currentContext) cfg.currentContext = ctx.name;\n }\n if ((incoming.apiKey ?? \"\").trim()) ctx.apiKey = incoming.apiKey;\n if ((incoming.spaceId ?? \"\").trim()) ctx.spaceId = incoming.spaceId;\n if ((incoming.spaceName ?? \"\").trim()) ctx.spaceName = incoming.spaceName;\n if ((incoming.baseUrl ?? \"\").trim()) ctx.baseUrl = incoming.baseUrl;\n return ctx;\n}\n\nexport function remove(cfg: Config, name: string): boolean {\n const before = (cfg.contexts ?? []).length;\n cfg.contexts = (cfg.contexts ?? []).filter((c) => c.name !== name);\n if (cfg.contexts.length === before) return false;\n if (cfg.currentContext === name) {\n cfg.currentContext = cfg.contexts[0]?.name ?? \"\";\n }\n return true;\n}\n\nexport type Source = \"flag\" | \"env\" | \"context\" | \"\";\n\nexport interface Resolved {\n apiKey: string;\n spaceId: string;\n baseUrl: string;\n apiKeySource: Source;\n spaceIdSource: Source;\n contextName: string;\n}\n\nexport interface GlobalFlags {\n apiKey?: string;\n space?: string;\n baseUrl?: string;\n context?: string;\n}\n\n/** Resolve credentials with precedence flag > env > active context. */\nexport function resolve(cfg: Config, flags: GlobalFlags): Resolved {\n const ctx = current(cfg, (flags.context ?? \"\").trim() || process.env[ENV.context]);\n const pick = (\n flag: string | undefined,\n env: string | undefined,\n ctxVal: string | undefined\n ): [string, Source] => {\n if ((flag ?? \"\").trim()) return [flag as string, \"flag\"];\n if ((env ?? \"\").trim()) return [env as string, \"env\"];\n if ((ctxVal ?? \"\").trim()) return [ctxVal as string, \"context\"];\n return [\"\", \"\"];\n };\n const [apiKey, apiKeySource] = pick(flags.apiKey, process.env[ENV.apiKey], ctx?.apiKey);\n const [spaceId, spaceIdSource] = pick(flags.space, process.env[ENV.spaceId], ctx?.spaceId);\n const [baseUrlRaw] = pick(flags.baseUrl, process.env[ENV.baseUrl], ctx?.baseUrl);\n return {\n apiKey,\n spaceId,\n baseUrl: baseUrlRaw || DEFAULT_BASE_URL,\n apiKeySource,\n spaceIdSource,\n contextName: ctx?.name ?? \"\",\n };\n}\n\nexport function sanitizeContextName(name: string): string {\n return name.trim().toLowerCase().replace(/\\s+/g, \"-\");\n}\n\nexport function maskKey(key: string): string {\n if (!key) return \"\";\n if (key.length <= 8) return \"****\";\n return `${key.slice(0, 6)}…${key.slice(-4)}`;\n}\n","export function printJSON(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nexport function printTable(header: string[], rows: string[][]): void {\n const widths = header.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => (r[i] ?? \"\").length))\n );\n const fmt = (cols: string[]) =>\n cols\n .map((c, i) => (c ?? \"\").padEnd(widths[i] ?? 0))\n .join(\" \")\n .replace(/\\s+$/, \"\");\n process.stdout.write(`${fmt(header)}\\n`);\n for (const r of rows) process.stdout.write(`${fmt(r)}\\n`);\n}\n\nexport function printKeyValue(pairs: Array<[string, string]>): void {\n const w = Math.max(0, ...pairs.map(([k]) => k.length));\n for (const [k, v] of pairs) {\n process.stdout.write(`${k.padEnd(w)} ${v}\\n`);\n }\n}\n","import { KrovaClient } from \"@krovacloud/sdk\";\n\nimport type { Resolved } from \"./config.js\";\n\n/** Build the SDK client, or throw the same message the Go CLI used. */\nexport function makeClient(res: Resolved): KrovaClient {\n if (!res.apiKey) {\n throw new Error(\n \"no API key found: run `krova auth login`, set KROVA_API_KEY, or pass --api-key\"\n );\n }\n return new KrovaClient({ apiKey: res.apiKey, baseUrl: res.baseUrl });\n}\n\n/** Raw JSON request for endpoints the SDK doesn't cover:\n * GET /space, GET .../ssh, POST /auth/cli/start, POST /auth/cli/poll. */\nexport async function rawRequest<T>(opts: {\n method: string;\n baseUrl: string;\n path: string;\n apiKey?: string;\n body?: unknown;\n timeoutMs: number;\n}): Promise<{ status: number; data: T | undefined }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), opts.timeoutMs);\n try {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (opts.apiKey) headers[\"X-API-KEY\"] = opts.apiKey;\n if (opts.body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n const res = await fetch(`${opts.baseUrl.replace(/\\/+$/, \"\")}${opts.path}`, {\n method: opts.method,\n headers,\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n redirect: \"manual\",\n signal: controller.signal,\n });\n let data: T | undefined;\n const text = await res.text();\n if (text) {\n try {\n data = JSON.parse(text) as T;\n } catch {\n data = undefined;\n }\n }\n return { status: res.status, data };\n } finally {\n clearTimeout(timer);\n }\n}\n","import type { Command } from \"commander\";\n\nimport {\n type Config,\n type GlobalFlags,\n type Resolved,\n load,\n resolve,\n save,\n upsert,\n} from \"./config.js\";\nimport { makeClient, rawRequest } from \"./client.js\";\n\n/** Parse a Go-style duration (\"30s\", \"500ms\", \"2m\", \"1h\") to ms. Non-positive\n * or unparseable floors to 30s (matches the Go requestTimeout behavior). */\nexport function parseDuration(input: string | undefined): number {\n const s = (input ?? \"\").trim();\n if (!s) return 30_000;\n let total = 0;\n const re = /(\\d+(?:\\.\\d+)?)(ms|s|m|h)/g;\n let m: RegExpExecArray | null = re.exec(s);\n let matched = false;\n while (m) {\n matched = true;\n const n = Number(m[1]);\n const unit = m[2];\n total += unit === \"ms\" ? n : unit === \"s\" ? n * 1000 : unit === \"m\" ? n * 60_000 : n * 3_600_000;\n m = re.exec(s);\n }\n if (!matched) {\n const n = Number(s);\n if (Number.isFinite(n)) total = n * 1000; // bare number = seconds\n }\n return total > 0 ? total : 30_000;\n}\n\nexport interface Runtime {\n flags: GlobalFlags;\n cfg: Config;\n res: Resolved;\n json: boolean;\n timeoutMs: number;\n}\n\nexport function getRuntime(cmd: Command): Runtime {\n const opts = cmd.optsWithGlobals() as Record<string, unknown>;\n const flags: GlobalFlags = {\n apiKey: opts.apiKey as string | undefined,\n space: opts.space as string | undefined,\n baseUrl: opts.baseUrl as string | undefined,\n context: opts.context as string | undefined,\n };\n const cfg = load();\n const res = resolve(cfg, flags);\n return {\n flags,\n cfg,\n res,\n json: Boolean(opts.json),\n timeoutMs: parseDuration(opts.timeout as string | undefined),\n };\n}\n\nexport interface SpaceInfo {\n id: string;\n name?: string;\n slug?: string;\n}\n\n/** GET /space with the given key; null on 404 / error (non-fatal). */\nexport async function fetchSpace(\n baseUrl: string,\n apiKey: string,\n timeoutMs: number\n): Promise<SpaceInfo | null> {\n try {\n const { status, data } = await rawRequest<SpaceInfo>({\n method: \"GET\",\n baseUrl,\n path: \"/space\",\n apiKey,\n timeoutMs,\n });\n if (status === 200 && data?.id) return data;\n return null;\n } catch {\n return null;\n }\n}\n\n/** Resolve the active space id: explicit value wins, else auto-detect via\n * GET /space (and cache it into the current context). */\nexport async function resolveSpace(rt: Runtime): Promise<string> {\n if (rt.res.spaceId) return rt.res.spaceId;\n const { status, data } = await rawRequest<SpaceInfo>({\n method: \"GET\",\n baseUrl: rt.res.baseUrl,\n path: \"/space\",\n apiKey: rt.res.apiKey,\n timeoutMs: rt.timeoutMs,\n });\n if (status === 200 && data?.id) {\n // Best-effort cache of the resolved space into the current named context.\n // Deliberately does NOT write baseUrl: rt.res.baseUrl already folds in a\n // one-off --base-url / KROVA_BASE_URL override, and persisting that here\n // would permanently rewrite the context's real base URL from a transient\n // flag. Only the space id/name are cached.\n if (rt.res.contextName) {\n upsert(rt.cfg, {\n name: rt.res.contextName,\n spaceId: data.id,\n spaceName: data.name,\n });\n try {\n save(rt.cfg);\n } catch {\n /* non-fatal */\n }\n }\n return data.id;\n }\n if (status === 404) {\n throw new Error(\n \"couldn't auto-detect your space (the server doesn't support it yet) — pass --space, set KROVA_SPACE_ID, or run `krova login`\"\n );\n }\n if (status === 401 || status === 403) {\n throw new Error(`auto-detect space failed: the API key was rejected (HTTP ${status})`);\n }\n throw new Error(`auto-detect space failed (HTTP ${status})`);\n}\n\nexport { makeClient };\n","import { DEFAULT_CONTEXT_NAME, load, sanitizeContextName, save, upsert } from \"./config.js\";\nimport { fetchSpace } from \"./runtime.js\";\n\n/** Save + switch to a context after a login. Best-effort space lookup fills in\n * spaceId/spaceName and a nicer context name. Mirrors the Go persistLogin. */\nexport async function persistLogin(input: {\n apiKey: string;\n baseUrl: string;\n spaceId?: string;\n ctxName?: string;\n timeoutMs: number;\n}): Promise<{ ctxName: string; spaceName: string }> {\n const cfg = load();\n let spaceId = input.spaceId ?? \"\";\n let spaceName = \"\";\n let derivedName = \"\";\n\n const sp = await fetchSpace(input.baseUrl, input.apiKey, input.timeoutMs);\n if (sp) {\n // Prefer an explicitly-provided --space over the fetched id; only fall back\n // to the resolved space when the caller didn't pin one.\n if (!spaceId) spaceId = sp.id;\n spaceName = sp.name ?? \"\";\n derivedName = (sp.slug || sp.name || \"\").trim();\n }\n\n let name = (input.ctxName ?? \"\").trim();\n if (!name) name = derivedName || DEFAULT_CONTEXT_NAME;\n name = sanitizeContextName(name);\n\n const cur = upsert(cfg, {\n name,\n apiKey: input.apiKey,\n spaceId,\n spaceName,\n baseUrl: input.baseUrl,\n });\n cfg.currentContext = cur.name; // login always switches current\n save(cfg);\n return { ctxName: cur.name, spaceName: cur.spaceName ?? \"\" };\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { getRuntime, makeClient } from \"../lib/runtime.js\";\n\nfunction fmtVal(v: unknown): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"object\") return JSON.stringify(v);\n return String(v);\n}\n\n/** Flatten a top-level object field one level deep into `key.subkey` rows, so\n * nested objects (e.g. pricing's `rates`) render as readable key/value pairs\n * instead of a JSON blob. Exported for testing. */\nexport function flattenRows(entries: [string, unknown][]): [string, string][] {\n const rows: [string, string][] = [];\n for (const [k, v] of entries) {\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [sk, sv] of Object.entries(v as Record<string, unknown>)) {\n rows.push([`${k}.${sk}`, fmtVal(sv)]);\n }\n } else {\n rows.push([k, fmtVal(v)]);\n }\n }\n return rows;\n}\n\n/**\n * Render a catalog payload as text. If the payload has an array field, print any\n * scalar/object fields first (as key/value) and then the array as a table —\n * otherwise the non-array fields are silently dropped. This matters for\n * `pricing`, whose per-resource `rates` (the actual hourly prices), `currency`,\n * and `note` sit alongside the `tiers` array. `regions`/`images` have only the\n * array, so their output is unchanged.\n */\nfunction renderCatalog(obj: Record<string, unknown>): void {\n const arrKey = Object.keys(obj).find((k) => Array.isArray(obj[k]));\n if (!arrKey) {\n printKeyValue(flattenRows(Object.entries(obj)));\n return;\n }\n const rest = flattenRows(Object.entries(obj).filter(([k]) => k !== arrKey));\n if (rest.length) printKeyValue(rest);\n const arr = (obj[arrKey] as Record<string, unknown>[]) ?? [];\n const cols = [...new Set(arr.flatMap((o) => Object.keys(o)))];\n printTable(\n cols.map((c) => c.toUpperCase()),\n arr.map((o) => cols.map((c) => fmtVal(o[c])))\n );\n}\n\nfunction catalogCmd(\n name: string,\n desc: string,\n fetch: (c: ReturnType<typeof makeClient>) => Promise<Record<string, unknown>>\n): Command {\n return new Command(name)\n .description(desc)\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const data = await fetch(client);\n if (rt.json) return printJSON(data);\n renderCatalog(data);\n });\n}\n\nexport function regionsCommand(): Command {\n return catalogCmd(\"regions\", \"list regions with available capacity\", (c) =>\n c.catalog.regions() as Promise<Record<string, unknown>>\n );\n}\nexport function imagesCommand(): Command {\n return catalogCmd(\"images\", \"list available OS images\", (c) =>\n c.catalog.images() as Promise<Record<string, unknown>>\n );\n}\nexport function pricingCommand(): Command {\n return catalogCmd(\"pricing\", \"show per-resource hourly pricing\", (c) =>\n c.catalog.pricing() as Promise<Record<string, unknown>>\n );\n}\n","import { Command } from \"commander\";\n\nimport { load, maskKey, remove, save } from \"../lib/config.js\";\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nexport function contextCommand(): Command {\n const ctx = new Command(\"context\")\n .aliases([\"ctx\", \"contexts\"])\n .description(\"manage named credential contexts (like kubectl/aws profiles)\");\n\n ctx\n .command(\"list\")\n .aliases([\"ls\"])\n .description(\"list all contexts\")\n .action((_opts, cmd: Command) => {\n const { json } = getRuntime(cmd);\n const cfg = load();\n if (json) {\n return printJSON({\n currentContext: cfg.currentContext ?? \"\",\n contexts: (cfg.contexts ?? []).map((c) => ({\n name: c.name,\n apiKey: maskKey(c.apiKey ?? \"\"),\n spaceId: c.spaceId ?? \"\",\n spaceName: c.spaceName ?? \"\",\n baseUrl: c.baseUrl ?? \"\",\n })),\n });\n }\n printTable(\n [\"CURRENT\", \"NAME\", \"SPACE\", \"SPACE ID\", \"BASE URL\"],\n (cfg.contexts ?? []).map((c) => [\n c.name === cfg.currentContext ? \"*\" : \"\",\n c.name,\n c.spaceName ?? \"\",\n c.spaceId ?? \"\",\n c.baseUrl ?? \"\",\n ])\n );\n });\n\n ctx\n .command(\"current\")\n .description(\"print the current context name\")\n .action(() => {\n const cfg = load();\n if (!cfg.currentContext) throw new Error(\"no current context set\");\n process.stdout.write(`${cfg.currentContext}\\n`);\n });\n\n ctx\n .command(\"use\")\n .argument(\"<name>\", \"context name\")\n .description(\"switch the current context\")\n .action((name: string) => {\n const cfg = load();\n if (!(cfg.contexts ?? []).some((c) => c.name === name)) {\n throw new Error(`no context named \"${name}\"`);\n }\n cfg.currentContext = name;\n save(cfg);\n process.stdout.write(`Switched to context ${name}\\n`);\n });\n\n ctx\n .command(\"rename\")\n .argument(\"<old>\", \"current name\")\n .argument(\"<new>\", \"new name\")\n .description(\"rename a context\")\n .action((oldName: string, newName: string) => {\n const cfg = load();\n if (!newName.trim()) throw new Error(\"new name must not be empty\");\n const c = (cfg.contexts ?? []).find((x) => x.name === oldName);\n if (!c) throw new Error(`no context named \"${oldName}\"`);\n if ((cfg.contexts ?? []).some((x) => x.name === newName)) {\n throw new Error(`a context named \"${newName}\" already exists`);\n }\n c.name = newName;\n if (cfg.currentContext === oldName) cfg.currentContext = newName;\n save(cfg);\n process.stdout.write(`Renamed ${oldName} → ${newName}\\n`);\n });\n\n ctx\n .command(\"delete\")\n .aliases([\"rm\"])\n .argument(\"<name>\", \"context name\")\n .description(\"delete a context\")\n .action((name: string) => {\n const cfg = load();\n if (!remove(cfg, name)) throw new Error(`no context named \"${name}\"`);\n save(cfg);\n process.stdout.write(`Deleted context ${name}\\n`);\n });\n\n return ctx;\n}\n\nexport function whoamiKeyValue(pairs: Array<[string, string]>): void {\n printKeyValue(pairs);\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\n\nfunction listCmd(): Command {\n return new Command(\"list\")\n .aliases([\"ls\"])\n .description(\"list Cubes in the space\")\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const { cubes } = await client.cubes.list(space);\n if (rt.json) return printJSON(cubes);\n printTable(\n [\"ID\", \"NAME\", \"STATE\", \"VCPU\", \"RAM(GB)\", \"DISK(GB)\", \"IMAGE\", \"IPV4\"],\n cubes.map((c) => [\n c.id,\n c.name,\n c.state,\n String(c.resources.vcpu),\n String(c.resources.ramGb),\n String(c.resources.diskGb),\n c.image,\n c.publicIpv4 ?? \"—\",\n ])\n );\n });\n}\n\nfunction getCmd(): Command {\n return new Command(\"get\")\n .argument(\"<cube>\", \"cube name or ID\")\n .description(\"show a single Cube\")\n .action(async (cubeRef: string, _opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const cube = await client.cubes.get(space, id);\n if (rt.json) return printJSON(cube);\n printKeyValue([\n [\"ID\", cube.id],\n [\"Name\", cube.name],\n [\"State\", cube.state],\n [\"Image\", cube.image],\n [\"vCPU\", String(cube.resources.vcpu)],\n [\"RAM (GB)\", String(cube.resources.ramGb)],\n [\"Disk (GB)\", String(cube.resources.diskGb)],\n [\"Public IPv4\", cube.publicIpv4 ?? \"—\"],\n [\"Cost/hour\", `$${cube.costPerHour}`],\n ]);\n });\n}\n\nfunction createCmd(): Command {\n return new Command(\"create\")\n .description(\"provision a new Cube\")\n .requiredOption(\"--name <name>\", \"cube name\")\n .requiredOption(\"--image <slug>\", \"OS image slug (see `krova images`)\")\n .requiredOption(\"--ssh-key <key>\", \"SSH public key written to authorized_keys\")\n .option(\"--vcpu <n>\", \"number of vCPUs\", \"1\")\n .option(\"--ram <gb>\", \"RAM in GB\", \"1\")\n .option(\"--disk <gb>\", \"disk size in GB\", \"10\")\n .option(\"--region <slug>\", \"region slug (see `krova regions`)\")\n .option(\"--user-data <script>\", \"cloud-init script\")\n .option(\"--idempotency-key <key>\", \"idempotency key (24h dedupe)\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n // Validate resources client-side so bad input fails with a clear message\n // rather than being coerced to NaN → JSON null → a generic server 400.\n const posInt = (flag: string, raw: string): number => {\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`--${flag} must be a positive integer (got \"${raw}\").`);\n }\n return n;\n };\n const body: Record<string, unknown> = {\n name: opts.name,\n image: opts.image,\n sshPublicKey: opts.sshKey,\n resources: {\n vcpu: posInt(\"vcpu\", opts.vcpu),\n ramGb: posInt(\"ram\", opts.ram),\n diskGb: posInt(\"disk\", opts.disk),\n },\n };\n if (opts.region) body.region = opts.region;\n if (opts.userData) body.userData = opts.userData;\n const cube = await client.cubes.create(\n space,\n body as never,\n opts.idempotencyKey ? { idempotencyKey: opts.idempotencyKey } : undefined\n );\n if (rt.json) return printJSON(cube);\n process.stdout.write(`Created cube ${cube.id} (${cube.state})\\n`);\n });\n}\n\nfunction actionCmd(\n name: string,\n past: string,\n fn: (c: ReturnType<typeof makeClient>[\"cubes\"], space: string, id: string) => Promise<unknown>\n): Command {\n return new Command(name)\n .argument(\"<cube>\", \"cube name or ID\")\n .description(`${name} a Cube`)\n .action(async (cubeRef: string, _opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await fn(client.cubes, space, id);\n if (rt.json) return printJSON({ id, result: past });\n process.stdout.write(`${past} cube ${id}\\n`);\n });\n}\n\nfunction sshPortCmd(): Command {\n return new Command(\"ssh-port\")\n .argument(\"<cube>\", \"cube name or ID\")\n .requiredOption(\"--port <n>\", \"the host port to expose SSH on\")\n .description(\"change the host port a Cube's SSH is reachable on\")\n .action(async (cubeRef: string, opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const cubePort = Number(opts.port);\n if (!Number.isInteger(cubePort) || cubePort < 1 || cubePort > 65535) {\n throw new Error(\"--port must be an integer between 1 and 65535\");\n }\n await client.cubes.update(space, id, { cubePort } as never);\n if (rt.json) return printJSON({ id, cubePort });\n process.stdout.write(`SSH port for cube ${id} set to ${cubePort}\\n`);\n });\n}\n\nexport function cubesCommand(): Command {\n const cubes = new Command(\"cubes\").description(\"manage Cubes (Firecracker microVMs)\");\n cubes.addCommand(listCmd());\n cubes.addCommand(getCmd());\n cubes.addCommand(createCmd());\n cubes.addCommand(actionCmd(\"sleep\", \"Sleeping\", (c, s, id) => c.sleep(s, id)));\n cubes.addCommand(actionCmd(\"wake\", \"Waking\", (c, s, id) => c.wake(s, id)));\n cubes.addCommand(actionCmd(\"delete\", \"Deleting\", (c, s, id) => c.delete(s, id)));\n cubes.addCommand(sshPortCmd());\n return cubes;\n}\n\n// `list` and `get` are also mounted at the root (parity with the Go CLI).\nexport const rootListCommand = listCmd;\nexport const rootGetCommand = getCmd;\n","import type { KrovaClient } from \"@krovacloud/sdk\";\n\n/** Resolve a cube name-or-id to an id (parity with the Go resolveCube):\n * exact id wins; else exactly one exact name match; else a clear error. */\nexport async function resolveCube(\n client: KrovaClient,\n spaceId: string,\n ref: string\n): Promise<string> {\n const { cubes } = await client.cubes.list(spaceId);\n if (cubes.some((c) => c.id === ref)) return ref;\n const byName = cubes.filter((c) => c.name === ref);\n if (byName.length === 1) return byName[0]!.id;\n if (byName.length === 0) {\n throw new Error(\n `no cube named or with ID \"${ref}\" in this space (see \\`krova cubes list\\`)`\n );\n }\n const ids = byName.map((c) => c.id).join(\", \");\n throw new Error(\n `cube name \"${ref}\" is ambiguous: it matches ${byName.length} cubes (${ids}) — use the cube ID instead`\n );\n}\n","import { spawn } from \"node:child_process\";\n\nimport { Command } from \"commander\";\n\nimport { rawRequest } from \"../lib/client.js\";\nimport { configPath } from \"../lib/config.js\";\nimport { persistLogin } from \"../lib/persist.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\ninterface StartResponse {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n interval: number;\n expiresIn: number;\n}\ninterface PollResponse {\n apiKey: string;\n spaceId: string;\n}\n\nconst BROWSER_UNAVAILABLE =\n \"Browser login isn't enabled on this server yet — run `krova auth login` to paste an API key from https://krova.cloud\";\n\n/** Only open https URLs, or http to a loopback host. Everything else is unsafe. */\nexport function safeBrowserURL(raw: string): string | null {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n return null;\n }\n if (u.protocol === \"https:\" && u.hostname) return raw;\n if (\n u.protocol === \"http:\" &&\n (u.hostname === \"localhost\" || u.hostname === \"127.0.0.1\" || u.hostname === \"::1\")\n ) {\n return raw;\n }\n return null;\n}\n\nfunction openBrowser(url: string): void {\n const cmd =\n process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n const args = process.platform === \"win32\" ? [\"\", url] : [url];\n const child = spawn(cmd, args, { stdio: \"ignore\", detached: true, shell: process.platform === \"win32\" });\n child.on(\"error\", () => {\n /* fall through — the URL was already printed */\n });\n child.unref();\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport function loginCommand(): Command {\n return new Command(\"login\")\n .description(\"log in through your browser (device authorization)\")\n .option(\"--no-browser\", \"don't open a browser; just print the URL\")\n .option(\"--context <name>\", \"name for the saved context\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const baseUrl = rt.res.baseUrl;\n\n const start = await rawRequest<StartResponse>({\n method: \"POST\",\n baseUrl,\n path: \"/auth/cli/start\",\n timeoutMs: rt.timeoutMs,\n });\n if (start.status === 404) throw new Error(BROWSER_UNAVAILABLE);\n if (start.status !== 200 || !start.data?.deviceCode) {\n throw new Error(`device login failed to start (HTTP ${start.status})`);\n }\n const s = start.data;\n process.stdout.write(`Your verification code is: ${s.userCode}\\n`);\n\n const target = s.verificationUriComplete || s.verificationUri;\n const safe = safeBrowserURL(target);\n if (safe && opts.browser !== false) {\n process.stdout.write(`Opening ${safe} …\\n`);\n openBrowser(safe);\n } else {\n process.stdout.write(`Open this URL to approve the login:\\n ${target}\\n`);\n }\n\n const intervalMs = Math.max((s.interval || 5) * 1000, 5000);\n const deadline = Date.now() + Math.max(s.expiresIn || 600, 1) * 1000;\n process.stdout.write(\"Waiting for approval…\\n\");\n\n // poll loop\n // eslint-disable-next-line no-constant-condition\n for (;;) {\n if (Date.now() >= deadline) {\n throw new Error(\n \"login timed out: the verification code expired before it was approved\"\n );\n }\n await sleep(intervalMs);\n const poll = await rawRequest<PollResponse>({\n method: \"POST\",\n baseUrl,\n path: \"/auth/cli/poll\",\n body: { deviceCode: s.deviceCode },\n timeoutMs: rt.timeoutMs,\n });\n if (poll.status === 200) {\n if (!poll.data?.apiKey) throw new Error(\"login succeeded but no API key was returned\");\n const { ctxName, spaceName } = await persistLogin({\n apiKey: poll.data.apiKey,\n baseUrl,\n spaceId: poll.data.spaceId,\n ctxName: opts.context as string | undefined,\n timeoutMs: rt.timeoutMs,\n });\n process.stdout.write(`Logged in. Saved context \"${ctxName}\" to ${configPath()}\\n`);\n if (spaceName) process.stdout.write(`Space: ${spaceName}\\n`);\n return;\n }\n if (poll.status === 202 || poll.status === 425 || poll.status === 428) continue;\n if (poll.status === 410) {\n throw new Error(\"login expired: request a new code with `krova login`\");\n }\n if (poll.status === 404) throw new Error(BROWSER_UNAVAILABLE);\n throw new Error(`login failed while polling (HTTP ${poll.status})`);\n }\n });\n}\n","import { Command } from \"commander\";\n\nimport { rawRequest } from \"../lib/client.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\nimport {\n type SshInfo,\n buildSSHArgs,\n execSSH,\n validateSSHHost,\n validateSSHUser,\n writeKnownHosts,\n} from \"../lib/ssh.js\";\n\nconst collect = (v: string, acc: string[]) => {\n acc.push(v);\n return acc;\n};\n\nexport function sshCommand(): Command {\n return new Command(\"ssh\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"[command...]\", \"command to run non-interactively (after --)\")\n .description(\"open an SSH session to a Cube (by name or ID)\")\n .option(\"-i, --identity <file>\", \"SSH identity (private key) file, passed to ssh -i\")\n .option(\"-L, --local-forward <spec>\", \"local port forward, passed to ssh -L (repeatable)\", collect, [])\n .option(\"-R, --remote-forward <spec>\", \"remote port forward, passed to ssh -R (repeatable)\", collect, [])\n .action(async (cubeRef: string, command: string[], opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n\n const { status, data } = await rawRequest<SshInfo>({\n method: \"GET\",\n baseUrl: rt.res.baseUrl,\n path: `/spaces/${space}/cubes/${id}/ssh`,\n apiKey: rt.res.apiKey,\n timeoutMs: rt.timeoutMs,\n });\n if (status === 404) {\n throw new Error(\n `SSH info isn't available on this server yet — try \\`krova cubes get ${cubeRef}\\` for the Cube's IP and ssh manually`\n );\n }\n if (status === 401 || status === 403) {\n throw new Error(`SSH info request was rejected (HTTP ${status})`);\n }\n if (status !== 200 || !data?.host) {\n throw new Error(`couldn't fetch SSH info (HTTP ${status})`);\n }\n\n const info: SshInfo = {\n host: data.host,\n port: data.port ?? 0,\n user: data.user ?? \"\",\n hostKeys: data.hostKeys ?? [],\n };\n validateSSHHost(info.host);\n validateSSHUser(info.user);\n if (info.port < 0 || info.port > 65535) throw new Error(\"invalid ssh port\");\n\n let knownHosts = \"\";\n if (info.hostKeys.length) {\n knownHosts = writeKnownHosts(info);\n } else {\n process.stderr.write(\n \"note: this server didn't provide host keys — using ssh trust-on-first-use (host-key checking stays on).\\n\"\n );\n }\n\n const args = buildSSHArgs(info, {\n identity: opts.identity as string | undefined,\n localFwd: opts.localForward as string[],\n remoteFwd: opts.remoteForward as string[],\n knownHosts,\n remoteCmd: command,\n });\n process.exitCode = await execSSH(args);\n });\n}\n","// SSH: fetch connection info, pin host keys, build a hardened `ssh` argv, exec.\n// Ports the Go CLI's option-injection guards and known_hosts pinning verbatim.\n\nimport { spawn } from \"node:child_process\";\nimport { appendFileSync, chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nimport { configDir } from \"./config.js\";\nimport { join } from \"node:path\";\n\nexport interface SshHostKey {\n type: string;\n key: string;\n}\nexport interface SshInfo {\n host: string;\n port: number;\n user: string;\n hostKeys: SshHostKey[];\n}\n\nexport interface SshOptions {\n identity?: string;\n localFwd?: string[];\n remoteFwd?: string[];\n knownHosts?: string;\n remoteCmd?: string[];\n}\n\n// Characters an ssh host must never contain (option/metacharacter injection).\nconst HOST_BANNED = new Set(\n \"@/\\\\'\\\"`$;&|<>(){}*?!#=,\".split(\"\")\n);\n// User is slightly looser — it may contain '=' (host may not).\nconst USER_BANNED = new Set(\n \"@/\\\\'\\\"`$;&|<>(){}*?!#,\".split(\"\")\n);\n\nexport function validateSSHHost(host: string): void {\n const h = host.trim();\n if (!h) throw new Error(\"empty host\");\n if (h.startsWith(\"-\")) throw new Error(\"host must not start with '-'\");\n for (const r of h) {\n const code = r.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n throw new Error(\"host contains whitespace or control characters\");\n }\n if (HOST_BANNED.has(r)) {\n throw new Error(`host contains a disallowed character ${JSON.stringify(r)}`);\n }\n }\n}\n\nexport function validateSSHUser(user: string): void {\n const u = user.trim();\n if (!u) return; // empty user is allowed\n if (u.startsWith(\"-\")) throw new Error(\"user must not start with '-'\");\n for (const r of u) {\n const code = r.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n throw new Error(\"user contains whitespace or control characters\");\n }\n if (USER_BANNED.has(r)) {\n throw new Error(`user contains a disallowed character ${JSON.stringify(r)}`);\n }\n }\n}\n\n/** known_hosts host field: \"[host]:port\" when the port isn't the default 22. */\nexport function knownHostsHost(host: string, port: number): string {\n if (port > 0 && port !== 22) return `[${host}]:${port}`;\n return host;\n}\n\nexport function knownHostsPath(): string {\n return join(configDir(), \"known_hosts\");\n}\n\n/** Pin the cube's host keys to ~/.config/krova/known_hosts (0600), pruning any\n * stale line for the same host:port (rebuilt cubes can reuse an IP+DNAT port). */\nexport function writeKnownHosts(info: SshInfo): string {\n const path = knownHostsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n const field = knownHostsHost(info.host, info.port);\n\n let existing = \"\";\n try {\n existing = readFileSync(path, \"utf8\");\n } catch {\n existing = \"\";\n }\n const kept = existing\n .split(\"\\n\")\n .filter((line) => line.trim() && line.split(/\\s+/)[0] !== field);\n writeFileSync(path, kept.length ? `${kept.join(\"\\n\")}\\n` : \"\", { mode: 0o600 });\n chmodSync(path, 0o600);\n\n for (const k of info.hostKeys) {\n appendFileSync(path, `${field} ${k.type} ${k.key}\\n`);\n }\n return path;\n}\n\n/** Build the ssh argv. `--` is placed immediately before the destination —\n * the primary option-injection guard (with the validators above). */\nexport function buildSSHArgs(info: SshInfo, o: SshOptions): string[] {\n const args: string[] = [];\n if (o.knownHosts) {\n args.push(\"-o\", `UserKnownHostsFile=${o.knownHosts}`, \"-o\", \"StrictHostKeyChecking=yes\");\n }\n if ((o.identity ?? \"\").trim()) args.push(\"-i\", o.identity as string);\n if (info.port > 0) args.push(\"-p\", String(info.port));\n for (const l of o.localFwd ?? []) if (l.trim()) args.push(\"-L\", l);\n for (const r of o.remoteFwd ?? []) if (r.trim()) args.push(\"-R\", r);\n const user = info.user.trim();\n const target = user ? `${user}@${info.host}` : info.host;\n args.push(\"--\", target);\n args.push(...(o.remoteCmd ?? []));\n return args;\n}\n\n/** Exec system ssh, inheriting stdio (interactive unless a remote cmd is given). */\nexport function execSSH(args: string[]): Promise<number> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"ssh\", args, { stdio: \"inherit\" });\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => resolve(code ?? 0));\n });\n}\n","import { createRequire } from \"node:module\";\n\nimport { Command } from \"commander\";\n\nimport { printJSON } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\nexport const CLI_VERSION = pkg.version;\n\nexport function versionCommand(): Command {\n return new Command(\"version\")\n .description(\"print the krova CLI version\")\n .action((_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const info = {\n version: CLI_VERSION,\n node: process.version,\n platform: `${process.platform}/${process.arch}`,\n };\n if (rt.json) return printJSON(info);\n process.stdout.write(`krova ${info.version} (node ${info.node}, ${info.platform})\\n`);\n });\n}\n","import { createServer } from \"node:http\";\n\nimport { verifyKrovaWebhookOrThrow } from \"@krovacloud/webhook\";\nimport { Command } from \"commander\";\n\nimport { printJSON } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nexport function webhooksCommand(): Command {\n const wh = new Command(\"webhooks\").description(\"developer tools for Krova Cloud webhooks\");\n\n wh.command(\"listen\")\n .description(\"run a local server that verifies + prints incoming webhook deliveries\")\n .option(\"--addr <host:port>\", \"address to listen on\", \"127.0.0.1:4666\")\n .option(\"--path <path>\", \"path to accept POSTs on\", \"/\")\n .option(\"--secret <secret>\", \"signing secret (or the KROVA_WEBHOOK_SECRET env var)\")\n .action((opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const secret = (opts.secret as string) || process.env.KROVA_WEBHOOK_SECRET || \"\";\n if (!secret) {\n throw new Error(\n \"a signing secret is required: pass --secret or set KROVA_WEBHOOK_SECRET\"\n );\n }\n const addr = String(opts.addr);\n const lastColon = addr.lastIndexOf(\":\");\n const host = lastColon > 0 ? addr.slice(0, lastColon) : \"127.0.0.1\";\n const port = Number(lastColon > 0 ? addr.slice(lastColon + 1) : addr) || 4666;\n const wantPath = String(opts.path);\n\n const server = createServer((req, res) => {\n const reqPath = (req.url ?? \"/\").split(\"?\")[0];\n if (req.method !== \"POST\" || reqPath !== wantPath) {\n res.writeHead(405);\n res.end(\"method not allowed\");\n return;\n }\n const chunks: Buffer[] = [];\n let size = 0;\n req.on(\"data\", (c: Buffer) => {\n size += c.length;\n if (size <= 1_048_576) chunks.push(c);\n });\n req.on(\"end\", () => {\n const body = Buffer.concat(chunks).toString(\"utf8\");\n const sig = (req.headers[\"x-krova-signature\"] as string) || \"\";\n try {\n verifyKrovaWebhookOrThrow({ payload: body, signature: sig, secret });\n } catch (e) {\n process.stderr.write(`✗ rejected delivery: ${(e as Error).message}\\n`);\n res.writeHead(400);\n res.end(\"invalid signature\");\n return;\n }\n try {\n const event = JSON.parse(body);\n if (rt.json) process.stdout.write(`${JSON.stringify(event)}\\n`);\n else printJSON(event);\n } catch {\n process.stdout.write(`${body}\\n`);\n }\n res.writeHead(200);\n res.end(\"ok\");\n });\n });\n\n server.listen(port, host, () => {\n process.stderr.write(`Listening for webhooks on http://${host}:${port}${wantPath}\\n`);\n });\n const stop = () => server.close(() => process.exit(0));\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n });\n\n return wh;\n}\n","import { Command } from \"commander\";\n\nimport { find, maskKey } from \"../lib/config.js\";\nimport { printJSON, printKeyValue } from \"../lib/output.js\";\nimport { fetchSpace, getRuntime } from \"../lib/runtime.js\";\n\nexport function whoamiCommand(): Command {\n return new Command(\"whoami\")\n .description(\"show the current context, space, and base URL\")\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const ctx = find(rt.cfg, rt.res.contextName);\n let spaceId = rt.res.spaceId;\n let spaceName = ctx?.spaceName ?? \"\";\n let spaceLive = false;\n\n if (rt.res.apiKey) {\n const sp = await fetchSpace(rt.res.baseUrl, rt.res.apiKey, rt.timeoutMs);\n if (sp) {\n spaceId = sp.id;\n spaceName = sp.name ?? spaceName;\n spaceLive = true;\n }\n }\n\n if (rt.json) {\n return printJSON({\n context: rt.res.contextName,\n spaceId,\n spaceName,\n apiKeyMasked: maskKey(rt.res.apiKey),\n apiKeySource: rt.res.apiKeySource,\n baseUrl: rt.res.baseUrl,\n spaceLive,\n });\n }\n printKeyValue([\n [\"Context\", rt.res.contextName || \"—\"],\n [\"Space\", spaceName || \"—\"],\n [\"Space ID\", spaceId || \"—\"],\n [\"API key\", rt.res.apiKey ? `${maskKey(rt.res.apiKey)} (${rt.res.apiKeySource})` : \"—\"],\n [\"Base URL\", rt.res.baseUrl],\n ]);\n });\n}\n"],"mappings":"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","names":["Command","resolve","Command","fetch","Command","Command","Command","Command","Command","Command","Command","Command","spawn","chmodSync","mkdirSync","readFileSync","writeFileSync","dirname","join","mkdirSync","dirname","readFileSync","writeFileSync","chmodSync","resolve","spawn","Command","Command","require","Command","Command","Command","Command","Command","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/auth.ts","../src/lib/config.ts","../src/lib/output.ts","../src/lib/client.ts","../src/lib/runtime.ts","../src/lib/persist.ts","../src/commands/catalog.ts","../src/commands/context.ts","../src/commands/cubes.ts","../src/lib/resolve.ts","../src/commands/domains.ts","../src/commands/login.ts","../src/commands/snapshots.ts","../src/commands/ssh.ts","../src/lib/ssh.ts","../src/commands/tcp.ts","../src/commands/version.ts","../src/commands/webhooks.ts","../src/commands/whoami.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { authCommand } from \"./commands/auth.js\";\nimport { imagesCommand, pricingCommand, regionsCommand } from \"./commands/catalog.js\";\nimport { contextCommand } from \"./commands/context.js\";\nimport { cubesCommand, rootGetCommand, rootListCommand } from \"./commands/cubes.js\";\nimport { domainsCommand } from \"./commands/domains.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { snapshotsCommand } from \"./commands/snapshots.js\";\nimport { sshCommand } from \"./commands/ssh.js\";\nimport { tcpCommand } from \"./commands/tcp.js\";\nimport { CLI_VERSION, versionCommand } from \"./commands/version.js\";\nimport { webhooksCommand } from \"./commands/webhooks.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\n\n/** cobra-style persistent flags: usable on any command, before or after it.\n * Skips a flag a command already defines locally (e.g. login's own --context). */\nfunction addGlobalOptions(cmd: Command): void {\n const have = new Set(cmd.options.map((o) => o.long));\n const add = (flags: string, desc: string, def?: string) => {\n const long = flags.split(/[ ,<[]/).find((f) => f.startsWith(\"--\"));\n if (long && !have.has(long)) cmd.option(flags, desc, def);\n };\n add(\"--api-key <key>\", \"Krova Cloud API key (overrides env and context)\");\n add(\"--space <id>\", \"Space ID (overrides KROVA_SPACE_ID and context)\");\n add(\"--base-url <url>\", \"override the API base URL\");\n add(\"--context <name>\", \"use a named context (overrides KROVA_CONTEXT)\");\n add(\"--json\", \"output machine-readable JSON instead of a table\");\n add(\"--timeout <duration>\", \"per-request timeout\", \"30s\");\n}\n\nconst program = new Command();\nprogram\n .name(\"krova\")\n .description(\n \"krova is the command-line interface for Krova Cloud — manage Cubes (Firecracker microVMs), browse the catalog, and receive webhooks.\"\n )\n .version(CLI_VERSION, \"-v, --version\", \"print the krova CLI version\")\n .showHelpAfterError();\n\nprogram.addCommand(loginCommand());\nprogram.addCommand(authCommand());\nprogram.addCommand(contextCommand());\nprogram.addCommand(whoamiCommand());\nprogram.addCommand(cubesCommand());\nprogram.addCommand(domainsCommand());\nprogram.addCommand(snapshotsCommand());\nprogram.addCommand(tcpCommand());\nprogram.addCommand(sshCommand());\nprogram.addCommand(rootListCommand()); // `krova list` (alias `ls`)\nprogram.addCommand(rootGetCommand()); // `krova get`\nprogram.addCommand(regionsCommand());\nprogram.addCommand(imagesCommand());\nprogram.addCommand(pricingCommand());\nprogram.addCommand(webhooksCommand());\nprogram.addCommand(versionCommand());\n\n// Apply the global flags to the root and every (sub)command.\nconst applyAll = (cmd: Command): void => {\n addGlobalOptions(cmd);\n for (const c of cmd.commands) applyAll(c);\n};\napplyAll(program);\n\nasync function main(): Promise<void> {\n try {\n await program.parseAsync(process.argv);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`Error: ${msg}\\n`);\n process.exitCode = 1;\n }\n}\n\nvoid main();\n","import { Command } from \"commander\";\n\nimport { configPath, maskKey } from \"../lib/config.js\";\nimport { printJSON, printKeyValue } from \"../lib/output.js\";\nimport { persistLogin } from \"../lib/persist.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\n/** Prompt for an API key. Hidden echo when stdin is a TTY. */\nfunction promptAPIKey(): Promise<string> {\n return new Promise((resolve, reject) => {\n process.stdout.write(\"Krova API key: \");\n const stdin = process.stdin;\n const tty = Boolean(stdin.isTTY);\n let buf = \"\";\n if (tty) stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding(\"utf8\");\n const finish = (fn: () => void) => {\n if (tty) stdin.setRawMode(false);\n stdin.pause();\n stdin.removeListener(\"data\", onData);\n fn();\n };\n const onData = (ch: string) => {\n for (const c of ch) {\n const code = c.charCodeAt(0);\n if (code === 10 || code === 13) {\n finish(() => {\n process.stdout.write(\"\\n\");\n resolve(buf.trim());\n });\n return;\n }\n if (code === 3) {\n finish(() => reject(new Error(\"cancelled\")));\n return;\n }\n if (code === 127 || code === 8) {\n buf = buf.slice(0, -1);\n } else if (code >= 32) {\n buf += c;\n }\n }\n };\n stdin.on(\"data\", onData);\n });\n}\n\nexport function authCommand(): Command {\n const auth = new Command(\"auth\").description(\"manage Krova Cloud credentials\");\n\n auth\n .command(\"login\")\n .description(\"log in by pasting an API key\")\n .option(\"--api-key <key>\", \"API key (else you'll be prompted)\")\n .option(\"--space <id>\", \"Space ID to store with the key\")\n .option(\"--context <name>\", \"name for the saved context\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n let key = (opts.apiKey as string) || rt.flags.apiKey || \"\";\n if (!key.trim()) key = await promptAPIKey();\n if (!key.trim()) throw new Error(\"no API key provided\");\n const { ctxName, spaceName } = await persistLogin({\n apiKey: key.trim(),\n baseUrl: rt.res.baseUrl,\n spaceId: opts.space as string | undefined,\n ctxName: opts.context as string | undefined,\n timeoutMs: rt.timeoutMs,\n });\n process.stdout.write(`Logged in. Saved context \"${ctxName}\" to ${configPath()}\\n`);\n if (spaceName) process.stdout.write(`Space: ${spaceName}\\n`);\n });\n\n auth\n .command(\"status\")\n .description(\"show the resolved credentials\")\n .action((_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const authenticated = Boolean(rt.res.apiKey);\n if (rt.json) {\n return printJSON({\n authenticated,\n context: rt.res.contextName,\n apiKeySource: rt.res.apiKeySource,\n apiKeyMasked: maskKey(rt.res.apiKey),\n spaceId: rt.res.spaceId,\n spaceSource: rt.res.spaceIdSource,\n baseUrl: rt.res.baseUrl,\n configPath: configPath(),\n });\n }\n printKeyValue([\n [\"Authenticated\", authenticated ? \"yes\" : \"no\"],\n [\"Context\", rt.res.contextName || \"—\"],\n [\"API key\", rt.res.apiKey ? `${maskKey(rt.res.apiKey)} (${rt.res.apiKeySource})` : \"—\"],\n [\"Space ID\", rt.res.spaceId ? `${rt.res.spaceId} (${rt.res.spaceIdSource})` : \"—\"],\n [\"Base URL\", rt.res.baseUrl],\n [\"Config\", configPath()],\n ]);\n });\n\n return auth;\n}\n","// Reads/writes ~/.config/krova/config.json in the EXACT shape the Go CLI used,\n// so existing configs keep working. Multi-context, with legacy single-key\n// migration. The file is always tightened to 0600 on save.\n\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport const DEFAULT_BASE_URL = \"https://krova.cloud/api/v1\";\nexport const DEFAULT_CONTEXT_NAME = \"default\";\n\nexport const ENV = {\n apiKey: \"KROVA_API_KEY\",\n spaceId: \"KROVA_SPACE_ID\",\n baseUrl: \"KROVA_BASE_URL\",\n context: \"KROVA_CONTEXT\",\n} as const;\n\nexport interface Context {\n name: string;\n apiKey?: string;\n spaceId?: string;\n spaceName?: string;\n baseUrl?: string;\n}\n\nexport interface Config {\n currentContext?: string;\n contexts?: Context[];\n // legacy (pre-context) fields — parsed then migrated into a \"default\" context\n apiKey?: string;\n spaceId?: string;\n baseUrl?: string;\n}\n\nexport function configDir(): string {\n const xdg = (process.env.XDG_CONFIG_HOME ?? \"\").trim();\n if (xdg) return join(xdg, \"krova\");\n return join(homedir(), \".config\", \"krova\");\n}\n\nexport function configPath(): string {\n return join(configDir(), \"config.json\");\n}\n\nexport function load(): Config {\n let cfg: Config = {};\n try {\n cfg = JSON.parse(readFileSync(configPath(), \"utf8\")) as Config;\n } catch {\n cfg = {};\n }\n return migrate(cfg);\n}\n\n// If only legacy fields are set, synthesize a \"default\" context from them.\nfunction migrate(cfg: Config): Config {\n if ((cfg.apiKey ?? \"\").trim() && (!cfg.contexts || cfg.contexts.length === 0)) {\n cfg.contexts = [\n {\n name: DEFAULT_CONTEXT_NAME,\n apiKey: cfg.apiKey,\n spaceId: cfg.spaceId,\n baseUrl: cfg.baseUrl,\n },\n ];\n cfg.currentContext = DEFAULT_CONTEXT_NAME;\n }\n cfg.apiKey = undefined;\n cfg.spaceId = undefined;\n cfg.baseUrl = undefined;\n return cfg;\n}\n\nexport function save(cfg: Config): void {\n const path = configPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n // clear legacy fields; only serialize non-empty keys (matches Go omitempty)\n const clean: Config = {};\n if (cfg.currentContext) clean.currentContext = cfg.currentContext;\n if (cfg.contexts && cfg.contexts.length) {\n clean.contexts = cfg.contexts.map((c) => {\n const o: Context = { name: c.name };\n if (c.apiKey) o.apiKey = c.apiKey;\n if (c.spaceId) o.spaceId = c.spaceId;\n if (c.spaceName) o.spaceName = c.spaceName;\n if (c.baseUrl) o.baseUrl = c.baseUrl;\n return o;\n });\n }\n writeFileSync(path, `${JSON.stringify(clean, null, 2)}\\n`, { mode: 0o600 });\n // writeFileSync only applies mode on creation — re-tighten an existing file.\n chmodSync(path, 0o600);\n}\n\nexport function find(cfg: Config, name: string): Context | undefined {\n return (cfg.contexts ?? []).find((c) => c.name === name);\n}\n\n/** The active context: `override` (e.g. --context) wins, else currentContext. */\nexport function current(cfg: Config, override?: string): Context | undefined {\n const name = (override ?? \"\").trim() || (cfg.currentContext ?? \"\").trim();\n if (!name) return undefined;\n return find(cfg, name);\n}\n\n/** Merge-in a context: only NON-EMPTY apiKey/spaceId/spaceName/baseUrl\n * overwrite an existing value. This keeps a transient per-command override\n * (e.g. a one-off `--base-url`) from being silently persisted over the\n * context's real base URL. First-ever context becomes current. Returns it. */\nexport function upsert(cfg: Config, incoming: Context): Context {\n cfg.contexts ??= [];\n let ctx = cfg.contexts.find((c) => c.name === incoming.name);\n if (!ctx) {\n ctx = { name: incoming.name };\n cfg.contexts.push(ctx);\n if (!cfg.currentContext) cfg.currentContext = ctx.name;\n }\n if ((incoming.apiKey ?? \"\").trim()) ctx.apiKey = incoming.apiKey;\n if ((incoming.spaceId ?? \"\").trim()) ctx.spaceId = incoming.spaceId;\n if ((incoming.spaceName ?? \"\").trim()) ctx.spaceName = incoming.spaceName;\n if ((incoming.baseUrl ?? \"\").trim()) ctx.baseUrl = incoming.baseUrl;\n return ctx;\n}\n\nexport function remove(cfg: Config, name: string): boolean {\n const before = (cfg.contexts ?? []).length;\n cfg.contexts = (cfg.contexts ?? []).filter((c) => c.name !== name);\n if (cfg.contexts.length === before) return false;\n if (cfg.currentContext === name) {\n cfg.currentContext = cfg.contexts[0]?.name ?? \"\";\n }\n return true;\n}\n\nexport type Source = \"flag\" | \"env\" | \"context\" | \"\";\n\nexport interface Resolved {\n apiKey: string;\n spaceId: string;\n baseUrl: string;\n apiKeySource: Source;\n spaceIdSource: Source;\n contextName: string;\n}\n\nexport interface GlobalFlags {\n apiKey?: string;\n space?: string;\n baseUrl?: string;\n context?: string;\n}\n\n/** Resolve credentials with precedence flag > env > active context. */\nexport function resolve(cfg: Config, flags: GlobalFlags): Resolved {\n const ctx = current(cfg, (flags.context ?? \"\").trim() || process.env[ENV.context]);\n const pick = (\n flag: string | undefined,\n env: string | undefined,\n ctxVal: string | undefined\n ): [string, Source] => {\n if ((flag ?? \"\").trim()) return [flag as string, \"flag\"];\n if ((env ?? \"\").trim()) return [env as string, \"env\"];\n if ((ctxVal ?? \"\").trim()) return [ctxVal as string, \"context\"];\n return [\"\", \"\"];\n };\n const [apiKey, apiKeySource] = pick(flags.apiKey, process.env[ENV.apiKey], ctx?.apiKey);\n const [spaceId, spaceIdSource] = pick(flags.space, process.env[ENV.spaceId], ctx?.spaceId);\n const [baseUrlRaw] = pick(flags.baseUrl, process.env[ENV.baseUrl], ctx?.baseUrl);\n return {\n apiKey,\n spaceId,\n baseUrl: baseUrlRaw || DEFAULT_BASE_URL,\n apiKeySource,\n spaceIdSource,\n contextName: ctx?.name ?? \"\",\n };\n}\n\nexport function sanitizeContextName(name: string): string {\n return name.trim().toLowerCase().replace(/\\s+/g, \"-\");\n}\n\nexport function maskKey(key: string): string {\n if (!key) return \"\";\n if (key.length <= 8) return \"****\";\n return `${key.slice(0, 6)}…${key.slice(-4)}`;\n}\n","export function printJSON(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nexport function printTable(header: string[], rows: string[][]): void {\n const widths = header.map((h, i) =>\n Math.max(h.length, ...rows.map((r) => (r[i] ?? \"\").length))\n );\n const fmt = (cols: string[]) =>\n cols\n .map((c, i) => (c ?? \"\").padEnd(widths[i] ?? 0))\n .join(\" \")\n .replace(/\\s+$/, \"\");\n process.stdout.write(`${fmt(header)}\\n`);\n for (const r of rows) process.stdout.write(`${fmt(r)}\\n`);\n}\n\nexport function printKeyValue(pairs: Array<[string, string]>): void {\n const w = Math.max(0, ...pairs.map(([k]) => k.length));\n for (const [k, v] of pairs) {\n process.stdout.write(`${k.padEnd(w)} ${v}\\n`);\n }\n}\n","import { KrovaClient } from \"@krovacloud/sdk\";\n\nimport type { Resolved } from \"./config.js\";\n\n/** Build the SDK client, or throw the same message the Go CLI used. */\nexport function makeClient(res: Resolved): KrovaClient {\n if (!res.apiKey) {\n throw new Error(\n \"no API key found: run `krova auth login`, set KROVA_API_KEY, or pass --api-key\"\n );\n }\n return new KrovaClient({ apiKey: res.apiKey, baseUrl: res.baseUrl });\n}\n\n/** Raw JSON request for endpoints the SDK doesn't cover:\n * GET /space, GET .../ssh, POST /auth/cli/start, POST /auth/cli/poll. */\nexport async function rawRequest<T>(opts: {\n method: string;\n baseUrl: string;\n path: string;\n apiKey?: string;\n body?: unknown;\n timeoutMs: number;\n}): Promise<{ status: number; data: T | undefined }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), opts.timeoutMs);\n try {\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (opts.apiKey) headers[\"X-API-KEY\"] = opts.apiKey;\n if (opts.body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n const res = await fetch(`${opts.baseUrl.replace(/\\/+$/, \"\")}${opts.path}`, {\n method: opts.method,\n headers,\n body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,\n redirect: \"manual\",\n signal: controller.signal,\n });\n let data: T | undefined;\n const text = await res.text();\n if (text) {\n try {\n data = JSON.parse(text) as T;\n } catch {\n data = undefined;\n }\n }\n return { status: res.status, data };\n } finally {\n clearTimeout(timer);\n }\n}\n","import type { Command } from \"commander\";\n\nimport {\n type Config,\n type GlobalFlags,\n type Resolved,\n load,\n resolve,\n save,\n upsert,\n} from \"./config.js\";\nimport { makeClient, rawRequest } from \"./client.js\";\n\n/** Parse a Go-style duration (\"30s\", \"500ms\", \"2m\", \"1h\") to ms. Non-positive\n * or unparseable floors to 30s (matches the Go requestTimeout behavior). */\nexport function parseDuration(input: string | undefined): number {\n const s = (input ?? \"\").trim();\n if (!s) return 30_000;\n let total = 0;\n const re = /(\\d+(?:\\.\\d+)?)(ms|s|m|h)/g;\n let m: RegExpExecArray | null = re.exec(s);\n let matched = false;\n while (m) {\n matched = true;\n const n = Number(m[1]);\n const unit = m[2];\n total += unit === \"ms\" ? n : unit === \"s\" ? n * 1000 : unit === \"m\" ? n * 60_000 : n * 3_600_000;\n m = re.exec(s);\n }\n if (!matched) {\n const n = Number(s);\n if (Number.isFinite(n)) total = n * 1000; // bare number = seconds\n }\n return total > 0 ? total : 30_000;\n}\n\nexport interface Runtime {\n flags: GlobalFlags;\n cfg: Config;\n res: Resolved;\n json: boolean;\n timeoutMs: number;\n}\n\nexport function getRuntime(cmd: Command): Runtime {\n const opts = cmd.optsWithGlobals() as Record<string, unknown>;\n const flags: GlobalFlags = {\n apiKey: opts.apiKey as string | undefined,\n space: opts.space as string | undefined,\n baseUrl: opts.baseUrl as string | undefined,\n context: opts.context as string | undefined,\n };\n const cfg = load();\n const res = resolve(cfg, flags);\n return {\n flags,\n cfg,\n res,\n json: Boolean(opts.json),\n timeoutMs: parseDuration(opts.timeout as string | undefined),\n };\n}\n\nexport interface SpaceInfo {\n id: string;\n name?: string;\n slug?: string;\n}\n\n/** GET /space with the given key; null on 404 / error (non-fatal). */\nexport async function fetchSpace(\n baseUrl: string,\n apiKey: string,\n timeoutMs: number\n): Promise<SpaceInfo | null> {\n try {\n const { status, data } = await rawRequest<SpaceInfo>({\n method: \"GET\",\n baseUrl,\n path: \"/space\",\n apiKey,\n timeoutMs,\n });\n if (status === 200 && data?.id) return data;\n return null;\n } catch {\n return null;\n }\n}\n\n/** Resolve the active space id: explicit value wins, else auto-detect via\n * GET /space (and cache it into the current context). */\nexport async function resolveSpace(rt: Runtime): Promise<string> {\n if (rt.res.spaceId) return rt.res.spaceId;\n const { status, data } = await rawRequest<SpaceInfo>({\n method: \"GET\",\n baseUrl: rt.res.baseUrl,\n path: \"/space\",\n apiKey: rt.res.apiKey,\n timeoutMs: rt.timeoutMs,\n });\n if (status === 200 && data?.id) {\n // Best-effort cache of the resolved space into the current named context.\n // Deliberately does NOT write baseUrl: rt.res.baseUrl already folds in a\n // one-off --base-url / KROVA_BASE_URL override, and persisting that here\n // would permanently rewrite the context's real base URL from a transient\n // flag. Only the space id/name are cached.\n if (rt.res.contextName) {\n upsert(rt.cfg, {\n name: rt.res.contextName,\n spaceId: data.id,\n spaceName: data.name,\n });\n try {\n save(rt.cfg);\n } catch {\n /* non-fatal */\n }\n }\n return data.id;\n }\n if (status === 404) {\n throw new Error(\n \"couldn't auto-detect your space (the server doesn't support it yet) — pass --space, set KROVA_SPACE_ID, or run `krova login`\"\n );\n }\n if (status === 401 || status === 403) {\n throw new Error(`auto-detect space failed: the API key was rejected (HTTP ${status})`);\n }\n throw new Error(`auto-detect space failed (HTTP ${status})`);\n}\n\nexport { makeClient };\n","import { DEFAULT_CONTEXT_NAME, load, sanitizeContextName, save, upsert } from \"./config.js\";\nimport { fetchSpace } from \"./runtime.js\";\n\n/** Save + switch to a context after a login. Best-effort space lookup fills in\n * spaceId/spaceName and a nicer context name. Mirrors the Go persistLogin. */\nexport async function persistLogin(input: {\n apiKey: string;\n baseUrl: string;\n spaceId?: string;\n ctxName?: string;\n timeoutMs: number;\n}): Promise<{ ctxName: string; spaceName: string }> {\n const cfg = load();\n let spaceId = input.spaceId ?? \"\";\n let spaceName = \"\";\n let derivedName = \"\";\n\n const sp = await fetchSpace(input.baseUrl, input.apiKey, input.timeoutMs);\n if (sp) {\n // Prefer an explicitly-provided --space over the fetched id; only fall back\n // to the resolved space when the caller didn't pin one.\n if (!spaceId) spaceId = sp.id;\n spaceName = sp.name ?? \"\";\n derivedName = (sp.slug || sp.name || \"\").trim();\n }\n\n let name = (input.ctxName ?? \"\").trim();\n if (!name) name = derivedName || DEFAULT_CONTEXT_NAME;\n name = sanitizeContextName(name);\n\n const cur = upsert(cfg, {\n name,\n apiKey: input.apiKey,\n spaceId,\n spaceName,\n baseUrl: input.baseUrl,\n });\n cfg.currentContext = cur.name; // login always switches current\n save(cfg);\n return { ctxName: cur.name, spaceName: cur.spaceName ?? \"\" };\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { getRuntime, makeClient } from \"../lib/runtime.js\";\n\nfunction fmtVal(v: unknown): string {\n if (v === null || v === undefined) return \"\";\n if (typeof v === \"object\") return JSON.stringify(v);\n return String(v);\n}\n\n/** Flatten a top-level object field one level deep into `key.subkey` rows, so\n * nested objects (e.g. pricing's `rates`) render as readable key/value pairs\n * instead of a JSON blob. Exported for testing. */\nexport function flattenRows(entries: [string, unknown][]): [string, string][] {\n const rows: [string, string][] = [];\n for (const [k, v] of entries) {\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [sk, sv] of Object.entries(v as Record<string, unknown>)) {\n rows.push([`${k}.${sk}`, fmtVal(sv)]);\n }\n } else {\n rows.push([k, fmtVal(v)]);\n }\n }\n return rows;\n}\n\n/**\n * Render a catalog payload as text. If the payload has an array field, print any\n * scalar/object fields first (as key/value) and then the array as a table —\n * otherwise the non-array fields are silently dropped. This matters for\n * `pricing`, whose per-resource `rates` (the actual hourly prices), `currency`,\n * and `note` sit alongside the `tiers` array. `regions`/`images` have only the\n * array, so their output is unchanged.\n */\nfunction renderCatalog(obj: Record<string, unknown>): void {\n const arrKey = Object.keys(obj).find((k) => Array.isArray(obj[k]));\n if (!arrKey) {\n printKeyValue(flattenRows(Object.entries(obj)));\n return;\n }\n const rest = flattenRows(Object.entries(obj).filter(([k]) => k !== arrKey));\n if (rest.length) printKeyValue(rest);\n const arr = (obj[arrKey] as Record<string, unknown>[]) ?? [];\n const cols = [...new Set(arr.flatMap((o) => Object.keys(o)))];\n printTable(\n cols.map((c) => c.toUpperCase()),\n arr.map((o) => cols.map((c) => fmtVal(o[c])))\n );\n}\n\nfunction catalogCmd(\n name: string,\n desc: string,\n fetch: (c: ReturnType<typeof makeClient>) => Promise<Record<string, unknown>>\n): Command {\n return new Command(name)\n .description(desc)\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const data = await fetch(client);\n if (rt.json) return printJSON(data);\n renderCatalog(data);\n });\n}\n\nexport function regionsCommand(): Command {\n return catalogCmd(\"regions\", \"list regions with available capacity\", (c) =>\n c.catalog.regions() as Promise<Record<string, unknown>>\n );\n}\nexport function imagesCommand(): Command {\n return catalogCmd(\"images\", \"list available OS images\", (c) =>\n c.catalog.images() as Promise<Record<string, unknown>>\n );\n}\nexport function pricingCommand(): Command {\n return catalogCmd(\"pricing\", \"show per-resource hourly pricing\", (c) =>\n c.catalog.pricing() as Promise<Record<string, unknown>>\n );\n}\n","import { Command } from \"commander\";\n\nimport { load, maskKey, remove, save } from \"../lib/config.js\";\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nexport function contextCommand(): Command {\n const ctx = new Command(\"context\")\n .aliases([\"ctx\", \"contexts\"])\n .description(\"manage named credential contexts (like kubectl/aws profiles)\");\n\n ctx\n .command(\"list\")\n .aliases([\"ls\"])\n .description(\"list all contexts\")\n .action((_opts, cmd: Command) => {\n const { json } = getRuntime(cmd);\n const cfg = load();\n if (json) {\n return printJSON({\n currentContext: cfg.currentContext ?? \"\",\n contexts: (cfg.contexts ?? []).map((c) => ({\n name: c.name,\n apiKey: maskKey(c.apiKey ?? \"\"),\n spaceId: c.spaceId ?? \"\",\n spaceName: c.spaceName ?? \"\",\n baseUrl: c.baseUrl ?? \"\",\n })),\n });\n }\n printTable(\n [\"CURRENT\", \"NAME\", \"SPACE\", \"SPACE ID\", \"BASE URL\"],\n (cfg.contexts ?? []).map((c) => [\n c.name === cfg.currentContext ? \"*\" : \"\",\n c.name,\n c.spaceName ?? \"\",\n c.spaceId ?? \"\",\n c.baseUrl ?? \"\",\n ])\n );\n });\n\n ctx\n .command(\"current\")\n .description(\"print the current context name\")\n .action(() => {\n const cfg = load();\n if (!cfg.currentContext) throw new Error(\"no current context set\");\n process.stdout.write(`${cfg.currentContext}\\n`);\n });\n\n ctx\n .command(\"use\")\n .argument(\"<name>\", \"context name\")\n .description(\"switch the current context\")\n .action((name: string) => {\n const cfg = load();\n if (!(cfg.contexts ?? []).some((c) => c.name === name)) {\n throw new Error(`no context named \"${name}\"`);\n }\n cfg.currentContext = name;\n save(cfg);\n process.stdout.write(`Switched to context ${name}\\n`);\n });\n\n ctx\n .command(\"rename\")\n .argument(\"<old>\", \"current name\")\n .argument(\"<new>\", \"new name\")\n .description(\"rename a context\")\n .action((oldName: string, newName: string) => {\n const cfg = load();\n if (!newName.trim()) throw new Error(\"new name must not be empty\");\n const c = (cfg.contexts ?? []).find((x) => x.name === oldName);\n if (!c) throw new Error(`no context named \"${oldName}\"`);\n if ((cfg.contexts ?? []).some((x) => x.name === newName)) {\n throw new Error(`a context named \"${newName}\" already exists`);\n }\n c.name = newName;\n if (cfg.currentContext === oldName) cfg.currentContext = newName;\n save(cfg);\n process.stdout.write(`Renamed ${oldName} → ${newName}\\n`);\n });\n\n ctx\n .command(\"delete\")\n .aliases([\"rm\"])\n .argument(\"<name>\", \"context name\")\n .description(\"delete a context\")\n .action((name: string) => {\n const cfg = load();\n if (!remove(cfg, name)) throw new Error(`no context named \"${name}\"`);\n save(cfg);\n process.stdout.write(`Deleted context ${name}\\n`);\n });\n\n return ctx;\n}\n\nexport function whoamiKeyValue(pairs: Array<[string, string]>): void {\n printKeyValue(pairs);\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printKeyValue, printTable } from \"../lib/output.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\n\nfunction listCmd(): Command {\n return new Command(\"list\")\n .aliases([\"ls\"])\n .description(\"list Cubes in the space\")\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const { cubes } = await client.cubes.list(space);\n if (rt.json) return printJSON(cubes);\n printTable(\n [\"ID\", \"NAME\", \"STATE\", \"VCPU\", \"RAM(GB)\", \"DISK(GB)\", \"IMAGE\", \"IPV4\"],\n cubes.map((c) => [\n c.id,\n c.name,\n c.state,\n String(c.resources.vcpu),\n String(c.resources.ramGb),\n String(c.resources.diskGb),\n c.image,\n c.publicIpv4 ?? \"—\",\n ])\n );\n });\n}\n\nfunction getCmd(): Command {\n return new Command(\"get\")\n .argument(\"<cube>\", \"cube name or ID\")\n .description(\"show a single Cube\")\n .action(async (cubeRef: string, _opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const cube = await client.cubes.get(space, id);\n if (rt.json) return printJSON(cube);\n printKeyValue([\n [\"ID\", cube.id],\n [\"Name\", cube.name],\n [\"State\", cube.state],\n [\"Image\", cube.image],\n [\"vCPU\", String(cube.resources.vcpu)],\n [\"RAM (GB)\", String(cube.resources.ramGb)],\n [\"Disk (GB)\", String(cube.resources.diskGb)],\n [\"Public IPv4\", cube.publicIpv4 ?? \"—\"],\n [\"Cost/hour\", `$${cube.costPerHour}`],\n ]);\n });\n}\n\nfunction createCmd(): Command {\n return new Command(\"create\")\n .description(\"provision a new Cube\")\n .requiredOption(\"--name <name>\", \"cube name\")\n .requiredOption(\"--image <slug>\", \"OS image slug (see `krova images`)\")\n .requiredOption(\"--ssh-key <key>\", \"SSH public key written to authorized_keys\")\n .option(\"--vcpu <n>\", \"number of vCPUs\", \"1\")\n .option(\"--ram <gb>\", \"RAM in GB\", \"1\")\n .option(\"--disk <gb>\", \"disk size in GB\", \"10\")\n .option(\"--region <slug>\", \"region slug (see `krova regions`)\")\n .option(\"--user-data <script>\", \"cloud-init script\")\n .option(\"--idempotency-key <key>\", \"idempotency key (24h dedupe)\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n // Validate resources client-side so bad input fails with a clear message\n // rather than being coerced to NaN → JSON null → a generic server 400.\n const posInt = (flag: string, raw: string): number => {\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`--${flag} must be a positive integer (got \"${raw}\").`);\n }\n return n;\n };\n const body: Record<string, unknown> = {\n name: opts.name,\n image: opts.image,\n sshPublicKey: opts.sshKey,\n resources: {\n vcpu: posInt(\"vcpu\", opts.vcpu),\n ramGb: posInt(\"ram\", opts.ram),\n diskGb: posInt(\"disk\", opts.disk),\n },\n };\n if (opts.region) body.region = opts.region;\n if (opts.userData) body.userData = opts.userData;\n const cube = await client.cubes.create(\n space,\n body as never,\n opts.idempotencyKey ? { idempotencyKey: opts.idempotencyKey } : undefined\n );\n if (rt.json) return printJSON(cube);\n process.stdout.write(`Created cube ${cube.id} (${cube.state})\\n`);\n });\n}\n\nfunction actionCmd(\n name: string,\n past: string,\n fn: (c: ReturnType<typeof makeClient>[\"cubes\"], space: string, id: string) => Promise<unknown>\n): Command {\n return new Command(name)\n .argument(\"<cube>\", \"cube name or ID\")\n .description(`${name} a Cube`)\n .action(async (cubeRef: string, _opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await fn(client.cubes, space, id);\n if (rt.json) return printJSON({ id, result: past });\n process.stdout.write(`${past} cube ${id}\\n`);\n });\n}\n\nfunction sshPortCmd(): Command {\n return new Command(\"ssh-port\")\n .argument(\"<cube>\", \"cube name or ID\")\n .requiredOption(\"--port <n>\", \"the host port to expose SSH on\")\n .description(\"change the host port a Cube's SSH is reachable on\")\n .action(async (cubeRef: string, opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const cubePort = Number(opts.port);\n if (!Number.isInteger(cubePort) || cubePort < 1 || cubePort > 65535) {\n throw new Error(\"--port must be an integer between 1 and 65535\");\n }\n await client.cubes.update(space, id, { cubePort } as never);\n if (rt.json) return printJSON({ id, cubePort });\n process.stdout.write(`SSH port for cube ${id} set to ${cubePort}\\n`);\n });\n}\n\nexport function cubesCommand(): Command {\n const cubes = new Command(\"cubes\").description(\"manage Cubes (Firecracker microVMs)\");\n cubes.addCommand(listCmd());\n cubes.addCommand(getCmd());\n cubes.addCommand(createCmd());\n cubes.addCommand(actionCmd(\"sleep\", \"Sleeping\", (c, s, id) => c.sleep(s, id)));\n cubes.addCommand(actionCmd(\"wake\", \"Waking\", (c, s, id) => c.wake(s, id)));\n cubes.addCommand(actionCmd(\"delete\", \"Deleting\", (c, s, id) => c.delete(s, id)));\n cubes.addCommand(sshPortCmd());\n return cubes;\n}\n\n// `list` and `get` are also mounted at the root (parity with the Go CLI).\nexport const rootListCommand = listCmd;\nexport const rootGetCommand = getCmd;\n","import type { KrovaClient } from \"@krovacloud/sdk\";\n\n/** Resolve a cube name-or-id to an id (parity with the Go resolveCube):\n * exact id wins; else exactly one exact name match; else a clear error. */\nexport async function resolveCube(\n client: KrovaClient,\n spaceId: string,\n ref: string\n): Promise<string> {\n const { cubes } = await client.cubes.list(spaceId);\n if (cubes.some((c) => c.id === ref)) return ref;\n const byName = cubes.filter((c) => c.name === ref);\n if (byName.length === 1) return byName[0]!.id;\n if (byName.length === 0) {\n throw new Error(\n `no cube named or with ID \"${ref}\" in this space (see \\`krova cubes list\\`)`\n );\n }\n const ids = byName.map((c) => c.id).join(\", \");\n throw new Error(\n `cube name \"${ref}\" is ambiguous: it matches ${byName.length} cubes (${ids}) — use the cube ID instead`\n );\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printTable } from \"../lib/output.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\n\n/** `krova domains` — manage a Cube's custom domains. */\nexport function domainsCommand(): Command {\n const cmd = new Command(\"domains\").description(\"manage a Cube's custom domains\");\n\n cmd\n .command(\"list\")\n .argument(\"<cube>\", \"cube name or ID\")\n .description(\"list the custom domains attached to a Cube\")\n .action(async (cubeRef: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const domains = await client.domains.list(space, id);\n if (rt.json) return printJSON(domains);\n printTable(\n [\"ID\", \"DOMAIN\", \"PORT\", \"STATUS\"],\n domains.map((d) => [d.id, d.domain, String(d.port ?? \"\"), d.status]),\n );\n });\n\n cmd\n .command(\"add\")\n .argument(\"<cube>\", \"cube name or ID\")\n .requiredOption(\"--domain <domain>\", \"the domain name to attach\")\n .requiredOption(\"--port <n>\", \"the in-Cube port to route to\")\n .description(\"attach a custom domain to a Cube\")\n .action(async (cubeRef: string, opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const port = Number(opts.port);\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(`--port must be a valid port (got \"${opts.port}\").`);\n }\n const domain = await client.domains.create(space, id, { domain: opts.domain, port });\n if (rt.json) return printJSON(domain);\n process.stdout.write(`Attached ${domain.domain} (${domain.id}) — status ${domain.status}\\n`);\n });\n\n cmd\n .command(\"rm\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"<domain-id>\", \"the domain mapping ID (see `krova domains list`)\")\n .description(\"detach a custom domain from a Cube\")\n .action(async (cubeRef: string, mappingId: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await client.domains.delete(space, id, mappingId);\n if (rt.json) return printJSON({ id: mappingId, result: \"detached\" });\n process.stdout.write(`Detached domain ${mappingId}\\n`);\n });\n\n return cmd;\n}\n","import { spawn } from \"node:child_process\";\n\nimport { Command } from \"commander\";\n\nimport { rawRequest } from \"../lib/client.js\";\nimport { configPath } from \"../lib/config.js\";\nimport { persistLogin } from \"../lib/persist.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\ninterface StartResponse {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n interval: number;\n expiresIn: number;\n}\ninterface PollResponse {\n apiKey: string;\n spaceId: string;\n}\n\nconst BROWSER_UNAVAILABLE =\n \"Browser login isn't enabled on this server yet — run `krova auth login` to paste an API key from https://krova.cloud\";\n\n/** Only open https URLs, or http to a loopback host. Everything else is unsafe. */\nexport function safeBrowserURL(raw: string): string | null {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n return null;\n }\n if (u.protocol === \"https:\" && u.hostname) return raw;\n if (\n u.protocol === \"http:\" &&\n (u.hostname === \"localhost\" || u.hostname === \"127.0.0.1\" || u.hostname === \"::1\")\n ) {\n return raw;\n }\n return null;\n}\n\nfunction openBrowser(url: string): void {\n const cmd =\n process.platform === \"darwin\" ? \"open\" : process.platform === \"win32\" ? \"start\" : \"xdg-open\";\n const args = process.platform === \"win32\" ? [\"\", url] : [url];\n const child = spawn(cmd, args, { stdio: \"ignore\", detached: true, shell: process.platform === \"win32\" });\n child.on(\"error\", () => {\n /* fall through — the URL was already printed */\n });\n child.unref();\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nexport function loginCommand(): Command {\n return new Command(\"login\")\n .description(\"log in through your browser (device authorization)\")\n .option(\"--no-browser\", \"don't open a browser; just print the URL\")\n .option(\"--context <name>\", \"name for the saved context\")\n .action(async (opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const baseUrl = rt.res.baseUrl;\n\n const start = await rawRequest<StartResponse>({\n method: \"POST\",\n baseUrl,\n path: \"/auth/cli/start\",\n timeoutMs: rt.timeoutMs,\n });\n if (start.status === 404) throw new Error(BROWSER_UNAVAILABLE);\n if (start.status !== 200 || !start.data?.deviceCode) {\n throw new Error(`device login failed to start (HTTP ${start.status})`);\n }\n const s = start.data;\n process.stdout.write(`Your verification code is: ${s.userCode}\\n`);\n\n const target = s.verificationUriComplete || s.verificationUri;\n const safe = safeBrowserURL(target);\n if (safe && opts.browser !== false) {\n process.stdout.write(`Opening ${safe} …\\n`);\n openBrowser(safe);\n } else {\n process.stdout.write(`Open this URL to approve the login:\\n ${target}\\n`);\n }\n\n const intervalMs = Math.max((s.interval || 5) * 1000, 5000);\n const deadline = Date.now() + Math.max(s.expiresIn || 600, 1) * 1000;\n process.stdout.write(\"Waiting for approval…\\n\");\n\n // poll loop\n // eslint-disable-next-line no-constant-condition\n for (;;) {\n if (Date.now() >= deadline) {\n throw new Error(\n \"login timed out: the verification code expired before it was approved\"\n );\n }\n await sleep(intervalMs);\n const poll = await rawRequest<PollResponse>({\n method: \"POST\",\n baseUrl,\n path: \"/auth/cli/poll\",\n body: { deviceCode: s.deviceCode },\n timeoutMs: rt.timeoutMs,\n });\n if (poll.status === 200) {\n if (!poll.data?.apiKey) throw new Error(\"login succeeded but no API key was returned\");\n const { ctxName, spaceName } = await persistLogin({\n apiKey: poll.data.apiKey,\n baseUrl,\n spaceId: poll.data.spaceId,\n ctxName: opts.context as string | undefined,\n timeoutMs: rt.timeoutMs,\n });\n process.stdout.write(`Logged in. Saved context \"${ctxName}\" to ${configPath()}\\n`);\n if (spaceName) process.stdout.write(`Space: ${spaceName}\\n`);\n return;\n }\n if (poll.status === 202 || poll.status === 425 || poll.status === 428) continue;\n if (poll.status === 410) {\n throw new Error(\"login expired: request a new code with `krova login`\");\n }\n if (poll.status === 404) throw new Error(BROWSER_UNAVAILABLE);\n throw new Error(`login failed while polling (HTTP ${poll.status})`);\n }\n });\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printTable } from \"../lib/output.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\n\n/** `krova snapshots` — snapshot and restore a Cube's disk. */\nexport function snapshotsCommand(): Command {\n const cmd = new Command(\"snapshots\").description(\"snapshot and restore a Cube's disk\");\n\n cmd\n .command(\"list\")\n .argument(\"<cube>\", \"cube name or ID\")\n .description(\"list a Cube's snapshots\")\n .action(async (cubeRef: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const snaps = await client.snapshots.list(space, id);\n if (rt.json) return printJSON(snaps);\n printTable(\n [\"ID\", \"NAME\", \"STATUS\", \"KIND\", \"SIZE (BYTES)\", \"CREATED\"],\n snaps.map((s) => [\n s.id,\n s.name,\n s.status,\n s.kind,\n s.sizeBytes == null ? \"\" : String(s.sizeBytes),\n s.createdAt,\n ]),\n );\n });\n\n cmd\n .command(\"create\")\n .argument(\"<cube>\", \"cube name or ID\")\n .option(\"--name <name>\", \"a name for the snapshot\")\n .description(\"create a snapshot of a Cube's disk\")\n .action(async (cubeRef: string, opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const snap = await client.snapshots.create(space, id, opts.name ? { name: opts.name } : {});\n if (rt.json) return printJSON(snap);\n process.stdout.write(`Created snapshot ${snap.id} (${snap.status})\\n`);\n });\n\n cmd\n .command(\"rm\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"<snapshot-id>\", \"the snapshot ID (see `krova snapshots list`)\")\n .description(\"delete a snapshot\")\n .action(async (cubeRef: string, snapshotId: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await client.snapshots.delete(space, id, snapshotId);\n if (rt.json) return printJSON({ id: snapshotId, result: \"deleted\" });\n process.stdout.write(`Deleted snapshot ${snapshotId}\\n`);\n });\n\n cmd\n .command(\"restore\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"<snapshot-id>\", \"the snapshot to restore the Cube's disk from\")\n .description(\"restore a Cube's disk from one of its snapshots (replaces the disk)\")\n .action(async (cubeRef: string, snapshotId: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await client.cubes.restore(space, id, snapshotId);\n if (rt.json) return printJSON({ id, snapshotId, result: \"restore enqueued\" });\n process.stdout.write(`Restore of cube ${id} from ${snapshotId} enqueued\\n`);\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\n\nimport { rawRequest } from \"../lib/client.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\nimport {\n type SshInfo,\n buildSSHArgs,\n execSSH,\n validateSSHHost,\n validateSSHUser,\n writeKnownHosts,\n} from \"../lib/ssh.js\";\n\nconst collect = (v: string, acc: string[]) => {\n acc.push(v);\n return acc;\n};\n\nexport function sshCommand(): Command {\n return new Command(\"ssh\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"[command...]\", \"command to run non-interactively (after --)\")\n .description(\"open an SSH session to a Cube (by name or ID)\")\n .option(\"-i, --identity <file>\", \"SSH identity (private key) file, passed to ssh -i\")\n .option(\"-L, --local-forward <spec>\", \"local port forward, passed to ssh -L (repeatable)\", collect, [])\n .option(\"-R, --remote-forward <spec>\", \"remote port forward, passed to ssh -R (repeatable)\", collect, [])\n .action(async (cubeRef: string, command: string[], opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n\n const { status, data } = await rawRequest<SshInfo>({\n method: \"GET\",\n baseUrl: rt.res.baseUrl,\n path: `/spaces/${space}/cubes/${id}/ssh`,\n apiKey: rt.res.apiKey,\n timeoutMs: rt.timeoutMs,\n });\n if (status === 404) {\n throw new Error(\n `SSH info isn't available on this server yet — try \\`krova cubes get ${cubeRef}\\` for the Cube's IP and ssh manually`\n );\n }\n if (status === 401 || status === 403) {\n throw new Error(`SSH info request was rejected (HTTP ${status})`);\n }\n if (status !== 200 || !data?.host) {\n throw new Error(`couldn't fetch SSH info (HTTP ${status})`);\n }\n\n const info: SshInfo = {\n host: data.host,\n port: data.port ?? 0,\n user: data.user ?? \"\",\n hostKeys: data.hostKeys ?? [],\n };\n validateSSHHost(info.host);\n validateSSHUser(info.user);\n if (info.port < 0 || info.port > 65535) throw new Error(\"invalid ssh port\");\n\n let knownHosts = \"\";\n if (info.hostKeys.length) {\n knownHosts = writeKnownHosts(info);\n } else {\n process.stderr.write(\n \"note: this server didn't provide host keys — using ssh trust-on-first-use (host-key checking stays on).\\n\"\n );\n }\n\n const args = buildSSHArgs(info, {\n identity: opts.identity as string | undefined,\n localFwd: opts.localForward as string[],\n remoteFwd: opts.remoteForward as string[],\n knownHosts,\n remoteCmd: command,\n });\n process.exitCode = await execSSH(args);\n });\n}\n","// SSH: fetch connection info, pin host keys, build a hardened `ssh` argv, exec.\n// Ports the Go CLI's option-injection guards and known_hosts pinning verbatim.\n\nimport { spawn } from \"node:child_process\";\nimport { appendFileSync, chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nimport { configDir } from \"./config.js\";\nimport { join } from \"node:path\";\n\nexport interface SshHostKey {\n type: string;\n key: string;\n}\nexport interface SshInfo {\n host: string;\n port: number;\n user: string;\n hostKeys: SshHostKey[];\n}\n\nexport interface SshOptions {\n identity?: string;\n localFwd?: string[];\n remoteFwd?: string[];\n knownHosts?: string;\n remoteCmd?: string[];\n}\n\n// Characters an ssh host must never contain (option/metacharacter injection).\nconst HOST_BANNED = new Set(\n \"@/\\\\'\\\"`$;&|<>(){}*?!#=,\".split(\"\")\n);\n// User is slightly looser — it may contain '=' (host may not).\nconst USER_BANNED = new Set(\n \"@/\\\\'\\\"`$;&|<>(){}*?!#,\".split(\"\")\n);\n\nexport function validateSSHHost(host: string): void {\n const h = host.trim();\n if (!h) throw new Error(\"empty host\");\n if (h.startsWith(\"-\")) throw new Error(\"host must not start with '-'\");\n for (const r of h) {\n const code = r.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n throw new Error(\"host contains whitespace or control characters\");\n }\n if (HOST_BANNED.has(r)) {\n throw new Error(`host contains a disallowed character ${JSON.stringify(r)}`);\n }\n }\n}\n\nexport function validateSSHUser(user: string): void {\n const u = user.trim();\n if (!u) return; // empty user is allowed\n if (u.startsWith(\"-\")) throw new Error(\"user must not start with '-'\");\n for (const r of u) {\n const code = r.codePointAt(0) ?? 0;\n if (code <= 0x20 || code === 0x7f) {\n throw new Error(\"user contains whitespace or control characters\");\n }\n if (USER_BANNED.has(r)) {\n throw new Error(`user contains a disallowed character ${JSON.stringify(r)}`);\n }\n }\n}\n\n/** known_hosts host field: \"[host]:port\" when the port isn't the default 22. */\nexport function knownHostsHost(host: string, port: number): string {\n if (port > 0 && port !== 22) return `[${host}]:${port}`;\n return host;\n}\n\nexport function knownHostsPath(): string {\n return join(configDir(), \"known_hosts\");\n}\n\n/** Pin the cube's host keys to ~/.config/krova/known_hosts (0600), pruning any\n * stale line for the same host:port (rebuilt cubes can reuse an IP+DNAT port). */\nexport function writeKnownHosts(info: SshInfo): string {\n const path = knownHostsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n const field = knownHostsHost(info.host, info.port);\n\n let existing = \"\";\n try {\n existing = readFileSync(path, \"utf8\");\n } catch {\n existing = \"\";\n }\n const kept = existing\n .split(\"\\n\")\n .filter((line) => line.trim() && line.split(/\\s+/)[0] !== field);\n writeFileSync(path, kept.length ? `${kept.join(\"\\n\")}\\n` : \"\", { mode: 0o600 });\n chmodSync(path, 0o600);\n\n for (const k of info.hostKeys) {\n appendFileSync(path, `${field} ${k.type} ${k.key}\\n`);\n }\n return path;\n}\n\n/** Build the ssh argv. `--` is placed immediately before the destination —\n * the primary option-injection guard (with the validators above). */\nexport function buildSSHArgs(info: SshInfo, o: SshOptions): string[] {\n const args: string[] = [];\n if (o.knownHosts) {\n args.push(\"-o\", `UserKnownHostsFile=${o.knownHosts}`, \"-o\", \"StrictHostKeyChecking=yes\");\n }\n if ((o.identity ?? \"\").trim()) args.push(\"-i\", o.identity as string);\n if (info.port > 0) args.push(\"-p\", String(info.port));\n for (const l of o.localFwd ?? []) if (l.trim()) args.push(\"-L\", l);\n for (const r of o.remoteFwd ?? []) if (r.trim()) args.push(\"-R\", r);\n const user = info.user.trim();\n const target = user ? `${user}@${info.host}` : info.host;\n args.push(\"--\", target);\n args.push(...(o.remoteCmd ?? []));\n return args;\n}\n\n/** Exec system ssh, inheriting stdio (interactive unless a remote cmd is given). */\nexport function execSSH(args: string[]): Promise<number> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"ssh\", args, { stdio: \"inherit\" });\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => resolve(code ?? 0));\n });\n}\n","import { Command } from \"commander\";\n\nimport { printJSON, printTable } from \"../lib/output.js\";\nimport { resolveCube } from \"../lib/resolve.js\";\nimport { getRuntime, makeClient, resolveSpace } from \"../lib/runtime.js\";\n\n/** `krova tcp` — manage a Cube's TCP port mappings. */\nexport function tcpCommand(): Command {\n const cmd = new Command(\"tcp\").description(\"manage a Cube's TCP port mappings\");\n\n cmd\n .command(\"list\")\n .argument(\"<cube>\", \"cube name or ID\")\n .description(\"list a Cube's TCP port mappings\")\n .action(async (cubeRef: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const maps = await client.tcpMappings.list(space, id);\n if (rt.json) return printJSON(maps);\n printTable(\n [\"ID\", \"CUBE PORT\", \"HOST PORT\", \"LABEL\", \"STATUS\", \"SSH\"],\n maps.map((m) => [\n m.id,\n String(m.cubePort),\n String(m.hostPort),\n m.label ?? \"\",\n m.status,\n m.isSsh ? \"yes\" : \"no\",\n ]),\n );\n });\n\n cmd\n .command(\"add\")\n .argument(\"<cube>\", \"cube name or ID\")\n .requiredOption(\"--port <n>\", \"the in-Cube port to expose\")\n .option(\n \"--whitelist <cidr>\",\n \"restrict access to this IP/CIDR (repeatable)\",\n (val: string, acc: string[]) => {\n acc.push(val);\n return acc;\n },\n [] as string[],\n )\n .description(\"expose a Cube TCP port on the host, optionally IP-restricted\")\n .action(async (cubeRef: string, opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n const cubePort = Number(opts.port);\n if (!Number.isInteger(cubePort) || cubePort <= 0 || cubePort > 65535) {\n throw new Error(`--port must be a valid port (got \"${opts.port}\").`);\n }\n const whitelist = opts.whitelist as string[];\n const mapping = await client.tcpMappings.create(space, id, {\n cubePort,\n ...(whitelist.length ? { whitelistIps: whitelist } : {}),\n });\n if (rt.json) return printJSON(mapping);\n process.stdout.write(\n `Mapped cube port ${mapping.cubePort} → host port ${mapping.hostPort} (${mapping.id})\\n`,\n );\n });\n\n cmd\n .command(\"rm\")\n .argument(\"<cube>\", \"cube name or ID\")\n .argument(\"<mapping-id>\", \"the mapping ID (see `krova tcp list`)\")\n .description(\"remove a TCP port mapping\")\n .action(async (cubeRef: string, mappingId: string, _opts, c: Command) => {\n const rt = getRuntime(c);\n const client = makeClient(rt.res);\n const space = await resolveSpace(rt);\n const id = await resolveCube(client, space, cubeRef);\n await client.tcpMappings.delete(space, id, mappingId);\n if (rt.json) return printJSON({ id: mappingId, result: \"removed\" });\n process.stdout.write(`Removed TCP mapping ${mappingId}\\n`);\n });\n\n return cmd;\n}\n","import { createRequire } from \"node:module\";\n\nimport { Command } from \"commander\";\n\nimport { printJSON } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nconst require = createRequire(import.meta.url);\nconst pkg = require(\"../package.json\") as { version: string };\n\nexport const CLI_VERSION = pkg.version;\n\nexport function versionCommand(): Command {\n return new Command(\"version\")\n .description(\"print the krova CLI version\")\n .action((_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const info = {\n version: CLI_VERSION,\n node: process.version,\n platform: `${process.platform}/${process.arch}`,\n };\n if (rt.json) return printJSON(info);\n process.stdout.write(`krova ${info.version} (node ${info.node}, ${info.platform})\\n`);\n });\n}\n","import { createServer } from \"node:http\";\n\nimport { verifyKrovaWebhookOrThrow } from \"@krovacloud/webhook\";\nimport { Command } from \"commander\";\n\nimport { printJSON } from \"../lib/output.js\";\nimport { getRuntime } from \"../lib/runtime.js\";\n\nconst DEFAULT_LISTEN_HOST = \"127.0.0.1\";\nconst DEFAULT_LISTEN_PORT = 4666;\n\n/**\n * Parse a `--addr` value into `{ host, port }`. Handles `host:port`, a bare host\n * (e.g. `localhost`), a bare port, bracketed IPv6 (`[::1]:4666`), and bare IPv6\n * (`::1`). Exported for testing.\n */\nexport function parseListenAddr(addr: string): { host: string; port: number } {\n const s = (addr ?? \"\").trim();\n // Bracketed IPv6: [::1] or [::1]:4666\n const bracket = s.match(/^\\[([^\\]]+)\\](?::(\\d+))?$/);\n if (bracket) {\n return { host: bracket[1] as string, port: bracket[2] ? Number(bracket[2]) : DEFAULT_LISTEN_PORT };\n }\n // Two or more colons and no brackets ⇒ a bare IPv6 address with no port.\n if ((s.match(/:/g)?.length ?? 0) >= 2) {\n return { host: s, port: DEFAULT_LISTEN_PORT };\n }\n // Single colon ⇒ host:port.\n const i = s.lastIndexOf(\":\");\n if (i > 0) {\n const port = Number(s.slice(i + 1));\n return {\n host: s.slice(0, i),\n port: Number.isInteger(port) && port > 0 && port <= 65535 ? port : DEFAULT_LISTEN_PORT,\n };\n }\n // No colon ⇒ a bare port (all digits) or a bare host.\n if (/^\\d+$/.test(s)) {\n const port = Number(s);\n return { host: DEFAULT_LISTEN_HOST, port: port > 0 && port <= 65535 ? port : DEFAULT_LISTEN_PORT };\n }\n return { host: s || DEFAULT_LISTEN_HOST, port: DEFAULT_LISTEN_PORT };\n}\n\nexport function webhooksCommand(): Command {\n const wh = new Command(\"webhooks\").description(\"developer tools for Krova Cloud webhooks\");\n\n wh.command(\"listen\")\n .description(\"run a local server that verifies + prints incoming webhook deliveries\")\n .option(\"--addr <host:port>\", \"address to listen on\", \"127.0.0.1:4666\")\n .option(\"--path <path>\", \"path to accept POSTs on\", \"/\")\n .option(\"--secret <secret>\", \"signing secret (or the KROVA_WEBHOOK_SECRET env var)\")\n .action((opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const secret = (opts.secret as string) || process.env.KROVA_WEBHOOK_SECRET || \"\";\n if (!secret) {\n throw new Error(\n \"a signing secret is required: pass --secret or set KROVA_WEBHOOK_SECRET\"\n );\n }\n const { host, port } = parseListenAddr(String(opts.addr));\n const wantPath = String(opts.path);\n\n const server = createServer((req, res) => {\n const reqPath = (req.url ?? \"/\").split(\"?\")[0];\n if (req.method !== \"POST\" || reqPath !== wantPath) {\n res.writeHead(405);\n res.end(\"method not allowed\");\n return;\n }\n const chunks: Buffer[] = [];\n let size = 0;\n req.on(\"data\", (c: Buffer) => {\n size += c.length;\n if (size <= 1_048_576) chunks.push(c);\n });\n req.on(\"end\", () => {\n const body = Buffer.concat(chunks).toString(\"utf8\");\n const sig = (req.headers[\"x-krova-signature\"] as string) || \"\";\n try {\n verifyKrovaWebhookOrThrow({ payload: body, signature: sig, secret });\n } catch (e) {\n process.stderr.write(`✗ rejected delivery: ${(e as Error).message}\\n`);\n res.writeHead(400);\n res.end(\"invalid signature\");\n return;\n }\n try {\n const event = JSON.parse(body);\n if (rt.json) process.stdout.write(`${JSON.stringify(event)}\\n`);\n else printJSON(event);\n } catch {\n process.stdout.write(`${body}\\n`);\n }\n res.writeHead(200);\n res.end(\"ok\");\n });\n });\n\n server.listen(port, host, () => {\n process.stderr.write(`Listening for webhooks on http://${host}:${port}${wantPath}\\n`);\n });\n const stop = () => server.close(() => process.exit(0));\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n });\n\n return wh;\n}\n","import { Command } from \"commander\";\n\nimport { find, maskKey } from \"../lib/config.js\";\nimport { printJSON, printKeyValue } from \"../lib/output.js\";\nimport { fetchSpace, getRuntime } from \"../lib/runtime.js\";\n\nexport function whoamiCommand(): Command {\n return new Command(\"whoami\")\n .description(\"show the current context, space, and base URL\")\n .action(async (_opts, cmd: Command) => {\n const rt = getRuntime(cmd);\n const ctx = find(rt.cfg, rt.res.contextName);\n let spaceId = rt.res.spaceId;\n let spaceName = ctx?.spaceName ?? \"\";\n let spaceLive = false;\n\n if (rt.res.apiKey) {\n const sp = await fetchSpace(rt.res.baseUrl, rt.res.apiKey, rt.timeoutMs);\n if (sp) {\n spaceId = sp.id;\n spaceName = sp.name ?? spaceName;\n spaceLive = true;\n }\n }\n\n if (rt.json) {\n return printJSON({\n context: rt.res.contextName,\n spaceId,\n spaceName,\n apiKeyMasked: maskKey(rt.res.apiKey),\n apiKeySource: rt.res.apiKeySource,\n baseUrl: rt.res.baseUrl,\n spaceLive,\n });\n }\n printKeyValue([\n [\"Context\", rt.res.contextName || \"—\"],\n [\"Space\", spaceName || \"—\"],\n [\"Space ID\", spaceId || \"—\"],\n [\"API key\", rt.res.apiKey ? `${maskKey(rt.res.apiKey)} (${rt.res.apiKeySource})` : \"—\"],\n [\"Base URL\", rt.res.baseUrl],\n ]);\n });\n}\n"],"mappings":"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","names":["Command","resolve","Command","fetch","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","spawn","chmodSync","mkdirSync","readFileSync","writeFileSync","dirname","join","mkdirSync","dirname","readFileSync","writeFileSync","chmodSync","resolve","spawn","Command","Command","Command","Command","require","Command","Command","Command","Command","Command","Command"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krovacloud/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Krova Cloud CLI (krova) — manage Cubes (Firecracker microVMs), browse the catalog, and log in, from your terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Krova Inc.",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"commander": "^15.0.0",
|
|
43
|
-
"@krovacloud/
|
|
44
|
-
"@krovacloud/
|
|
43
|
+
"@krovacloud/sdk": "0.3.0",
|
|
44
|
+
"@krovacloud/webhook": "0.1.4"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^26.1.0",
|