@arker-ai/sdk 0.3.0 → 0.5.2

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/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,618 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ARKER_ORG_ID,
4
+ Arker,
5
+ ArkerError
6
+ } from "./chunk-YGZOUXII.js";
7
+
8
+ // src/cli.ts
9
+ import { readFileSync, existsSync } from "fs";
10
+ import { homedir } from "os";
11
+ import { join } from "path";
12
+ import * as readline from "readline/promises";
13
+ import { stdin as input, stdout as output } from "process";
14
+ function parseArgs(argv) {
15
+ const positional = [];
16
+ const flags = {};
17
+ for (let i = 0; i < argv.length; i++) {
18
+ const arg = argv[i];
19
+ if (arg.startsWith("--")) {
20
+ const eq = arg.indexOf("=");
21
+ if (eq !== -1) {
22
+ flags[arg.slice(2, eq)] = arg.slice(eq + 1);
23
+ } else {
24
+ const next = argv[i + 1];
25
+ if (next !== void 0 && !next.startsWith("--")) {
26
+ flags[arg.slice(2)] = next;
27
+ i++;
28
+ } else {
29
+ flags[arg.slice(2)] = true;
30
+ }
31
+ }
32
+ } else if (arg.startsWith("-") && arg.length > 1) {
33
+ flags[arg.slice(1)] = true;
34
+ } else {
35
+ positional.push(arg);
36
+ }
37
+ }
38
+ return { positional, flags };
39
+ }
40
+ function readFileConfig() {
41
+ const path = join(homedir(), ".arker", "config.json");
42
+ if (!existsSync(path)) return {};
43
+ try {
44
+ return JSON.parse(readFileSync(path, "utf8"));
45
+ } catch {
46
+ return {};
47
+ }
48
+ }
49
+ function clientFromArgs(args) {
50
+ const file = readFileConfig();
51
+ const apiKey = args.flags["api-key"] ?? process.env.ARKER_API_KEY ?? file.apiKey;
52
+ const baseUrl = args.flags["base-url"] ?? process.env.ARKER_BASE_URL ?? file.baseUrl;
53
+ const controlBaseUrl = args.flags["control-base-url"] ?? process.env.ARKER_CONTROL_BASE_URL;
54
+ const region = args.flags.region ?? process.env.ARKER_REGION ?? file.region;
55
+ const provider = args.flags.provider ?? process.env.ARKER_PROVIDER;
56
+ if (!apiKey) {
57
+ die("Missing API key. Set ARKER_API_KEY or pass --api-key.");
58
+ }
59
+ if (!baseUrl && !region) {
60
+ die("Missing region. Set ARKER_REGION or pass --region (e.g. us-west-2). --provider (aws|aws-burst) defaults to aws.");
61
+ }
62
+ return new Arker({ apiKey, baseUrl, region, provider, controlBaseUrl });
63
+ }
64
+ function out(value) {
65
+ if (typeof value === "string") {
66
+ output.write(value + "\n");
67
+ } else {
68
+ output.write(JSON.stringify(value, null, 2) + "\n");
69
+ }
70
+ }
71
+ function err(msg) {
72
+ process.stderr.write(`arker: ${msg}
73
+ `);
74
+ }
75
+ function die(msg) {
76
+ err(msg);
77
+ process.exit(1);
78
+ }
79
+ function fmtVm(vm) {
80
+ const provider = vm.provider ?? "?";
81
+ const region = vm.region ?? "?";
82
+ const name = vm.name ?? "\u2014";
83
+ const state = vm.state ?? "?";
84
+ return `${vm.vm_id ?? vm.id} ${provider}-${region} ${state} ${name}`;
85
+ }
86
+ async function cmdVms(args, client) {
87
+ const sub = args.positional[0];
88
+ const rest = args.positional.slice(1);
89
+ switch (sub) {
90
+ case void 0:
91
+ case "ls":
92
+ case "list": {
93
+ const res = await client.listVms({
94
+ provider: args.flags.provider,
95
+ region: args.flags.region,
96
+ state: args.flags.state,
97
+ cursor: args.flags.cursor,
98
+ limit: numFlag(args, "limit")
99
+ });
100
+ if (args.flags.json) return out({ vms: res.vms, next_cursor: res.nextCursor });
101
+ for (const vm of res.vms) out(fmtVm(vm));
102
+ if (res.nextCursor) out(`# next_cursor=${res.nextCursor}`);
103
+ return;
104
+ }
105
+ case "get": {
106
+ const id = rest[0] ?? die("usage: arker vms get <vm_id>");
107
+ out(await client.getVm(id));
108
+ return;
109
+ }
110
+ case "rm":
111
+ case "delete": {
112
+ const id = rest[0] ?? die("usage: arker vms rm <vm_id>");
113
+ const r = await client.vm(id).delete();
114
+ if (r.deleted) out(`deleted ${id}`);
115
+ else {
116
+ err("delete failed");
117
+ process.exitCode = 1;
118
+ }
119
+ return;
120
+ }
121
+ case "fork": {
122
+ await cmdFork({ ...args, positional: rest }, client);
123
+ return;
124
+ }
125
+ case "run": {
126
+ await cmdRun({ ...args, positional: rest }, client);
127
+ return;
128
+ }
129
+ default:
130
+ die(`unknown vms subcommand: ${sub}`);
131
+ }
132
+ }
133
+ async function cmdFork(args, client) {
134
+ const refPositional = args.positional[0];
135
+ const srcVmIdFlag = args.flags["source-vm-id"];
136
+ const srcVmNameFlag = args.flags["source-vm-name"];
137
+ const srcOrgIdFlag = args.flags["source-org-id"];
138
+ const name = args.flags.name;
139
+ const publicFlag = boolFlag(args, "public");
140
+ let sourceVmId = srcVmIdFlag;
141
+ let sourceVmName = srcVmNameFlag;
142
+ let sourceOrgId = srcOrgIdFlag;
143
+ if (!sourceVmId && !sourceVmName && refPositional) {
144
+ sourceVmName = refPositional;
145
+ }
146
+ if (!sourceVmId && !sourceVmName) {
147
+ die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]");
148
+ }
149
+ const computer = await client.fork({
150
+ sourceVmId,
151
+ sourceVmName,
152
+ sourceOrgId,
153
+ name,
154
+ public: publicFlag
155
+ });
156
+ out({ vm_id: computer.id });
157
+ }
158
+ async function cmdRun(args, client) {
159
+ const vmId = args.positional[0] ?? die("usage: arker run <vm_id> <command...>");
160
+ const command = args.positional.slice(1).join(" ");
161
+ if (!command) die("missing command to run");
162
+ const result = await client.vm(vmId).run(command, {
163
+ background: boolFlag(args, "background"),
164
+ timeout: numFlag(args, "timeout"),
165
+ acquire: args.flags.acquire,
166
+ release: args.flags.release
167
+ });
168
+ if (result.type === "completed") {
169
+ process.stdout.write(new TextDecoder().decode(result.stdout));
170
+ if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
171
+ process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
172
+ return;
173
+ }
174
+ out({ run_id: result.runId, state: result.state });
175
+ }
176
+ async function cmdRuns(args, client) {
177
+ const sub = args.positional[0];
178
+ const rest = args.positional.slice(1);
179
+ switch (sub) {
180
+ case "ls":
181
+ case "list": {
182
+ const vm = rest[0] ?? die("usage: arker runs ls <vm_id>");
183
+ const res = await client.vm(vm).listRuns({
184
+ state: args.flags.state,
185
+ cursor: args.flags.cursor,
186
+ limit: numFlag(args, "limit")
187
+ });
188
+ if (args.flags.json) return out(res);
189
+ for (const r of res.runs) {
190
+ out(`${r.run_id} ${r.state} ${r.exit_code ?? "-"} ${r.command ?? ""}`);
191
+ }
192
+ if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
193
+ return;
194
+ }
195
+ case "get": {
196
+ const [vm, runId] = rest;
197
+ if (!vm || !runId) die("usage: arker runs get <vm_id> <run_id>");
198
+ out(await client.vm(vm).getRun(runId));
199
+ return;
200
+ }
201
+ case "rm":
202
+ case "cancel": {
203
+ const [vm, runId] = rest;
204
+ if (!vm || !runId) die("usage: arker runs rm <vm_id> <run_id>");
205
+ const r = await client.vm(vm).cancelRun(runId);
206
+ out(r.cancelled ? `cancelled ${runId}` : "cancel failed");
207
+ return;
208
+ }
209
+ default:
210
+ die(`usage: arker runs <ls|get|rm> ...`);
211
+ }
212
+ }
213
+ async function cmdSessions(args, client) {
214
+ const sub = args.positional[0];
215
+ const rest = args.positional.slice(1);
216
+ const vm = rest[0];
217
+ switch (sub) {
218
+ case "ls":
219
+ case "list": {
220
+ if (!vm) die("usage: arker sessions ls <vm_id>");
221
+ const res = await client.vm(vm).listSessions({
222
+ state: args.flags.state,
223
+ cursor: args.flags.cursor,
224
+ limit: numFlag(args, "limit")
225
+ });
226
+ if (args.flags.json) return out(res);
227
+ for (const s of res.sessions) {
228
+ out(`${s.session_id} ${s.state} ${s.cwd}`);
229
+ }
230
+ if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
231
+ return;
232
+ }
233
+ case "get": {
234
+ if (!vm) die("usage: arker sessions get <vm_id> <session_id>");
235
+ const sid = rest[1] ?? die("missing session_id");
236
+ out(await client.vm(vm).getSession(sid));
237
+ return;
238
+ }
239
+ case "create": {
240
+ if (!vm) die("usage: arker sessions create <vm_id>");
241
+ out(await client.vm(vm).createSession({ cwd: args.flags.cwd }));
242
+ return;
243
+ }
244
+ case "rm":
245
+ case "delete": {
246
+ if (!vm) die("usage: arker sessions rm <vm_id> <session_id>");
247
+ const sid = rest[1] ?? die("missing session_id");
248
+ const r = await client.vm(vm).deleteSession(sid);
249
+ out(r.deleted ? `deleted ${sid}` : "delete failed");
250
+ return;
251
+ }
252
+ default:
253
+ die(`usage: arker sessions <ls|get|create|rm> ...`);
254
+ }
255
+ }
256
+ async function cmdSyncs(args, client) {
257
+ const sub = args.positional[0];
258
+ const rest = args.positional.slice(1);
259
+ const vm = rest[0];
260
+ switch (sub) {
261
+ case "ls":
262
+ case "list": {
263
+ if (!vm) die("usage: arker syncs ls <vm_id>");
264
+ const res = await client.vm(vm).listSyncs({
265
+ cursor: args.flags.cursor,
266
+ limit: numFlag(args, "limit"),
267
+ filesystemId: args.flags["filesystem-id"]
268
+ });
269
+ if (args.flags.json) return out(res);
270
+ for (const s of res.syncs) {
271
+ out(`${s.sync_id} ${s.filesystem_id} ${s.path}`);
272
+ }
273
+ if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
274
+ return;
275
+ }
276
+ case "create": {
277
+ if (!vm) die("usage: arker syncs create <vm_id> --filesystem-id <fs> [--path /mnt]");
278
+ const filesystemId = args.flags["filesystem-id"];
279
+ if (!filesystemId) die("missing --filesystem-id");
280
+ out(await client.vm(vm).createSync({
281
+ filesystemId,
282
+ path: args.flags.path
283
+ }));
284
+ return;
285
+ }
286
+ case "rm":
287
+ case "delete": {
288
+ if (!vm) die("usage: arker syncs rm <vm_id> <sync_id>");
289
+ const sid = rest[1] ?? die("missing sync_id");
290
+ const r = await client.vm(vm).deleteSync(sid);
291
+ out(r.deleted ? `deleted ${sid}` : "delete failed");
292
+ return;
293
+ }
294
+ default:
295
+ die(`usage: arker syncs <ls|create|rm> ... (read/write files with: arker sync)`);
296
+ }
297
+ }
298
+ async function cmdSync(args, client) {
299
+ const vm = args.positional[0] ?? die("usage: arker sync <vm_id> <path> [data] (omit data to read; or pipe stdin to write)");
300
+ const path = args.positional[1] ?? die("missing path");
301
+ const inline = args.positional[2];
302
+ if (inline !== void 0) {
303
+ await client.vm(vm).sync(path, inline);
304
+ out(`wrote ${Buffer.byteLength(inline)} bytes to ${path}`);
305
+ return;
306
+ }
307
+ if (!process.stdin.isTTY) {
308
+ const buf = await readAllStdin();
309
+ if (buf.length > 0) {
310
+ await client.vm(vm).sync(path, buf);
311
+ out(`wrote ${buf.length} bytes to ${path}`);
312
+ return;
313
+ }
314
+ }
315
+ output.write(await client.vm(vm).sync(path));
316
+ }
317
+ async function cmdTunnels(args, client) {
318
+ const sub = args.positional[0];
319
+ const rest = args.positional.slice(1);
320
+ const vm = rest[0];
321
+ switch (sub) {
322
+ case "ls":
323
+ case "list": {
324
+ if (!vm) die("usage: arker tunnels ls <vm_id>");
325
+ const res = await client.vm(vm).listTunnels({
326
+ state: args.flags.state,
327
+ cursor: args.flags.cursor,
328
+ limit: numFlag(args, "limit")
329
+ });
330
+ if (args.flags.json) return out(res);
331
+ for (const t of res.tunnels) {
332
+ out(`${t.tunnel_key ?? "-"} ${t.port} ${t.state} ${t.protocol} ${t.url ?? "-"}`);
333
+ }
334
+ if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
335
+ return;
336
+ }
337
+ case "create": {
338
+ if (!vm) die("usage: arker tunnels create <vm_id> [--ports 80,8080] [--auth-mode open|authenticated]");
339
+ const tunnel = await client.vm(vm).createTunnel({
340
+ ports: parsePorts(args.flags.ports),
341
+ auth_mode: args.flags["auth-mode"]
342
+ });
343
+ return out(tunnel);
344
+ }
345
+ case "get": {
346
+ if (!vm) die("usage: arker tunnels get <vm_id> <key>");
347
+ const key = rest[1] ?? die("missing key");
348
+ out(await client.vm(vm).getTunnel(key));
349
+ return;
350
+ }
351
+ case "rm":
352
+ case "delete": {
353
+ if (!vm) die("usage: arker tunnels rm <vm_id> <key>");
354
+ const key = rest[1] ?? die("missing key");
355
+ const r = await client.vm(vm).deleteTunnel(key);
356
+ out(r.deleted ? `deleted tunnel ${key}` : "delete failed");
357
+ return;
358
+ }
359
+ default:
360
+ die(`usage: arker tunnels <ls|create|get|rm> ...`);
361
+ }
362
+ }
363
+ async function cmdFilesystems(args, client) {
364
+ const sub = args.positional[0];
365
+ const rest = args.positional.slice(1);
366
+ switch (sub) {
367
+ case void 0:
368
+ case "ls":
369
+ case "list": {
370
+ const res = await client.listFilesystems({
371
+ cursor: args.flags.cursor,
372
+ limit: numFlag(args, "limit"),
373
+ namePrefix: args.flags["name-prefix"]
374
+ });
375
+ if (args.flags.json) return out(res);
376
+ for (const f of res.filesystems) {
377
+ out(`${f.filesystem_id} ${f.name} ${f.size_bytes ?? "-"}`);
378
+ }
379
+ if (res.next_cursor) out(`# next_cursor=${res.next_cursor}`);
380
+ return;
381
+ }
382
+ case "create": {
383
+ const name = args.flags.name ?? rest[0];
384
+ if (!name) die("usage: arker fs create --name <name> (or: arker fs create <name>)");
385
+ out(await client.createFilesystem({ name }));
386
+ return;
387
+ }
388
+ case "get": {
389
+ const id = rest[0] ?? die("usage: arker fs get <filesystem_id>");
390
+ out(await client.getFilesystem(id));
391
+ return;
392
+ }
393
+ case "rm":
394
+ case "delete": {
395
+ const id = rest[0] ?? die("usage: arker fs rm <filesystem_id>");
396
+ const r = await client.deleteFilesystem(id);
397
+ out(r.deleted ? `deleted ${id}` : "delete failed");
398
+ return;
399
+ }
400
+ default:
401
+ die(`usage: arker fs <ls|create|get|rm> ...`);
402
+ }
403
+ }
404
+ async function cmdShell(args, client) {
405
+ let computer;
406
+ const vmIdArg = args.flags["vm-id"] ?? args.positional[0];
407
+ if (vmIdArg) {
408
+ computer = await client.vm(vmIdArg).refresh();
409
+ } else {
410
+ const sourceVmName = args.flags["source-vm-name"] ?? "ubuntu-full";
411
+ computer = await client.fork({
412
+ sourceVmName,
413
+ sourceOrgId: ARKER_ORG_ID
414
+ });
415
+ }
416
+ const header = computer;
417
+ const session = await computer.createSession({
418
+ cwd: args.flags.cwd
419
+ });
420
+ const sessionId = session.session_id;
421
+ const timeout = numFlag(args, "timeout");
422
+ const preload = args.positional.slice(vmIdArg ? 1 : 0).join(" ").trim();
423
+ const exitAfter = args.flags.exit === true;
424
+ output.write(JSON.stringify(header, null, 2) + "\n");
425
+ let inFlight = false;
426
+ let exitCode = 0;
427
+ try {
428
+ if (preload && preload !== "exit") {
429
+ const step = await runShellLine(computer, sessionId, preload, timeout);
430
+ if (step.kind === "fatal") {
431
+ err(`shell ended: ${step.message}`);
432
+ return;
433
+ }
434
+ if (step.kind === "recoverable") {
435
+ err(`error: ${step.message}`);
436
+ exitCode = 1;
437
+ } else {
438
+ exitCode = step.exitCode;
439
+ }
440
+ }
441
+ if (exitAfter || preload === "exit") {
442
+ process.exit(exitCode);
443
+ }
444
+ const rl = readline.createInterface({ input, output, prompt: "> " });
445
+ rl.on("SIGINT", () => {
446
+ if (inFlight) {
447
+ process.stderr.write("^C\n");
448
+ return;
449
+ }
450
+ process.stdout.write("^C\n");
451
+ rl.write(null, { ctrl: true, name: "u" });
452
+ rl.prompt();
453
+ });
454
+ rl.prompt();
455
+ for await (const line of rl) {
456
+ const cmd = line.trim();
457
+ if (!cmd) {
458
+ rl.prompt();
459
+ continue;
460
+ }
461
+ if (cmd === "exit" || cmd === "quit") break;
462
+ inFlight = true;
463
+ const step = await runShellLine(computer, sessionId, cmd, timeout);
464
+ inFlight = false;
465
+ if (step.kind === "fatal") {
466
+ err(`shell ended: ${step.message}`);
467
+ exitCode = 1;
468
+ break;
469
+ }
470
+ if (step.kind === "recoverable") {
471
+ err(`error: ${step.message}`);
472
+ }
473
+ rl.prompt();
474
+ }
475
+ rl.close();
476
+ } finally {
477
+ await computer.deleteSession(sessionId).catch(() => {
478
+ });
479
+ }
480
+ if (exitCode !== 0) process.exit(exitCode);
481
+ }
482
+ async function runShellLine(computer, sessionId, cmd, timeout) {
483
+ try {
484
+ const result = await computer.run(cmd, { session_id: sessionId, timeout });
485
+ if (result.type === "completed") {
486
+ if (result.stdout.length) process.stdout.write(new TextDecoder().decode(result.stdout));
487
+ if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
488
+ const tail = result.stderr.length > 0 ? result.stderr[result.stderr.length - 1] : result.stdout.length > 0 ? result.stdout[result.stdout.length - 1] : void 0;
489
+ if (tail !== void 0 && tail !== 10) process.stdout.write("\n");
490
+ return { kind: "ok", exitCode: result.exitCode };
491
+ }
492
+ out({ run_id: result.runId });
493
+ return { kind: "ok", exitCode: 0 };
494
+ } catch (e) {
495
+ const message = e instanceof Error ? e.message : String(e);
496
+ const kind = classifyShellError(message, computer.id);
497
+ return { kind, message };
498
+ }
499
+ }
500
+ function classifyShellError(message, vmId) {
501
+ const msg = message.toLowerCase();
502
+ if (msg.includes("unauthor") || msg.includes("forbidden") || msg.includes("invalid api key")) {
503
+ return "fatal";
504
+ }
505
+ if ((msg.includes("not_found") || msg.includes("not found")) && msg.includes(vmId.toLowerCase())) {
506
+ return "fatal";
507
+ }
508
+ return "recoverable";
509
+ }
510
+ function numFlag(args, name) {
511
+ const v = args.flags[name];
512
+ if (typeof v === "string") return Number(v);
513
+ return void 0;
514
+ }
515
+ function boolFlag(args, name) {
516
+ const v = args.flags[name];
517
+ if (v === void 0) return void 0;
518
+ if (typeof v === "boolean") return v;
519
+ if (v === "false" || v === "0") return false;
520
+ return true;
521
+ }
522
+ function parsePorts(value) {
523
+ if (typeof value !== "string" || value.trim() === "") return void 0;
524
+ return value.split(",").map((part) => Number(part.trim())).filter((port) => Number.isFinite(port));
525
+ }
526
+ async function readAllStdin() {
527
+ const chunks = [];
528
+ for await (const chunk of input) chunks.push(chunk);
529
+ return new Uint8Array(Buffer.concat(chunks));
530
+ }
531
+ function usage() {
532
+ out(
533
+ [
534
+ "arker \u2014 VM control plane CLI",
535
+ "",
536
+ "Usage:",
537
+ " arker <command> [args]",
538
+ "",
539
+ "Shortcuts:",
540
+ " arker ls list VMs",
541
+ " arker rm <vm> delete VM",
542
+ " arker fork <vm_name> fork the public golden (in Arker org)",
543
+ " arker fork --source-vm-id <id> fork by global id",
544
+ " arker fork --source-vm-name <n> --source-org-id <org>",
545
+ " fork by name in another org",
546
+ " arker run <vm> <command> run a command",
547
+ " arker shell [vm_id] interactive shell (forks arkuntu if no vm)",
548
+ "",
549
+ "Resources:",
550
+ " arker vms <ls|get|rm|fork|run> ...",
551
+ " arker runs <ls|get|rm> <vm_id> ...",
552
+ " arker sessions <ls|get|create|rm> <vm_id> ...",
553
+ " arker syncs <ls|create|rm> <vm_id> ...",
554
+ " arker tunnels <ls|get|rm> <vm_id> ...",
555
+ " arker filesystems <ls|create|get|rm> ... (alias: fs)",
556
+ "",
557
+ "Flags:",
558
+ " --api-key <key> (or env ARKER_API_KEY)",
559
+ " --region <region> (or env ARKER_REGION; e.g. us-west-2)",
560
+ " --provider <aws|aws-burst> (or env ARKER_PROVIDER; default aws)",
561
+ " --base-url <url> override compute URL (env ARKER_BASE_URL)",
562
+ " --control-base-url <url> override CF Worker URL (env ARKER_CONTROL_BASE_URL)",
563
+ " --json emit JSON instead of tabular output",
564
+ "",
565
+ `Arker org id: ${ARKER_ORG_ID}`
566
+ ].join("\n")
567
+ );
568
+ process.exit(2);
569
+ }
570
+ async function main() {
571
+ const argv = process.argv.slice(2);
572
+ if (argv.length === 0 || argv[0] === "-h" || argv[0] === "--help") usage();
573
+ const cmd = argv[0];
574
+ const args = parseArgs(argv.slice(1));
575
+ const client = clientFromArgs(args);
576
+ try {
577
+ switch (cmd) {
578
+ // Shortcuts.
579
+ case "ls":
580
+ case "list":
581
+ return await cmdVms({ ...args, positional: ["ls", ...args.positional] }, client);
582
+ case "rm":
583
+ case "delete":
584
+ return await cmdVms({ ...args, positional: ["rm", ...args.positional] }, client);
585
+ case "fork":
586
+ return await cmdFork(args, client);
587
+ case "run":
588
+ return await cmdRun(args, client);
589
+ case "sync":
590
+ return await cmdSync(args, client);
591
+ case "syncs":
592
+ return await cmdSyncs(args, client);
593
+ case "shell":
594
+ return await cmdShell(args, client);
595
+ // Resources.
596
+ case "vms":
597
+ return await cmdVms(args, client);
598
+ case "runs":
599
+ return await cmdRuns(args, client);
600
+ case "sessions":
601
+ return await cmdSessions(args, client);
602
+ case "tunnels":
603
+ return await cmdTunnels(args, client);
604
+ case "filesystems":
605
+ case "fs":
606
+ return await cmdFilesystems(args, client);
607
+ default:
608
+ die(`unknown command: ${cmd}. Run 'arker --help'.`);
609
+ }
610
+ } catch (e) {
611
+ if (e instanceof ArkerError) {
612
+ err(`${e.code}: ${e.message}`);
613
+ process.exit(1);
614
+ }
615
+ throw e;
616
+ }
617
+ }
618
+ void main();