cassian-cli 0.3.1 → 0.3.3

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.
@@ -3,42 +3,47 @@ import { writeFileSync, existsSync } from "fs";
3
3
  import { green, dim, bold } from "../lib/output.js";
4
4
  import { fatal } from "../lib/errors.js";
5
5
  import { AGENT_URL } from "../lib/constants.js";
6
- const GPU_METADATA = {
7
- "h100": { memory: "80GB", hint: "best for large training" },
8
- "a100": { memory: "80GB", hint: "reliable workhorse" },
9
- "l40s": { memory: "48GB", hint: "great for inference" },
10
- "l4": { memory: "24GB", hint: "efficient inference" },
11
- "a10g": { memory: "24GB", hint: "good all-rounder" },
12
- "rtx4090": { memory: "24GB", hint: "fast, affordable" },
13
- "rtx3090": { memory: "24GB" },
14
- };
15
- async function fetchAvailableGpus() {
6
+ const ALL_GPUS = [
7
+ { label: "H100 SXM", value: "h100-sxm", memory: "80GB", hint: "best for large training" },
8
+ { label: "H100 PCIe", value: "h100-pcie", memory: "80GB" },
9
+ { label: "A100 SXM", value: "a100-sxm", memory: "80GB", hint: "reliable workhorse" },
10
+ { label: "A100 PCIe", value: "a100-pcie", memory: "80GB" },
11
+ { label: "L40S", value: "l40s", memory: "48GB", hint: "great for inference" },
12
+ { label: "L4", value: "l4", memory: "24GB", hint: "efficient inference" },
13
+ { label: "A10G", value: "a10g", memory: "24GB", hint: "good all-rounder" },
14
+ { label: "RTX 4090", value: "rtx4090", memory: "24GB", hint: "fast, affordable" },
15
+ { label: "RTX 3090", value: "rtx3090", memory: "24GB" },
16
+ ];
17
+ async function fetchAvailability() {
16
18
  try {
17
19
  const resp = await fetch(`${AGENT_URL}/v1/gpu-types`);
18
20
  if (!resp.ok)
19
- return [];
21
+ return {};
20
22
  const { gpu_types } = await resp.json();
21
- const options = [];
22
- for (const gpu of gpu_types) {
23
- const type = gpu.type.toLowerCase();
24
- const meta = GPU_METADATA[type];
25
- const label = type.toUpperCase().replace("RTX", "RTX ");
26
- const hint = meta
27
- ? `${meta.memory}${meta.hint ? ` — ${meta.hint}` : ""} — ${gpu.available} available`
28
- : `${gpu.available} available`;
29
- options.push({ label, value: type, hint });
30
- }
31
- return options;
23
+ const map = {};
24
+ for (const g of gpu_types)
25
+ map[g.type.toLowerCase()] = g.available;
26
+ return map;
32
27
  }
33
28
  catch {
34
- return [];
29
+ return {};
35
30
  }
36
31
  }
37
- const FALLBACK_GPU_OPTIONS = [
38
- { label: "RTX 3090", value: "rtx3090", hint: "24GB" },
39
- { label: "L4", value: "l4", hint: "24GB — efficient inference" },
40
- { label: "A10G", value: "a10g", hint: "24GB — good all-rounder" },
41
- ];
32
+ function buildGpuOptions(availability) {
33
+ return ALL_GPUS.map(gpu => {
34
+ const count = availability[gpu.value] ?? 0;
35
+ const parts = [gpu.memory];
36
+ if (gpu.hint)
37
+ parts.push(gpu.hint);
38
+ if (count > 0) {
39
+ parts.push(`${count} available`);
40
+ }
41
+ else {
42
+ parts.push("unavailable");
43
+ }
44
+ return { label: gpu.label, value: gpu.value, hint: parts.join(" — ") };
45
+ });
46
+ }
42
47
  function prompt(rl, question, fallback) {
43
48
  return new Promise((resolve) => {
44
49
  rl.question(question, (answer) => resolve(answer.trim() || fallback));
@@ -123,9 +128,10 @@ export async function init(options = {}) {
123
128
  console.log(dim(" Press enter to accept defaults. Or pass flags to skip: cassian init --help\n"));
124
129
  const name = options.name || await prompt(rl, ` Instance name ${dim(`[${dirName}]`)}: `, dirName);
125
130
  console.log();
126
- const liveGpus = await fetchAvailableGpus();
127
- const gpuOptions = liveGpus.length > 0 ? liveGpus : FALLBACK_GPU_OPTIONS;
128
- const defaultGpu = gpuOptions[0].value;
131
+ const availability = await fetchAvailability();
132
+ const gpuOptions = buildGpuOptions(availability);
133
+ const availableTypes = Object.keys(availability).filter(k => availability[k] > 0);
134
+ const defaultGpu = availableTypes[0] || "rtx3090";
129
135
  const gpuType = options.gpu || await promptChoice(rl, " GPU type:", gpuOptions, defaultGpu);
130
136
  console.log();
131
137
  const gpuCountStr = options.gpuCount || await promptChoice(rl, " Number of GPUs:", [
@@ -99,20 +99,6 @@ export async function up() {
99
99
  await new Promise((r) => setTimeout(r, 1000));
100
100
  spinner.text = "Starting instance...";
101
101
  }
102
- // Validate GPU type against what the host offers before provisioning
103
- if (config.gpu.type) {
104
- const gpus = await client.get("/v1/gpus").catch(() => null);
105
- if (gpus && gpus.gpus.length > 0) {
106
- const available = gpus.gpus[0].name.toLowerCase().replace(/[\s_]/g, "-");
107
- const requested = config.gpu.type.toLowerCase().replace(/[\s_]/g, "-");
108
- // Check if the requested type is a substring match of what's available
109
- if (!available.includes(requested) && !requested.includes(available.split("-").pop())) {
110
- spinner.fail("GPU type not available");
111
- const names = [...new Set(gpus.gpus.map((g) => g.name))];
112
- fatal(`GPU type '${config.gpu.type}' is not available on this host.`, `Available: ${names.join(", ")} — update gpu.type in cassian.yaml`);
113
- }
114
- }
115
- }
116
102
  const instance = await client.post("/v1/instances", {
117
103
  name: config.name,
118
104
  gpu_count: config.gpu.count,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cassian-cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "The Cassian GPU cloud CLI — provision GPUs, sync files, and run workloads from your terminal.",
5
5
  "type": "module",
6
6
  "bin": {