@arker-ai/sdk 0.5.2 → 0.6.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.
package/dist/cli.js CHANGED
@@ -3,14 +3,22 @@ import {
3
3
  ARKER_ORG_ID,
4
4
  Arker,
5
5
  ArkerError
6
- } from "./chunk-YGZOUXII.js";
6
+ } from "./chunk-7BHPVQNG.js";
7
7
 
8
8
  // src/cli.ts
9
9
  import { readFileSync, existsSync } from "fs";
10
+ import { spawnSync } from "child_process";
11
+ import { createRequire } from "module";
10
12
  import { homedir } from "os";
11
13
  import { join } from "path";
12
- import * as readline from "readline/promises";
13
14
  import { stdin as input, stdout as output } from "process";
15
+ var VERSION = (() => {
16
+ try {
17
+ return createRequire(import.meta.url)("../package.json").version;
18
+ } catch {
19
+ return "unknown";
20
+ }
21
+ })();
14
22
  function parseArgs(argv) {
15
23
  const positional = [];
16
24
  const flags = {};
@@ -38,27 +46,30 @@ function parseArgs(argv) {
38
46
  return { positional, flags };
39
47
  }
40
48
  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 {};
49
+ for (const name of ["config.json", "config"]) {
50
+ const path = join(homedir(), ".arker", name);
51
+ if (!existsSync(path)) continue;
52
+ try {
53
+ return JSON.parse(readFileSync(path, "utf8"));
54
+ } catch {
55
+ return {};
56
+ }
47
57
  }
58
+ return {};
48
59
  }
60
+ var DEFAULT_REGION = "us-west-2";
49
61
  function clientFromArgs(args) {
50
62
  const file = readFileConfig();
63
+ const explicitBaseUrl = args.flags["base-url"] ?? process.env.ARKER_BASE_URL;
64
+ const explicitRegion = args.flags.region ?? process.env.ARKER_REGION;
51
65
  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;
66
+ const baseUrl = explicitBaseUrl ?? (explicitRegion ? void 0 : file.baseUrl);
53
67
  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;
68
+ const region = explicitRegion ?? file.region ?? (baseUrl ? void 0 : DEFAULT_REGION);
55
69
  const provider = args.flags.provider ?? process.env.ARKER_PROVIDER;
56
70
  if (!apiKey) {
57
71
  die("Missing API key. Set ARKER_API_KEY or pass --api-key.");
58
72
  }
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
73
  return new Arker({ apiKey, baseUrl, region, provider, controlBaseUrl });
63
74
  }
64
75
  function out(value) {
@@ -81,7 +92,8 @@ function fmtVm(vm) {
81
92
  const region = vm.region ?? "?";
82
93
  const name = vm.name ?? "\u2014";
83
94
  const state = vm.state ?? "?";
84
- return `${vm.vm_id ?? vm.id} ${provider}-${region} ${state} ${name}`;
95
+ const id = vm.vm_id ?? vm.id;
96
+ return `${id} ${provider}-${region} ${state} ${name}`;
85
97
  }
86
98
  async function cmdVms(args, client) {
87
99
  const sub = args.positional[0];
@@ -126,6 +138,10 @@ async function cmdVms(args, client) {
126
138
  await cmdRun({ ...args, positional: rest }, client);
127
139
  return;
128
140
  }
141
+ case "resize": {
142
+ await cmdResize({ ...args, positional: rest }, client);
143
+ return;
144
+ }
129
145
  default:
130
146
  die(`unknown vms subcommand: ${sub}`);
131
147
  }
@@ -144,14 +160,22 @@ async function cmdFork(args, client) {
144
160
  sourceVmName = refPositional;
145
161
  }
146
162
  if (!sourceVmId && !sourceVmName) {
147
- die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]");
163
+ die("usage: arker fork <vm_name> | --source-vm-id <id> | --source-vm-name <name> [--source-org-id <org>]\n [--vcpu N] [--memory-mib N] [--disk-mib N] [--no-disk]");
148
164
  }
