@krovacloud/cli 0.4.3 → 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 CHANGED
@@ -3,6 +3,16 @@
3
3
  All notable changes to `@krovacloud/cli` are documented here.
4
4
 
5
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.
6
16
  ## 0.4.3
7
17
 
8
18
  ### Fixed
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
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 Command10 } from "commander";
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 Command5 } from "commander";
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 Command5("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) => {
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 Command6 } from "commander";
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 Command6("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) => {
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 Command7 } from "commander";
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 Command7("version").description("print the krova CLI version").action((_opts, cmd) => {
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,7 +1101,7 @@ 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 Command8 } from "commander";
1104
+ import { Command as Command11 } from "commander";
942
1105
  var DEFAULT_LISTEN_HOST = "127.0.0.1";
943
1106
  var DEFAULT_LISTEN_PORT = 4666;
944
1107
  function parseListenAddr(addr) {
@@ -965,7 +1128,7 @@ function parseListenAddr(addr) {
965
1128
  return { host: s || DEFAULT_LISTEN_HOST, port: DEFAULT_LISTEN_PORT };
966
1129
  }
967
1130
  function webhooksCommand() {
968
- const wh = new Command8("webhooks").description("developer tools for Krova Cloud webhooks");
1131
+ const wh = new Command11("webhooks").description("developer tools for Krova Cloud webhooks");
969
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) => {
970
1133
  const rt = getRuntime(cmd);
971
1134
  const secret = opts.secret || process.env.KROVA_WEBHOOK_SECRET || "";
@@ -1026,9 +1189,9 @@ function webhooksCommand() {
1026
1189
  }
1027
1190
 
1028
1191
  // src/commands/whoami.ts
1029
- import { Command as Command9 } from "commander";
1192
+ import { Command as Command12 } from "commander";
1030
1193
  function whoamiCommand() {
1031
- return new Command9("whoami").description("show the current context, space, and base URL").action(async (_opts, cmd) => {
1194
+ return new Command12("whoami").description("show the current context, space, and base URL").action(async (_opts, cmd) => {
1032
1195
  const rt = getRuntime(cmd);
1033
1196
  const ctx = find(rt.cfg, rt.res.contextName);
1034
1197
  let spaceId = rt.res.spaceId;
@@ -1077,7 +1240,7 @@ function addGlobalOptions(cmd) {
1077
1240
  add("--json", "output machine-readable JSON instead of a table");
1078
1241
  add("--timeout <duration>", "per-request timeout", "30s");
1079
1242
  }
1080
- var program = new Command10();
1243
+ var program = new Command13();
1081
1244
  program.name("krova").description(
1082
1245
  "krova is the command-line interface for Krova Cloud \u2014 manage Cubes (Firecracker microVMs), browse the catalog, and receive webhooks."
1083
1246
  ).version(CLI_VERSION, "-v, --version", "print the krova CLI version").showHelpAfterError();
@@ -1086,6 +1249,9 @@ program.addCommand(authCommand());
1086
1249
  program.addCommand(contextCommand());
1087
1250
  program.addCommand(whoamiCommand());
1088
1251
  program.addCommand(cubesCommand());
1252
+ program.addCommand(domainsCommand());
1253
+ program.addCommand(snapshotsCommand());
1254
+ program.addCommand(tcpCommand());
1089
1255
  program.addCommand(sshCommand());
1090
1256
  program.addCommand(rootListCommand());
1091
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\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","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.4.3",
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/sdk": "0.2.0",
44
- "@krovacloud/webhook": "0.1.5"
43
+ "@krovacloud/sdk": "0.3.0",
44
+ "@krovacloud/webhook": "0.1.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/node": "^26.1.0",