@lizard-build/cli 0.3.74 → 0.3.76

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.
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerSandbox(program: Command): void;
@@ -0,0 +1,409 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import fs from "node:fs";
4
+ import * as https from "node:https";
5
+ import * as http from "node:http";
6
+ import * as p from "@clack/prompts";
7
+ import { api, getBaseURL, getRawText, streamSSE, withQuery, withScope } from "../lib/api.js";
8
+ import { getToken } from "../lib/auth.js";
9
+ import { resolveProjectScope } from "../lib/resolve.js";
10
+ import { resolveWorkspace } from "../lib/picker.js";
11
+ import { success, info, error, isJSONMode, printJSON, table, statusColor, timeAgo, isTTY } from "../lib/format.js";
12
+ const VALID_TEMPLATES = ["base", "code-interpreter-v1"];
13
+ function parseIntOption(v) {
14
+ const n = parseInt(v, 10);
15
+ if (Number.isNaN(n))
16
+ throw new Error(`Invalid number: ${v}`);
17
+ return n;
18
+ }
19
+ /** Resolve a volume by name or ID. Requires a project — volumes are project-scoped. */
20
+ async function resolveVolumeId(projectId, scope, nameOrId) {
21
+ const volumes = await api.get(withScope(`/api/projects/${projectId}/volumes`, scope));
22
+ const lower = nameOrId.toLowerCase();
23
+ const match = volumes.find((v) => v.id.toLowerCase() === lower || v.name.toLowerCase() === lower);
24
+ if (!match) {
25
+ throw new Error(`Volume "${nameOrId}" not found. Available: ${volumes.map((v) => v.name).join(", ") || "(none)"}`);
26
+ }
27
+ return match.id;
28
+ }
29
+ function printSandboxList(sandboxes) {
30
+ if (isJSONMode()) {
31
+ printJSON(sandboxes);
32
+ return;
33
+ }
34
+ if (sandboxes.length === 0) {
35
+ console.log("No sandboxes. Use `lizard sandbox create`.");
36
+ return;
37
+ }
38
+ table(["ID", "Template", "Status", "Region", "CPU/Mem", "Created"], sandboxes.map((s) => [
39
+ s.id,
40
+ s.template,
41
+ statusColor(s.status),
42
+ s.region,
43
+ `${s.cpus} vCPU / ${s.memoryMb} MB`,
44
+ timeAgo(s.startedAt),
45
+ ]));
46
+ }
47
+ export function registerSandbox(program) {
48
+ const sb = program
49
+ .command("sandbox")
50
+ .alias("sb")
51
+ .description("Manage ephemeral compute sandboxes");
52
+ sb.command("create")
53
+ .description("Create a sandbox")
54
+ .option("-t, --template <name>", `Template (${VALID_TEMPLATES.join(", ")})`, "base")
55
+ .option("--cpus <n>", "vCPUs (1-8, default 1)", parseIntOption)
56
+ .option("--memory <mb>", "Memory in MB (128-8192, default 2048)", parseIntOption)
57
+ .option("--timeout <ms>", "Idle timeout in ms before auto-stop (default 300000)", parseIntOption)
58
+ .option("--region <code>", "Region to create the sandbox in")
59
+ .option("--volume <name-or-id>", "Attach a persistent volume (requires --project or a linked project)")
60
+ .option("-p, --project <id>", "Associate with a project (name, slug, or ID)")
61
+ .option("-w, --workspace <ws>", "Workspace to create the sandbox in")
62
+ .action(async (opts) => {
63
+ if (opts.template && !VALID_TEMPLATES.includes(opts.template)) {
64
+ throw new Error(`Unknown template "${opts.template}". Available: ${VALID_TEMPLATES.join(", ")}`);
65
+ }
66
+ let projectId;
67
+ let workspaceId;
68
+ let scope;
69
+ if (opts.project || opts.volume) {
70
+ const resolved = await resolveProjectScope(opts.project);
71
+ projectId = resolved.projectId;
72
+ scope = resolved.scope;
73
+ workspaceId = resolved.scope.workspaceId ?? undefined;
74
+ }
75
+ else if (opts.workspace) {
76
+ workspaceId = (await resolveWorkspace(opts.workspace)).id;
77
+ }
78
+ let volumeId;
79
+ if (opts.volume) {
80
+ volumeId = await resolveVolumeId(projectId, scope, opts.volume);
81
+ }
82
+ const spinner = isJSONMode() ? null : ora("Creating sandbox...").start();
83
+ let sandbox;
84
+ try {
85
+ sandbox = await api.post("/api/sandboxes", {
86
+ template: opts.template,
87
+ cpus: opts.cpus,
88
+ memoryMb: opts.memory,
89
+ timeoutMs: opts.timeout,
90
+ region: opts.region,
91
+ volumeId,
92
+ workspaceId,
93
+ projectId,
94
+ });
95
+ }
96
+ catch (e) {
97
+ spinner?.stop();
98
+ throw e;
99
+ }
100
+ spinner?.stop();
101
+ if (isJSONMode()) {
102
+ printJSON(sandbox);
103
+ return;
104
+ }
105
+ success(`Sandbox ${chalk.bold(sandbox.id)} created`);
106
+ info(chalk.dim(` Template: ${sandbox.template} Region: ${sandbox.region}`));
107
+ info(chalk.dim(` Exec: lizard sandbox exec ${sandbox.id} -- <cmd>`));
108
+ });
109
+ sb.command("list")
110
+ .alias("ls")
111
+ .description("List sandboxes in the linked (or given) project")
112
+ .option("-p, --project <id>", "List sandboxes for this project instead of the linked one")
113
+ .option("--all", "List every sandbox across all your workspaces")
114
+ .action(async (opts) => {
115
+ // `--all` is the only way to get the workspace-wide view. Without it we
116
+ // scope to a project — the linked one, or `--project` — and error like
117
+ // `ps` when nothing is linked, so the default never leaks other members'
118
+ // or other projects' sandboxes.
119
+ if (opts.all) {
120
+ const sandboxes = await api.get("/api/sandboxes");
121
+ printSandboxList(sandboxes);
122
+ return;
123
+ }
124
+ const { projectId, scope } = await resolveProjectScope(opts.project);
125
+ const sandboxes = await api.get(withScope(`/api/projects/${projectId}/sandboxes`, scope));
126
+ printSandboxList(sandboxes);
127
+ });
128
+ sb.command("rm")
129
+ .alias("delete")
130
+ .argument("<id>", "Sandbox ID")
131
+ .description("Delete a sandbox")
132
+ .option("-y, --yes", "Skip confirmation")
133
+ .action(async (id, opts) => {
134
+ if (!opts.yes && isTTY() && !isJSONMode()) {
135
+ const ok = await p.confirm({ message: `Delete sandbox ${chalk.bold(id)}?` });
136
+ if (p.isCancel(ok) || !ok)
137
+ process.exit(5);
138
+ }
139
+ await api.delete(`/api/sandboxes/${id}`);
140
+ if (isJSONMode())
141
+ printJSON({ id, status: "deleted" });
142
+ else
143
+ success(`Sandbox ${chalk.bold(id)} deleted`);
144
+ });
145
+ sb.command("pause")
146
+ .argument("<id>", "Sandbox ID")
147
+ .description("Pause a sandbox")
148
+ .action(async (id) => {
149
+ const updated = await api.post(`/api/sandboxes/${id}/pause`);
150
+ if (isJSONMode())
151
+ printJSON(updated);
152
+ else
153
+ success(`Sandbox ${chalk.bold(id)} paused`);
154
+ });
155
+ sb.command("resume")
156
+ .argument("<id>", "Sandbox ID")
157
+ .description("Resume a paused sandbox")
158
+ .action(async (id) => {
159
+ const updated = await api.post(`/api/sandboxes/${id}/resume`);
160
+ if (isJSONMode())
161
+ printJSON(updated);
162
+ else
163
+ success(`Sandbox ${chalk.bold(id)} resumed`);
164
+ });
165
+ sb.command("timeout")
166
+ .argument("<id>", "Sandbox ID")
167
+ .argument("<ms>", "New idle timeout in milliseconds", parseIntOption)
168
+ .description("Update a sandbox's idle timeout")
169
+ .action(async (id, ms) => {
170
+ const updated = await api.post(`/api/sandboxes/${id}/timeout`, { timeoutMs: ms });
171
+ if (isJSONMode())
172
+ printJSON(updated);
173
+ else
174
+ success(`Sandbox ${chalk.bold(id)} timeout set to ${ms}ms`);
175
+ });
176
+ sb.command("exec")
177
+ .argument("<id>", "Sandbox ID")
178
+ .argument("[cmd...]", "Command and args to run (pass after `--`, e.g. `-- ls -la /tmp`)")
179
+ .description("Execute a command inside a sandbox, streaming output")
180
+ .addHelpText("after", `
181
+ Examples:
182
+ lizard sandbox exec sb_abc123 -- ls -la /tmp
183
+ lizard sandbox exec sb_abc123 -- python3 script.py`)
184
+ .action(async (id, cmdArgs) => {
185
+ if (cmdArgs.length === 0) {
186
+ throw new Error("No command given. Usage: lizard sandbox exec <id> -- <cmd> [args...]");
187
+ }
188
+ // The server runs `cmd` via `/bin/sh -c` only when it's a string — an
189
+ // array execs the binary directly with no PATH lookup or shell
190
+ // features (pipes, globs). Shell-quote and join so `sh -c` sees it.
191
+ const cmd = cmdArgs.map(shellQuote).join(" ");
192
+ if (!isJSONMode()) {
193
+ process.stdout.write(chalk.dim(`$ ${cmd}\n`));
194
+ }
195
+ const exitCode = await execStream(id, cmd, (stream, line) => {
196
+ if (stream === "stderr")
197
+ process.stderr.write(line + "\n");
198
+ else
199
+ process.stdout.write(line + "\n");
200
+ });
201
+ process.exit(exitCode);
202
+ });
203
+ sb.command("logs")
204
+ .argument("<id>", "Sandbox ID")
205
+ .description("Stream sandbox vm-agent logs")
206
+ .option("--tail <n>", "Number of historical lines to include before following", "200")
207
+ .action(async (id, opts) => {
208
+ info(chalk.dim("Streaming logs... (Ctrl+C to stop)\n"));
209
+ await streamSSE(withQuery(`/api/sandboxes/${id}/logs`, { tail: opts.tail }), (_event, data) => {
210
+ let parsed;
211
+ try {
212
+ parsed = JSON.parse(data);
213
+ }
214
+ catch {
215
+ parsed = { message: data };
216
+ }
217
+ if (isJSONMode()) {
218
+ process.stdout.write(JSON.stringify(parsed) + "\n");
219
+ }
220
+ else {
221
+ process.stdout.write((parsed.message ?? data) + "\n");
222
+ }
223
+ return true;
224
+ });
225
+ });
226
+ sb.command("expose")
227
+ .argument("<id>", "Sandbox ID")
228
+ .argument("<port>", "Port to expose", parseIntOption)
229
+ .description("Expose a sandbox port over HTTPS")
230
+ .action(async (id, port) => {
231
+ const result = await api.post(`/api/sandboxes/${id}/expose/${port}`);
232
+ if (isJSONMode()) {
233
+ printJSON(result);
234
+ return;
235
+ }
236
+ success(`Port ${port} exposed`);
237
+ info(` ${chalk.cyan(result.url)}`);
238
+ });
239
+ sb.command("unexpose")
240
+ .argument("<id>", "Sandbox ID")
241
+ .argument("<port>", "Port to unexpose", parseIntOption)
242
+ .description("Remove an exposed sandbox port")
243
+ .action(async (id, port) => {
244
+ await api.delete(`/api/sandboxes/${id}/expose/${port}`);
245
+ if (isJSONMode())
246
+ printJSON({ id, port, status: "unexposed" });
247
+ else
248
+ success(`Port ${port} unexposed`);
249
+ });
250
+ registerSandboxFiles(sb);
251
+ }
252
+ function registerSandboxFiles(sb) {
253
+ const files = sb.command("files").description("Manage files inside a sandbox");
254
+ files
255
+ .command("ls")
256
+ .argument("<id>", "Sandbox ID")
257
+ .argument("[path]", "Directory to list", "/")
258
+ .description("List a directory inside a sandbox")
259
+ .action(async (id, path) => {
260
+ const entries = await api.get(withQuery(`/api/sandboxes/${id}/files/list`, { path }));
261
+ if (isJSONMode()) {
262
+ printJSON(entries);
263
+ return;
264
+ }
265
+ if (entries.length === 0) {
266
+ console.log("(empty)");
267
+ return;
268
+ }
269
+ table(["Type", "Name", "Size"], entries.map((e) => [e.type, e.name, e.type === "dir" ? "" : `${e.size}B`]));
270
+ });
271
+ files
272
+ .command("cat")
273
+ .argument("<id>", "Sandbox ID")
274
+ .argument("<path>", "File path inside the sandbox")
275
+ .description("Print a file from inside a sandbox")
276
+ .action(async (id, path) => {
277
+ const content = await getRawText(withQuery(`/api/sandboxes/${id}/files`, { path }));
278
+ process.stdout.write(content);
279
+ });
280
+ files
281
+ .command("put")
282
+ .argument("<id>", "Sandbox ID")
283
+ .argument("<local>", "Local file path")
284
+ .argument("<remote>", "Destination path inside the sandbox")
285
+ .description("Upload a local file into a sandbox")
286
+ .action(async (id, local, remote) => {
287
+ const content = fs.readFileSync(local, "utf-8");
288
+ await api.post(`/api/sandboxes/${id}/files`, { path: remote, content });
289
+ if (isJSONMode())
290
+ printJSON({ id, path: remote, status: "written" });
291
+ else
292
+ success(`Wrote ${chalk.bold(remote)} in sandbox ${id}`);
293
+ });
294
+ files
295
+ .command("get")
296
+ .argument("<id>", "Sandbox ID")
297
+ .argument("<remote>", "File path inside the sandbox")
298
+ .argument("<local>", "Local destination path")
299
+ .description("Download a file from a sandbox")
300
+ .action(async (id, remote, local) => {
301
+ const content = await getRawText(withQuery(`/api/sandboxes/${id}/files`, { path: remote }));
302
+ fs.writeFileSync(local, content);
303
+ if (isJSONMode())
304
+ printJSON({ id, path: remote, local, status: "downloaded" });
305
+ else
306
+ success(`Downloaded ${chalk.bold(remote)} to ${local}`);
307
+ });
308
+ files
309
+ .command("rm")
310
+ .argument("<id>", "Sandbox ID")
311
+ .argument("<path>", "Path inside the sandbox")
312
+ .description("Delete a file or directory inside a sandbox")
313
+ .action(async (id, path) => {
314
+ await api.delete(`/api/sandboxes/${id}/files`, { path });
315
+ if (isJSONMode())
316
+ printJSON({ id, path, status: "deleted" });
317
+ else
318
+ success(`Deleted ${chalk.bold(path)} in sandbox ${id}`);
319
+ });
320
+ }
321
+ /** Run a command inside a sandbox, streaming output. Resolves with the exit
322
+ * code: the remote command's code from the `exit` event, or 1 when the
323
+ * server reported an `error` event without one. Mirrors ssh.ts's parser. */
324
+ function execStream(sandboxId, cmd, onLine) {
325
+ return new Promise((resolve, reject) => {
326
+ let exitCode = null;
327
+ let sawError = false;
328
+ const baseURL = getBaseURL();
329
+ const url = new URL(`${baseURL}/api/sandboxes/${sandboxId}/exec`);
330
+ const token = getToken();
331
+ const body = JSON.stringify({ cmd });
332
+ const reqHeaders = {
333
+ "Content-Type": "application/json",
334
+ "Content-Length": String(Buffer.byteLength(body)),
335
+ Accept: "text/event-stream",
336
+ };
337
+ if (token)
338
+ reqHeaders["Authorization"] = `Bearer ${token}`;
339
+ const transport = url.protocol === "https:" ? https : http;
340
+ const req = transport.request({
341
+ hostname: url.hostname,
342
+ port: url.port || (url.protocol === "https:" ? 443 : 80),
343
+ path: url.pathname,
344
+ method: "POST",
345
+ headers: reqHeaders,
346
+ }, (res) => {
347
+ if (res.statusCode && res.statusCode >= 400) {
348
+ let errBody = "";
349
+ res.on("data", (c) => (errBody += c.toString()));
350
+ res.on("end", () => reject(new Error(`exec failed ${res.statusCode}: ${errBody}`)));
351
+ return;
352
+ }
353
+ let buf = "";
354
+ let currentEvent = "";
355
+ res.setEncoding("utf8");
356
+ res.on("data", (chunk) => {
357
+ buf += chunk;
358
+ const lines = buf.split("\n");
359
+ buf = lines.pop() ?? "";
360
+ for (const line of lines) {
361
+ const trimmed = line.replace(/\r$/, "");
362
+ if (trimmed === "") {
363
+ currentEvent = "";
364
+ }
365
+ else if (trimmed.startsWith("event:")) {
366
+ currentEvent = trimmed.slice(6).trim();
367
+ }
368
+ else if (trimmed.startsWith("data:")) {
369
+ const data = trimmed.slice(5).trimStart();
370
+ if (currentEvent === "exit") {
371
+ try {
372
+ exitCode = JSON.parse(data).exitCode ?? 0;
373
+ }
374
+ catch { }
375
+ }
376
+ else if (currentEvent === "error") {
377
+ sawError = true;
378
+ error(data);
379
+ }
380
+ else {
381
+ try {
382
+ const parsed = JSON.parse(data);
383
+ onLine(parsed.stream ?? "stdout", parsed.line ?? data);
384
+ }
385
+ catch {
386
+ onLine("stdout", data);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ });
392
+ res.on("end", () => resolve(exitCode ?? (sawError ? 1 : 0)));
393
+ res.on("error", reject);
394
+ });
395
+ req.on("error", reject);
396
+ req.write(body);
397
+ req.end();
398
+ });
399
+ }
400
+ /** POSIX single-quote escaping. Safe-token chars pass through verbatim;
401
+ * anything else gets wrapped in '…' with embedded `'` rewritten as `'\''`. */
402
+ function shellQuote(arg) {
403
+ if (arg === "")
404
+ return "''";
405
+ if (/^[A-Za-z0-9_./:=@%+,-]+$/.test(arg))
406
+ return arg;
407
+ return "'" + arg.replace(/'/g, "'\\''") + "'";
408
+ }
409
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/commands/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function registerVolume(program: Command): void;
@@ -0,0 +1,103 @@
1
+ import chalk from "chalk";
2
+ import * as p from "@clack/prompts";
3
+ import { api, withScope } from "../lib/api.js";
4
+ import { resolveProjectScope } from "../lib/resolve.js";
5
+ import { success, info, isJSONMode, printJSON, table, isTTY } from "../lib/format.js";
6
+ /** Resolve a volume by name or ID within a project. Mirrors resolveService. */
7
+ async function resolveVolume(projectId, scope, nameOrId) {
8
+ const volumes = await api.get(withScope(`/api/projects/${projectId}/volumes`, scope));
9
+ const lower = nameOrId.toLowerCase();
10
+ const match = volumes.find((v) => v.id.toLowerCase() === lower || v.name.toLowerCase() === lower);
11
+ if (!match) {
12
+ throw new Error(`Volume "${nameOrId}" not found. Available: ${volumes.map((v) => v.name).join(", ") || "(none)"}`);
13
+ }
14
+ return match;
15
+ }
16
+ function parseIntOption(v) {
17
+ const n = parseInt(v, 10);
18
+ if (Number.isNaN(n))
19
+ throw new Error(`Invalid number: ${v}`);
20
+ return n;
21
+ }
22
+ export function registerVolume(program) {
23
+ const vol = program
24
+ .command("volume")
25
+ .alias("vol")
26
+ .description("Manage persistent volumes for sandboxes");
27
+ vol
28
+ .command("list")
29
+ .alias("ls")
30
+ .description("List volumes in a project")
31
+ .option("-p, --project <id>", "Project name, slug, or ID")
32
+ .action(async (opts) => {
33
+ const { projectId, scope } = await resolveProjectScope(opts.project);
34
+ const volumes = await api.get(withScope(`/api/projects/${projectId}/volumes`, scope));
35
+ if (isJSONMode()) {
36
+ printJSON(volumes);
37
+ return;
38
+ }
39
+ if (volumes.length === 0) {
40
+ console.log("No volumes. Use `lizard volume create <name>`.");
41
+ return;
42
+ }
43
+ table(["Name", "ID", "Size", "Status", "Attached to"], volumes.map((v) => [
44
+ v.name,
45
+ chalk.dim(v.id),
46
+ `${v.sizeGb} GB`,
47
+ v.status,
48
+ v.attachedTo ? chalk.dim(v.attachedTo) : chalk.dim("—"),
49
+ ]));
50
+ });
51
+ vol
52
+ .command("create")
53
+ .argument("<name>", "Volume name")
54
+ .description("Create a persistent volume")
55
+ .option("--size <gb>", "Size in GB (1-100, default 5)", parseIntOption)
56
+ .option("-p, --project <id>", "Project name, slug, or ID")
57
+ .action(async (name, opts) => {
58
+ const { projectId, scope } = await resolveProjectScope(opts.project);
59
+ const sizeGb = opts.size ?? 5;
60
+ if (sizeGb < 1 || sizeGb > 100) {
61
+ throw new Error(`--size must be between 1 and 100 (got ${sizeGb}).`);
62
+ }
63
+ if (!isJSONMode())
64
+ info(`Creating volume ${chalk.cyan(name)}...`);
65
+ const created = await api.post(withScope(`/api/projects/${projectId}/volumes`, scope), { name, sizeGb });
66
+ if (isJSONMode()) {
67
+ printJSON(created);
68
+ return;
69
+ }
70
+ success(`Volume ${chalk.bold(created.name)} created (${created.sizeGb} GB)`);
71
+ info(chalk.dim(` ID: ${created.id}`));
72
+ info(chalk.dim(` Attach it to a sandbox: lizard sandbox create --volume ${created.id}`));
73
+ });
74
+ vol
75
+ .command("rm")
76
+ .alias("delete")
77
+ .argument("<volume>", "Volume name or ID")
78
+ .description("Delete a volume")
79
+ .option("-p, --project <id>", "Project name, slug, or ID")
80
+ .option("-y, --yes", "Skip confirmation")
81
+ .action(async (nameOrId, opts) => {
82
+ const { projectId, scope } = await resolveProjectScope(opts.project);
83
+ const volume = await resolveVolume(projectId, scope, nameOrId);
84
+ if (volume.attachedTo) {
85
+ throw new Error(`Volume "${volume.name}" is attached to sandbox ${volume.attachedTo}. Delete the sandbox first.`);
86
+ }
87
+ if (!opts.yes && isTTY() && !isJSONMode()) {
88
+ const ok = await p.confirm({
89
+ message: `Delete volume ${chalk.bold(volume.name)}? This cannot be undone.`,
90
+ });
91
+ if (p.isCancel(ok) || !ok)
92
+ process.exit(5);
93
+ }
94
+ await api.delete(withScope(`/api/projects/${projectId}/volumes/${volume.id}`, scope));
95
+ if (isJSONMode()) {
96
+ printJSON({ id: volume.id, status: "deleted" });
97
+ }
98
+ else {
99
+ success(`Volume ${chalk.bold(volume.name)} deleted`);
100
+ }
101
+ });
102
+ }
103
+ //# sourceMappingURL=volume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume.js","sourceRoot":"","sources":["../../src/commands/volume.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -64,6 +64,7 @@ import { registerRedeploy } from "./commands/redeploy.js";
64
64
  import { registerRegions } from "./commands/regions.js";
65
65
  import { registerRestart } from "./commands/restart.js";
66
66
  import { registerRun } from "./commands/run.js";
67
+ import { registerSandbox } from "./commands/sandbox.js";
67
68
  import { registerScale } from "./commands/scale.js";
68
69
  import { registerSecrets } from "./commands/secrets.js";
69
70
  import { registerService } from "./commands/service.js";
@@ -73,6 +74,7 @@ import { registerStatus } from "./commands/status.js";
73
74
  import { registerUnlink } from "./commands/unlink.js";
74
75
  import { registerUp } from "./commands/up.js";
75
76
  import { registerUpgrade } from "./commands/upgrade.js";
77
+ import { registerVolume } from "./commands/volume.js";
76
78
  import { registerWhoami } from "./commands/whoami.js";
77
79
  import { registerWorkspace } from "./commands/workspace.js";
78
80
  const program = new Command();
@@ -146,6 +148,7 @@ registerRedeploy(program);
146
148
  registerRegions(program);
147
149
  registerRestart(program);
148
150
  registerRun(program);
151
+ registerSandbox(program);
149
152
  registerScale(program);
150
153
  registerSecrets(program);
151
154
  registerService(program);
@@ -155,6 +158,7 @@ registerStatus(program);
155
158
  registerUnlink(program);
156
159
  registerUp(program);
157
160
  registerUpgrade(program);
161
+ registerVolume(program);
158
162
  registerWhoami(program);
159
163
  registerWorkspace(program);
160
164
  // Root help already carries the full AGENTS_HELP block; mirror a compact pointer