agentbox-sdk 0.0.0 → 0.1.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,1436 @@
1
+ import {
2
+ AsyncQueue,
3
+ UnsupportedProviderError,
4
+ pipeReadableStream,
5
+ readNodeStream,
6
+ readStreamAsText,
7
+ sleep
8
+ } from "./chunk-HMBWQSVN.js";
9
+ import {
10
+ shellQuote,
11
+ toShellCommand
12
+ } from "./chunk-JFDP556Q.js";
13
+
14
+ // src/sandboxes/git.ts
15
+ function encodeExtraHeader(name, value) {
16
+ return `http.extraHeader=${name}: ${value}`;
17
+ }
18
+ function buildGitCloneCommand(options) {
19
+ const targetDir = options.targetDir ?? ".";
20
+ const cloneArgs = [];
21
+ if (options.depth) {
22
+ cloneArgs.push("--depth", String(options.depth));
23
+ }
24
+ if (options.branch) {
25
+ cloneArgs.push("--branch", options.branch, "--single-branch");
26
+ }
27
+ const configArgs = [];
28
+ if (options.token) {
29
+ configArgs.push(
30
+ "-c",
31
+ encodeExtraHeader("Authorization", `Bearer ${options.token}`)
32
+ );
33
+ }
34
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
35
+ configArgs.push("-c", encodeExtraHeader(name, value));
36
+ }
37
+ const command = [
38
+ "git",
39
+ ...configArgs.map(shellQuote),
40
+ "clone",
41
+ ...cloneArgs.map(shellQuote),
42
+ shellQuote(options.repoUrl),
43
+ shellQuote(targetDir)
44
+ ].join(" ");
45
+ if (targetDir === ".") {
46
+ return command;
47
+ }
48
+ return `mkdir -p ${shellQuote(targetDir)} && rm -rf ${shellQuote(targetDir)} && ${command}`;
49
+ }
50
+
51
+ // src/sandboxes/base.ts
52
+ var SandboxAdapter = class {
53
+ options;
54
+ secrets = {};
55
+ baseEnv;
56
+ provisioned = false;
57
+ provisioning;
58
+ constructor(options) {
59
+ this.options = options;
60
+ this.baseEnv = { ...options.env ?? {} };
61
+ }
62
+ async ensureProvisioned() {
63
+ if (this.provisioned) {
64
+ return;
65
+ }
66
+ if (!this.provisioning) {
67
+ this.provisioning = (async () => {
68
+ await this.provision();
69
+ this.provisioned = true;
70
+ })().finally(() => {
71
+ this.provisioning = void 0;
72
+ });
73
+ }
74
+ await this.provisioning;
75
+ }
76
+ get tags() {
77
+ return { ...this.options.tags ?? {} };
78
+ }
79
+ get workingDir() {
80
+ return this.options.workingDir ?? "/workspace";
81
+ }
82
+ getMergedEnv(extra) {
83
+ return {
84
+ ...this.baseEnv,
85
+ ...this.secrets,
86
+ ...extra ?? {}
87
+ };
88
+ }
89
+ setSecret(name, value) {
90
+ this.secrets[name] = value;
91
+ }
92
+ setSecrets(values) {
93
+ Object.assign(this.secrets, values);
94
+ }
95
+ async gitClone(options) {
96
+ await this.ensureProvisioned();
97
+ return this.run(buildGitCloneCommand(options), {
98
+ cwd: this.workingDir,
99
+ env: this.getMergedEnv()
100
+ });
101
+ }
102
+ };
103
+
104
+ // src/sandboxes/providers/daytona.ts
105
+ import { Daytona } from "@daytonaio/sdk";
106
+
107
+ // src/sandboxes/image-utils.ts
108
+ function resolveSandboxImage(image) {
109
+ return image;
110
+ }
111
+ function resolveSandboxResources(resources) {
112
+ return resources && Object.values(resources).some((value) => value !== void 0) ? resources : void 0;
113
+ }
114
+
115
+ // src/sandboxes/providers/daytona.ts
116
+ var DaytonaSandboxAdapter = class extends SandboxAdapter {
117
+ client;
118
+ sandbox;
119
+ constructor(options) {
120
+ super(options);
121
+ this.client = new Daytona({
122
+ apiKey: options.provider?.apiKey,
123
+ jwtToken: options.provider?.jwtToken,
124
+ organizationId: options.provider?.organizationId,
125
+ apiUrl: options.provider?.apiUrl,
126
+ target: options.provider?.target
127
+ });
128
+ }
129
+ get provider() {
130
+ return "daytona";
131
+ }
132
+ get raw() {
133
+ return {
134
+ client: this.client,
135
+ sandbox: this.sandbox
136
+ };
137
+ }
138
+ get id() {
139
+ return this.sandbox?.id;
140
+ }
141
+ async provision() {
142
+ const existing = await this.findMatchingSandbox();
143
+ if (existing) {
144
+ this.sandbox = existing;
145
+ await existing.start();
146
+ return;
147
+ }
148
+ const labels = this.getLabels();
149
+ const autoStopInterval = this.options.idleTimeoutMs ? Math.max(1, Math.ceil(this.options.idleTimeoutMs / 6e4)) : void 0;
150
+ const autoDeleteInterval = this.options.autoStopMs ? Math.max(1, Math.ceil(this.options.autoStopMs / 6e4)) : void 0;
151
+ const image = resolveSandboxImage(this.options.image);
152
+ const resources = resolveSandboxResources(this.options.resources);
153
+ if (!image) {
154
+ throw new Error(
155
+ "daytona sandboxes require options.image to reference a prebuilt Daytona snapshot."
156
+ );
157
+ }
158
+ if (resources) {
159
+ throw new Error(
160
+ "daytona sandbox sizing is embedded in the image id and cannot be set via options.resources."
161
+ );
162
+ }
163
+ const createBase = {
164
+ name: this.options.provider?.name,
165
+ language: this.options.provider?.language ?? "typescript",
166
+ user: this.options.provider?.user,
167
+ envVars: this.getMergedEnv(),
168
+ labels,
169
+ public: this.options.provider?.public ?? true,
170
+ autoStopInterval,
171
+ autoDeleteInterval
172
+ };
173
+ const sandbox = await this.client.create({
174
+ ...createBase,
175
+ snapshot: image
176
+ });
177
+ await sandbox.start();
178
+ this.sandbox = sandbox;
179
+ }
180
+ async run(command, options) {
181
+ await this.ensureProvisioned();
182
+ const sandbox = this.requireSandbox();
183
+ const result = await sandbox.process.executeCommand(
184
+ toShellCommand(command),
185
+ options?.cwd ?? this.workingDir,
186
+ this.getMergedEnv(options?.env),
187
+ options?.timeoutMs ? Math.ceil(options.timeoutMs / 1e3) : void 0
188
+ );
189
+ const output = result.result ?? "";
190
+ return {
191
+ exitCode: result.exitCode,
192
+ stdout: output,
193
+ stderr: output,
194
+ combinedOutput: output,
195
+ raw: result
196
+ };
197
+ }
198
+ async runAsync(command, options) {
199
+ await this.ensureProvisioned();
200
+ const sandbox = this.requireSandbox();
201
+ const sessionId = `agentbox-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
202
+ await sandbox.process.createSession(sessionId);
203
+ const response = await sandbox.process.executeSessionCommand(
204
+ sessionId,
205
+ {
206
+ command: this.buildSessionCommand(command, options),
207
+ runAsync: true
208
+ },
209
+ options?.timeoutMs ? Math.ceil(options.timeoutMs / 1e3) : void 0
210
+ );
211
+ const commandId = response.cmdId;
212
+ const queue = new AsyncQueue();
213
+ let stdout = "";
214
+ let stderr = "";
215
+ let exitCode = 0;
216
+ let killed = false;
217
+ const streamLogs = sandbox.process.getSessionCommandLogs(
218
+ sessionId,
219
+ commandId,
220
+ (chunk) => {
221
+ stdout += chunk;
222
+ queue.push({
223
+ type: "stdout",
224
+ chunk,
225
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
226
+ });
227
+ },
228
+ (chunk) => {
229
+ stderr += chunk;
230
+ queue.push({
231
+ type: "stderr",
232
+ chunk,
233
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
234
+ });
235
+ }
236
+ );
237
+ const pollTimeoutMs = options?.timeoutMs ?? 0;
238
+ const completion = (async () => {
239
+ const pollStart = Date.now();
240
+ while (true) {
241
+ let status;
242
+ try {
243
+ status = await sandbox.process.getSessionCommand(
244
+ sessionId,
245
+ commandId
246
+ );
247
+ } catch (error) {
248
+ if (killed) {
249
+ break;
250
+ }
251
+ throw error;
252
+ }
253
+ if (status.exitCode !== null && status.exitCode !== void 0) {
254
+ if (!killed) {
255
+ exitCode = status.exitCode;
256
+ }
257
+ break;
258
+ }
259
+ if (pollTimeoutMs > 0 && Date.now() - pollStart > pollTimeoutMs) {
260
+ await sandbox.process.deleteSession(sessionId).catch(() => void 0);
261
+ killed = true;
262
+ exitCode = 130;
263
+ break;
264
+ }
265
+ await sleep(500);
266
+ }
267
+ try {
268
+ await streamLogs;
269
+ } catch (error) {
270
+ if (!killed) {
271
+ throw error;
272
+ }
273
+ }
274
+ queue.push({
275
+ type: "exit",
276
+ exitCode,
277
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
278
+ });
279
+ queue.finish();
280
+ return {
281
+ exitCode,
282
+ stdout,
283
+ stderr,
284
+ combinedOutput: `${stdout}${stderr}`,
285
+ raw: { sessionId, commandId }
286
+ };
287
+ })().catch((error) => {
288
+ queue.fail(error);
289
+ throw error;
290
+ });
291
+ return {
292
+ id: commandId,
293
+ raw: { sessionId, commandId },
294
+ wait: () => completion,
295
+ kill: async () => {
296
+ killed = true;
297
+ exitCode = 130;
298
+ await sandbox.process.deleteSession(sessionId).catch(() => void 0);
299
+ },
300
+ [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator]()
301
+ };
302
+ }
303
+ async list(options) {
304
+ const result = await this.client.list(options?.tags ?? this.getLabels());
305
+ return result.items.map((sandbox) => ({
306
+ provider: this.provider,
307
+ id: sandbox.id,
308
+ state: sandbox.state,
309
+ tags: sandbox.labels ?? {},
310
+ createdAt: sandbox.createdAt,
311
+ raw: sandbox
312
+ }));
313
+ }
314
+ async snapshot() {
315
+ return null;
316
+ }
317
+ async stop() {
318
+ const sandbox = this.sandbox;
319
+ if (!sandbox) {
320
+ return;
321
+ }
322
+ await sandbox.stop();
323
+ this.sandbox = void 0;
324
+ }
325
+ async delete() {
326
+ const sandbox = this.sandbox;
327
+ if (!sandbox) {
328
+ return;
329
+ }
330
+ await sandbox.delete();
331
+ this.sandbox = void 0;
332
+ }
333
+ async openPort(port) {
334
+ await this.ensureProvisioned();
335
+ await this.requireSandbox().getPreviewLink(port);
336
+ }
337
+ async getPreviewLink(port) {
338
+ await this.ensureProvisioned();
339
+ const sandbox = this.requireSandbox();
340
+ const preview = await sandbox.getPreviewLink(port);
341
+ return preview.url;
342
+ }
343
+ getLabels() {
344
+ return {
345
+ "agentbox.provider": this.provider,
346
+ ...this.options.tags ?? {}
347
+ };
348
+ }
349
+ buildSessionCommand(command, options) {
350
+ const statements = [];
351
+ const cwd = options?.cwd ?? this.workingDir;
352
+ const env = this.getMergedEnv(options?.env);
353
+ if (cwd) {
354
+ statements.push(`cd ${shellQuote(cwd)}`);
355
+ }
356
+ for (const [name, value] of Object.entries(env)) {
357
+ statements.push(`export ${name}=${shellQuote(value)}`);
358
+ }
359
+ statements.push(toShellCommand(command));
360
+ return statements.join(" && ");
361
+ }
362
+ async findMatchingSandbox() {
363
+ const result = await this.client.list(this.getLabels());
364
+ return result.items[0];
365
+ }
366
+ requireSandbox() {
367
+ if (!this.sandbox) {
368
+ throw new Error("Daytona sandbox has not been provisioned.");
369
+ }
370
+ return this.sandbox;
371
+ }
372
+ };
373
+
374
+ // src/sandboxes/providers/e2b.ts
375
+ var e2bModulePromise;
376
+ async function loadE2bModule() {
377
+ if (!e2bModulePromise) {
378
+ e2bModulePromise = import("e2b");
379
+ }
380
+ return e2bModulePromise;
381
+ }
382
+ var E2bSandboxAdapter = class extends SandboxAdapter {
383
+ sandbox;
384
+ get provider() {
385
+ return "e2b";
386
+ }
387
+ get raw() {
388
+ return {
389
+ sandbox: this.sandbox
390
+ };
391
+ }
392
+ get id() {
393
+ return this.sandbox?.sandboxId;
394
+ }
395
+ async provision() {
396
+ const { Sandbox: E2bSandbox } = await loadE2bModule();
397
+ const existing = await this.findMatchingSandbox();
398
+ if (existing) {
399
+ this.sandbox = existing;
400
+ return;
401
+ }
402
+ const template = resolveSandboxImage(this.options.image);
403
+ const resources = resolveSandboxResources(this.options.resources);
404
+ if (!template) {
405
+ throw new Error(
406
+ "e2b sandboxes require options.image to reference an existing E2B template name or tag."
407
+ );
408
+ }
409
+ if (resources) {
410
+ throw new Error(
411
+ "e2b sandbox sizing must be defined when building the E2B template and cannot be set via options.resources."
412
+ );
413
+ }
414
+ const timeout = this.resolveTimeoutConfig();
415
+ this.sandbox = await E2bSandbox.create(template, {
416
+ ...this.getConnectionOptions(),
417
+ metadata: this.getMetadata(),
418
+ envs: this.getMergedEnv(),
419
+ secure: this.options.provider?.secure,
420
+ allowInternetAccess: this.options.provider?.allowInternetAccess,
421
+ ...timeout
422
+ });
423
+ }
424
+ async run(command, options) {
425
+ await this.ensureProvisioned();
426
+ const sandbox = this.requireSandbox();
427
+ const { CommandExitError } = await loadE2bModule();
428
+ if (options?.pty) {
429
+ const queue = new AsyncQueue();
430
+ const handle = await this.runAsyncWithPty(
431
+ sandbox,
432
+ command,
433
+ options,
434
+ queue
435
+ );
436
+ const result = await handle.wait();
437
+ return result;
438
+ }
439
+ try {
440
+ const result = await sandbox.commands.run(
441
+ toShellCommand(command),
442
+ this.getCommandStartOptions(options)
443
+ );
444
+ return this.toCommandResult(result, result);
445
+ } catch (error) {
446
+ if (error instanceof CommandExitError) {
447
+ return this.toCommandResult(error, error);
448
+ }
449
+ throw error;
450
+ }
451
+ }
452
+ async runAsync(command, options) {
453
+ await this.ensureProvisioned();
454
+ const sandbox = this.requireSandbox();
455
+ const { CommandExitError } = await loadE2bModule();
456
+ const queue = new AsyncQueue();
457
+ let stdout = "";
458
+ let stderr = "";
459
+ if (options?.pty) {
460
+ return this.runAsyncWithPty(sandbox, command, options, queue);
461
+ }
462
+ const handle = await sandbox.commands.run(toShellCommand(command), {
463
+ ...this.getCommandStartOptions(options),
464
+ timeoutMs: options?.timeoutMs ?? 0,
465
+ background: true,
466
+ stdin: true,
467
+ onStdout: async (chunk) => {
468
+ stdout += chunk;
469
+ queue.push({
470
+ type: "stdout",
471
+ chunk,
472
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
473
+ });
474
+ },
475
+ onStderr: async (chunk) => {
476
+ stderr += chunk;
477
+ queue.push({
478
+ type: "stderr",
479
+ chunk,
480
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
481
+ });
482
+ }
483
+ });
484
+ const completion = handle.wait().then((result) => {
485
+ const mapped = this.toCommandResult(
486
+ {
487
+ exitCode: result.exitCode,
488
+ stdout: stdout || result.stdout,
489
+ stderr: stderr || result.stderr,
490
+ error: result.error
491
+ },
492
+ result
493
+ );
494
+ queue.push({
495
+ type: "exit",
496
+ exitCode: mapped.exitCode,
497
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
498
+ });
499
+ queue.finish();
500
+ return mapped;
501
+ }).catch((error) => {
502
+ if (error instanceof CommandExitError) {
503
+ const mapped = this.toCommandResult(
504
+ {
505
+ exitCode: error.exitCode,
506
+ stdout: stdout || error.stdout,
507
+ stderr: stderr || error.stderr,
508
+ error: error.error
509
+ },
510
+ error
511
+ );
512
+ queue.push({
513
+ type: "exit",
514
+ exitCode: mapped.exitCode,
515
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
516
+ });
517
+ queue.finish();
518
+ return mapped;
519
+ }
520
+ queue.fail(error);
521
+ throw error;
522
+ });
523
+ return {
524
+ id: String(handle.pid),
525
+ raw: handle,
526
+ write: async (input) => {
527
+ await sandbox.commands.sendStdin(handle.pid, input);
528
+ },
529
+ wait: () => completion,
530
+ kill: async () => {
531
+ await handle.kill();
532
+ },
533
+ [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator]()
534
+ };
535
+ }
536
+ async runAsyncWithPty(sandbox, command, options, queue) {
537
+ const decoder = new TextDecoder();
538
+ const encoder = new TextEncoder();
539
+ let output = "";
540
+ const handle = await sandbox.pty.create({
541
+ cols: 120,
542
+ rows: 40,
543
+ cwd: options?.cwd ?? this.workingDir,
544
+ envs: this.getMergedEnv(options?.env),
545
+ timeoutMs: options?.timeoutMs ?? 0,
546
+ onData: async (chunk) => {
547
+ const text = decoder.decode(chunk, { stream: true });
548
+ output += text;
549
+ queue.push({
550
+ type: "stdout",
551
+ chunk: text,
552
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
553
+ });
554
+ }
555
+ });
556
+ await sandbox.pty.sendInput(
557
+ handle.pid,
558
+ encoder.encode(`${toShellCommand(command)}
559
+ `)
560
+ );
561
+ const completion = handle.wait().then((result) => {
562
+ const flush = decoder.decode();
563
+ if (flush) {
564
+ output += flush;
565
+ queue.push({
566
+ type: "stdout",
567
+ chunk: flush,
568
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
569
+ });
570
+ }
571
+ queue.push({
572
+ type: "exit",
573
+ exitCode: result.exitCode,
574
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
575
+ });
576
+ queue.finish();
577
+ return {
578
+ exitCode: result.exitCode,
579
+ stdout: output || result.stdout,
580
+ stderr: result.stderr,
581
+ combinedOutput: `${output || result.stdout}${result.stderr}`,
582
+ raw: result
583
+ };
584
+ }).catch((error) => {
585
+ queue.fail(error);
586
+ throw error;
587
+ });
588
+ return {
589
+ id: String(handle.pid),
590
+ raw: handle,
591
+ write: async (input) => {
592
+ await sandbox.pty.sendInput(handle.pid, encoder.encode(input));
593
+ },
594
+ wait: () => completion,
595
+ kill: async () => {
596
+ await handle.kill();
597
+ },
598
+ [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator]()
599
+ };
600
+ }
601
+ async list(options) {
602
+ const { Sandbox: E2bSandbox } = await loadE2bModule();
603
+ const paginator = E2bSandbox.list({
604
+ ...this.getConnectionOptions(),
605
+ query: {
606
+ metadata: options?.tags ?? this.getMetadata(),
607
+ state: ["running", "paused"]
608
+ }
609
+ });
610
+ const sandboxes = [];
611
+ while (paginator.hasNext) {
612
+ const items = await paginator.nextItems();
613
+ for (const sandbox of items) {
614
+ sandboxes.push({
615
+ provider: this.provider,
616
+ id: sandbox.sandboxId,
617
+ state: sandbox.state,
618
+ tags: sandbox.metadata,
619
+ createdAt: sandbox.startedAt.toISOString(),
620
+ raw: sandbox
621
+ });
622
+ }
623
+ }
624
+ return sandboxes;
625
+ }
626
+ async snapshot() {
627
+ await this.ensureProvisioned();
628
+ const sandbox = this.requireSandbox();
629
+ const snapshot = await sandbox.createSnapshot();
630
+ return snapshot.snapshotId;
631
+ }
632
+ async stop() {
633
+ const sandbox = this.sandbox;
634
+ if (!sandbox) {
635
+ return;
636
+ }
637
+ await sandbox.kill();
638
+ this.sandbox = void 0;
639
+ }
640
+ async delete() {
641
+ await this.stop();
642
+ }
643
+ async openPort(_port) {
644
+ void _port;
645
+ }
646
+ async getPreviewLink(port) {
647
+ await this.ensureProvisioned();
648
+ const sandbox = this.requireSandbox();
649
+ const host = sandbox.getHost(port);
650
+ return host.startsWith("localhost:") ? `http://${host}` : `https://${host}`;
651
+ }
652
+ async findMatchingSandbox() {
653
+ const { Sandbox: E2bSandbox } = await loadE2bModule();
654
+ const matches = await this.list();
655
+ const match = matches[0];
656
+ if (!match) {
657
+ return void 0;
658
+ }
659
+ const timeout = this.resolveTimeoutConfig();
660
+ return E2bSandbox.connect(match.id, {
661
+ ...this.getConnectionOptions(),
662
+ timeoutMs: timeout.timeoutMs
663
+ });
664
+ }
665
+ getMetadata() {
666
+ return {
667
+ "agentbox.provider": this.provider,
668
+ ...this.options.tags ?? {}
669
+ };
670
+ }
671
+ getConnectionOptions() {
672
+ return {
673
+ accessToken: this.options.provider?.accessToken,
674
+ apiKey: this.options.provider?.apiKey,
675
+ apiUrl: this.options.provider?.apiUrl,
676
+ debug: this.options.provider?.debug,
677
+ domain: this.options.provider?.domain,
678
+ headers: this.options.provider?.headers,
679
+ requestTimeoutMs: this.options.provider?.requestTimeoutMs,
680
+ sandboxUrl: this.options.provider?.sandboxUrl
681
+ };
682
+ }
683
+ getCommandStartOptions(options) {
684
+ return {
685
+ cwd: options?.cwd ?? this.workingDir,
686
+ envs: this.getMergedEnv(options?.env),
687
+ timeoutMs: options?.timeoutMs
688
+ };
689
+ }
690
+ resolveTimeoutConfig() {
691
+ const providerTimeoutMs = this.options.provider?.timeoutMs;
692
+ const providerLifecycle = this.options.provider?.lifecycle;
693
+ const hasProviderTimeoutOverride = providerTimeoutMs !== void 0 || providerLifecycle !== void 0;
694
+ const normalizedLifecycle = providerLifecycle?.onTimeout ? {
695
+ onTimeout: providerLifecycle.onTimeout,
696
+ autoResume: providerLifecycle.autoResume
697
+ } : void 0;
698
+ if (hasProviderTimeoutOverride && (this.options.idleTimeoutMs !== void 0 || this.options.autoStopMs !== void 0)) {
699
+ throw new Error(
700
+ "e2b sandbox timeout configuration must use either provider.timeoutMs/provider.lifecycle or the shared idleTimeoutMs/autoStopMs fields, but not both."
701
+ );
702
+ }
703
+ if (providerLifecycle?.autoResume && providerLifecycle.onTimeout !== "pause") {
704
+ throw new Error(
705
+ "e2b provider.lifecycle.autoResume can only be enabled when provider.lifecycle.onTimeout is 'pause'."
706
+ );
707
+ }
708
+ if (hasProviderTimeoutOverride) {
709
+ return {
710
+ timeoutMs: providerTimeoutMs,
711
+ lifecycle: normalizedLifecycle
712
+ };
713
+ }
714
+ if (this.options.idleTimeoutMs !== void 0 && this.options.autoStopMs !== void 0) {
715
+ throw new Error(
716
+ "e2b sandboxes do not support combining idleTimeoutMs and autoStopMs because the provider exposes a single timeout/lifecycle configuration."
717
+ );
718
+ }
719
+ if (this.options.idleTimeoutMs !== void 0) {
720
+ return {
721
+ timeoutMs: this.options.idleTimeoutMs,
722
+ lifecycle: {
723
+ onTimeout: "pause",
724
+ autoResume: false
725
+ }
726
+ };
727
+ }
728
+ if (this.options.autoStopMs !== void 0) {
729
+ return {
730
+ timeoutMs: this.options.autoStopMs,
731
+ lifecycle: {
732
+ onTimeout: "kill",
733
+ autoResume: false
734
+ }
735
+ };
736
+ }
737
+ return {};
738
+ }
739
+ requireSandbox() {
740
+ if (!this.sandbox) {
741
+ throw new Error("E2B sandbox has not been provisioned.");
742
+ }
743
+ return this.sandbox;
744
+ }
745
+ toCommandResult(result, raw) {
746
+ return {
747
+ exitCode: result.exitCode,
748
+ stdout: result.stdout,
749
+ stderr: result.stderr,
750
+ combinedOutput: `${result.stdout}${result.stderr}`,
751
+ raw
752
+ };
753
+ }
754
+ };
755
+
756
+ // src/sandboxes/providers/local-docker.ts
757
+ import Docker from "dockerode";
758
+ import tar from "tar-stream";
759
+ import { PassThrough } from "stream";
760
+ import { finished } from "stream/promises";
761
+ var LocalDockerSandboxAdapter = class extends SandboxAdapter {
762
+ client = new Docker();
763
+ container;
764
+ get provider() {
765
+ return "local-docker";
766
+ }
767
+ get raw() {
768
+ return {
769
+ client: this.client,
770
+ container: this.container
771
+ };
772
+ }
773
+ get id() {
774
+ return this.container?.id;
775
+ }
776
+ async provision() {
777
+ const existing = await this.findMatchingContainer();
778
+ if (existing) {
779
+ this.container = this.client.getContainer(existing.Id);
780
+ if (existing.State !== "running") {
781
+ await this.container.start();
782
+ }
783
+ return;
784
+ }
785
+ const normalizedImage = resolveSandboxImage(this.options.image);
786
+ const image = await this.resolveContainerImage(normalizedImage);
787
+ const resources = resolveSandboxResources(this.options.resources);
788
+ const labels = this.getLabels();
789
+ const env = Object.entries(this.getMergedEnv()).map(
790
+ ([key, value]) => `${key}=${value}`
791
+ );
792
+ const publishedPorts = this.options.provider?.publishedPorts ?? [];
793
+ const portBindings = publishedPorts.length > 0 ? Object.fromEntries(
794
+ publishedPorts.map((port) => [
795
+ `${port}/tcp`,
796
+ [{ HostIp: "127.0.0.1", HostPort: String(port) }]
797
+ ])
798
+ ) : void 0;
799
+ const exposedPorts = publishedPorts.length > 0 ? Object.fromEntries(publishedPorts.map((port) => [`${port}/tcp`, {}])) : void 0;
800
+ const container = await this.client.createContainer({
801
+ Image: image,
802
+ name: this.options.provider?.name,
803
+ Cmd: this.options.provider?.command ?? ["sleep", "infinity"],
804
+ WorkingDir: this.workingDir,
805
+ Env: env,
806
+ Labels: labels,
807
+ Tty: false,
808
+ OpenStdin: true,
809
+ ...exposedPorts ? { ExposedPorts: exposedPorts } : {},
810
+ HostConfig: {
811
+ AutoRemove: this.options.provider?.autoRemove ?? false,
812
+ Binds: this.options.provider?.binds,
813
+ NetworkMode: this.options.provider?.networkMode,
814
+ ExtraHosts: ["host.docker.internal:host-gateway"],
815
+ ...portBindings ? { PortBindings: portBindings } : {},
816
+ ...resources?.cpu ? { NanoCpus: Math.round(resources.cpu * 1e9) } : {},
817
+ ...resources?.memoryMiB ? { Memory: resources.memoryMiB * 1024 * 1024 } : {}
818
+ }
819
+ });
820
+ this.container = container;
821
+ await container.start();
822
+ }
823
+ async run(command, options) {
824
+ await this.ensureProvisioned();
825
+ const container = this.requireContainer();
826
+ const exec = await container.exec({
827
+ AttachStdout: true,
828
+ AttachStderr: true,
829
+ Cmd: ["/bin/sh", "-lc", toShellCommand(command)],
830
+ Env: this.toDockerEnv(options?.env),
831
+ WorkingDir: options?.cwd ?? this.workingDir
832
+ });
833
+ const stream = await exec.start({ hijack: true, stdin: false, Tty: false });
834
+ const { stdout, stderr } = this.demuxExecStream(container, stream);
835
+ const work = Promise.all([
836
+ readNodeStream(stdout),
837
+ readNodeStream(stderr),
838
+ finished(stream)
839
+ ]).then(([out, err]) => [out, err]);
840
+ let result;
841
+ if (options?.timeoutMs && options.timeoutMs > 0) {
842
+ const timeout = new Promise(
843
+ (_, reject) => setTimeout(
844
+ () => reject(
845
+ new Error(`Command timed out after ${options.timeoutMs}ms.`)
846
+ ),
847
+ options.timeoutMs
848
+ )
849
+ );
850
+ result = await Promise.race([work, timeout]);
851
+ } else {
852
+ result = await work;
853
+ }
854
+ const [stdoutBuffer, stderrBuffer] = result;
855
+ const inspect = await exec.inspect();
856
+ const stdoutText = stdoutBuffer.toString("utf8");
857
+ const stderrText = stderrBuffer.toString("utf8");
858
+ return {
859
+ exitCode: inspect.ExitCode ?? 0,
860
+ stdout: stdoutText,
861
+ stderr: stderrText,
862
+ combinedOutput: `${stdoutText}${stderrText}`,
863
+ raw: { exec, inspect }
864
+ };
865
+ }
866
+ async runAsync(command, options) {
867
+ await this.ensureProvisioned();
868
+ const container = this.requireContainer();
869
+ const exec = await container.exec({
870
+ AttachStdin: true,
871
+ AttachStdout: true,
872
+ AttachStderr: true,
873
+ Cmd: ["/bin/sh", "-lc", toShellCommand(command)],
874
+ Env: this.toDockerEnv(options?.env),
875
+ WorkingDir: options?.cwd ?? this.workingDir,
876
+ Tty: options?.pty ?? false
877
+ });
878
+ const tty = options?.pty ?? false;
879
+ const stream = await exec.start({ hijack: true, stdin: true, Tty: tty });
880
+ const { stdout, stderr } = tty ? this.wrapTtyExecStream(stream) : this.demuxExecStream(container, stream);
881
+ const queue = new AsyncQueue();
882
+ let stdoutText = "";
883
+ let stderrText = "";
884
+ stdout.on("data", (chunk) => {
885
+ const text = chunk.toString("utf8");
886
+ stdoutText += text;
887
+ queue.push({
888
+ type: "stdout",
889
+ chunk: text,
890
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
891
+ });
892
+ });
893
+ stderr.on("data", (chunk) => {
894
+ const text = chunk.toString("utf8");
895
+ stderrText += text;
896
+ queue.push({
897
+ type: "stderr",
898
+ chunk: text,
899
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
900
+ });
901
+ });
902
+ const completion = (async () => {
903
+ await finished(stream);
904
+ const inspect = await exec.inspect();
905
+ const exitCode = inspect.ExitCode ?? 0;
906
+ queue.push({
907
+ type: "exit",
908
+ exitCode,
909
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
910
+ raw: inspect
911
+ });
912
+ queue.finish();
913
+ return {
914
+ exitCode,
915
+ stdout: stdoutText,
916
+ stderr: stderrText,
917
+ combinedOutput: `${stdoutText}${stderrText}`,
918
+ raw: { exec, inspect }
919
+ };
920
+ })().catch((error) => {
921
+ queue.fail(error);
922
+ throw error;
923
+ });
924
+ return {
925
+ id: exec.id,
926
+ raw: { exec, stream },
927
+ write: async (input) => {
928
+ stream.write(input);
929
+ },
930
+ wait: () => completion,
931
+ kill: async () => {
932
+ try {
933
+ stream.write("");
934
+ stream.end();
935
+ } catch {
936
+ }
937
+ },
938
+ [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator]()
939
+ };
940
+ }
941
+ demuxExecStream(container, stream) {
942
+ const stdout = new PassThrough();
943
+ const stderr = new PassThrough();
944
+ container.modem.demuxStream(stream, stdout, stderr);
945
+ const endOutputs = () => {
946
+ stdout.end();
947
+ stderr.end();
948
+ };
949
+ stream.on("end", endOutputs);
950
+ stream.on("close", endOutputs);
951
+ stream.on("error", (error) => {
952
+ stdout.destroy(error);
953
+ stderr.destroy(error);
954
+ });
955
+ return { stdout, stderr };
956
+ }
957
+ wrapTtyExecStream(stream) {
958
+ const stdout = new PassThrough();
959
+ const stderr = new PassThrough();
960
+ stream.on("data", (chunk) => {
961
+ stdout.write(chunk);
962
+ });
963
+ stream.on("end", () => {
964
+ stdout.end();
965
+ stderr.end();
966
+ });
967
+ stream.on("close", () => {
968
+ stdout.end();
969
+ stderr.end();
970
+ });
971
+ stream.on("error", (error) => {
972
+ stdout.destroy(error);
973
+ stderr.destroy(error);
974
+ });
975
+ return { stdout, stderr };
976
+ }
977
+ async list(options) {
978
+ const filters = {
979
+ label: this.toDockerLabelFilters(options?.tags)
980
+ };
981
+ const containers = await this.client.listContainers({ all: true, filters });
982
+ return containers.map((container) => ({
983
+ provider: this.provider,
984
+ id: container.Id,
985
+ state: container.State,
986
+ tags: container.Labels ?? {},
987
+ raw: container
988
+ }));
989
+ }
990
+ async snapshot() {
991
+ return null;
992
+ }
993
+ async stop() {
994
+ const container = this.container;
995
+ if (!container) {
996
+ return;
997
+ }
998
+ await container.stop().catch(() => void 0);
999
+ }
1000
+ async delete() {
1001
+ const container = this.container;
1002
+ if (!container) {
1003
+ return;
1004
+ }
1005
+ await container.remove({ force: true }).catch(() => void 0);
1006
+ this.container = void 0;
1007
+ }
1008
+ async openPort(port) {
1009
+ const provider = this.options.provider ?? (this.options.provider = {});
1010
+ if (provider.networkMode === "host") {
1011
+ return;
1012
+ }
1013
+ provider.publishedPorts = provider.publishedPorts?.includes(port) ? provider.publishedPorts : [...provider.publishedPorts ?? [], port];
1014
+ }
1015
+ async getPreviewLink(port) {
1016
+ const networkMode = this.options.provider?.networkMode;
1017
+ if (networkMode === "host") {
1018
+ return `http://127.0.0.1:${port}`;
1019
+ }
1020
+ if (this.options.provider?.publishedPorts?.includes(port)) {
1021
+ return `http://127.0.0.1:${port}`;
1022
+ }
1023
+ throw new Error(
1024
+ `Port ${port} is not reachable from the host. Use local-docker provider.networkMode="host" or provider.publishedPorts to expose it.`
1025
+ );
1026
+ }
1027
+ async uploadFile(content, targetPath) {
1028
+ await this.ensureProvisioned();
1029
+ const container = this.requireContainer();
1030
+ const pack = tar.pack();
1031
+ const body = Buffer.isBuffer(content) ? content : Buffer.from(content, "utf8");
1032
+ pack.entry({ name: targetPath.replace(/^\/+/, "") }, body);
1033
+ pack.finalize();
1034
+ await container.putArchive(pack, { path: "/" });
1035
+ }
1036
+ async downloadFile(sourcePath) {
1037
+ await this.ensureProvisioned();
1038
+ const container = this.requireContainer();
1039
+ const archive = await container.getArchive({ path: sourcePath });
1040
+ const chunks = [];
1041
+ for await (const chunk of archive) {
1042
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1043
+ }
1044
+ return Buffer.concat(chunks);
1045
+ }
1046
+ requireContainer() {
1047
+ if (!this.container) {
1048
+ throw new Error("Docker container is not provisioned.");
1049
+ }
1050
+ return this.container;
1051
+ }
1052
+ getLabels() {
1053
+ return {
1054
+ "agentbox.provider": this.provider,
1055
+ ...this.options.tags ?? {}
1056
+ };
1057
+ }
1058
+ toDockerEnv(extra) {
1059
+ return Object.entries(this.getMergedEnv(extra)).map(
1060
+ ([key, value]) => `${key}=${value}`
1061
+ );
1062
+ }
1063
+ toDockerLabelFilters(tags) {
1064
+ const labels = {
1065
+ "agentbox.provider": this.provider,
1066
+ ...tags ?? {}
1067
+ };
1068
+ return Object.entries(labels).map(([key, value]) => `${key}=${value}`);
1069
+ }
1070
+ async findMatchingContainer() {
1071
+ const containers = await this.client.listContainers({
1072
+ all: true,
1073
+ filters: { label: this.toDockerLabelFilters(this.options.tags) }
1074
+ });
1075
+ return containers[0];
1076
+ }
1077
+ async pullImage(image) {
1078
+ const stream = await this.client.pull(image);
1079
+ await new Promise((resolve, reject) => {
1080
+ this.client.modem.followProgress(stream, (error) => {
1081
+ if (error) {
1082
+ reject(error);
1083
+ return;
1084
+ }
1085
+ resolve();
1086
+ });
1087
+ });
1088
+ }
1089
+ async resolveContainerImage(image) {
1090
+ if (!image) {
1091
+ throw new Error(
1092
+ "local-docker sandboxes require options.image to reference a local Docker image."
1093
+ );
1094
+ }
1095
+ if (this.options.provider?.pull) {
1096
+ await this.pullImage(image);
1097
+ }
1098
+ return image;
1099
+ }
1100
+ };
1101
+
1102
+ // src/sandboxes/providers/modal.ts
1103
+ import { ModalClient } from "modal";
1104
+ var ModalSandboxAdapter = class extends SandboxAdapter {
1105
+ client;
1106
+ sandbox;
1107
+ clientClosed = false;
1108
+ constructor(options) {
1109
+ super(options);
1110
+ this.client = new ModalClient({
1111
+ tokenId: options.provider?.tokenId,
1112
+ tokenSecret: options.provider?.tokenSecret,
1113
+ environment: options.provider?.environment,
1114
+ endpoint: options.provider?.endpoint
1115
+ });
1116
+ }
1117
+ get provider() {
1118
+ return "modal";
1119
+ }
1120
+ get raw() {
1121
+ return {
1122
+ client: this.client,
1123
+ sandbox: this.sandbox
1124
+ };
1125
+ }
1126
+ get id() {
1127
+ return this.sandbox?.sandboxId;
1128
+ }
1129
+ async provision() {
1130
+ const existing = await this.findMatchingSandbox();
1131
+ if (existing) {
1132
+ this.sandbox = existing;
1133
+ return;
1134
+ }
1135
+ const appName = this.options.provider?.appName ?? "agentbox";
1136
+ const app = await this.client.apps.fromName(appName, {
1137
+ createIfMissing: true,
1138
+ environment: this.options.provider?.environment
1139
+ });
1140
+ const image = await this.resolveModalImage();
1141
+ const resources = resolveSandboxResources(this.options.resources);
1142
+ const sandbox = await this.client.sandboxes.create(app, image, {
1143
+ cpu: resources?.cpu,
1144
+ memoryMiB: resources?.memoryMiB,
1145
+ timeoutMs: this.options.autoStopMs,
1146
+ idleTimeoutMs: this.options.idleTimeoutMs,
1147
+ workdir: this.workingDir,
1148
+ command: this.options.provider?.command ?? ["sleep", "infinity"],
1149
+ env: this.getMergedEnv(),
1150
+ encryptedPorts: this.options.provider?.encryptedPorts,
1151
+ unencryptedPorts: this.options.provider?.unencryptedPorts,
1152
+ verbose: this.options.provider?.verbose
1153
+ });
1154
+ await sandbox.setTags(this.getTags());
1155
+ this.sandbox = sandbox;
1156
+ }
1157
+ async run(command, options) {
1158
+ await this.ensureProvisioned();
1159
+ const sandbox = this.requireSandbox();
1160
+ const process2 = await sandbox.exec(
1161
+ ["/bin/sh", "-lc", toShellCommand(command)],
1162
+ {
1163
+ workdir: options?.cwd ?? this.workingDir,
1164
+ timeoutMs: options?.timeoutMs,
1165
+ env: this.getMergedEnv(options?.env),
1166
+ pty: options?.pty,
1167
+ mode: "text"
1168
+ }
1169
+ );
1170
+ const [stdout, stderr, exitCode] = await Promise.all([
1171
+ readStreamAsText(process2.stdout),
1172
+ readStreamAsText(process2.stderr),
1173
+ process2.wait()
1174
+ ]);
1175
+ return {
1176
+ exitCode,
1177
+ stdout,
1178
+ stderr,
1179
+ combinedOutput: `${stdout}${stderr}`,
1180
+ raw: process2
1181
+ };
1182
+ }
1183
+ async runAsync(command, options) {
1184
+ await this.ensureProvisioned();
1185
+ const sandbox = this.requireSandbox();
1186
+ const process2 = await sandbox.exec(
1187
+ ["/bin/sh", "-lc", toShellCommand(command)],
1188
+ {
1189
+ workdir: options?.cwd ?? this.workingDir,
1190
+ timeoutMs: options?.timeoutMs,
1191
+ env: this.getMergedEnv(options?.env),
1192
+ pty: options?.pty,
1193
+ mode: "text"
1194
+ }
1195
+ );
1196
+ const queue = new AsyncQueue();
1197
+ let stdout = "";
1198
+ let stderr = "";
1199
+ const stdoutPump = pipeReadableStream(process2.stdout, (chunk) => {
1200
+ stdout += chunk;
1201
+ queue.push({
1202
+ type: "stdout",
1203
+ chunk,
1204
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1205
+ });
1206
+ });
1207
+ const stderrPump = pipeReadableStream(process2.stderr, (chunk) => {
1208
+ stderr += chunk;
1209
+ queue.push({
1210
+ type: "stderr",
1211
+ chunk,
1212
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1213
+ });
1214
+ });
1215
+ const completion = Promise.all([stdoutPump, stderrPump, process2.wait()]).then(([, , exitCode]) => {
1216
+ queue.push({
1217
+ type: "exit",
1218
+ exitCode,
1219
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1220
+ });
1221
+ queue.finish();
1222
+ return {
1223
+ exitCode,
1224
+ stdout,
1225
+ stderr,
1226
+ combinedOutput: `${stdout}${stderr}`,
1227
+ raw: process2
1228
+ };
1229
+ }).catch((error) => {
1230
+ queue.fail(error);
1231
+ throw error;
1232
+ });
1233
+ return {
1234
+ id: `${sandbox.sandboxId}:${Date.now()}`,
1235
+ raw: process2,
1236
+ write: async (input) => {
1237
+ await process2.stdin.writeText(input);
1238
+ },
1239
+ wait: () => completion,
1240
+ kill: async () => {
1241
+ try {
1242
+ await process2.stdin.writeText("");
1243
+ } catch {
1244
+ }
1245
+ },
1246
+ [Symbol.asyncIterator]: () => queue[Symbol.asyncIterator]()
1247
+ };
1248
+ }
1249
+ async list(options) {
1250
+ const sandboxes = [];
1251
+ for await (const sandbox of this.client.sandboxes.list({
1252
+ tags: options?.tags ?? this.tags
1253
+ })) {
1254
+ sandboxes.push({
1255
+ provider: this.provider,
1256
+ id: sandbox.sandboxId,
1257
+ state: await sandbox.poll() === null ? "running" : "finished",
1258
+ tags: await sandbox.getTags(),
1259
+ raw: sandbox
1260
+ });
1261
+ }
1262
+ return sandboxes;
1263
+ }
1264
+ async snapshot() {
1265
+ await this.ensureProvisioned();
1266
+ const sandbox = this.requireSandbox();
1267
+ const image = await sandbox.snapshotFilesystem();
1268
+ return image.imageId;
1269
+ }
1270
+ async stop() {
1271
+ const sandbox = this.sandbox;
1272
+ if (!sandbox) {
1273
+ return;
1274
+ }
1275
+ await sandbox.terminate();
1276
+ this.sandbox = void 0;
1277
+ }
1278
+ async delete() {
1279
+ await this.stop();
1280
+ await this.closeClient();
1281
+ }
1282
+ async openPort(port) {
1283
+ const provider = this.options.provider ?? (this.options.provider = {});
1284
+ if (provider.encryptedPorts?.includes(port)) {
1285
+ return;
1286
+ }
1287
+ provider.unencryptedPorts = provider.unencryptedPorts?.includes(port) ? provider.unencryptedPorts : [...provider.unencryptedPorts ?? [], port];
1288
+ }
1289
+ async getPreviewLink(port) {
1290
+ await this.ensureProvisioned();
1291
+ const sandbox = this.requireSandbox();
1292
+ const tunnels = await sandbox.tunnels();
1293
+ const tunnel = tunnels[port];
1294
+ if (!tunnel) {
1295
+ throw new Error(`Modal sandbox does not expose port ${port}.`);
1296
+ }
1297
+ return tunnel.url;
1298
+ }
1299
+ async findMatchingSandbox() {
1300
+ for await (const sandbox of this.client.sandboxes.list({
1301
+ tags: this.getTags()
1302
+ })) {
1303
+ return sandbox;
1304
+ }
1305
+ return void 0;
1306
+ }
1307
+ getTags() {
1308
+ return {
1309
+ "agentbox.provider": this.provider,
1310
+ ...this.options.tags ?? {}
1311
+ };
1312
+ }
1313
+ async closeClient() {
1314
+ if (this.clientClosed) {
1315
+ return;
1316
+ }
1317
+ this.clientClosed = true;
1318
+ const swallowGrpcShutdown = (reason) => {
1319
+ if (reason instanceof Error && reason.message.includes("Channel has been shut down")) {
1320
+ return;
1321
+ }
1322
+ throw reason;
1323
+ };
1324
+ process.on("unhandledRejection", swallowGrpcShutdown);
1325
+ try {
1326
+ this.client.close();
1327
+ await new Promise((resolve) => setTimeout(resolve, 250));
1328
+ } catch {
1329
+ } finally {
1330
+ process.off("unhandledRejection", swallowGrpcShutdown);
1331
+ }
1332
+ }
1333
+ requireSandbox() {
1334
+ if (!this.sandbox) {
1335
+ throw new Error("Modal sandbox has not been provisioned.");
1336
+ }
1337
+ return this.sandbox;
1338
+ }
1339
+ async resolveModalImage() {
1340
+ const image = resolveSandboxImage(this.options.image);
1341
+ if (!image) {
1342
+ throw new Error(
1343
+ "modal sandboxes require options.image to reference an existing Modal image id."
1344
+ );
1345
+ }
1346
+ return this.client.images.fromId(image);
1347
+ }
1348
+ };
1349
+
1350
+ // src/sandboxes/Sandbox.ts
1351
+ function createSandboxAdapter(provider, options) {
1352
+ switch (provider) {
1353
+ case "local-docker":
1354
+ return new LocalDockerSandboxAdapter(
1355
+ options
1356
+ );
1357
+ case "modal":
1358
+ return new ModalSandboxAdapter(
1359
+ options
1360
+ );
1361
+ case "daytona":
1362
+ return new DaytonaSandboxAdapter(
1363
+ options
1364
+ );
1365
+ case "e2b":
1366
+ return new E2bSandboxAdapter(
1367
+ options
1368
+ );
1369
+ default:
1370
+ throw new UnsupportedProviderError("sandbox", provider);
1371
+ }
1372
+ }
1373
+ var Sandbox = class {
1374
+ constructor(providerName, options) {
1375
+ this.providerName = providerName;
1376
+ this.options = options;
1377
+ this.adapter = createSandboxAdapter(providerName, options);
1378
+ }
1379
+ providerName;
1380
+ options;
1381
+ adapter;
1382
+ get provider() {
1383
+ return this.providerName;
1384
+ }
1385
+ get optionsSnapshot() {
1386
+ return this.options;
1387
+ }
1388
+ get id() {
1389
+ return this.adapter.id;
1390
+ }
1391
+ get raw() {
1392
+ return this.adapter.raw;
1393
+ }
1394
+ async openPort(port) {
1395
+ await this.adapter.openPort(port);
1396
+ return this;
1397
+ }
1398
+ setSecret(name, value) {
1399
+ this.adapter.setSecret(name, value);
1400
+ return this;
1401
+ }
1402
+ setSecrets(values) {
1403
+ this.adapter.setSecrets(values);
1404
+ return this;
1405
+ }
1406
+ async gitClone(options) {
1407
+ return this.adapter.gitClone(options);
1408
+ }
1409
+ async run(command, options) {
1410
+ return this.adapter.run(command, options);
1411
+ }
1412
+ async runAsync(command, options) {
1413
+ return this.adapter.runAsync(command, options);
1414
+ }
1415
+ async list(options) {
1416
+ return this.adapter.list(options);
1417
+ }
1418
+ async snapshot() {
1419
+ return this.adapter.snapshot();
1420
+ }
1421
+ async stop() {
1422
+ return this.adapter.stop();
1423
+ }
1424
+ async delete() {
1425
+ return this.adapter.delete();
1426
+ }
1427
+ async getPreviewLink(port) {
1428
+ return this.adapter.getPreviewLink(port);
1429
+ }
1430
+ };
1431
+
1432
+ export {
1433
+ buildGitCloneCommand,
1434
+ SandboxAdapter,
1435
+ Sandbox
1436
+ };