165
+ const vcpu = numFlag(args, "vcpu");
166
+ const memoryMib = numFlag(args, "memory-mib");
167
+ const diskMib = numFlag(args, "disk-mib");
168
+ const hasResources = vcpu !== void 0 || memoryMib !== void 0 || diskMib !== void 0;
169
+ const resources = hasResources ? { vcpu: vcpu ?? null, memory_mib: memoryMib ?? null, disk_mib: diskMib ?? null } : void 0;
170
+ const disk = boolFlag(args, "no-disk") ? false : void 0;
149
171
  const computer = await client.fork({
150
172
  sourceVmId,
151
173
  sourceVmName,
152
174
  sourceOrgId,
153
175
  name,
154
- public: publicFlag
176
+ public: publicFlag,
177
+ ...resources ? { resources } : {},
178
+ ...disk !== void 0 ? { disk } : {}
155
179
  });
156
180
  out({ vm_id: computer.id });
157
181
  }
@@ -159,13 +183,24 @@ async function cmdRun(args, client) {
159
183
  const vmId = args.positional[0] ?? die("usage: arker run <vm_id> <command...>");
160
184
  const command = args.positional.slice(1).join(" ");
161
185
  if (!command) die("missing command to run");
186
+ const sessionIdx = numFlag(args, "session-idx");
162
187
  const result = await client.vm(vmId).run(command, {
163
188
  background: boolFlag(args, "background"),
164
189
  timeout: numFlag(args, "timeout"),
165
190
  acquire: args.flags.acquire,
166
- release: args.flags.release
191
+ release: args.flags.release,
192
+ session_id: args.flags["session-id"],
193
+ ...sessionIdx !== void 0 ? { session_idx: sessionIdx } : {}
167
194
  });
195
+ if (args.flags.json) {
196
+ out(runResultForJson(result));
197
+ if (result.type === "completed") process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
198
+ return;
199
+ }
168
200
  if (result.type === "completed") {
201
+ if (result.memoryPartial) {
202
+ err(`Memory target partially applied: requested ${formatMib(result.memoryRequestedMib)}, achieved ${formatMib(result.memoryAchievedMib)}.`);
203
+ }
169
204
  process.stdout.write(new TextDecoder().decode(result.stdout));
170
205
  if (result.stderr.length) process.stderr.write(new TextDecoder().decode(result.stderr));
171
206
  process.exitCode = result.exitCode === 0 ? 0 : result.exitCode;
@@ -173,6 +208,30 @@ async function cmdRun(args, client) {
173
208
  }
174
209
  out({ run_id: result.runId, state: result.state });
175
210
  }
211
+ function formatMib(value) {
212
+ return typeof value === "number" ? `${value} MiB` : "unknown";
213
+ }
214
+ function runResultForJson(result) {
215
+ switch (result.type) {
216
+ case "completed":
217
+ return {
218
+ type: result.type,
219
+ runId: result.runId,
220
+ state: result.state,
221
+ stdout: new TextDecoder().decode(result.stdout),
222
+ stdoutEncoding: result.stdoutEncoding,
223
+ stderr: new TextDecoder().decode(result.stderr),
224
+ stderrEncoding: result.stderrEncoding,
225
+ exitCode: result.exitCode,
226
+ failReason: result.failReason,
227
+ memoryRequestedMib: result.memoryRequestedMib,
228
+ memoryAchievedMib: result.memoryAchievedMib,
229
+ memoryPartial: result.memoryPartial
230
+ };
231
+ case "background":
232
+ return result;
233
+ }
234
+ }
176
235
  async function cmdRuns(args, client) {
177
236
  const sub = args.positional[0];
178
237
  const rest = args.positional.slice(1);
@@ -314,51 +373,24 @@ async function cmdSync(args, client) {
314
373
  }
315
374
  output.write(await client.vm(vm).sync(path));
316
375
  }
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> ...`);
376
+ async function cmdResize(args, client) {
377
+ const vm = args.positional[0];
378
+ if (!vm) die("usage: arker resize <vm_id> [--memory-mib N] [--vcpu N] [--disk-mib N]");
379
+ const memoryMib = numFlag(args, "memory-mib");
380
+ const vcpu = numFlag(args, "vcpu");
381
+ const diskMib = numFlag(args, "disk-mib");
382
+ if (memoryMib === void 0 && vcpu === void 0 && diskMib === void 0) {
383
+ die("resize: pass at least one of --memory-mib, --vcpu, --disk-mib");
361
384
  }
385
+ const updated = await client.vm(vm).resize({
386
+ resources: {
387
+ vcpu: vcpu ?? null,
388
+ memory_mib: memoryMib ?? null,
389
+ disk_mib: diskMib ?? null
390
+ }
391
+ });
392
+ if (args.flags.json) return out(updated);
393
+ out(fmtVm(updated));
362
394
  }
363
395
  async function cmdFilesystems(args, client) {
364
396
  const sub = args.positional[0];
@@ -404,6 +436,10 @@ async function cmdFilesystems(args, client) {
404
436
  async function cmdShell(args, client) {
405
437
  let computer;
406
438
  const vmIdArg = args.flags["vm-id"] ?? args.positional[0];
439
+ const explicitSessionId = args.flags["session-id"];
440
+ if (!vmIdArg && explicitSessionId) {
441
+ die("usage: arker shell <vm_id> --session-id <session_id>");
442
+ }
407
443
  if (vmIdArg) {
408
444
  computer = await client.vm(vmIdArg).refresh();
409
445
  } else {
@@ -412,100 +448,114 @@ async function cmdShell(args, client) {
412
448
  sourceVmName,
413
449
  sourceOrgId: ARKER_ORG_ID
414
450
  });
451
+ err(`forked ${computer.id}`);
452
+ }
453
+ let sessionId = explicitSessionId;
454
+ if (!sessionId) {
455
+ const session = await computer.createSession({
456
+ cwd: args.flags.cwd
457
+ });
458
+ sessionId = session.session_id ?? session.id;
459
+ if (!sessionId) die("createSession response missing session_id");
415
460
  }
416
- const header = computer;
417
- const session = await computer.createSession({
418
- cwd: args.flags.cwd
461
+ const persist = args.flags["no-persist"] === true ? false : boolFlag(args, "persist");
462
+ const colsFlag = numFlag(args, "cols");
463
+ const rowsFlag = numFlag(args, "rows");
464
+ const cols = colsFlag ?? output.columns ?? 80;
465
+ const rows = rowsFlag ?? output.rows ?? 24;
466
+ const cancelTtlSecs = numFlag(args, "cancel-ttl");
467
+ const pty = await computer.connectPty({
468
+ sessionId,
469
+ cols,
470
+ rows,
471
+ command: args.flags.command,
472
+ persist,
473
+ cancelTtlSecs
419
474
  });
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;
475
+ err(`connected ${computer.id} session ${sessionId}`);
476
+ const exitCode = await bridgePty(pty, {
477
+ fallbackCols: cols,
478
+ fallbackRows: rows,
479
+ autoResize: colsFlag === void 0 && rowsFlag === void 0 && Boolean(output.isTTY)
480
+ });
481
+ if (exitCode !== 0) process.exit(exitCode);
482
+ }
483
+ function bridgePty(pty, options) {
484
+ return new Promise((resolve) => {
485
+ let settled = false;
486
+ let rawEnabled = false;
487
+ const wasRaw = Boolean(input.isTTY && input.isRaw);
488
+ const restoreTerminal = () => {
489
+ if (rawEnabled && input.isTTY && typeof input.setRawMode === "function") {
490
+ input.setRawMode(wasRaw);
449
491
  }
450
- process.stdout.write("^C\n");
451
- rl.write(null, { ctrl: true, name: "u" });
452
- rl.prompt();
492
+ rawEnabled = false;
493
+ };
494
+ const finish = (code) => {
495
+ if (settled) return;
496
+ settled = true;
497
+ restoreTerminal();
498
+ input.off("data", onInput);
499
+ input.off("end", onInputEnd);
500
+ process.off("SIGWINCH", onResize);
501
+ process.off("SIGINT", onSigint);
502
+ process.off("SIGTERM", onSigterm);
503
+ process.off("SIGHUP", onSighup);
504
+ process.off("exit", restoreTerminal);
505
+ offData();
506
+ offClose();
507
+ offError();
508
+ resolve(code);
509
+ };
510
+ const onInput = (chunk) => {
511
+ pty.send(chunk);
512
+ };
513
+ const onInputEnd = () => {
514
+ pty.close();
515
+ };
516
+ const onResize = () => {
517
+ pty.resize(output.columns ?? options.fallbackCols, output.rows ?? options.fallbackRows);
518
+ };
519
+ const onSigint = () => {
520
+ pty.send(new Uint8Array([3]));
521
+ };
522
+ const onSigterm = () => {
523
+ pty.close();
524
+ finish(143);
525
+ };
526
+ const onSighup = () => {
527
+ pty.close();
528
+ finish(129);
529
+ };
530
+ const offData = pty.onData((data) => {
531
+ output.write(data);
453
532
  });
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}`);
533
+ const offClose = pty.onClose(() => finish(0));
534
+ const offError = pty.onError((error) => {
535
+ const message = error instanceof Error ? error.message : String(error);
536
+ err(`pty error: ${message}`);
537
+ });
538
+ process.once("exit", restoreTerminal);
539
+ pty.ready.then(() => {
540
+ if (settled) return;
541
+ if (input.isTTY && typeof input.setRawMode === "function") {
542
+ input.setRawMode(true);
543
+ rawEnabled = true;
472
544
  }
473
- rl.prompt();
474
- }
475
- rl.close();
476
- } finally {
477
- await computer.deleteSession(sessionId).catch(() => {
545
+ input.resume();
546
+ input.on("data", onInput);
547
+ input.on("end", onInputEnd);
548
+ if (options.autoResize) process.on("SIGWINCH", onResize);
549
+ process.on("SIGINT", onSigint);
550
+ process.on("SIGTERM", onSigterm);
551
+ process.on("SIGHUP", onSighup);
552
+ if (options.autoResize) onResize();
553
+ }).catch((error) => {
554
+ const message = error instanceof Error ? error.message : String(error);
555
+ err(`pty failed to open: ${message}`);
556
+ finish(1);
478
557
  });
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";
558
+ });
509
559
  }
