cassian-cli 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init.d.ts +1 -4
- package/dist/commands/init.js +18 -59
- package/dist/commands/up.js +15 -7
- package/dist/index.js +4 -10
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/dist/commands/init.d.ts
CHANGED
|
@@ -2,11 +2,8 @@ export interface InitOptions {
|
|
|
2
2
|
name?: string;
|
|
3
3
|
gpu?: string;
|
|
4
4
|
gpuCount?: string;
|
|
5
|
-
memory?: string;
|
|
6
|
-
shm?: string;
|
|
7
5
|
disk?: string;
|
|
8
|
-
|
|
9
|
-
syncignore?: string;
|
|
6
|
+
storage?: string;
|
|
10
7
|
yes?: boolean;
|
|
11
8
|
}
|
|
12
9
|
export declare function init(options?: InitOptions): Promise<void>;
|
package/dist/commands/init.js
CHANGED
|
@@ -64,33 +64,18 @@ function promptChoice(rl, question, choices, fallback) {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
function buildYaml(opts) {
|
|
67
|
-
const volName = opts.name.replace(/[^a-z0-9-]/g, "-") + "-data";
|
|
68
|
-
const setupLine = opts.setup ? ` setup: ${opts.setup}\n` : "";
|
|
69
|
-
const noSyncLines = opts.noSync.length
|
|
70
|
-
? ` no_sync:\n${opts.noSync.map(p => ` - "${p}"`).join("\n")}\n` : "";
|
|
71
67
|
const storageLines = opts.storage.length
|
|
72
|
-
?
|
|
68
|
+
? `\nstorage:\n${opts.storage.map(p => ` - ${p}`).join("\n")}\n` : "";
|
|
73
69
|
const excludeLines = opts.exclude.length
|
|
74
|
-
?
|
|
70
|
+
? `\nworkspace:\n exclude:\n${opts.exclude.map(p => ` - "${p}"`).join("\n")}\n` : "";
|
|
75
71
|
return `name: ${opts.name}
|
|
76
72
|
|
|
77
73
|
gpu:
|
|
78
74
|
count: ${opts.gpuCount}
|
|
79
75
|
type: ${opts.gpuType}
|
|
80
76
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
volumes:
|
|
84
|
-
- name: ${volName}
|
|
85
|
-
size: ${opts.diskSize}
|
|
86
|
-
mount: /workspace
|
|
87
|
-
|
|
88
|
-
resources:
|
|
89
|
-
memory: ${opts.memory}
|
|
90
|
-
shm_size: ${opts.shmSize}
|
|
91
|
-
|
|
92
|
-
workspace:
|
|
93
|
-
${setupLine}${noSyncLines}${storageLines}${excludeLines}`;
|
|
77
|
+
disk: ${opts.diskSize}
|
|
78
|
+
${storageLines}${excludeLines}`;
|
|
94
79
|
}
|
|
95
80
|
export async function init(options = {}) {
|
|
96
81
|
if (existsSync("cassian.yaml")) {
|
|
@@ -98,18 +83,12 @@ export async function init(options = {}) {
|
|
|
98
83
|
}
|
|
99
84
|
const dirName = process.cwd().split("/").pop().toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
100
85
|
const skipPrompts = options.yes ?? false;
|
|
101
|
-
|
|
102
|
-
const allFlagsProvided = !!(options.name && options.gpu && options.gpuCount && options.memory && options.disk);
|
|
103
|
-
if (allFlagsProvided || skipPrompts) {
|
|
86
|
+
if (skipPrompts) {
|
|
104
87
|
const yaml = buildYaml({
|
|
105
88
|
name: options.name || dirName,
|
|
106
89
|
gpuType: options.gpu || "rtx3090",
|
|
107
90
|
gpuCount: parseInt(options.gpuCount || "1"),
|
|
108
|
-
memory: options.memory || "32G",
|
|
109
|
-
shmSize: options.shm || "16G",
|
|
110
91
|
diskSize: options.disk || "50G",
|
|
111
|
-
setup: options.setup || (existsSync("requirements.txt") ? "pip install -r /workspace/requirements.txt" : ""),
|
|
112
|
-
noSync: ["checkpoints/", "outputs/"],
|
|
113
92
|
storage: [],
|
|
114
93
|
exclude: ["node_modules/", ".venv/", "__pycache__/", "*.pyc", "wandb/"],
|
|
115
94
|
});
|
|
@@ -125,7 +104,7 @@ export async function init(options = {}) {
|
|
|
125
104
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
126
105
|
console.log();
|
|
127
106
|
console.log(bold(" Let's set up your Cassian project."));
|
|
128
|
-
console.log(dim(" Press enter to accept defaults
|
|
107
|
+
console.log(dim(" Press enter to accept defaults.\n"));
|
|
129
108
|
const name = options.name || await prompt(rl, ` Instance name ${dim(`[${dirName}]`)}: `, dirName);
|
|
130
109
|
console.log();
|
|
131
110
|
const availability = await fetchAvailability();
|
|
@@ -140,48 +119,28 @@ export async function init(options = {}) {
|
|
|
140
119
|
], "1");
|
|
141
120
|
const gpuCount = parseInt(gpuCountStr);
|
|
142
121
|
console.log();
|
|
143
|
-
const
|
|
144
|
-
{ label: "
|
|
145
|
-
{ label: "
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{ label: "4 GB", value: "4G" }, { label: "8 GB", value: "8G" },
|
|
150
|
-
{ label: "16 GB", value: "16G", hint: "recommended" }, { label: "32 GB", value: "32G" },
|
|
151
|
-
], "16G");
|
|
152
|
-
console.log();
|
|
153
|
-
const diskSize = options.disk || await promptChoice(rl, " Workspace disk size:", [
|
|
154
|
-
{ label: "20 GB", value: "20G" }, { label: "50 GB", value: "50G", hint: "recommended" },
|
|
155
|
-
{ label: "100 GB", value: "100G" }, { label: "200 GB", value: "200G" },
|
|
156
|
-
{ label: "500 GB", value: "500G", hint: "for large datasets / checkpoints" }, { label: "1 TB", value: "1T" },
|
|
122
|
+
const diskSize = options.disk || await promptChoice(rl, " Disk size (fast storage for code + training):", [
|
|
123
|
+
{ label: "20 GB", value: "20G" },
|
|
124
|
+
{ label: "50 GB", value: "50G", hint: "recommended" },
|
|
125
|
+
{ label: "100 GB", value: "100G" },
|
|
126
|
+
{ label: "200 GB", value: "200G" },
|
|
127
|
+
{ label: "500 GB", value: "500G" },
|
|
157
128
|
], "50G");
|
|
158
129
|
console.log();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
const setup = setupRaw === "skip" ? "" : setupRaw;
|
|
163
|
-
console.log();
|
|
164
|
-
console.log(dim(" Folders that stay on the GPU instance but don't sync to your machine"));
|
|
165
|
-
console.log(dim(" (large files like checkpoints, training outputs — still persists across sessions)"));
|
|
166
|
-
const noSyncRaw = options.syncignore ?? await prompt(rl, ` No-sync folders ${dim("[checkpoints/, outputs/]")}: `, "");
|
|
167
|
-
const noSync = noSyncRaw
|
|
168
|
-
? noSyncRaw.split(",").map(s => s.trim()).filter(Boolean)
|
|
169
|
-
: ["checkpoints/", "outputs/"];
|
|
170
|
-
console.log();
|
|
171
|
-
console.log(dim(" Folders streamed from cloud storage (huge datasets, pretrained models)"));
|
|
172
|
-
console.log(dim(" (doesn't use instance disk — reads directly from cloud)"));
|
|
173
|
-
const storageRaw = await prompt(rl, ` Cloud storage folders ${dim("[none]")}: `, "");
|
|
130
|
+
console.log(dim(" Large folders that need more storage (datasets, pretrained models)"));
|
|
131
|
+
console.log(dim(" These get unlimited storage, accessible at /workspace/<folder>"));
|
|
132
|
+
const storageRaw = options.storage ?? await prompt(rl, ` Storage folders ${dim("[none]")}: `, "");
|
|
174
133
|
const storage = storageRaw
|
|
175
|
-
? storageRaw.split(",").map(s => s.trim()).filter(Boolean)
|
|
134
|
+
? storageRaw.split(",").map(s => s.trim().replace(/\/+$/, "/")).filter(Boolean)
|
|
176
135
|
: [];
|
|
177
136
|
console.log();
|
|
178
|
-
console.log(dim(" Folders to exclude
|
|
137
|
+
console.log(dim(" Folders to exclude (build artifacts, can be recreated)"));
|
|
179
138
|
const excludeRaw = await prompt(rl, ` Exclude ${dim("[node_modules/, .venv/, __pycache__/, *.pyc, wandb/]")}: `, "");
|
|
180
139
|
const exclude = excludeRaw
|
|
181
140
|
? excludeRaw.split(",").map(s => s.trim()).filter(Boolean)
|
|
182
141
|
: ["node_modules/", ".venv/", "__pycache__/", "*.pyc", "wandb/"];
|
|
183
142
|
rl.close();
|
|
184
|
-
const yaml = buildYaml({ name, gpuType, gpuCount,
|
|
143
|
+
const yaml = buildYaml({ name, gpuType, gpuCount, diskSize, storage, exclude });
|
|
185
144
|
writeFileSync("cassian.yaml", yaml);
|
|
186
145
|
console.log();
|
|
187
146
|
console.log(` ${green("✓")} Created cassian.yaml`);
|
package/dist/commands/up.js
CHANGED
|
@@ -54,9 +54,15 @@ export async function up() {
|
|
|
54
54
|
console.log();
|
|
55
55
|
info("Instance", config.name);
|
|
56
56
|
info("GPUs", `${config.gpu.count}x ${config.gpu.type || "any"}`);
|
|
57
|
-
if (config.
|
|
57
|
+
if (config.disk) {
|
|
58
|
+
info("Disk", config.disk);
|
|
59
|
+
}
|
|
60
|
+
else if (config.volumes?.length) {
|
|
58
61
|
info("Storage", config.volumes.map((v) => `${v.size} at ${v.mount}`).join(", "));
|
|
59
62
|
}
|
|
63
|
+
if (config.storage?.length) {
|
|
64
|
+
info("Storage", config.storage.join(", "));
|
|
65
|
+
}
|
|
60
66
|
console.log();
|
|
61
67
|
const vm = dev.vm;
|
|
62
68
|
if (vm) {
|
|
@@ -99,17 +105,19 @@ export async function up() {
|
|
|
99
105
|
await new Promise((r) => setTimeout(r, 1000));
|
|
100
106
|
spinner.text = "Starting instance...";
|
|
101
107
|
}
|
|
108
|
+
// Build volumes: use new `disk` field or legacy `volumes` array
|
|
109
|
+
const volumes = config.volumes
|
|
110
|
+
? config.volumes.map((v) => ({ name: v.name, size_gb: parseSizeToGb(v.size), mount: v.mount }))
|
|
111
|
+
: config.disk
|
|
112
|
+
? [{ name: config.name, size_gb: parseSizeToGb(config.disk), mount: "/workspace" }]
|
|
113
|
+
: [];
|
|
102
114
|
const instance = await client.post("/v1/instances", {
|
|
103
115
|
name: config.name,
|
|
104
116
|
gpu_count: config.gpu.count,
|
|
105
117
|
gpu_type: config.gpu.type || null,
|
|
106
118
|
image: config.image || "default",
|
|
107
119
|
ssh_public_key: sshPubKey,
|
|
108
|
-
volumes
|
|
109
|
-
name: v.name,
|
|
110
|
-
size_gb: parseSizeToGb(v.size),
|
|
111
|
-
mount: v.mount,
|
|
112
|
-
})),
|
|
120
|
+
volumes,
|
|
113
121
|
resources: {
|
|
114
122
|
memory: config.resources?.memory || null,
|
|
115
123
|
shm_size: config.resources?.shm_size || null,
|
|
@@ -117,7 +125,7 @@ export async function up() {
|
|
|
117
125
|
},
|
|
118
126
|
workspace: {
|
|
119
127
|
no_sync: config.workspace?.no_sync || [],
|
|
120
|
-
storage: config.workspace?.storage || [],
|
|
128
|
+
storage: config.storage || config.workspace?.storage || [],
|
|
121
129
|
exclude: config.workspace?.exclude || config.workspace?.syncignore || [],
|
|
122
130
|
},
|
|
123
131
|
});
|
package/dist/index.js
CHANGED
|
@@ -87,21 +87,15 @@ program
|
|
|
87
87
|
.option("--name <name>", "Instance name")
|
|
88
88
|
.option("--gpu <type>", "GPU type (e.g. h100-sxm, a100-sxm, rtx3090)")
|
|
89
89
|
.option("--gpu-count <n>", "Number of GPUs")
|
|
90
|
-
.option("--
|
|
91
|
-
.option("--
|
|
92
|
-
.option("--
|
|
93
|
-
.option("--setup <cmd>", "Setup command to run after sync")
|
|
94
|
-
.option("--syncignore <list>", "Comma-separated patterns to exclude from sync")
|
|
95
|
-
.option("-y, --yes", "Skip all prompts, use defaults or provided flags")
|
|
90
|
+
.option("--disk <size>", "Disk size (e.g. 50G, 200G)")
|
|
91
|
+
.option("--storage <folders>", "Comma-separated storage folders (e.g. datasets/,models/)")
|
|
92
|
+
.option("-y, --yes", "Skip all prompts, use defaults")
|
|
96
93
|
.action((opts) => init({
|
|
97
94
|
name: opts.name,
|
|
98
95
|
gpu: opts.gpu,
|
|
99
96
|
gpuCount: opts.gpuCount,
|
|
100
|
-
memory: opts.memory,
|
|
101
|
-
shm: opts.shm,
|
|
102
97
|
disk: opts.disk,
|
|
103
|
-
|
|
104
|
-
syncignore: opts.syncignore,
|
|
98
|
+
storage: opts.storage,
|
|
105
99
|
yes: opts.yes,
|
|
106
100
|
}));
|
|
107
101
|
program.parse();
|
package/dist/types.d.ts
CHANGED