@exedev/sdk 0.0.6 → 0.2.0

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,1640 @@
1
+ // Code generated by "go run ./cmd/gensdkjs" in the exe.dev repository. DO NOT EDIT.
2
+ import { Transport, ExeAPIError, ExeProtocolError, abortable, delay } from "./client.js";
3
+ export class ExedevClient {
4
+ #transport;
5
+ constructor(options) { this.#transport = new Transport(options); }
6
+ /** Reference an existing VM without a request. Use refresh() to fetch its metadata. */
7
+ vm(name) {
8
+ if (typeof name !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(name)) {
9
+ throw new TypeError("exedev: expected a VM name, not a command or SSH destination");
10
+ }
11
+ return new VM(this.#transport, { name, tags: [] });
12
+ }
13
+ /**
14
+ * Browse documentation
15
+ *
16
+ * Usage: `doc [slug-or-query...]`
17
+ *
18
+ * Tag-scoped API keys may run this command.
19
+ */
20
+ async doc(slugOrQueries, options) {
21
+ const result = await this.#transport.call("doc", [slugOrQueries], options, {}, false);
22
+ return result;
23
+ }
24
+ /**
25
+ * List your VMs
26
+ *
27
+ * Usage: `ls [-l] [--group=tag|region|type] [name|pattern]`
28
+ *
29
+ * Tag-scoped API keys may run this command.
30
+ */
31
+ async ls(nameOrPattern, options) {
32
+ const result = await this.#transport.call("ls", [nameOrPattern], options, {
33
+ group: "string",
34
+ l: "bool",
35
+ }, true);
36
+ return listVMs(this.#transport, result);
37
+ }
38
+ /**
39
+ * Create a new VM
40
+ *
41
+ * CLI examples:
42
+ * ```
43
+ * new # just give me a computer
44
+ * new --name=b --image=ubuntu:22.04 # custom image and name
45
+ * new --cpu=4 --memory=16GB # 4 CPUs, 16GB RAM
46
+ * new --disk=50GB # 50GB disk
47
+ * new --tag=prod,staging # create with tags
48
+ * new --env FOO=bar --env BAZ=qux # with environment variables
49
+ * new --integration=myproxy # attach an integration
50
+ * echo 'build me a web app' | ssh exe.dev new --prompt=/dev/stdin
51
+ * ```
52
+ *
53
+ * Tag-scoped API keys may run this command.
54
+ */
55
+ async new(options) {
56
+ const ready = readiness(options ?? {});
57
+ const { waitUntil, timeoutMs, ...flags } = options ?? {};
58
+ const result = await this.#transport.call("new", [], flags, {
59
+ comment: "string",
60
+ cpu: "number",
61
+ disk: "string",
62
+ env: "repeated",
63
+ image: "string",
64
+ integration: "repeated",
65
+ memory: "string",
66
+ name: "string",
67
+ "no-email": "bool",
68
+ "no-pool": "bool",
69
+ pool: "string",
70
+ prompt: "string",
71
+ "registry-auth": "string",
72
+ sandbox: "bool",
73
+ "setup-script": "string",
74
+ standalone: "bool",
75
+ tag: "repeated",
76
+ }, true);
77
+ const vm = new VM(this.#transport, vmInfo(result, "new"));
78
+ if (ready)
79
+ await vm.waitUntilReady(ready);
80
+ return vm;
81
+ }
82
+ /**
83
+ * List custom domains for a VM (or -a for all your VMs)
84
+ *
85
+ * Usage: `domain ls <vm> | domain ls -a`
86
+ */
87
+ async domainLs(args, options) {
88
+ const result = await this.#transport.call("domain ls", [args], options, {
89
+ a: "bool",
90
+ }, false);
91
+ return result;
92
+ }
93
+ /**
94
+ * Show user information (email, keys, etc)
95
+ *
96
+ * Usage: `whoami`
97
+ *
98
+ * Tag-scoped API keys may run this command.
99
+ */
100
+ async whoami(options) {
101
+ const result = await this.#transport.call("whoami", [], options, {}, true);
102
+ return result;
103
+ }
104
+ /**
105
+ * List all SSH keys associated with your account
106
+ *
107
+ * Usage: `ssh-key list`
108
+ *
109
+ * Tag-scoped API keys may run this command.
110
+ */
111
+ async sshKeyList(options) {
112
+ const result = await this.#transport.call("ssh-key list", [], options, {}, false);
113
+ return result;
114
+ }
115
+ /**
116
+ * Add a new SSH key to your account
117
+ *
118
+ * Usage: `ssh-key add [--tag=TAG] <public-key>`
119
+ *
120
+ * CLI examples:
121
+ * ```
122
+ * ssh-key add 'ssh-ed25519 AAAA... my-laptop'
123
+ *
124
+ * To generate a new key locally:
125
+ * ssh-keygen -t ed25519 -C "mnemonic-for-this-key" -f ~/.ssh/id_exe
126
+ *
127
+ * The -C flag sets a name for the key.
128
+ *
129
+ * Then add the public key from your local shell:
130
+ * cat ~/.ssh/id_exe.pub | ssh exe.dev ssh-key add
131
+ *
132
+ * Or from the exe.dev shell:
133
+ * ssh-key add 'ssh-ed25519 AAAA... my-laptop'
134
+ * ```
135
+ *
136
+ * Tag-scoped API keys may run this command.
137
+ */
138
+ async sshKeyAdd(publicKey, options) {
139
+ const result = await this.#transport.call("ssh-key add", [publicKey], options, {
140
+ tag: "string",
141
+ }, false);
142
+ return result;
143
+ }
144
+ /**
145
+ * Remove an SSH key from your account
146
+ *
147
+ * Usage: `ssh-key remove <name|fingerprint|public-key>`
148
+ *
149
+ * Tag-scoped API keys may run this command.
150
+ */
151
+ async sshKeyRemove(nameOrFingerprintOrPublicKey, options) {
152
+ const result = await this.#transport.call("ssh-key remove", [nameOrFingerprintOrPublicKey], options, {}, false);
153
+ return result;
154
+ }
155
+ /**
156
+ * Rename an SSH key
157
+ *
158
+ * Usage: `ssh-key rename <old-name> <new-name>`
159
+ *
160
+ * Tag-scoped API keys may run this command.
161
+ */
162
+ async sshKeyRename(oldName, newName, options) {
163
+ const result = await this.#transport.call("ssh-key rename", [oldName, newName], options, {}, false);
164
+ return result;
165
+ }
166
+ /**
167
+ * Generate an API key for the exe.dev HTTPS API or for a specific VM
168
+ *
169
+ * Usage: `ssh-key generate-api-key [--label=NAME] [--vm=VMNAME] [--cmds=CMD1,CMD2] [--exp=30d]`
170
+ *
171
+ * CLI examples:
172
+ * ```
173
+ * # Generate a key for the exe.dev API (lobby commands like ls, new, whoami):
174
+ * ssh-key generate-api-key --label=ci --cmds=ls,new --exp=90d
175
+ *
176
+ * # Generate a key scoped to a VM (authenticates to its HTTPS proxy):
177
+ * ssh-key generate-api-key --vm=my-vm --label=deploy
178
+ * ```
179
+ *
180
+ * Tag-scoped API keys may run this command.
181
+ */
182
+ async sshKeyGenerateApiKey(options) {
183
+ const result = await this.#transport.call("ssh-key generate-api-key", [], options, {
184
+ cmds: "string",
185
+ exp: "string",
186
+ label: "string",
187
+ vm: "string",
188
+ }, false);
189
+ return result;
190
+ }
191
+ /**
192
+ * Set your preferred region for new VMs.
193
+ *
194
+ * Usage: `set-region <region-code>`
195
+ */
196
+ async setRegion(regionCode, options) {
197
+ const result = await this.#transport.call("set-region", [regionCode], options, {}, false);
198
+ return result;
199
+ }
200
+ /**
201
+ * List your integrations
202
+ *
203
+ * Usage: `integrations list [--json [--usage]]`
204
+ *
205
+ * Tag-scoped API keys may run this command.
206
+ */
207
+ async integrationsList(options) {
208
+ const result = await this.#transport.call("integrations list", [], options, {
209
+ usage: "bool",
210
+ }, false);
211
+ return result;
212
+ }
213
+ /**
214
+ * Set up GitHub integration
215
+ *
216
+ * Usage: `integrations setup github [--list|--verify|-d]`
217
+ */
218
+ async integrationsSetupGithub(options) {
219
+ const result = await this.#transport.call("integrations setup github", [], options, {
220
+ d: "bool",
221
+ delete: "bool",
222
+ list: "bool",
223
+ verify: "bool",
224
+ }, false);
225
+ return result;
226
+ }
227
+ /**
228
+ * Set up ChatGPT account access for LLM integrations
229
+ *
230
+ * Usage: `integrations setup chatgpt [--name=<account-name>|--list|--verify|-d]`
231
+ */
232
+ async integrationsSetupChatgpt(options) {
233
+ const result = await this.#transport.call("integrations setup chatgpt", [], options, {
234
+ d: "bool",
235
+ delete: "bool",
236
+ list: "bool",
237
+ name: "string",
238
+ verify: "bool",
239
+ }, false);
240
+ return result;
241
+ }
242
+ /**
243
+ * Add a new integration
244
+ *
245
+ * Credential value flags (keys, tokens, passwords, bearer tokens, and webhook URLs) accept - to read from stdin.
246
+ *
247
+ * Usage: `integrations add <type> [--default | --name=<name> [--team] [args...]]`
248
+ */
249
+ async integrationsAdd(type, options) {
250
+ const result = await this.#transport.call("integrations add", [type], options, {
251
+ "act-as-user": "bool",
252
+ attach: "repeated",
253
+ bearer: "string",
254
+ comment: "string",
255
+ default: "bool",
256
+ fields: "string",
257
+ for: "string",
258
+ header: "repeated",
259
+ "host-key": "repeated",
260
+ name: "string",
261
+ "no-auth": "bool",
262
+ peer: "bool",
263
+ readonly: "bool",
264
+ repository: "string",
265
+ "strip-prefix": "string",
266
+ target: "string",
267
+ team: "bool",
268
+ }, false);
269
+ return result;
270
+ }
271
+ /**
272
+ * Remove an integration
273
+ *
274
+ * Usage: `integrations remove <name> [--team]`
275
+ */
276
+ async integrationsRemove(name, options) {
277
+ const result = await this.#transport.call("integrations remove", [name], options, {
278
+ team: "bool",
279
+ }, false);
280
+ return result;
281
+ }
282
+ /**
283
+ * Test an integration's credential (connection check)
284
+ *
285
+ * Usage: `integrations test <name> [--team]`
286
+ */
287
+ async integrationsTest(name, options) {
288
+ const result = await this.#transport.call("integrations test", [name], options, {
289
+ team: "bool",
290
+ }, false);
291
+ return result;
292
+ }
293
+ /**
294
+ * Edit an integration
295
+ *
296
+ * Credential value flags (keys, tokens, passwords, bearer tokens, and webhook URLs) accept - to read from stdin.
297
+ *
298
+ * Usage: `integrations edit <name> [--team] [args...]`
299
+ */
300
+ async integrationsEdit(name, args, options) {
301
+ const result = await this.#transport.call("integrations edit", [name, args], options, {
302
+ "act-as-user": "bool",
303
+ bearer: "string",
304
+ "clear-header": "bool",
305
+ comment: "string",
306
+ fields: "string",
307
+ header: "repeated",
308
+ "host-key": "repeated",
309
+ "no-auth": "bool",
310
+ readonly: "bool",
311
+ repository: "string",
312
+ "strip-prefix": "string",
313
+ target: "string",
314
+ team: "bool",
315
+ "webhook-url": "string",
316
+ }, false);
317
+ return result;
318
+ }
319
+ /**
320
+ * Attach an integration to a VM, tag, or all VMs
321
+ *
322
+ * A <spec> controls where the integration is mounted:
323
+ * vm:<vm-name> attach to a specific VM (personal only)
324
+ * tag:<tag-name> attach to every VM with the given tag
325
+ * auto:all attach to all current and future VMs (personal only)
326
+ *
327
+ * You can attach the same integration multiple times with different specs.
328
+ * Team integrations only support tag:<tag-name>.
329
+ *
330
+ * A grant can be time-boxed with --for <duration> or --until <RFC3339>;
331
+ * when it lapses, access stops immediately, with nothing to revoke.
332
+ * Re-attaching the same spec with a new --for/--until extends or shortens it.
333
+ *
334
+ * Usage: `integrations attach <name> <spec> [--team] [--for <duration> | --until <time>]`
335
+ *
336
+ * CLI examples:
337
+ * ```
338
+ * int attach my-mcp vm:dev1
339
+ * int attach my-mcp tag:production
340
+ * int attach my-mcp auto:all
341
+ * int attach shared-mcp tag:production
342
+ * int attach gmail vm:dev1 --for 2h
343
+ * ```
344
+ */
345
+ async integrationsAttach(name, spec, options) {
346
+ const result = await this.#transport.call("integrations attach", [name, spec], options, {
347
+ for: "string",
348
+ team: "bool",
349
+ until: "string",
350
+ }, false);
351
+ return result;
352
+ }
353
+ /**
354
+ * Detach an integration from a VM, tag, or all VMs
355
+ *
356
+ * Usage: `integrations detach <name> <spec> [--team]`
357
+ */
358
+ async integrationsDetach(name, spec, options) {
359
+ const result = await this.#transport.call("integrations detach", [name, spec], options, {
360
+ team: "bool",
361
+ }, false);
362
+ return result;
363
+ }
364
+ /**
365
+ * Rename an integration
366
+ *
367
+ * Usage: `integrations rename <name> <new-name> [--team]`
368
+ */
369
+ async integrationsRename(name, newName, options) {
370
+ const result = await this.#transport.call("integrations rename", [name, newName], options, {
371
+ team: "bool",
372
+ }, false);
373
+ return result;
374
+ }
375
+ /**
376
+ * Browse the catalog of ready-made service integrations
377
+ *
378
+ * Usage: `integrations catalog [service-or-search-term]`
379
+ *
380
+ * CLI examples:
381
+ * ```
382
+ * int catalog
383
+ * int catalog stripe
384
+ * ```
385
+ */
386
+ async integrationsCatalog(serviceOrSearchTerm, options) {
387
+ const result = await this.#transport.call("integrations catalog", [serviceOrSearchTerm], options, {}, false);
388
+ return result;
389
+ }
390
+ /**
391
+ * View and manage your team
392
+ */
393
+ async team(options) {
394
+ const result = await this.#transport.call("team", [], options, {}, false);
395
+ return result;
396
+ }
397
+ /**
398
+ * Disband your team
399
+ *
400
+ * Usage: `team disable`
401
+ */
402
+ async teamDisable(options) {
403
+ const result = await this.#transport.call("team disable", [], options, {
404
+ yes: "bool",
405
+ }, false);
406
+ return result;
407
+ }
408
+ /**
409
+ * List team members
410
+ *
411
+ * Usage: `team members`
412
+ */
413
+ async teamMembers(options) {
414
+ const result = await this.#transport.call("team members", [], options, {}, false);
415
+ return result;
416
+ }
417
+ /**
418
+ * Show team pool, disk, and bandwidth usage for the billing period
419
+ *
420
+ * Usage: `team usage`
421
+ */
422
+ async teamUsage(options) {
423
+ const result = await this.#transport.call("team usage", [], options, {}, false);
424
+ return result;
425
+ }
426
+ /**
427
+ * Add a user to the team
428
+ *
429
+ * Usage: `team add <email> [<user|admin|billing_owner>]`
430
+ */
431
+ async teamAdd(email, userOrAdminOrBillingOwner, options) {
432
+ const result = await this.#transport.call("team add", [email, userOrAdminOrBillingOwner], options, {}, false);
433
+ return result;
434
+ }
435
+ /**
436
+ * Remove a user from the team
437
+ *
438
+ * Usage: `team remove <email> [--transfer-vms-to <email>]`
439
+ */
440
+ async teamRemove(email, options) {
441
+ const result = await this.#transport.call("team remove", [email], options, {
442
+ "transfer-vms-to": "string",
443
+ }, false);
444
+ return result;
445
+ }
446
+ /**
447
+ * Change a team member's role
448
+ *
449
+ * Usage: `team role <email> <user|admin|billing_owner>`
450
+ */
451
+ async teamRole(email, userOrAdminOrBillingOwner, options) {
452
+ const result = await this.#transport.call("team role", [email, userOrAdminOrBillingOwner], options, {}, false);
453
+ return result;
454
+ }
455
+ /**
456
+ * Rename your team
457
+ *
458
+ * Usage: `team rename <name>`
459
+ */
460
+ async teamRename(name, options) {
461
+ const result = await this.#transport.call("team rename", [name], options, {}, false);
462
+ return result;
463
+ }
464
+ /**
465
+ * Show your team's plan
466
+ *
467
+ * Usage: `team billing plan [--all]`
468
+ *
469
+ * CLI examples:
470
+ * ```
471
+ * team billing plan
472
+ * team billing plan --all # plans your team can switch to
473
+ * ```
474
+ */
475
+ async teamBillingPlan(options) {
476
+ const result = await this.#transport.call("team billing plan", [], options, {
477
+ all: "bool",
478
+ }, false);
479
+ return result;
480
+ }
481
+ /**
482
+ * Update team billing information
483
+ *
484
+ * Usage: `team billing update [--email=<email>] [--name=<name>] [--business-name=<name>] [--phone=<phone>] [--address-line1=<line>] [--address-line2=<line>] [--address-city=<city>] [--address-state=<state>] [--address-postal-code=<code>] [--address-country=<country>] [--tax-id-type=<type>] [--tax-id-value=<value>]`
485
+ */
486
+ async teamBillingUpdate(options) {
487
+ const result = await this.#transport.call("team billing update", [], options, {
488
+ "address-city": "string",
489
+ "address-country": "string",
490
+ "address-line1": "string",
491
+ "address-line2": "string",
492
+ "address-postal-code": "string",
493
+ "address-state": "string",
494
+ "business-name": "string",
495
+ email: "string",
496
+ name: "string",
497
+ phone: "string",
498
+ "tax-id-type": "string",
499
+ "tax-id-value": "string",
500
+ }, false);
501
+ return result;
502
+ }
503
+ /**
504
+ * Transfer a VM to another team member
505
+ *
506
+ * Usage: `team transfer <vm_name> <target_email>`
507
+ */
508
+ async teamTransfer(vmName, targetEmail, options) {
509
+ const result = await this.#transport.call("team transfer", [vmName, targetEmail], options, {}, false);
510
+ return result;
511
+ }
512
+ /**
513
+ * View and manage team auth settings
514
+ *
515
+ * Usage: `team auth`
516
+ */
517
+ async teamAuth(options) {
518
+ const result = await this.#transport.call("team auth", [], options, {}, false);
519
+ return result;
520
+ }
521
+ /**
522
+ * Require OIDC for web login (web|off)
523
+ *
524
+ * Usage: `team auth require-oidc <web|off>`
525
+ */
526
+ async teamAuthRequireOidc(webOrOff, options) {
527
+ const result = await this.#transport.call("team auth require-oidc", [webOrOff], options, {}, false);
528
+ return result;
529
+ }
530
+ /**
531
+ * Set the team auth provider (default, google, oidc)
532
+ *
533
+ * Usage: `team auth set <default|google|oidc> [--issuer-url=<url> --client-id=<id> --client-secret=<secret>]`
534
+ */
535
+ async teamAuthSet(defaultOrGoogleOrOidc, options) {
536
+ const result = await this.#transport.call("team auth set", [defaultOrGoogleOrOidc], options, {
537
+ "client-id": "string",
538
+ "client-secret": "string",
539
+ "display-name": "string",
540
+ "issuer-url": "string",
541
+ }, false);
542
+ return result;
543
+ }
544
+ /**
545
+ * View and manage team settings
546
+ *
547
+ * Usage: `team settings`
548
+ */
549
+ async teamSettings(options) {
550
+ const result = await this.#transport.call("team settings", [], options, {}, false);
551
+ return result;
552
+ }
553
+ /**
554
+ * View and manage automatic VM placement
555
+ *
556
+ * Usage: `team settings vm-placement`
557
+ */
558
+ async teamSettingsVmPlacement(options) {
559
+ const result = await this.#transport.call("team settings vm-placement", [], options, {}, false);
560
+ return result;
561
+ }
562
+ /**
563
+ * Use ordinary VM placement
564
+ *
565
+ * Usage: `team settings vm-placement default`
566
+ */
567
+ async teamSettingsVmPlacementDefault(options) {
568
+ const result = await this.#transport.call("team settings vm-placement default", [], options, {}, false);
569
+ return result;
570
+ }
571
+ /**
572
+ * Send bare new commands to a shared team pool
573
+ *
574
+ * Usage: `team settings vm-placement pool <name>`
575
+ */
576
+ async teamSettingsVmPlacementPool(name, options) {
577
+ const result = await this.#transport.call("team settings vm-placement pool", [name], options, {}, false);
578
+ return result;
579
+ }
580
+ /**
581
+ * Create or reuse one team pool per member for bare new commands
582
+ *
583
+ * Usage: `team settings vm-placement member-pool --cpus=N [--max-vms=N]`
584
+ */
585
+ async teamSettingsVmPlacementMemberPool(options) {
586
+ const result = await this.#transport.call("team settings vm-placement member-pool", [], options, {
587
+ cpus: "number",
588
+ "max-vms": "number",
589
+ }, false);
590
+ return result;
591
+ }
592
+ /**
593
+ * Keep bare new commands outside pools while migrating (legacy)
594
+ *
595
+ * Usage: `team settings vm-placement poolless`
596
+ */
597
+ async teamSettingsVmPlacementPoolless(options) {
598
+ const result = await this.#transport.call("team settings vm-placement poolless", [], options, {}, false);
599
+ return result;
600
+ }
601
+ /**
602
+ * Set who can create standalone VMs
603
+ *
604
+ * Usage: `team settings standalone <off|admins-only|all-users>`
605
+ */
606
+ async teamSettingsStandalone(offOrAdminsOnlyOrAllUsers, options) {
607
+ const result = await this.#transport.call("team settings standalone", [offOrAdminsOnlyOrAllUsers], options, {}, false);
608
+ return result;
609
+ }
610
+ /**
611
+ * Allow or block the exe.dev LLM gateway (your own API keys are unaffected)
612
+ *
613
+ * Usage: `team settings llm-gateway <on|off>`
614
+ */
615
+ async teamSettingsLlmGateway(onOrOff, options) {
616
+ const result = await this.#transport.call("team settings llm-gateway", [onOrOff], options, {}, false);
617
+ return result;
618
+ }
619
+ /**
620
+ * Allow team VMs to share CPU cores with each other
621
+ *
622
+ * Usage: `team settings core-sharing <on|off>`
623
+ */
624
+ async teamSettingsCoreSharing(onOrOff, options) {
625
+ const result = await this.#transport.call("team settings core-sharing", [onOrOff], options, {}, false);
626
+ return result;
627
+ }
628
+ /**
629
+ * Set who can share team VMs
630
+ *
631
+ * Usage: `team settings vm-sharing <admins-only|all-members>`
632
+ */
633
+ async teamSettingsVmSharing(adminsOnlyOrAllMembers, options) {
634
+ const result = await this.#transport.call("team settings vm-sharing", [adminsOnlyOrAllMembers], options, {}, false);
635
+ return result;
636
+ }
637
+ /**
638
+ * Set how long members stay signed in on the web and mobile apps
639
+ *
640
+ * Usage: `team settings session-length <length>`
641
+ *
642
+ * CLI examples:
643
+ * ```
644
+ * team settings session-length 1d
645
+ * team settings session-length default
646
+ * ```
647
+ */
648
+ async teamSettingsSessionLength(length, options) {
649
+ const result = await this.#transport.call("team settings session-length", [length], options, {}, false);
650
+ return result;
651
+ }
652
+ /**
653
+ * Allow users from your email domain to join this team on signup
654
+ *
655
+ * Usage: `team settings auto-join <on|off>`
656
+ */
657
+ async teamSettingsAutoJoin(onOrOff, options) {
658
+ const result = await this.#transport.call("team settings auto-join", [onOrOff], options, {}, false);
659
+ return result;
660
+ }
661
+ /**
662
+ * List all VMs across your team
663
+ *
664
+ * Usage: `team vm ls [-l] [--group=tag|region|type|user|access] [name|pattern]`
665
+ *
666
+ * Tag-scoped API keys may run this command.
667
+ */
668
+ async teamVmLs(nameOrPattern, options) {
669
+ const result = await this.#transport.call("team vm ls", [nameOrPattern], options, {
670
+ group: "string",
671
+ l: "bool",
672
+ }, false);
673
+ return result;
674
+ }
675
+ /**
676
+ * Create a pool: reserved capacity for your team's VMs
677
+ *
678
+ * Usage: `pool new <name> --cpus=N [--region=<region>] [--max-vms=M]`
679
+ */
680
+ async poolNew(name, options) {
681
+ const result = await this.#transport.call("pool new", [name], options, {
682
+ cpus: "number",
683
+ "max-vms": "number",
684
+ region: "string",
685
+ }, false);
686
+ return result;
687
+ }
688
+ /**
689
+ * Show your team's dedicated hosts, where its new pools are placed
690
+ *
691
+ * Usage: `pool hosts`
692
+ */
693
+ async poolHosts(options) {
694
+ const result = await this.#transport.call("pool hosts", [], options, {}, false);
695
+ return result;
696
+ }
697
+ /**
698
+ * List your team's pools, or show live or historical usage with --usage
699
+ *
700
+ * Usage: `pool list [pool-name] [--usage [--range=live|24h|7d|30d]]`
701
+ */
702
+ async poolList(poolName, options) {
703
+ const result = await this.#transport.call("pool list", [poolName], options, {
704
+ range: "string",
705
+ usage: "bool",
706
+ }, false);
707
+ return result;
708
+ }
709
+ /**
710
+ * Adopt a VM into a pool; this can take several minutes
711
+ *
712
+ * Usage: `pool adopt --vm=<vm-name> --pool=<pool-name>`
713
+ *
714
+ * CLI examples:
715
+ * ```
716
+ * pool adopt --vm=builder --pool=compile
717
+ * ```
718
+ */
719
+ async poolAdopt(options) {
720
+ const result = await this.#transport.call("pool adopt", [], options, {
721
+ pool: "string",
722
+ vm: "string",
723
+ }, false);
724
+ return result;
725
+ }
726
+ /**
727
+ * Detach a VM from its pool into its own standalone capacity (--poolless leaves it outside any pool)
728
+ *
729
+ * Usage: `pool detach --vm=<vm-name> [--poolless]`
730
+ *
731
+ * CLI examples:
732
+ * ```
733
+ * pool detach --vm=builder
734
+ * pool detach --vm=builder --poolless
735
+ * ```
736
+ */
737
+ async poolDetach(options) {
738
+ const result = await this.#transport.call("pool detach", [], options, {
739
+ poolless: "bool",
740
+ vm: "string",
741
+ }, false);
742
+ return result;
743
+ }
744
+ /**
745
+ * Change a pool's CPU capacity or VM cap
746
+ *
747
+ * Usage: `pool resize <name> --cpus=N | pool resize <name> --max-vms=N [--force]`
748
+ */
749
+ async poolResize(args, options) {
750
+ const result = await this.#transport.call("pool resize", [args], options, {
751
+ cpus: "number",
752
+ force: "bool",
753
+ "max-vms": "string",
754
+ }, false);
755
+ return result;
756
+ }
757
+ /**
758
+ * Rename a pool without changing its capacity or VMs
759
+ *
760
+ * Usage: `pool rename <old-name> <new-name>`
761
+ */
762
+ async poolRename(oldName, newName, options) {
763
+ const result = await this.#transport.call("pool rename", [oldName, newName], options, {}, false);
764
+ return result;
765
+ }
766
+ /**
767
+ * Delete a pool (refused while it has VMs; --force detaches them)
768
+ *
769
+ * Usage: `pool delete <name> [--force]`
770
+ */
771
+ async poolDelete(name, options) {
772
+ const result = await this.#transport.call("pool delete", [name], options, {}, false);
773
+ return result;
774
+ }
775
+ /**
776
+ * Show your current plan and resource limits
777
+ *
778
+ * Usage: `billing plan [--all]`
779
+ *
780
+ * CLI examples:
781
+ * ```
782
+ * billing plan
783
+ * billing plan --all # plans you can switch to
784
+ * ```
785
+ */
786
+ async billingPlan(options) {
787
+ const result = await this.#transport.call("billing plan", [], options, {
788
+ all: "bool",
789
+ }, false);
790
+ return result;
791
+ }
792
+ /**
793
+ * Show VM resource usage against your plan quotas
794
+ *
795
+ * Usage: `billing usage [--range=cycle|24h|7d|30d] [--group=vm]`
796
+ *
797
+ * CLI examples:
798
+ * ```
799
+ * billing usage --range=7d
800
+ * billing credits usage # Shelley/LLM credit spend instead
801
+ * ```
802
+ */
803
+ async billingUsage(options) {
804
+ const result = await this.#transport.call("billing usage", [], options, {
805
+ group: "string",
806
+ range: "string",
807
+ }, false);
808
+ return result;
809
+ }
810
+ /**
811
+ * Show Shelley credit balances
812
+ *
813
+ * Usage: `billing credits [usage|transactions|buy]`
814
+ */
815
+ async billingCredits(options) {
816
+ const result = await this.#transport.call("billing credits", [], options, {}, false);
817
+ return result;
818
+ }
819
+ /**
820
+ * Show Shelley (LLM) credit spend by model, day, or VM
821
+ *
822
+ * Usage: `billing credits usage [--month=YYYY-MM] [--group=model|day|box] [--detail]`
823
+ *
824
+ * CLI examples:
825
+ * ```
826
+ * billing credits usage --group=day
827
+ * billing credits usage --group=box --detail
828
+ * billing credits usage --month=2026-05 --group=box
829
+ * ```
830
+ */
831
+ async billingCreditsUsage(options) {
832
+ const result = await this.#transport.call("billing credits usage", [], options, {
833
+ detail: "bool",
834
+ group: "string",
835
+ month: "string",
836
+ }, false);
837
+ return result;
838
+ }
839
+ /**
840
+ * Show your credit purchases and gifts
841
+ *
842
+ * Usage: `billing credits transactions [--limit=N]`
843
+ */
844
+ async billingCreditsTransactions(options) {
845
+ const result = await this.#transport.call("billing credits transactions", [], options, {
846
+ limit: "string",
847
+ }, false);
848
+ return result;
849
+ }
850
+ /**
851
+ * Buy Shelley credits with your personal payment method
852
+ *
853
+ * Usage: `billing credits buy <dollars> [--yes]`
854
+ *
855
+ * CLI examples:
856
+ * ```
857
+ * billing credits buy 25
858
+ * billing credits buy 100 --yes
859
+ * ```
860
+ */
861
+ async billingCreditsBuy(dollars, options) {
862
+ const result = await this.#transport.call("billing credits buy", [dollars], options, {
863
+ "idempotency-key": "string",
864
+ yes: "bool",
865
+ }, false);
866
+ return result;
867
+ }
868
+ /**
869
+ * Show invite rewards you've earned
870
+ *
871
+ * Usage: `billing rewards`
872
+ */
873
+ async billingRewards(options) {
874
+ const result = await this.#transport.call("billing rewards", [], options, {}, false);
875
+ return result;
876
+ }
877
+ /**
878
+ * Change your subscription capacity
879
+ *
880
+ * Usage: `billing capacity [--cpu=N] [--yes]`
881
+ *
882
+ * CLI examples:
883
+ * ```
884
+ * billing capacity
885
+ * billing capacity --cpu=4 --yes
886
+ * ```
887
+ */
888
+ async billingCapacity(options) {
889
+ const result = await this.#transport.call("billing capacity", [], options, {
890
+ cpu: "number",
891
+ yes: "bool",
892
+ }, false);
893
+ return result;
894
+ }
895
+ /**
896
+ * Show your payment methods
897
+ *
898
+ * Usage: `billing payment [list]`
899
+ */
900
+ async billingPayment(options) {
901
+ const result = await this.#transport.call("billing payment", [], options, {}, false);
902
+ return result;
903
+ }
904
+ /**
905
+ * List all payment methods on file
906
+ *
907
+ * Usage: `billing payment list`
908
+ */
909
+ async billingPaymentList(options) {
910
+ const result = await this.#transport.call("billing payment list", [], options, {}, false);
911
+ return result;
912
+ }
913
+ /**
914
+ * Remove a saved payment method
915
+ *
916
+ * Usage: `billing payment remove <ref>`
917
+ *
918
+ * CLI examples:
919
+ * ```
920
+ * billing payment remove 4f1c2a9b8d3e
921
+ * ```
922
+ */
923
+ async billingPaymentRemove(ref, options) {
924
+ const result = await this.#transport.call("billing payment remove", [ref], options, {}, false);
925
+ return result;
926
+ }
927
+ /**
928
+ * Make a saved payment method the default
929
+ *
930
+ * Usage: `billing payment default <ref>`
931
+ *
932
+ * CLI examples:
933
+ * ```
934
+ * billing payment default 4f1c2a9b8d3e
935
+ * ```
936
+ */
937
+ async billingPaymentDefault(ref, options) {
938
+ const result = await this.#transport.call("billing payment default", [ref], options, {}, false);
939
+ return result;
940
+ }
941
+ /**
942
+ * Open the billing management page
943
+ *
944
+ * Usage: `billing manage`
945
+ */
946
+ async billingManage(options) {
947
+ const result = await this.#transport.call("billing manage", [], options, {}, false);
948
+ return result;
949
+ }
950
+ /**
951
+ * Open the personal plan activation page
952
+ *
953
+ * Usage: `billing activate`
954
+ */
955
+ async billingActivate(options) {
956
+ const result = await this.#transport.call("billing activate", [], options, {}, false);
957
+ return result;
958
+ }
959
+ /**
960
+ * Update your billing contact information
961
+ *
962
+ * Usage: `billing update [--email=<email>] [--name=<name>] [--business-name=<name>] [--phone=<phone>] [--address-line1=<line>] [--address-line2=<line>] [--address-city=<city>] [--address-state=<state>] [--address-postal-code=<code>] [--address-country=<country>] [--tax-id-type=<type>] [--tax-id-value=<value>]`
963
+ */
964
+ async billingUpdate(options) {
965
+ const result = await this.#transport.call("billing update", [], options, {
966
+ "address-city": "string",
967
+ "address-country": "string",
968
+ "address-line1": "string",
969
+ "address-line2": "string",
970
+ "address-postal-code": "string",
971
+ "address-state": "string",
972
+ "business-name": "string",
973
+ email: "string",
974
+ name: "string",
975
+ phone: "string",
976
+ "tax-id-type": "string",
977
+ "tax-id-value": "string",
978
+ }, false);
979
+ return result;
980
+ }
981
+ /**
982
+ * Show recent invoices
983
+ *
984
+ * Usage: `billing invoices`
985
+ */
986
+ async billingInvoices(options) {
987
+ const result = await this.#transport.call("billing invoices", [], options, {}, false);
988
+ return result;
989
+ }
990
+ /**
991
+ * List invoices for your personal or team account
992
+ *
993
+ * Usage: `billing invoices list [--account=personal|team]`
994
+ *
995
+ * CLI examples:
996
+ * ```
997
+ * billing invoices list --account=team
998
+ * ```
999
+ */
1000
+ async billingInvoicesList(options) {
1001
+ const result = await this.#transport.call("billing invoices list", [], options, {
1002
+ account: "string",
1003
+ }, false);
1004
+ return result;
1005
+ }
1006
+ /**
1007
+ * Show one invoice with its usage breakdown
1008
+ *
1009
+ * Usage: `billing invoices show <id> [--vms]`
1010
+ *
1011
+ * CLI examples:
1012
+ * ```
1013
+ * billing invoices show in_1Abc --vms
1014
+ * ```
1015
+ */
1016
+ async billingInvoicesShow(id, options) {
1017
+ const result = await this.#transport.call("billing invoices show", [id], options, {
1018
+ vms: "bool",
1019
+ }, false);
1020
+ return result;
1021
+ }
1022
+ /**
1023
+ * Show credit purchase receipts and purchases (this billing account only)
1024
+ *
1025
+ * Usage: `billing receipts [--from=<YYYY-MM-DD>] [--to=<YYYY-MM-DD>]`
1026
+ *
1027
+ * CLI examples:
1028
+ * ```
1029
+ * billing receipts --from=2026-01-01 --to=2026-06-30
1030
+ * ```
1031
+ */
1032
+ async billingReceipts(options) {
1033
+ const result = await this.#transport.call("billing receipts", [], options, {
1034
+ from: "string",
1035
+ to: "string",
1036
+ }, false);
1037
+ return result;
1038
+ }
1039
+ /**
1040
+ * Open a consolidated credit purchase statement
1041
+ *
1042
+ * Usage: `billing statement [--from=<YYYY-MM-DD>] [--to=<YYYY-MM-DD>]`
1043
+ *
1044
+ * CLI examples:
1045
+ * ```
1046
+ * billing statement --from=2026-01-01 --to=2026-06-30
1047
+ * ```
1048
+ */
1049
+ async billingStatement(options) {
1050
+ const result = await this.#transport.call("billing statement", [], options, {
1051
+ from: "string",
1052
+ to: "string",
1053
+ }, false);
1054
+ return result;
1055
+ }
1056
+ /**
1057
+ * Connect a marketplace subscription to your team
1058
+ *
1059
+ * Usage: `billing provider link <aws|azure> --token=<link-token> [--size=<team-size>] [--team-name=<name>]`
1060
+ */
1061
+ async billingProviderLink(awsOrAzure, options) {
1062
+ const result = await this.#transport.call("billing provider link", [awsOrAzure], options, {
1063
+ size: "string",
1064
+ "team-name": "string",
1065
+ token: "string",
1066
+ }, false);
1067
+ return result;
1068
+ }
1069
+ /**
1070
+ * Manage your invite link and rewards
1071
+ */
1072
+ async invite(options) {
1073
+ const result = await this.#transport.call("invite", [], options, {}, false);
1074
+ return result;
1075
+ }
1076
+ /**
1077
+ * Show your active invite link and reward
1078
+ *
1079
+ * Usage: `invite show`
1080
+ */
1081
+ async inviteShow(options) {
1082
+ const result = await this.#transport.call("invite show", [], options, {}, false);
1083
+ return result;
1084
+ }
1085
+ /**
1086
+ * Print only your active invite link
1087
+ *
1088
+ * Usage: `invite link`
1089
+ */
1090
+ async inviteLink(options) {
1091
+ const result = await this.#transport.call("invite link", [], options, {}, false);
1092
+ return result;
1093
+ }
1094
+ /**
1095
+ * List invite rewards you can use
1096
+ *
1097
+ * Usage: `invite rewards`
1098
+ */
1099
+ async inviteRewards(options) {
1100
+ const result = await this.#transport.call("invite rewards", [], options, {}, false);
1101
+ return result;
1102
+ }
1103
+ /**
1104
+ * Choose the reward for your invite link
1105
+ *
1106
+ * Usage: `invite set-reward standard|bonus-credits|extra-memory|extra-disk`
1107
+ */
1108
+ async inviteSetReward(standardOrBonusCreditsOrExtraMemoryOrExtraDisk, options) {
1109
+ const result = await this.#transport.call("invite set-reward", [standardOrBonusCreditsOrExtraMemoryOrExtraDisk], options, {}, false);
1110
+ return result;
1111
+ }
1112
+ /**
1113
+ * Show signups, upgrades, and reward status
1114
+ *
1115
+ * Usage: `invite activity`
1116
+ */
1117
+ async inviteActivity(options) {
1118
+ const result = await this.#transport.call("invite activity", [], options, {}, false);
1119
+ return result;
1120
+ }
1121
+ /**
1122
+ * Request more trial invites
1123
+ *
1124
+ * Usage: `invite request`
1125
+ */
1126
+ async inviteRequest(options) {
1127
+ const result = await this.#transport.call("invite request", [], options, {}, false);
1128
+ return result;
1129
+ }
1130
+ /**
1131
+ * Open the invites page
1132
+ *
1133
+ * Usage: `invite manage`
1134
+ */
1135
+ async inviteManage(options) {
1136
+ const result = await this.#transport.call("invite manage", [], options, {}, false);
1137
+ return result;
1138
+ }
1139
+ /**
1140
+ * Generate a magic link to log in to the website
1141
+ *
1142
+ * Usage: `browser`
1143
+ */
1144
+ async browser(options) {
1145
+ const result = await this.#transport.call("browser", [], options, {
1146
+ qr: "bool",
1147
+ }, false);
1148
+ return result;
1149
+ }
1150
+ }
1151
+ /** A VM reference. info is a snapshot; refresh() fetches current metadata. */
1152
+ export class VM {
1153
+ #transport;
1154
+ #info;
1155
+ /** @internal Obtain VMs through exe.new(), exe.ls(), exe.vm(), or vm.cp(). */
1156
+ constructor(transport, info) {
1157
+ this.#transport = transport;
1158
+ this.#info = Object.freeze({ ...info, tags: Object.freeze([...info.tags]) });
1159
+ }
1160
+ get info() { return this.#info; }
1161
+ get name() { return this.#info.name; }
1162
+ get httpsUrl() { return this.#info.httpsUrl; }
1163
+ get sshDest() { return this.#info.sshDest; }
1164
+ get tags() { return this.#info.tags; }
1165
+ /** Run a shell command once. Nonzero exit codes are results, not exceptions. */
1166
+ ssh(command, options) {
1167
+ return this.#transport.ssh(this.name, command, options);
1168
+ }
1169
+ /** Refresh metadata without changing this reference's identity. Requires ls permission. */
1170
+ async refresh(options) {
1171
+ const result = await this.#transport.call("ls", [this.name], options, {}, true);
1172
+ const vm = listVMs(this.#transport, result).find((vm) => vm.name === this.name);
1173
+ if (!vm)
1174
+ throw new ExeAPIError("ls", 404, "VM not found");
1175
+ this.#info = vm.info;
1176
+ return this;
1177
+ }
1178
+ /**
1179
+ * Probe SSH with `true` until it exits successfully. Never reruns a user command.
1180
+ * The default deadline is 60 seconds, including requests and backoff. This does
1181
+ * not wait for application servers or setup scripts. Requires ssh permission.
1182
+ */
1183
+ async waitUntilReady(options = {}) {
1184
+ const timeoutMs = readyTimeout(options.timeoutMs);
1185
+ options.signal?.throwIfAborted();
1186
+ const controller = new AbortController();
1187
+ const abort = () => controller.abort(options.signal.reason);
1188
+ options.signal?.addEventListener("abort", abort, { once: true });
1189
+ const timer = setTimeout(() => controller.abort(new DOMException("SSH readiness timed out", "TimeoutError")), timeoutMs);
1190
+ let backoff = 100;
1191
+ try {
1192
+ while (true) {
1193
+ try {
1194
+ const result = await abortable(this.ssh("true", { signal: controller.signal, capture: false }), controller.signal);
1195
+ controller.signal.throwIfAborted();
1196
+ if (result.exitCode !== 0)
1197
+ throw new ExeProtocolError("ssh readiness probe");
1198
+ return this;
1199
+ }
1200
+ catch (err) {
1201
+ controller.signal.throwIfAborted();
1202
+ // /exec reports these failures before a remote command starts. Other
1203
+ // rejections (not found, permissions, no SSH configured) fail fast.
1204
+ if (!(err instanceof ExeAPIError) || err.status !== 422 ||
1205
+ !/failed to (?:connect|dial|create session|run command on VM)/i.test(err.details().body))
1206
+ throw err;
1207
+ }
1208
+ await delay(backoff, controller.signal);
1209
+ backoff = Math.min(backoff * 2, 1000);
1210
+ }
1211
+ }
1212
+ catch (err) {
1213
+ options.signal?.throwIfAborted();
1214
+ throw new VMReadyError(this, err);
1215
+ }
1216
+ finally {
1217
+ clearTimeout(timer);
1218
+ options.signal?.removeEventListener("abort", abort);
1219
+ }
1220
+ }
1221
+ /**
1222
+ * Delete a VM
1223
+ *
1224
+ * Usage: `rm <vmname>...`
1225
+ *
1226
+ * Tag-scoped API keys may run this command.
1227
+ */
1228
+ async rm(options) {
1229
+ const result = await this.#transport.call("rm", [this.name], options, {}, true);
1230
+ return result;
1231
+ }
1232
+ /**
1233
+ * Restart a VM
1234
+ *
1235
+ * Usage: `restart <vmname>`
1236
+ *
1237
+ * Tag-scoped API keys may run this command.
1238
+ */
1239
+ async restart(options) {
1240
+ const ready = readiness(options ?? {});
1241
+ const { waitUntil, timeoutMs, ...flags } = options ?? {};
1242
+ const result = await this.#transport.call("restart", [this.name], flags, {}, true);
1243
+ if (ready)
1244
+ await this.waitUntilReady(ready);
1245
+ return this;
1246
+ }
1247
+ /**
1248
+ * Pause a VM (snapshot RAM to disk, free its CPU and memory)
1249
+ *
1250
+ * Usage: `pause <vmname>`
1251
+ *
1252
+ * CLI examples:
1253
+ * ```
1254
+ * pause my-vm # snapshot RAM to disk; resume later with 'resume my-vm'
1255
+ * ```
1256
+ *
1257
+ * Tag-scoped API keys may run this command.
1258
+ */
1259
+ async pause(options) {
1260
+ const result = await this.#transport.call("pause", [this.name], options, {}, false);
1261
+ return result;
1262
+ }
1263
+ /**
1264
+ * Resume a paused VM (restore RAM from disk)
1265
+ *
1266
+ * Usage: `resume <vmname>`
1267
+ *
1268
+ * Tag-scoped API keys may run this command.
1269
+ */
1270
+ async resume(options) {
1271
+ const ready = readiness(options ?? {});
1272
+ const { waitUntil, timeoutMs, ...flags } = options ?? {};
1273
+ const result = await this.#transport.call("resume", [this.name], flags, {}, false);
1274
+ if (ready)
1275
+ await this.waitUntilReady(ready);
1276
+ return this;
1277
+ }
1278
+ /**
1279
+ * rename a vm
1280
+ *
1281
+ * Usage: `rename <oldname> <newname>`
1282
+ *
1283
+ * Tag-scoped API keys may run this command.
1284
+ */
1285
+ async rename(newname, options) {
1286
+ if (newname === this.name)
1287
+ return this;
1288
+ const result = await this.#transport.call("rename", [this.name, newname], options, {}, true);
1289
+ if (result?.new_name !== newname || result?.old_name !== this.name)
1290
+ throw new ExeProtocolError("rename");
1291
+ // Destinations and other metadata may have changed. Do not invent URLs.
1292
+ this.#info = Object.freeze({ name: newname, tags: this.tags });
1293
+ return this;
1294
+ }
1295
+ /**
1296
+ * Add or remove tags on a VM
1297
+ *
1298
+ * Usage: `tag [-d] <vm> <tag-name> [tag-name...]`
1299
+ *
1300
+ * CLI examples:
1301
+ * ```
1302
+ * tag my-vm prod web # add tags
1303
+ * tag -d my-vm prod web # remove tags
1304
+ * ```
1305
+ *
1306
+ * Tag-scoped API keys may run this command.
1307
+ */
1308
+ async tag(tagNames, options) {
1309
+ const result = await this.#transport.call("tag", [this.name, tagNames], options, {
1310
+ d: "bool",
1311
+ }, false);
1312
+ return result;
1313
+ }
1314
+ /**
1315
+ * Copy an existing VM
1316
+ *
1317
+ * Usage: `cp <source-vm> [new-name] [--pool=<name>] [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
1318
+ *
1319
+ * CLI examples:
1320
+ * ```
1321
+ * cp my-vm # copy with auto-generated name
1322
+ * cp my-vm my-vm-copy # copy with specific name
1323
+ * cp my-vm --cpu=4 --memory=16GB # copy with different resources
1324
+ * cp my-vm my-pool-copy --pool=build # copy into a team pool
1325
+ * cp my-vm --copy-tags=false # copy without tags
1326
+ * ```
1327
+ *
1328
+ * Tag-scoped API keys may run this command.
1329
+ */
1330
+ async cp(options) {
1331
+ const ready = readiness(options ?? {});
1332
+ const { waitUntil, timeoutMs, name, ...flags } = options ?? {};
1333
+ const result = await this.#transport.call("cp", [this.name, name], flags, {
1334
+ "copy-tags": "bool",
1335
+ cpu: "number",
1336
+ disk: "string",
1337
+ memory: "string",
1338
+ pool: "string",
1339
+ sandbox: "bool",
1340
+ standalone: "bool",
1341
+ }, true);
1342
+ const vm = new VM(this.#transport, vmInfo(result, "cp"));
1343
+ if (ready)
1344
+ await vm.waitUntilReady(ready);
1345
+ return vm;
1346
+ }
1347
+ /**
1348
+ * Resize a VM's resources (memory, CPU, disk)
1349
+ *
1350
+ * Usage: `resize <vmname> [--memory=<size>] [--cpu=<count>] [--disk=<size>]`
1351
+ *
1352
+ * Tag-scoped API keys may run this command.
1353
+ */
1354
+ async resize(options) {
1355
+ const result = await this.#transport.call("resize", [this.name], options, {
1356
+ cpu: "number",
1357
+ disk: "string",
1358
+ memory: "string",
1359
+ }, false);
1360
+ return result;
1361
+ }
1362
+ /**
1363
+ * Set or clear a short comment on a VM
1364
+ *
1365
+ * Usage: `comment <hostname> <text>`
1366
+ *
1367
+ * CLI examples:
1368
+ * ```
1369
+ * comment my-vm staging copy
1370
+ * comment my-vm "" # clear the comment
1371
+ * ```
1372
+ *
1373
+ * Tag-scoped API keys may run this command.
1374
+ */
1375
+ async comment(text, options) {
1376
+ const result = await this.#transport.call("comment", [this.name, text], options, {}, false);
1377
+ return result;
1378
+ }
1379
+ /**
1380
+ * Link a custom domain to a VM
1381
+ *
1382
+ * Usage: `domain add [--wildcard] <vm> <domain>`
1383
+ */
1384
+ async domainAdd(domain, options) {
1385
+ const result = await this.#transport.call("domain add", [this.name, domain], options, {
1386
+ wildcard: "bool",
1387
+ }, false);
1388
+ return result;
1389
+ }
1390
+ /**
1391
+ * Remove a custom domain from a VM
1392
+ *
1393
+ * Usage: `domain rm <vm> <domain>`
1394
+ */
1395
+ async domainRm(domain, options) {
1396
+ const result = await this.#transport.call("domain rm", [this.name, domain], options, {}, false);
1397
+ return result;
1398
+ }
1399
+ /**
1400
+ * Show current shares for a VM
1401
+ *
1402
+ * Usage: `share show <vm>`
1403
+ *
1404
+ * Tag-scoped API keys may run this command.
1405
+ */
1406
+ async shareShow(options) {
1407
+ const result = await this.#transport.call("share show", [this.name], options, {
1408
+ qr: "bool",
1409
+ }, false);
1410
+ return result;
1411
+ }
1412
+ /**
1413
+ * Set the HTTP proxy port for a VM
1414
+ *
1415
+ * Usage: `share port <vm> [port]`
1416
+ *
1417
+ * CLI examples:
1418
+ * ```
1419
+ * share port mybox 8080
1420
+ * ```
1421
+ *
1422
+ * Tag-scoped API keys may run this command.
1423
+ */
1424
+ async sharePort(port, options) {
1425
+ const result = await this.#transport.call("share port", [this.name, port], options, {}, false);
1426
+ return result;
1427
+ }
1428
+ /**
1429
+ * Make the HTTP proxy publicly accessible
1430
+ *
1431
+ * Usage: `share set-public <vm>`
1432
+ *
1433
+ * Tag-scoped API keys may run this command.
1434
+ */
1435
+ async shareSetPublic(options) {
1436
+ const result = await this.#transport.call("share set-public", [this.name], options, {}, false);
1437
+ return result;
1438
+ }
1439
+ /**
1440
+ * Restrict the HTTP proxy to authenticated users
1441
+ *
1442
+ * Usage: `share set-private <vm>`
1443
+ *
1444
+ * Tag-scoped API keys may run this command.
1445
+ */
1446
+ async shareSetPrivate(options) {
1447
+ const result = await this.#transport.call("share set-private", [this.name], options, {}, false);
1448
+ return result;
1449
+ }
1450
+ /**
1451
+ * Share VM with a user via email, or grant shell access with --root
1452
+ *
1453
+ * Usage: `share add <vm> <email|team> [--root] [--message='...']`
1454
+ *
1455
+ * CLI examples:
1456
+ * ```
1457
+ * share add mybox user@example.com
1458
+ * share add mybox user@example.com --message='Check this out'
1459
+ * share add mybox team
1460
+ * share add mybox teammate@example.com --root
1461
+ * share add mybox team --root
1462
+ * ```
1463
+ *
1464
+ * Tag-scoped API keys may run this command.
1465
+ */
1466
+ async shareAdd(emailOrTeam, options) {
1467
+ const result = await this.#transport.call("share add", [this.name, emailOrTeam], options, {
1468
+ message: "string",
1469
+ qr: "bool",
1470
+ root: "bool",
1471
+ }, false);
1472
+ return result;
1473
+ }
1474
+ /**
1475
+ * Revoke a user's access to a VM, or downgrade shell access to web with --root
1476
+ *
1477
+ * Usage: `share remove <vm> <email|team> [--root]`
1478
+ *
1479
+ * CLI examples:
1480
+ * ```
1481
+ * share remove mybox user@example.com
1482
+ * share remove mybox team
1483
+ * share remove mybox teammate@example.com --root
1484
+ * share remove mybox team --root
1485
+ * ```
1486
+ *
1487
+ * Tag-scoped API keys may run this command.
1488
+ */
1489
+ async shareRemove(emailOrTeam, options) {
1490
+ const result = await this.#transport.call("share remove", [this.name, emailOrTeam], options, {
1491
+ root: "bool",
1492
+ }, false);
1493
+ return result;
1494
+ }
1495
+ /**
1496
+ * Create a shareable link for a VM
1497
+ *
1498
+ * Usage: `share add-link <vm>`
1499
+ *
1500
+ * Tag-scoped API keys may run this command.
1501
+ */
1502
+ async shareAddLink(options) {
1503
+ const result = await this.#transport.call("share add-link", [this.name], options, {
1504
+ qr: "bool",
1505
+ }, false);
1506
+ return result;
1507
+ }
1508
+ /**
1509
+ * Revoke a shareable link
1510
+ *
1511
+ * Usage: `share remove-link <vm> <token>`
1512
+ *
1513
+ * Tag-scoped API keys may run this command.
1514
+ */
1515
+ async shareRemoveLink(token, options) {
1516
+ const result = await this.#transport.call("share remove-link", [this.name, token], options, {}, false);
1517
+ return result;
1518
+ }
1519
+ /**
1520
+ * Enable or disable inbound email for a VM
1521
+ *
1522
+ * Usage: `share receive-email <vm> [on|off] [--reply-policy=all|known|owner|none]`
1523
+ *
1524
+ * CLI examples:
1525
+ * ```
1526
+ * share receive-email mybox on
1527
+ * share receive-email mybox off
1528
+ * share receive-email mybox --reply-policy=known
1529
+ * share receive-email mybox
1530
+ * ```
1531
+ *
1532
+ * Tag-scoped API keys may run this command.
1533
+ */
1534
+ async shareReceiveEmail(onOrOff, options) {
1535
+ const result = await this.#transport.call("share receive-email", [this.name, onOrOff], options, {
1536
+ "reply-policy": "string",
1537
+ }, false);
1538
+ return result;
1539
+ }
1540
+ /**
1541
+ * Install or upgrade Shelley to the current version
1542
+ *
1543
+ * Usage: `shelley install <vm>`
1544
+ *
1545
+ * Tag-scoped API keys may run this command.
1546
+ */
1547
+ async shelleyInstall(options) {
1548
+ const result = await this.#transport.call("shelley install", [this.name], options, {}, false);
1549
+ return result;
1550
+ }
1551
+ /**
1552
+ * Allow exe.dev support to log in to a VM
1553
+ *
1554
+ * Usage: `grant-support-root <vmname> on|off`
1555
+ *
1556
+ * Tag-scoped API keys may run this command.
1557
+ */
1558
+ async grantSupportRoot(onOrOff, options) {
1559
+ const result = await this.#transport.call("grant-support-root", [this.name, onOrOff], options, {}, false);
1560
+ return result;
1561
+ }
1562
+ /**
1563
+ * Show vCPU, disk, IO, and network (RX/TX) metrics for a VM
1564
+ *
1565
+ * Usage: `stat <vm-name> [--range=24h|7d|30d]`
1566
+ *
1567
+ * CLI examples:
1568
+ * ```
1569
+ * stat my-vm # last 24 hours (default)
1570
+ * stat my-vm --range=7d # last 7 days
1571
+ * stat my-vm --range=30d # last 30 days
1572
+ * ```
1573
+ *
1574
+ * Tag-scoped API keys may run this command.
1575
+ */
1576
+ async stat(options) {
1577
+ const result = await this.#transport.call("stat", [this.name], options, {
1578
+ range: "string",
1579
+ }, true);
1580
+ return result;
1581
+ }
1582
+ }
1583
+ /** Readiness failed after a VM was obtained/created. The VM is not deleted. */
1584
+ export class VMReadyError extends Error {
1585
+ vm;
1586
+ constructor(vm, cause) {
1587
+ super(`exedev: VM ${vm.name} is not SSH-ready`, { cause });
1588
+ this.vm = vm;
1589
+ this.name = "VMReadyError";
1590
+ }
1591
+ }
1592
+ function readyTimeout(value = 60_000) {
1593
+ if (!Number.isSafeInteger(value) || value <= 0 || value > 2_147_483_647) {
1594
+ throw new TypeError("exedev: timeoutMs must be a positive integer no greater than 2147483647");
1595
+ }
1596
+ return value;
1597
+ }
1598
+ function readiness(options) {
1599
+ const { waitUntil = "ssh", timeoutMs, signal } = options;
1600
+ readyTimeout(timeoutMs); // Validate before creating/copying/restarting a VM.
1601
+ if (waitUntil !== "ssh" && waitUntil !== "created")
1602
+ throw new TypeError("exedev: waitUntil must be ssh or created");
1603
+ return waitUntil === "ssh" ? { timeoutMs, signal } : undefined;
1604
+ }
1605
+ function vmInfo(value, operation) {
1606
+ if (!value || typeof value !== "object" || Array.isArray(value))
1607
+ throw new ExeProtocolError(operation);
1608
+ const obj = value;
1609
+ const string = (key, required = false) => {
1610
+ const value = obj[key];
1611
+ if (value === undefined && !required)
1612
+ return undefined;
1613
+ if (typeof value !== "string" || required && !value)
1614
+ throw new ExeProtocolError(operation);
1615
+ return value;
1616
+ };
1617
+ const name = string(operation === "cp" ? "name" : "vm_name", true);
1618
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(name))
1619
+ throw new ExeProtocolError(operation);
1620
+ const tags = obj.tags ?? [];
1621
+ if (!Array.isArray(tags) || !tags.every((tag) => typeof tag === "string"))
1622
+ throw new ExeProtocolError(operation);
1623
+ return {
1624
+ name, tags,
1625
+ sshDest: string(operation === "cp" ? "ssh" : "ssh_dest", true),
1626
+ httpsUrl: string("https_url", operation !== "cp"),
1627
+ status: string(operation === "cp" ? "state" : "status"),
1628
+ region: string("region"),
1629
+ comment: string("comment"),
1630
+ createdAt: string("created_at"),
1631
+ setupError: string("error"),
1632
+ };
1633
+ }
1634
+ function listVMs(transport, value) {
1635
+ if (!value || typeof value !== "object" || !("vms" in value) || !Array.isArray(value.vms)) {
1636
+ throw new ExeProtocolError("ls");
1637
+ }
1638
+ return value.vms.map((row) => new VM(transport, vmInfo(row, "ls")));
1639
+ }
1640
+ //# sourceMappingURL=commands.gen.js.map