510
560
  function numFlag(args, name) {
511
561
  const v = args.flags[name];
@@ -519,10 +569,6 @@ function boolFlag(args, name) {
519
569
  if (v === "false" || v === "0") return false;
520
570
  return true;
521
571
  }
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
572
  async function readAllStdin() {
527
573
  const chunks = [];
528
574
  for await (const chunk of input) chunks.push(chunk);
@@ -531,7 +577,7 @@ async function readAllStdin() {
531
577
  function usage() {
532
578
  out(
533
579
  [
534
- "arker \u2014 VM control plane CLI",
580
+ `arker v${VERSION}`,
535
581
  "",
536
582
  "Usage:",
537
583
  " arker <command> [args]",
@@ -543,26 +589,46 @@ function usage() {
543
589
  " arker fork --source-vm-id <id> fork by global id",
544
590
  " arker fork --source-vm-name <n> --source-org-id <org>",
545
591
  " 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)",
592
+ " arker fork <vm> [--vcpu N] [--memory-mib N] [--disk-mib N] [--no-disk]",
593
+ " fork with resource/network overrides",
594
+ " arker run <vm> <command> [--session-id <id>] [--session-idx N] run a command",
595
+ " arker resize <vm> [--memory-mib N] [--vcpu N] [--disk-mib N] resize a VM (PATCH)",
596
+ " arker shell [vm_id] native PTY shell (forks ubuntu-full if no vm)",
548
597
  "",
549
598
  "Resources:",
550
599
  " arker vms <ls|get|rm|fork|run> ...",
551
600
  " arker runs <ls|get|rm> <vm_id> ...",
552
601
  " arker sessions <ls|get|create|rm> <vm_id> ...",
553
602
  " arker syncs <ls|create|rm> <vm_id> ...",
554
- " arker tunnels <ls|get|rm> <vm_id> ...",
555
603
  " arker filesystems <ls|create|get|rm> ... (alias: fs)",
556
604
  "",
557
605
  "Flags:",
558
606
  " --api-key <key> (or env ARKER_API_KEY)",
559
607
  " --region <region> (or env ARKER_REGION; e.g. us-west-2)",
560
- " --provider <aws|aws-burst> (or env ARKER_PROVIDER; default aws)",
608
+ " --provider <aws> (or env ARKER_PROVIDER; default aws)",
561
609
  " --base-url <url> override compute URL (env ARKER_BASE_URL)",
562
610
  " --control-base-url <url> override CF Worker URL (env ARKER_CONTROL_BASE_URL)",
563
611
  " --json emit JSON instead of tabular output",
564
612
  "",
565
- `Arker org id: ${ARKER_ORG_ID}`
613
+ "Fork flags:",
614
+ " --vcpu <n> vCPU count for the new VM (capped by source max_vcpus)",
615
+ " --memory-mib <n> memory (MiB) for the new VM",
616
+ " --disk-mib <n> disk size (MiB) for the new VM",
617
+ " --no-disk fork a memory-backed (nodisk) VM",
618
+ "",
619
+ "Run flags:",
620
+ " --session-id <ulid> run in a specific existing session",
621
+ " --session-idx <n> run in the session at this index (default 0)",
622
+ " --background return a run id instead of blocking",
623
+ " --timeout <secs> per-run timeout",
624
+ " --acquire <list> warm resources before the run (cpu,memory,disk)",
625
+ " --release <list> release resources after the run (cpu,memory,disk)",
626
+ "",
627
+ "Shell flags:",
628
+ " --session-id <id> reconnect to an existing PTY session",
629
+ " --command <path> shell executable path (default: /bin/bash)",
630
+ " --cols <n> --rows <n> initial terminal size",
631
+ " --no-persist close the remote PTY process on disconnect"
566
632
  ].join("\n")
567
633
  );
568
634
  process.exit(2);
@@ -592,6 +658,10 @@ async function main() {
592
658
  return await cmdSyncs(args, client);
593
659
  case "shell":
594
660
  return await cmdShell(args, client);
661
+ // SSH is descoped/unsupported and hidden from the interface. The
662
+ // implementation below (cmdSsh / cmdSshKeys) is kept intact; re-add
663
+ // the `ssh` / `ssh-keys` cases here and their help entries to expose
664
+ // it once the server-side SSH path is supported.
595
665
  // Resources.
596
666
  case "vms":
597
667
  return await cmdVms(args, client);
@@ -599,8 +669,8 @@ async function main() {
599
669
  return await cmdRuns(args, client);
600
670
  case "sessions":
601
671
  return await cmdSessions(args, client);
602
- case "tunnels":
603
- return await cmdTunnels(args, client);
672
+ case "resize":
673
+ return await cmdResize(args, client);
604
674
  case "filesystems":
605
675
  case "fs":
606
676
  return await cmdFilesystems(args, client);
@@ -0,0 +1,9 @@
1
+ import { SandboxInterface } from 'computesdk';
2
+
3
+ type UniversalSandbox = SandboxInterface;
4
+ interface CreateOptions {
5
+ timeout?: number;
6
+ timeoutMs?: number;
7
+ }
8
+
9
+ export type { CreateOptions as C, UniversalSandbox as U };
@@ -0,0 +1,9 @@
1
+ import { SandboxInterface } from 'computesdk';
2
+
3
+ type UniversalSandbox = SandboxInterface;
4
+ interface CreateOptions {
5
+ timeout?: number;
6
+ timeoutMs?: number;
7
+ }
8
+
9
+ export type { CreateOptions as C, UniversalSandbox as U };