sandbox-agent 0.4.0 → 0.4.1

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.
Files changed (36) hide show
  1. package/dist/chunk-7BNDCDDU.js +18 -0
  2. package/dist/chunk-7BNDCDDU.js.map +1 -0
  3. package/dist/chunk-TVCDKGSM.js +3029 -0
  4. package/dist/chunk-TVCDKGSM.js.map +1 -0
  5. package/dist/index.d.ts +1674 -144
  6. package/dist/index.js +17 -2353
  7. package/dist/index.js.map +1 -1
  8. package/dist/providers/cloudflare.d.ts +1 -1
  9. package/dist/providers/cloudflare.js +1 -0
  10. package/dist/providers/cloudflare.js.map +1 -1
  11. package/dist/providers/computesdk.d.ts +4 -4
  12. package/dist/providers/computesdk.js +9 -3
  13. package/dist/providers/computesdk.js.map +1 -1
  14. package/dist/providers/daytona.d.ts +3 -2
  15. package/dist/providers/daytona.js +4 -1
  16. package/dist/providers/daytona.js.map +1 -1
  17. package/dist/providers/docker.d.ts +1 -1
  18. package/dist/providers/docker.js +2 -1
  19. package/dist/providers/docker.js.map +1 -1
  20. package/dist/providers/e2b.d.ts +10 -3
  21. package/dist/providers/e2b.js +55 -10
  22. package/dist/providers/e2b.js.map +1 -1
  23. package/dist/providers/local.d.ts +1 -1
  24. package/dist/providers/modal.d.ts +9 -6
  25. package/dist/providers/modal.js +20 -14
  26. package/dist/providers/modal.js.map +1 -1
  27. package/dist/providers/sprites.d.ts +22 -0
  28. package/dist/providers/sprites.js +209 -0
  29. package/dist/providers/sprites.js.map +1 -0
  30. package/dist/providers/vercel.d.ts +1 -1
  31. package/dist/providers/vercel.js +2 -1
  32. package/dist/providers/vercel.js.map +1 -1
  33. package/dist/{types-DLlJOfyX.d.ts → types-DdcvY5CI.d.ts} +22 -0
  34. package/package.json +13 -4
  35. package/dist/chunk-TWTMX66J.js +0 -15
  36. package/dist/chunk-TWTMX66J.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DEFAULT_SANDBOX_AGENT_IMAGE
3
- } from "../chunk-TWTMX66J.js";
3
+ } from "../chunk-7BNDCDDU.js";
4
4
 
5
5
  // src/providers/docker.ts
6
6
  import Docker from "dockerode";
@@ -30,6 +30,7 @@ function docker(options = {}) {
30
30
  const client = new Docker({ socketPath: "/var/run/docker.sock" });
31
31
  return {
32
32
  name: "docker",
33
+ defaultCwd: "/home/sandbox",
33
34
  async create() {
34
35
  const hostPort = await getPort();
35
36
  const env = await resolveValue(options.env, []);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/docker.ts"],"sourcesContent":["import Docker from \"dockerode\";\nimport getPort from \"get-port\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_SANDBOX_AGENT_IMAGE } from \"./shared.ts\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_AGENT_PORT = 3000;\n\nexport interface DockerProviderOptions {\n image?: string;\n host?: string;\n agentPort?: number;\n env?: string[] | (() => string[] | Promise<string[]>);\n binds?: string[] | (() => string[] | Promise<string[]>);\n createContainerOptions?: Record<string, unknown>;\n}\n\nasync function resolveValue<T>(value: T | (() => T | Promise<T>) | undefined, fallback: T): Promise<T> {\n if (value === undefined) {\n return fallback;\n }\n if (typeof value === \"function\") {\n return await (value as () => T | Promise<T>)();\n }\n return value;\n}\n\nfunction extractMappedPort(\n inspect: { NetworkSettings?: { Ports?: Record<string, Array<{ HostPort?: string }> | null | undefined> } },\n containerPort: number,\n): number {\n const hostPort = inspect.NetworkSettings?.Ports?.[`${containerPort}/tcp`]?.[0]?.HostPort;\n if (!hostPort) {\n throw new Error(`docker sandbox-agent port ${containerPort} is not published`);\n }\n return Number(hostPort);\n}\n\nexport function docker(options: DockerProviderOptions = {}): SandboxProvider {\n const image = options.image ?? DEFAULT_SANDBOX_AGENT_IMAGE;\n const host = options.host ?? DEFAULT_HOST;\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const client = new Docker({ socketPath: \"/var/run/docker.sock\" });\n\n return {\n name: \"docker\",\n async create(): Promise<string> {\n const hostPort = await getPort();\n const env = await resolveValue(options.env, []);\n const binds = await resolveValue(options.binds, []);\n\n const container = await client.createContainer({\n Image: image,\n Cmd: [\"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)],\n Env: env,\n ExposedPorts: { [`${agentPort}/tcp`]: {} },\n HostConfig: {\n AutoRemove: true,\n Binds: binds,\n PortBindings: {\n [`${agentPort}/tcp`]: [{ HostPort: String(hostPort) }],\n },\n },\n ...(options.createContainerOptions ?? {}),\n });\n\n await container.start();\n return container.id;\n },\n async destroy(sandboxId: string): Promise<void> {\n const container = client.getContainer(sandboxId);\n try {\n await container.stop({ t: 5 });\n } catch {}\n try {\n await container.remove({ force: true });\n } catch {}\n },\n async getUrl(sandboxId: string): Promise<string> {\n const container = client.getContainer(sandboxId);\n const hostPort = extractMappedPort(await container.inspect(), agentPort);\n return `http://${host}:${hostPort}`;\n },\n };\n}\n"],"mappings":";;;;;AAAA,OAAO,YAAY;AACnB,OAAO,aAAa;AAIpB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAW3B,eAAe,aAAgB,OAA+C,UAAyB;AACrG,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY;AAC/B,WAAO,MAAO,MAA+B;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,kBACP,SACA,eACQ;AACR,QAAM,WAAW,QAAQ,iBAAiB,QAAQ,GAAG,aAAa,MAAM,IAAI,CAAC,GAAG;AAChF,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,6BAA6B,aAAa,mBAAmB;AAAA,EAC/E;AACA,SAAO,OAAO,QAAQ;AACxB;AAEO,SAAS,OAAO,UAAiC,CAAC,GAAoB;AAC3E,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,IAAI,OAAO,EAAE,YAAY,uBAAuB,CAAC;AAEhE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,SAA0B;AAC9B,YAAM,WAAW,MAAM,QAAQ;AAC/B,YAAM,MAAM,MAAM,aAAa,QAAQ,KAAK,CAAC,CAAC;AAC9C,YAAM,QAAQ,MAAM,aAAa,QAAQ,OAAO,CAAC,CAAC;AAElD,YAAM,YAAY,MAAM,OAAO,gBAAgB;AAAA,QAC7C,OAAO;AAAA,QACP,KAAK,CAAC,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC;AAAA,QAC9E,KAAK;AAAA,QACL,cAAc,EAAE,CAAC,GAAG,SAAS,MAAM,GAAG,CAAC,EAAE;AAAA,QACzC,YAAY;AAAA,UACV,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,cAAc;AAAA,YACZ,CAAC,GAAG,SAAS,MAAM,GAAG,CAAC,EAAE,UAAU,OAAO,QAAQ,EAAE,CAAC;AAAA,UACvD;AAAA,QACF;AAAA,QACA,GAAI,QAAQ,0BAA0B,CAAC;AAAA,MACzC,CAAC;AAED,YAAM,UAAU,MAAM;AACtB,aAAO,UAAU;AAAA,IACnB;AAAA,IACA,MAAM,QAAQ,WAAkC;AAC9C,YAAM,YAAY,OAAO,aAAa,SAAS;AAC/C,UAAI;AACF,cAAM,UAAU,KAAK,EAAE,GAAG,EAAE,CAAC;AAAA,MAC/B,QAAQ;AAAA,MAAC;AACT,UAAI;AACF,cAAM,UAAU,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,MACxC,QAAQ;AAAA,MAAC;AAAA,IACX;AAAA,IACA,MAAM,OAAO,WAAoC;AAC/C,YAAM,YAAY,OAAO,aAAa,SAAS;AAC/C,YAAM,WAAW,kBAAkB,MAAM,UAAU,QAAQ,GAAG,SAAS;AACvE,aAAO,UAAU,IAAI,IAAI,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/docker.ts"],"sourcesContent":["import Docker from \"dockerode\";\nimport getPort from \"get-port\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_SANDBOX_AGENT_IMAGE } from \"./shared.ts\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_AGENT_PORT = 3000;\n\nexport interface DockerProviderOptions {\n image?: string;\n host?: string;\n agentPort?: number;\n env?: string[] | (() => string[] | Promise<string[]>);\n binds?: string[] | (() => string[] | Promise<string[]>);\n createContainerOptions?: Record<string, unknown>;\n}\n\nasync function resolveValue<T>(value: T | (() => T | Promise<T>) | undefined, fallback: T): Promise<T> {\n if (value === undefined) {\n return fallback;\n }\n if (typeof value === \"function\") {\n return await (value as () => T | Promise<T>)();\n }\n return value;\n}\n\nfunction extractMappedPort(\n inspect: { NetworkSettings?: { Ports?: Record<string, Array<{ HostPort?: string }> | null | undefined> } },\n containerPort: number,\n): number {\n const hostPort = inspect.NetworkSettings?.Ports?.[`${containerPort}/tcp`]?.[0]?.HostPort;\n if (!hostPort) {\n throw new Error(`docker sandbox-agent port ${containerPort} is not published`);\n }\n return Number(hostPort);\n}\n\nexport function docker(options: DockerProviderOptions = {}): SandboxProvider {\n const image = options.image ?? DEFAULT_SANDBOX_AGENT_IMAGE;\n const host = options.host ?? DEFAULT_HOST;\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const client = new Docker({ socketPath: \"/var/run/docker.sock\" });\n\n return {\n name: \"docker\",\n defaultCwd: \"/home/sandbox\",\n async create(): Promise<string> {\n const hostPort = await getPort();\n const env = await resolveValue(options.env, []);\n const binds = await resolveValue(options.binds, []);\n\n const container = await client.createContainer({\n Image: image,\n Cmd: [\"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)],\n Env: env,\n ExposedPorts: { [`${agentPort}/tcp`]: {} },\n HostConfig: {\n AutoRemove: true,\n Binds: binds,\n PortBindings: {\n [`${agentPort}/tcp`]: [{ HostPort: String(hostPort) }],\n },\n },\n ...(options.createContainerOptions ?? {}),\n });\n\n await container.start();\n return container.id;\n },\n async destroy(sandboxId: string): Promise<void> {\n const container = client.getContainer(sandboxId);\n try {\n await container.stop({ t: 5 });\n } catch {}\n try {\n await container.remove({ force: true });\n } catch {}\n },\n async getUrl(sandboxId: string): Promise<string> {\n const container = client.getContainer(sandboxId);\n const hostPort = extractMappedPort(await container.inspect(), agentPort);\n return `http://${host}:${hostPort}`;\n },\n };\n}\n"],"mappings":";;;;;AAAA,OAAO,YAAY;AACnB,OAAO,aAAa;AAIpB,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAW3B,eAAe,aAAgB,OAA+C,UAAyB;AACrG,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY;AAC/B,WAAO,MAAO,MAA+B;AAAA,EAC/C;AACA,SAAO;AACT;AAEA,SAAS,kBACP,SACA,eACQ;AACR,QAAM,WAAW,QAAQ,iBAAiB,QAAQ,GAAG,aAAa,MAAM,IAAI,CAAC,GAAG;AAChF,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,6BAA6B,aAAa,mBAAmB;AAAA,EAC/E;AACA,SAAO,OAAO,QAAQ;AACxB;AAEO,SAAS,OAAO,UAAiC,CAAC,GAAoB;AAC3E,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,IAAI,OAAO,EAAE,YAAY,uBAAuB,CAAC;AAEhE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,MAAM,SAA0B;AAC9B,YAAM,WAAW,MAAM,QAAQ;AAC/B,YAAM,MAAM,MAAM,aAAa,QAAQ,KAAK,CAAC,CAAC;AAC9C,YAAM,QAAQ,MAAM,aAAa,QAAQ,OAAO,CAAC,CAAC;AAElD,YAAM,YAAY,MAAM,OAAO,gBAAgB;AAAA,QAC7C,OAAO;AAAA,QACP,KAAK,CAAC,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC;AAAA,QAC9E,KAAK;AAAA,QACL,cAAc,EAAE,CAAC,GAAG,SAAS,MAAM,GAAG,CAAC,EAAE;AAAA,QACzC,YAAY;AAAA,UACV,YAAY;AAAA,UACZ,OAAO;AAAA,UACP,cAAc;AAAA,YACZ,CAAC,GAAG,SAAS,MAAM,GAAG,CAAC,EAAE,UAAU,OAAO,QAAQ,EAAE,CAAC;AAAA,UACvD;AAAA,QACF;AAAA,QACA,GAAI,QAAQ,0BAA0B,CAAC;AAAA,MACzC,CAAC;AAED,YAAM,UAAU,MAAM;AACtB,aAAO,UAAU;AAAA,IACnB;AAAA,IACA,MAAM,QAAQ,WAAkC;AAC9C,YAAM,YAAY,OAAO,aAAa,SAAS;AAC/C,UAAI;AACF,cAAM,UAAU,KAAK,EAAE,GAAG,EAAE,CAAC;AAAA,MAC/B,QAAQ;AAAA,MAAC;AACT,UAAI;AACF,cAAM,UAAU,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,MACxC,QAAQ;AAAA,MAAC;AAAA,IACX;AAAA,IACA,MAAM,OAAO,WAAoC;AAC/C,YAAM,YAAY,OAAO,aAAa,SAAS;AAC/C,YAAM,WAAW,kBAAkB,MAAM,UAAU,QAAQ,GAAG,SAAS;AACvE,aAAO,UAAU,IAAI,IAAI,QAAQ;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}
@@ -1,9 +1,16 @@
1
- import { S as SandboxProvider } from '../types-DLlJOfyX.js';
1
+ import { SandboxBetaCreateOpts, SandboxConnectOpts } from '@e2b/code-interpreter';
2
+ import { S as SandboxProvider } from '../types-DdcvY5CI.js';
2
3
 
4
+ type E2BCreateOverrides = Omit<Partial<SandboxBetaCreateOpts>, "timeoutMs" | "autoPause">;
5
+ type E2BConnectOverrides = Omit<Partial<SandboxConnectOpts>, "timeoutMs">;
6
+ type E2BTemplateOverride = string | (() => string | Promise<string>);
3
7
  interface E2BProviderOptions {
4
- create?: Record<string, unknown> | (() => Record<string, unknown> | Promise<Record<string, unknown>>);
5
- connect?: Record<string, unknown> | ((sandboxId: string) => Record<string, unknown> | Promise<Record<string, unknown>>);
8
+ create?: E2BCreateOverrides | (() => E2BCreateOverrides | Promise<E2BCreateOverrides>);
9
+ connect?: E2BConnectOverrides | ((sandboxId: string) => E2BConnectOverrides | Promise<E2BConnectOverrides>);
10
+ template?: E2BTemplateOverride;
6
11
  agentPort?: number;
12
+ timeoutMs?: number;
13
+ autoPause?: boolean;
7
14
  }
8
15
  declare function e2b(options?: E2BProviderOptions): SandboxProvider;
9
16
 
@@ -1,11 +1,16 @@
1
+ import {
2
+ SandboxDestroyedError
3
+ } from "../chunk-TVCDKGSM.js";
1
4
  import {
2
5
  DEFAULT_AGENTS,
3
6
  SANDBOX_AGENT_INSTALL_SCRIPT
4
- } from "../chunk-TWTMX66J.js";
7
+ } from "../chunk-7BNDCDDU.js";
5
8
 
6
9
  // src/providers/e2b.ts
7
- import { Sandbox } from "@e2b/code-interpreter";
10
+ import { NotFoundError, Sandbox } from "@e2b/code-interpreter";
8
11
  var DEFAULT_AGENT_PORT = 3e3;
12
+ var DEFAULT_TIMEOUT_MS = 36e5;
13
+ var SANDBOX_AGENT_PATH_EXPORT = 'export PATH="/usr/local/bin:$HOME/.local/bin:$PATH"';
9
14
  async function resolveOptions(value, sandboxId) {
10
15
  if (!value) return {};
11
16
  if (typeof value === "function") {
@@ -16,40 +21,80 @@ async function resolveOptions(value, sandboxId) {
16
21
  }
17
22
  return value;
18
23
  }
24
+ async function resolveTemplate(value) {
25
+ if (!value) return void 0;
26
+ return typeof value === "function" ? await value() : value;
27
+ }
28
+ function buildShellCommand(command, strict = false) {
29
+ const strictPrefix = strict ? "set -euo pipefail; " : "";
30
+ return `bash -lc '${strictPrefix}${SANDBOX_AGENT_PATH_EXPORT}; ${command}'`;
31
+ }
19
32
  function e2b(options = {}) {
20
33
  const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;
34
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
35
+ const autoPause = options.autoPause ?? true;
21
36
  return {
22
37
  name: "e2b",
38
+ defaultCwd: "/home/user",
23
39
  async create() {
24
40
  const createOpts = await resolveOptions(options.create);
25
- const sandbox = await Sandbox.create({ allowInternetAccess: true, ...createOpts });
26
- await sandbox.commands.run(`curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`).then((r) => {
41
+ const rawTemplate = typeof createOpts.template === "string" ? createOpts.template : void 0;
42
+ const restCreateOpts = { ...createOpts };
43
+ delete restCreateOpts.template;
44
+ const template = await resolveTemplate(options.template) ?? rawTemplate;
45
+ const sandbox = template ? (
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ await Sandbox.betaCreate(template, { allowInternetAccess: true, ...restCreateOpts, timeoutMs, autoPause })
48
+ ) : (
49
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
+ await Sandbox.betaCreate({ allowInternetAccess: true, ...restCreateOpts, timeoutMs, autoPause })
51
+ );
52
+ await sandbox.commands.run(buildShellCommand(`curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`, true)).then((r) => {
27
53
  if (r.exitCode !== 0) throw new Error(`e2b install failed:
28
54
  ${r.stderr}`);
29
55
  });
30
56
  for (const agent of DEFAULT_AGENTS) {
31
- await sandbox.commands.run(`sandbox-agent install-agent ${agent}`).then((r) => {
57
+ await sandbox.commands.run(buildShellCommand(`sandbox-agent install-agent ${agent}`)).then((r) => {
32
58
  if (r.exitCode !== 0) throw new Error(`e2b agent install failed: ${agent}
33
59
  ${r.stderr}`);
34
60
  });
35
61
  }
36
- await sandbox.commands.run(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`, { background: true, timeoutMs: 0 });
62
+ await sandbox.commands.run(buildShellCommand(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`), { background: true, timeoutMs: 0 });
37
63
  return sandbox.sandboxId;
38
64
  },
39
65
  async destroy(sandboxId) {
66
+ await this.pause?.(sandboxId);
67
+ },
68
+ async reconnect(sandboxId) {
69
+ const connectOpts = await resolveOptions(options.connect, sandboxId);
70
+ try {
71
+ await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs });
72
+ } catch (error) {
73
+ if (error instanceof NotFoundError) {
74
+ throw new SandboxDestroyedError(sandboxId, "e2b", { cause: error });
75
+ }
76
+ throw error;
77
+ }
78
+ },
79
+ async pause(sandboxId) {
80
+ const connectOpts = await resolveOptions(options.connect, sandboxId);
81
+ const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs });
82
+ await sandbox.betaPause();
83
+ },
84
+ async kill(sandboxId) {
40
85
  const connectOpts = await resolveOptions(options.connect, sandboxId);
41
- const sandbox = await Sandbox.connect(sandboxId, connectOpts);
86
+ const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs });
42
87
  await sandbox.kill();
43
88
  },
44
89
  async getUrl(sandboxId) {
45
90
  const connectOpts = await resolveOptions(options.connect, sandboxId);
46
- const sandbox = await Sandbox.connect(sandboxId, connectOpts);
91
+ const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs });
47
92
  return `https://${sandbox.getHost(agentPort)}`;
48
93
  },
49
94
  async ensureServer(sandboxId) {
50
95
  const connectOpts = await resolveOptions(options.connect, sandboxId);
51
- const sandbox = await Sandbox.connect(sandboxId, connectOpts);
52
- await sandbox.commands.run(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`, { background: true, timeoutMs: 0 });
96
+ const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs });
97
+ await sandbox.commands.run(buildShellCommand(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`), { background: true, timeoutMs: 0 });
53
98
  }
54
99
  };
55
100
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/e2b.ts"],"sourcesContent":["import { Sandbox } from \"@e2b/code-interpreter\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_AGENTS, SANDBOX_AGENT_INSTALL_SCRIPT } from \"./shared.ts\";\n\nconst DEFAULT_AGENT_PORT = 3000;\n\nexport interface E2BProviderOptions {\n create?: Record<string, unknown> | (() => Record<string, unknown> | Promise<Record<string, unknown>>);\n connect?: Record<string, unknown> | ((sandboxId: string) => Record<string, unknown> | Promise<Record<string, unknown>>);\n agentPort?: number;\n}\n\nasync function resolveOptions(value: E2BProviderOptions[\"create\"] | E2BProviderOptions[\"connect\"], sandboxId?: string): Promise<Record<string, unknown>> {\n if (!value) return {};\n if (typeof value === \"function\") {\n if (sandboxId) {\n return await (value as (id: string) => Record<string, unknown> | Promise<Record<string, unknown>>)(sandboxId);\n }\n return await (value as () => Record<string, unknown> | Promise<Record<string, unknown>>)();\n }\n return value;\n}\n\nexport function e2b(options: E2BProviderOptions = {}): SandboxProvider {\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n\n return {\n name: \"e2b\",\n async create(): Promise<string> {\n const createOpts = await resolveOptions(options.create);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sandbox = await Sandbox.create({ allowInternetAccess: true, ...createOpts } as any);\n\n await sandbox.commands.run(`curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`).then((r) => {\n if (r.exitCode !== 0) throw new Error(`e2b install failed:\\n${r.stderr}`);\n });\n for (const agent of DEFAULT_AGENTS) {\n await sandbox.commands.run(`sandbox-agent install-agent ${agent}`).then((r) => {\n if (r.exitCode !== 0) throw new Error(`e2b agent install failed: ${agent}\\n${r.stderr}`);\n });\n }\n await sandbox.commands.run(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`, { background: true, timeoutMs: 0 });\n\n return sandbox.sandboxId;\n },\n async destroy(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, connectOpts as any);\n await sandbox.kill();\n },\n async getUrl(sandboxId: string): Promise<string> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, connectOpts as any);\n return `https://${sandbox.getHost(agentPort)}`;\n },\n async ensureServer(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, connectOpts as any);\n await sandbox.commands.run(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`, { background: true, timeoutMs: 0 });\n },\n };\n}\n"],"mappings":";;;;;;AAAA,SAAS,eAAe;AAIxB,IAAM,qBAAqB;AAQ3B,eAAe,eAAe,OAAqE,WAAsD;AACvJ,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,MAAI,OAAO,UAAU,YAAY;AAC/B,QAAI,WAAW;AACb,aAAO,MAAO,MAAqF,SAAS;AAAA,IAC9G;AACA,WAAO,MAAO,MAA2E;AAAA,EAC3F;AACA,SAAO;AACT;AAEO,SAAS,IAAI,UAA8B,CAAC,GAAoB;AACrE,QAAM,YAAY,QAAQ,aAAa;AAEvC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,SAA0B;AAC9B,YAAM,aAAa,MAAM,eAAe,QAAQ,MAAM;AAEtD,YAAM,UAAU,MAAM,QAAQ,OAAO,EAAE,qBAAqB,MAAM,GAAG,WAAW,CAAQ;AAExF,YAAM,QAAQ,SAAS,IAAI,cAAc,4BAA4B,OAAO,EAAE,KAAK,CAAC,MAAM;AACxF,YAAI,EAAE,aAAa,EAAG,OAAM,IAAI,MAAM;AAAA,EAAwB,EAAE,MAAM,EAAE;AAAA,MAC1E,CAAC;AACD,iBAAW,SAAS,gBAAgB;AAClC,cAAM,QAAQ,SAAS,IAAI,+BAA+B,KAAK,EAAE,EAAE,KAAK,CAAC,MAAM;AAC7E,cAAI,EAAE,aAAa,EAAG,OAAM,IAAI,MAAM,6BAA6B,KAAK;AAAA,EAAK,EAAE,MAAM,EAAE;AAAA,QACzF,CAAC;AAAA,MACH;AACA,YAAM,QAAQ,SAAS,IAAI,yDAAyD,SAAS,IAAI,EAAE,YAAY,MAAM,WAAW,EAAE,CAAC;AAEnI,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,MAAM,QAAQ,WAAkC;AAC9C,YAAM,cAAc,MAAM,eAAe,QAAQ,SAAS,SAAS;AACnE,YAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,WAAkB;AACnE,YAAM,QAAQ,KAAK;AAAA,IACrB;AAAA,IACA,MAAM,OAAO,WAAoC;AAC/C,YAAM,cAAc,MAAM,eAAe,QAAQ,SAAS,SAAS;AACnE,YAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,WAAkB;AACnE,aAAO,WAAW,QAAQ,QAAQ,SAAS,CAAC;AAAA,IAC9C;AAAA,IACA,MAAM,aAAa,WAAkC;AACnD,YAAM,cAAc,MAAM,eAAe,QAAQ,SAAS,SAAS;AACnE,YAAM,UAAU,MAAM,QAAQ,QAAQ,WAAW,WAAkB;AACnE,YAAM,QAAQ,SAAS,IAAI,yDAAyD,SAAS,IAAI,EAAE,YAAY,MAAM,WAAW,EAAE,CAAC;AAAA,IACrI;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/e2b.ts"],"sourcesContent":["import { NotFoundError, Sandbox, type SandboxBetaCreateOpts, type SandboxConnectOpts } from \"@e2b/code-interpreter\";\nimport { SandboxDestroyedError } from \"../client.ts\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_AGENTS, SANDBOX_AGENT_INSTALL_SCRIPT } from \"./shared.ts\";\n\nconst DEFAULT_AGENT_PORT = 3000;\nconst DEFAULT_TIMEOUT_MS = 3_600_000;\nconst SANDBOX_AGENT_PATH_EXPORT = 'export PATH=\"/usr/local/bin:$HOME/.local/bin:$PATH\"';\n\ntype E2BCreateOverrides = Omit<Partial<SandboxBetaCreateOpts>, \"timeoutMs\" | \"autoPause\">;\ntype E2BConnectOverrides = Omit<Partial<SandboxConnectOpts>, \"timeoutMs\">;\ntype E2BTemplateOverride = string | (() => string | Promise<string>);\n\nexport interface E2BProviderOptions {\n create?: E2BCreateOverrides | (() => E2BCreateOverrides | Promise<E2BCreateOverrides>);\n connect?: E2BConnectOverrides | ((sandboxId: string) => E2BConnectOverrides | Promise<E2BConnectOverrides>);\n template?: E2BTemplateOverride;\n agentPort?: number;\n timeoutMs?: number;\n autoPause?: boolean;\n}\n\nasync function resolveOptions(value: E2BProviderOptions[\"create\"] | E2BProviderOptions[\"connect\"], sandboxId?: string): Promise<Record<string, unknown>> {\n if (!value) return {};\n if (typeof value === \"function\") {\n if (sandboxId) {\n return await (value as (id: string) => Record<string, unknown> | Promise<Record<string, unknown>>)(sandboxId);\n }\n return await (value as () => Record<string, unknown> | Promise<Record<string, unknown>>)();\n }\n return value;\n}\n\nasync function resolveTemplate(value: E2BTemplateOverride | undefined): Promise<string | undefined> {\n if (!value) return undefined;\n return typeof value === \"function\" ? await value() : value;\n}\n\nfunction buildShellCommand(command: string, strict = false): string {\n const strictPrefix = strict ? \"set -euo pipefail; \" : \"\";\n return `bash -lc '${strictPrefix}${SANDBOX_AGENT_PATH_EXPORT}; ${command}'`;\n}\n\nexport function e2b(options: E2BProviderOptions = {}): SandboxProvider {\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const autoPause = options.autoPause ?? true;\n\n return {\n name: \"e2b\",\n defaultCwd: \"/home/user\",\n async create(): Promise<string> {\n const createOpts = await resolveOptions(options.create);\n const rawTemplate = typeof createOpts.template === \"string\" ? createOpts.template : undefined;\n const restCreateOpts = { ...createOpts };\n delete restCreateOpts.template;\n const template = (await resolveTemplate(options.template)) ?? rawTemplate;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sandbox = template\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await Sandbox.betaCreate(template, { allowInternetAccess: true, ...restCreateOpts, timeoutMs, autoPause } as any)\n : // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await Sandbox.betaCreate({ allowInternetAccess: true, ...restCreateOpts, timeoutMs, autoPause } as any);\n\n await sandbox.commands.run(buildShellCommand(`curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`, true)).then((r) => {\n if (r.exitCode !== 0) throw new Error(`e2b install failed:\\n${r.stderr}`);\n });\n for (const agent of DEFAULT_AGENTS) {\n await sandbox.commands.run(buildShellCommand(`sandbox-agent install-agent ${agent}`)).then((r) => {\n if (r.exitCode !== 0) throw new Error(`e2b agent install failed: ${agent}\\n${r.stderr}`);\n });\n }\n await sandbox.commands.run(buildShellCommand(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`), { background: true, timeoutMs: 0 });\n\n return sandbox.sandboxId;\n },\n async destroy(sandboxId: string): Promise<void> {\n await this.pause?.(sandboxId);\n },\n async reconnect(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n try {\n await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs } as SandboxConnectOpts);\n } catch (error) {\n if (error instanceof NotFoundError) {\n throw new SandboxDestroyedError(sandboxId, \"e2b\", { cause: error });\n }\n throw error;\n }\n },\n async pause(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs } as SandboxConnectOpts);\n await sandbox.betaPause();\n },\n async kill(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs } as SandboxConnectOpts);\n await sandbox.kill();\n },\n async getUrl(sandboxId: string): Promise<string> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs } as SandboxConnectOpts);\n return `https://${sandbox.getHost(agentPort)}`;\n },\n async ensureServer(sandboxId: string): Promise<void> {\n const connectOpts = await resolveOptions(options.connect, sandboxId);\n const sandbox = await Sandbox.connect(sandboxId, { ...connectOpts, timeoutMs } as SandboxConnectOpts);\n await sandbox.commands.run(buildShellCommand(`sandbox-agent server --no-token --host 0.0.0.0 --port ${agentPort}`), { background: true, timeoutMs: 0 });\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { S as SandboxAgentSpawnLogMode } from '../spawn-76JDF5d3.js';
2
- import { S as SandboxProvider } from '../types-DLlJOfyX.js';
2
+ import { S as SandboxProvider } from '../types-DdcvY5CI.js';
3
3
 
4
4
  interface LocalProviderOptions {
5
5
  host?: string;
@@ -1,11 +1,14 @@
1
- import { S as SandboxProvider } from '../types-DLlJOfyX.js';
1
+ import { SandboxCreateParams, Image } from 'modal';
2
+ import { S as SandboxProvider } from '../types-DdcvY5CI.js';
2
3
 
4
+ type ModalCreateOverrides = Omit<Partial<SandboxCreateParams>, "secrets" | "encryptedPorts"> & {
5
+ secrets?: Record<string, string>;
6
+ encryptedPorts?: number[];
7
+ appName?: string;
8
+ };
3
9
  interface ModalProviderOptions {
4
- create?: {
5
- secrets?: Record<string, string>;
6
- appName?: string;
7
- memoryMiB?: number;
8
- };
10
+ create?: ModalCreateOverrides | (() => ModalCreateOverrides | Promise<ModalCreateOverrides>);
11
+ image?: string | Image;
9
12
  agentPort?: number;
10
13
  }
11
14
  declare function modal(options?: ModalProviderOptions): SandboxProvider;
@@ -1,34 +1,40 @@
1
1
  import {
2
- DEFAULT_AGENTS,
3
- SANDBOX_AGENT_INSTALL_SCRIPT
4
- } from "../chunk-TWTMX66J.js";
2
+ DEFAULT_SANDBOX_AGENT_IMAGE
3
+ } from "../chunk-7BNDCDDU.js";
5
4
 
6
5
  // src/providers/modal.ts
7
6
  import { ModalClient } from "modal";
8
7
  var DEFAULT_AGENT_PORT = 3e3;
9
8
  var DEFAULT_APP_NAME = "sandbox-agent";
10
9
  var DEFAULT_MEMORY_MIB = 2048;
10
+ async function resolveCreateOptions(value) {
11
+ if (!value) return {};
12
+ return typeof value === "function" ? await value() : value;
13
+ }
11
14
  function modal(options = {}) {
12
15
  const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;
13
- const appName = options.create?.appName ?? DEFAULT_APP_NAME;
14
- const memoryMiB = options.create?.memoryMiB ?? DEFAULT_MEMORY_MIB;
15
16
  const client = new ModalClient();
16
17
  return {
17
18
  name: "modal",
19
+ defaultCwd: "/root",
18
20
  async create() {
21
+ const createOpts = await resolveCreateOptions(options.create);
22
+ const appName = createOpts.appName ?? DEFAULT_APP_NAME;
23
+ const baseImage = options.image ?? DEFAULT_SANDBOX_AGENT_IMAGE;
19
24
  const app = await client.apps.fromName(appName, { createIfMissing: true });
20
- const installAgentCmds = DEFAULT_AGENTS.map((agent) => `RUN sandbox-agent install-agent ${agent}`);
21
- const image = client.images.fromRegistry("node:22-slim").dockerfileCommands([
22
- "RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*",
23
- `RUN curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`,
24
- ...installAgentCmds
25
- ]);
26
- const envVars = options.create?.secrets ?? {};
25
+ const image = typeof baseImage === "string" ? client.images.fromRegistry(baseImage) : baseImage;
26
+ const envVars = createOpts.secrets ?? {};
27
27
  const secrets = Object.keys(envVars).length > 0 ? [await client.secrets.fromObject(envVars)] : [];
28
+ const sandboxCreateOpts = { ...createOpts };
29
+ delete sandboxCreateOpts.appName;
30
+ delete sandboxCreateOpts.secrets;
31
+ const extraPorts = createOpts.encryptedPorts ?? [];
32
+ delete sandboxCreateOpts.encryptedPorts;
28
33
  const sb = await client.sandboxes.create(app, image, {
29
- encryptedPorts: [agentPort],
34
+ ...sandboxCreateOpts,
35
+ encryptedPorts: [agentPort, ...extraPorts],
30
36
  secrets,
31
- memoryMiB
37
+ memoryMiB: sandboxCreateOpts.memoryMiB ?? DEFAULT_MEMORY_MIB
32
38
  });
33
39
  sb.exec(["sandbox-agent", "server", "--no-token", "--host", "0.0.0.0", "--port", String(agentPort)]);
34
40
  return sb.sandboxId;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/providers/modal.ts"],"sourcesContent":["import { ModalClient } from \"modal\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_AGENTS, SANDBOX_AGENT_INSTALL_SCRIPT } from \"./shared.ts\";\n\nconst DEFAULT_AGENT_PORT = 3000;\nconst DEFAULT_APP_NAME = \"sandbox-agent\";\nconst DEFAULT_MEMORY_MIB = 2048;\n\nexport interface ModalProviderOptions {\n create?: {\n secrets?: Record<string, string>;\n appName?: string;\n memoryMiB?: number;\n };\n agentPort?: number;\n}\n\nexport function modal(options: ModalProviderOptions = {}): SandboxProvider {\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const appName = options.create?.appName ?? DEFAULT_APP_NAME;\n const memoryMiB = options.create?.memoryMiB ?? DEFAULT_MEMORY_MIB;\n const client = new ModalClient();\n\n return {\n name: \"modal\",\n async create(): Promise<string> {\n const app = await client.apps.fromName(appName, { createIfMissing: true });\n\n // Pre-install sandbox-agent and agents in the image so they are cached\n // across sandbox creates and don't need to be installed at runtime.\n const installAgentCmds = DEFAULT_AGENTS.map((agent) => `RUN sandbox-agent install-agent ${agent}`);\n const image = client.images\n .fromRegistry(\"node:22-slim\")\n .dockerfileCommands([\n \"RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*\",\n `RUN curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`,\n ...installAgentCmds,\n ]);\n\n const envVars = options.create?.secrets ?? {};\n const secrets = Object.keys(envVars).length > 0 ? [await client.secrets.fromObject(envVars)] : [];\n\n const sb = await client.sandboxes.create(app, image, {\n encryptedPorts: [agentPort],\n secrets,\n memoryMiB,\n });\n\n // Start the server as a long-running exec process. We intentionally\n // do NOT await p.wait() — the process stays alive for the sandbox\n // lifetime and keeps the port open for the tunnel.\n sb.exec([\"sandbox-agent\", \"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)]);\n\n return sb.sandboxId;\n },\n async destroy(sandboxId: string): Promise<void> {\n const sb = await client.sandboxes.fromId(sandboxId);\n await sb.terminate();\n },\n async getUrl(sandboxId: string): Promise<string> {\n const sb = await client.sandboxes.fromId(sandboxId);\n const tunnels = await sb.tunnels();\n const tunnel = tunnels[agentPort];\n if (!tunnel) {\n throw new Error(`modal: no tunnel found for port ${agentPort}`);\n }\n return tunnel.url;\n },\n async ensureServer(sandboxId: string): Promise<void> {\n const sb = await client.sandboxes.fromId(sandboxId);\n sb.exec([\"sandbox-agent\", \"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)]);\n },\n };\n}\n"],"mappings":";;;;;;AAAA,SAAS,mBAAmB;AAI5B,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAWpB,SAAS,MAAM,UAAgC,CAAC,GAAoB;AACzE,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,UAAU,QAAQ,QAAQ,WAAW;AAC3C,QAAM,YAAY,QAAQ,QAAQ,aAAa;AAC/C,QAAM,SAAS,IAAI,YAAY;AAE/B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM,SAA0B;AAC9B,YAAM,MAAM,MAAM,OAAO,KAAK,SAAS,SAAS,EAAE,iBAAiB,KAAK,CAAC;AAIzE,YAAM,mBAAmB,eAAe,IAAI,CAAC,UAAU,mCAAmC,KAAK,EAAE;AACjG,YAAM,QAAQ,OAAO,OAClB,aAAa,cAAc,EAC3B,mBAAmB;AAAA,QAClB;AAAA,QACA,kBAAkB,4BAA4B;AAAA,QAC9C,GAAG;AAAA,MACL,CAAC;AAEH,YAAM,UAAU,QAAQ,QAAQ,WAAW,CAAC;AAC5C,YAAM,UAAU,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,CAAC,MAAM,OAAO,QAAQ,WAAW,OAAO,CAAC,IAAI,CAAC;AAEhG,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,KAAK,OAAO;AAAA,QACnD,gBAAgB,CAAC,SAAS;AAAA,QAC1B;AAAA,QACA;AAAA,MACF,CAAC;AAKD,SAAG,KAAK,CAAC,iBAAiB,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC,CAAC;AAEnG,aAAO,GAAG;AAAA,IACZ;AAAA,IACA,MAAM,QAAQ,WAAkC;AAC9C,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,YAAM,GAAG,UAAU;AAAA,IACrB;AAAA,IACA,MAAM,OAAO,WAAoC;AAC/C,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,YAAM,UAAU,MAAM,GAAG,QAAQ;AACjC,YAAM,SAAS,QAAQ,SAAS;AAChC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,mCAAmC,SAAS,EAAE;AAAA,MAChE;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,aAAa,WAAkC;AACnD,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,SAAG,KAAK,CAAC,iBAAiB,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC,CAAC;AAAA,IACrG;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/providers/modal.ts"],"sourcesContent":["import { ModalClient, type Image, type SandboxCreateParams } from \"modal\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { DEFAULT_SANDBOX_AGENT_IMAGE } from \"./shared.ts\";\n\nconst DEFAULT_AGENT_PORT = 3000;\nconst DEFAULT_APP_NAME = \"sandbox-agent\";\nconst DEFAULT_MEMORY_MIB = 2048;\n\ntype ModalCreateOverrides = Omit<Partial<SandboxCreateParams>, \"secrets\" | \"encryptedPorts\"> & {\n secrets?: Record<string, string>;\n encryptedPorts?: number[];\n appName?: string;\n};\n\nexport interface ModalProviderOptions {\n create?: ModalCreateOverrides | (() => ModalCreateOverrides | Promise<ModalCreateOverrides>);\n image?: string | Image;\n agentPort?: number;\n}\n\nasync function resolveCreateOptions(value: ModalProviderOptions[\"create\"]): Promise<ModalCreateOverrides> {\n if (!value) return {};\n return typeof value === \"function\" ? await value() : value;\n}\n\nexport function modal(options: ModalProviderOptions = {}): SandboxProvider {\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const client = new ModalClient();\n\n return {\n name: \"modal\",\n defaultCwd: \"/root\",\n async create(): Promise<string> {\n const createOpts = await resolveCreateOptions(options.create);\n const appName = createOpts.appName ?? DEFAULT_APP_NAME;\n const baseImage = options.image ?? DEFAULT_SANDBOX_AGENT_IMAGE;\n const app = await client.apps.fromName(appName, { createIfMissing: true });\n\n // The default `-full` base image already includes sandbox-agent and all\n // agents pre-installed, so no additional dockerfile commands are needed.\n const image = typeof baseImage === \"string\" ? client.images.fromRegistry(baseImage) : baseImage;\n\n const envVars = createOpts.secrets ?? {};\n const secrets = Object.keys(envVars).length > 0 ? [await client.secrets.fromObject(envVars)] : [];\n const sandboxCreateOpts = { ...createOpts };\n delete sandboxCreateOpts.appName;\n delete sandboxCreateOpts.secrets;\n\n const extraPorts = createOpts.encryptedPorts ?? [];\n delete sandboxCreateOpts.encryptedPorts;\n\n const sb = await client.sandboxes.create(app, image, {\n ...sandboxCreateOpts,\n encryptedPorts: [agentPort, ...extraPorts],\n secrets,\n memoryMiB: sandboxCreateOpts.memoryMiB ?? DEFAULT_MEMORY_MIB,\n });\n\n // Start the server as a long-running exec process. We intentionally\n // do NOT await p.wait() — the process stays alive for the sandbox\n // lifetime and keeps the port open for the tunnel.\n sb.exec([\"sandbox-agent\", \"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)]);\n\n return sb.sandboxId;\n },\n async destroy(sandboxId: string): Promise<void> {\n const sb = await client.sandboxes.fromId(sandboxId);\n await sb.terminate();\n },\n async getUrl(sandboxId: string): Promise<string> {\n const sb = await client.sandboxes.fromId(sandboxId);\n const tunnels = await sb.tunnels();\n const tunnel = tunnels[agentPort];\n if (!tunnel) {\n throw new Error(`modal: no tunnel found for port ${agentPort}`);\n }\n return tunnel.url;\n },\n async ensureServer(sandboxId: string): Promise<void> {\n const sb = await client.sandboxes.fromId(sandboxId);\n sb.exec([\"sandbox-agent\", \"server\", \"--no-token\", \"--host\", \"0.0.0.0\", \"--port\", String(agentPort)]);\n },\n };\n}\n"],"mappings":";;;;;AAAA,SAAS,mBAAyD;AAIlE,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AAc3B,eAAe,qBAAqB,OAAsE;AACxG,MAAI,CAAC,MAAO,QAAO,CAAC;AACpB,SAAO,OAAO,UAAU,aAAa,MAAM,MAAM,IAAI;AACvD;AAEO,SAAS,MAAM,UAAgC,CAAC,GAAoB;AACzE,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,SAAS,IAAI,YAAY;AAE/B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,MAAM,SAA0B;AAC9B,YAAM,aAAa,MAAM,qBAAqB,QAAQ,MAAM;AAC5D,YAAM,UAAU,WAAW,WAAW;AACtC,YAAM,YAAY,QAAQ,SAAS;AACnC,YAAM,MAAM,MAAM,OAAO,KAAK,SAAS,SAAS,EAAE,iBAAiB,KAAK,CAAC;AAIzE,YAAM,QAAQ,OAAO,cAAc,WAAW,OAAO,OAAO,aAAa,SAAS,IAAI;AAEtF,YAAM,UAAU,WAAW,WAAW,CAAC;AACvC,YAAM,UAAU,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,CAAC,MAAM,OAAO,QAAQ,WAAW,OAAO,CAAC,IAAI,CAAC;AAChG,YAAM,oBAAoB,EAAE,GAAG,WAAW;AAC1C,aAAO,kBAAkB;AACzB,aAAO,kBAAkB;AAEzB,YAAM,aAAa,WAAW,kBAAkB,CAAC;AACjD,aAAO,kBAAkB;AAEzB,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,KAAK,OAAO;AAAA,QACnD,GAAG;AAAA,QACH,gBAAgB,CAAC,WAAW,GAAG,UAAU;AAAA,QACzC;AAAA,QACA,WAAW,kBAAkB,aAAa;AAAA,MAC5C,CAAC;AAKD,SAAG,KAAK,CAAC,iBAAiB,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC,CAAC;AAEnG,aAAO,GAAG;AAAA,IACZ;AAAA,IACA,MAAM,QAAQ,WAAkC;AAC9C,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,YAAM,GAAG,UAAU;AAAA,IACrB;AAAA,IACA,MAAM,OAAO,WAAoC;AAC/C,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,YAAM,UAAU,MAAM,GAAG,QAAQ;AACjC,YAAM,SAAS,QAAQ,SAAS;AAChC,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,mCAAmC,SAAS,EAAE;AAAA,MAChE;AACA,aAAO,OAAO;AAAA,IAChB;AAAA,IACA,MAAM,aAAa,WAAkC;AACnD,YAAM,KAAK,MAAM,OAAO,UAAU,OAAO,SAAS;AAClD,SAAG,KAAK,CAAC,iBAAiB,UAAU,cAAc,UAAU,WAAW,UAAU,OAAO,SAAS,CAAC,CAAC;AAAA,IACrG;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,22 @@
1
+ import { ClientOptions, SpriteConfig } from '@fly/sprites';
2
+ import { S as SandboxProvider } from '../types-DdcvY5CI.js';
3
+
4
+ interface SpritesCreateOverrides {
5
+ name?: string;
6
+ config?: SpriteConfig;
7
+ }
8
+ type SpritesClientOverrides = Partial<ClientOptions>;
9
+ interface SpritesProviderOptions {
10
+ token?: string | (() => string | Promise<string>);
11
+ client?: SpritesClientOverrides | (() => SpritesClientOverrides | Promise<SpritesClientOverrides>);
12
+ create?: SpritesCreateOverrides | (() => SpritesCreateOverrides | Promise<SpritesCreateOverrides>);
13
+ env?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
14
+ installAgents?: readonly string[];
15
+ agentPort?: number;
16
+ serviceName?: string;
17
+ serviceStartDuration?: string;
18
+ namePrefix?: string;
19
+ }
20
+ declare function sprites(options?: SpritesProviderOptions): SandboxProvider;
21
+
22
+ export { type SpritesClientOverrides, type SpritesCreateOverrides, type SpritesProviderOptions, sprites };
@@ -0,0 +1,209 @@
1
+ import {
2
+ SandboxDestroyedError
3
+ } from "../chunk-TVCDKGSM.js";
4
+ import {
5
+ SANDBOX_AGENT_NPX_SPEC
6
+ } from "../chunk-7BNDCDDU.js";
7
+
8
+ // src/providers/sprites.ts
9
+ import { ExecError, SpritesClient } from "@fly/sprites";
10
+ var DEFAULT_AGENT_PORT = 8080;
11
+ var DEFAULT_SERVICE_NAME = "sandbox-agent";
12
+ var DEFAULT_NAME_PREFIX = "sandbox-agent";
13
+ var DEFAULT_SERVICE_START_DURATION = "10m";
14
+ async function resolveValue(value, fallback) {
15
+ if (value === void 0) {
16
+ return fallback;
17
+ }
18
+ if (typeof value === "function") {
19
+ return await value();
20
+ }
21
+ return value;
22
+ }
23
+ async function resolveToken(value) {
24
+ const token = await resolveValue(value, process.env.SPRITES_API_KEY ?? process.env.SPRITE_TOKEN ?? process.env.SPRITES_TOKEN ?? "");
25
+ if (!token) {
26
+ throw new Error("sprites provider requires a token. Set SPRITES_API_KEY (or SPRITE_TOKEN) or pass `token`.");
27
+ }
28
+ return token;
29
+ }
30
+ function createSpritesClient(token, options) {
31
+ return new SpritesClient(token, options);
32
+ }
33
+ function generateSpriteName(prefix) {
34
+ const suffix = typeof globalThis.crypto?.randomUUID === "function" ? globalThis.crypto.randomUUID().slice(0, 8) : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
35
+ return `${prefix}-${suffix}`.toLowerCase();
36
+ }
37
+ function isSpriteNotFoundError(error) {
38
+ return error instanceof Error && error.message.startsWith("Sprite not found:");
39
+ }
40
+ function shellQuote(value) {
41
+ return `'${value.replace(/'/g, `'\\''`)}'`;
42
+ }
43
+ function buildServiceCommand(env, port) {
44
+ const exportParts = [];
45
+ for (const [key, value] of Object.entries(env)) {
46
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
47
+ throw new Error(`sprites provider received an invalid environment variable name: ${key}`);
48
+ }
49
+ exportParts.push(`export ${key}=${shellQuote(value)}`);
50
+ }
51
+ exportParts.push(`exec npx -y ${SANDBOX_AGENT_NPX_SPEC} server --no-token --host 0.0.0.0 --port ${port}`);
52
+ return exportParts.join("; ");
53
+ }
54
+ async function runSpriteCommand(sprite, file, args, env) {
55
+ try {
56
+ const result = await sprite.execFile(file, args, env ? { env } : void 0);
57
+ if (result.exitCode !== 0) {
58
+ throw new Error(`sprites command failed: ${file} ${args.join(" ")}`);
59
+ }
60
+ } catch (error) {
61
+ if (error instanceof ExecError) {
62
+ throw new Error(
63
+ `sprites command failed: ${file} ${args.join(" ")} (exit ${error.exitCode})
64
+ stdout:
65
+ ${String(error.stdout)}
66
+ stderr:
67
+ ${String(error.stderr)}`,
68
+ { cause: error }
69
+ );
70
+ }
71
+ throw error;
72
+ }
73
+ }
74
+ async function fetchService(client, spriteName, serviceName) {
75
+ const response = await fetch(`${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}`, {
76
+ method: "GET",
77
+ headers: {
78
+ Authorization: `Bearer ${client.token}`
79
+ }
80
+ });
81
+ if (response.status === 404) {
82
+ return void 0;
83
+ }
84
+ if (!response.ok) {
85
+ throw new Error(`sprites service lookup failed (status ${response.status}): ${await response.text()}`);
86
+ }
87
+ return await response.json();
88
+ }
89
+ async function upsertService(client, spriteName, serviceName, port, command) {
90
+ const existing = await fetchService(client, spriteName, serviceName);
91
+ const expectedArgs = ["-lc", command];
92
+ const isCurrent = existing?.cmd === "bash" && existing.http_port === port && JSON.stringify(existing.args ?? []) === JSON.stringify(expectedArgs);
93
+ if (isCurrent) {
94
+ return;
95
+ }
96
+ const response = await fetch(`${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}`, {
97
+ method: "PUT",
98
+ headers: {
99
+ Authorization: `Bearer ${client.token}`,
100
+ "Content-Type": "application/json"
101
+ },
102
+ body: JSON.stringify({
103
+ cmd: "bash",
104
+ args: expectedArgs,
105
+ http_port: port
106
+ })
107
+ });
108
+ if (!response.ok) {
109
+ throw new Error(`sprites service upsert failed (status ${response.status}): ${await response.text()}`);
110
+ }
111
+ }
112
+ async function startServiceIfNeeded(client, spriteName, serviceName, duration) {
113
+ const existing = await fetchService(client, spriteName, serviceName);
114
+ if (existing?.state?.status === "running" || existing?.state?.status === "starting") {
115
+ return;
116
+ }
117
+ const response = await fetch(
118
+ `${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}/start?duration=${encodeURIComponent(duration)}`,
119
+ {
120
+ method: "POST",
121
+ headers: {
122
+ Authorization: `Bearer ${client.token}`
123
+ }
124
+ }
125
+ );
126
+ if (!response.ok) {
127
+ throw new Error(`sprites service start failed (status ${response.status}): ${await response.text()}`);
128
+ }
129
+ await response.text();
130
+ }
131
+ async function ensureService(client, spriteName, serviceName, port, duration, env) {
132
+ const command = buildServiceCommand(env, port);
133
+ await upsertService(client, spriteName, serviceName, port, command);
134
+ await startServiceIfNeeded(client, spriteName, serviceName, duration);
135
+ }
136
+ function sprites(options = {}) {
137
+ const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;
138
+ const serviceName = options.serviceName ?? DEFAULT_SERVICE_NAME;
139
+ const serviceStartDuration = options.serviceStartDuration ?? DEFAULT_SERVICE_START_DURATION;
140
+ const namePrefix = options.namePrefix ?? DEFAULT_NAME_PREFIX;
141
+ const installAgents = [...options.installAgents ?? []];
142
+ const getClient = async () => {
143
+ const token = await resolveToken(options.token);
144
+ const clientOptions = await resolveValue(options.client, {});
145
+ return createSpritesClient(token, clientOptions);
146
+ };
147
+ const getServerEnv = async () => {
148
+ return await resolveValue(options.env, {});
149
+ };
150
+ const provider = {
151
+ name: "sprites",
152
+ defaultCwd: "/home/sprite",
153
+ async create() {
154
+ const client = await getClient();
155
+ const createOptions = await resolveValue(options.create, {});
156
+ const spriteName = createOptions.name ?? generateSpriteName(namePrefix);
157
+ const sprite = await client.createSprite(spriteName, createOptions.config);
158
+ const serverEnv = await getServerEnv();
159
+ for (const agent of installAgents) {
160
+ await runSpriteCommand(sprite, "bash", ["-lc", `npx -y ${SANDBOX_AGENT_NPX_SPEC} install-agent ${agent}`], serverEnv);
161
+ }
162
+ await ensureService(client, spriteName, serviceName, agentPort, serviceStartDuration, serverEnv);
163
+ return sprite.name;
164
+ },
165
+ async destroy(sandboxId) {
166
+ const client = await getClient();
167
+ try {
168
+ await client.deleteSprite(sandboxId);
169
+ } catch (error) {
170
+ if (isSpriteNotFoundError(error) || error instanceof Error && error.message.includes("status 404")) {
171
+ return;
172
+ }
173
+ throw error;
174
+ }
175
+ },
176
+ async reconnect(sandboxId) {
177
+ const client = await getClient();
178
+ try {
179
+ await client.getSprite(sandboxId);
180
+ } catch (error) {
181
+ if (isSpriteNotFoundError(error)) {
182
+ throw new SandboxDestroyedError(sandboxId, "sprites", { cause: error });
183
+ }
184
+ throw error;
185
+ }
186
+ },
187
+ async getUrl(sandboxId) {
188
+ const client = await getClient();
189
+ const sprite = await client.getSprite(sandboxId);
190
+ const url = sprite.url;
191
+ if (!url) {
192
+ throw new Error(`sprites API did not return a URL for sprite: ${sandboxId}`);
193
+ }
194
+ return url;
195
+ },
196
+ async ensureServer(sandboxId) {
197
+ const client = await getClient();
198
+ await ensureService(client, sandboxId, serviceName, agentPort, serviceStartDuration, await getServerEnv());
199
+ },
200
+ async getToken() {
201
+ return await resolveToken(options.token);
202
+ }
203
+ };
204
+ return provider;
205
+ }
206
+ export {
207
+ sprites
208
+ };
209
+ //# sourceMappingURL=sprites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/sprites.ts"],"sourcesContent":["import { ExecError, SpritesClient, type ClientOptions as SpritesClientOptions, type SpriteConfig } from \"@fly/sprites\";\nimport { SandboxDestroyedError } from \"../client.ts\";\nimport type { SandboxProvider } from \"./types.ts\";\nimport { SANDBOX_AGENT_NPX_SPEC } from \"./shared.ts\";\n\nconst DEFAULT_AGENT_PORT = 8080;\nconst DEFAULT_SERVICE_NAME = \"sandbox-agent\";\nconst DEFAULT_NAME_PREFIX = \"sandbox-agent\";\nconst DEFAULT_SERVICE_START_DURATION = \"10m\";\n\nexport interface SpritesCreateOverrides {\n name?: string;\n config?: SpriteConfig;\n}\n\nexport type SpritesClientOverrides = Partial<SpritesClientOptions>;\n\nexport interface SpritesProviderOptions {\n token?: string | (() => string | Promise<string>);\n client?: SpritesClientOverrides | (() => SpritesClientOverrides | Promise<SpritesClientOverrides>);\n create?: SpritesCreateOverrides | (() => SpritesCreateOverrides | Promise<SpritesCreateOverrides>);\n env?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);\n installAgents?: readonly string[];\n agentPort?: number;\n serviceName?: string;\n serviceStartDuration?: string;\n namePrefix?: string;\n}\n\ntype SpritesSandboxProvider = SandboxProvider & {\n getToken(sandboxId: string): Promise<string>;\n};\n\ninterface SpritesService {\n cmd?: string;\n args?: string[];\n http_port?: number | null;\n state?: {\n status?: string;\n };\n}\n\nasync function resolveValue<T>(value: T | (() => T | Promise<T>) | undefined, fallback: T): Promise<T> {\n if (value === undefined) {\n return fallback;\n }\n if (typeof value === \"function\") {\n return await (value as () => T | Promise<T>)();\n }\n return value;\n}\n\nasync function resolveToken(value: SpritesProviderOptions[\"token\"]): Promise<string> {\n const token = await resolveValue(value, process.env.SPRITES_API_KEY ?? process.env.SPRITE_TOKEN ?? process.env.SPRITES_TOKEN ?? \"\");\n if (!token) {\n throw new Error(\"sprites provider requires a token. Set SPRITES_API_KEY (or SPRITE_TOKEN) or pass `token`.\");\n }\n return token;\n}\n\nfunction createSpritesClient(token: string, options: SpritesClientOverrides): SpritesClient {\n return new SpritesClient(token, options);\n}\n\nfunction generateSpriteName(prefix: string): string {\n const suffix =\n typeof globalThis.crypto?.randomUUID === \"function\"\n ? globalThis.crypto.randomUUID().slice(0, 8)\n : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n return `${prefix}-${suffix}`.toLowerCase();\n}\n\nfunction isSpriteNotFoundError(error: unknown): boolean {\n return error instanceof Error && error.message.startsWith(\"Sprite not found:\");\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`;\n}\n\nfunction buildServiceCommand(env: Record<string, string>, port: number): string {\n const exportParts: string[] = [];\n for (const [key, value] of Object.entries(env)) {\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {\n throw new Error(`sprites provider received an invalid environment variable name: ${key}`);\n }\n exportParts.push(`export ${key}=${shellQuote(value)}`);\n }\n\n exportParts.push(`exec npx -y ${SANDBOX_AGENT_NPX_SPEC} server --no-token --host 0.0.0.0 --port ${port}`);\n return exportParts.join(\"; \");\n}\n\nasync function runSpriteCommand(sprite: ReturnType<SpritesClient[\"sprite\"]>, file: string, args: string[], env?: Record<string, string>): Promise<void> {\n try {\n const result = await sprite.execFile(file, args, env ? { env } : undefined);\n if (result.exitCode !== 0) {\n throw new Error(`sprites command failed: ${file} ${args.join(\" \")}`);\n }\n } catch (error) {\n if (error instanceof ExecError) {\n throw new Error(\n `sprites command failed: ${file} ${args.join(\" \")} (exit ${error.exitCode})\\nstdout:\\n${String(error.stdout)}\\nstderr:\\n${String(error.stderr)}`,\n { cause: error },\n );\n }\n throw error;\n }\n}\n\nasync function fetchService(client: SpritesClient, spriteName: string, serviceName: string): Promise<SpritesService | undefined> {\n const response = await fetch(`${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}`, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${client.token}`,\n },\n });\n\n if (response.status === 404) {\n return undefined;\n }\n\n if (!response.ok) {\n throw new Error(`sprites service lookup failed (status ${response.status}): ${await response.text()}`);\n }\n\n return (await response.json()) as SpritesService;\n}\n\nasync function upsertService(client: SpritesClient, spriteName: string, serviceName: string, port: number, command: string): Promise<void> {\n const existing = await fetchService(client, spriteName, serviceName);\n const expectedArgs = [\"-lc\", command];\n const isCurrent = existing?.cmd === \"bash\" && existing.http_port === port && JSON.stringify(existing.args ?? []) === JSON.stringify(expectedArgs);\n if (isCurrent) {\n return;\n }\n\n const response = await fetch(`${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}`, {\n method: \"PUT\",\n headers: {\n Authorization: `Bearer ${client.token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n cmd: \"bash\",\n args: expectedArgs,\n http_port: port,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`sprites service upsert failed (status ${response.status}): ${await response.text()}`);\n }\n}\n\nasync function startServiceIfNeeded(client: SpritesClient, spriteName: string, serviceName: string, duration: string): Promise<void> {\n const existing = await fetchService(client, spriteName, serviceName);\n if (existing?.state?.status === \"running\" || existing?.state?.status === \"starting\") {\n return;\n }\n\n const response = await fetch(\n `${client.baseURL}/v1/sprites/${encodeURIComponent(spriteName)}/services/${encodeURIComponent(serviceName)}/start?duration=${encodeURIComponent(duration)}`,\n {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${client.token}`,\n },\n },\n );\n\n if (!response.ok) {\n throw new Error(`sprites service start failed (status ${response.status}): ${await response.text()}`);\n }\n\n await response.text();\n}\n\nasync function ensureService(\n client: SpritesClient,\n spriteName: string,\n serviceName: string,\n port: number,\n duration: string,\n env: Record<string, string>,\n): Promise<void> {\n const command = buildServiceCommand(env, port);\n await upsertService(client, spriteName, serviceName, port, command);\n await startServiceIfNeeded(client, spriteName, serviceName, duration);\n}\n\nexport function sprites(options: SpritesProviderOptions = {}): SandboxProvider {\n const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;\n const serviceName = options.serviceName ?? DEFAULT_SERVICE_NAME;\n const serviceStartDuration = options.serviceStartDuration ?? DEFAULT_SERVICE_START_DURATION;\n const namePrefix = options.namePrefix ?? DEFAULT_NAME_PREFIX;\n const installAgents = [...(options.installAgents ?? [])];\n\n const getClient = async (): Promise<SpritesClient> => {\n const token = await resolveToken(options.token);\n const clientOptions = await resolveValue(options.client, {});\n return createSpritesClient(token, clientOptions);\n };\n\n const getServerEnv = async (): Promise<Record<string, string>> => {\n return await resolveValue(options.env, {});\n };\n\n const provider: SpritesSandboxProvider = {\n name: \"sprites\",\n defaultCwd: \"/home/sprite\",\n async create(): Promise<string> {\n const client = await getClient();\n const createOptions = await resolveValue(options.create, {});\n const spriteName = createOptions.name ?? generateSpriteName(namePrefix);\n const sprite = await client.createSprite(spriteName, createOptions.config);\n\n const serverEnv = await getServerEnv();\n for (const agent of installAgents) {\n await runSpriteCommand(sprite, \"bash\", [\"-lc\", `npx -y ${SANDBOX_AGENT_NPX_SPEC} install-agent ${agent}`], serverEnv);\n }\n\n await ensureService(client, spriteName, serviceName, agentPort, serviceStartDuration, serverEnv);\n return sprite.name;\n },\n async destroy(sandboxId: string): Promise<void> {\n const client = await getClient();\n try {\n await client.deleteSprite(sandboxId);\n } catch (error) {\n if (isSpriteNotFoundError(error) || (error instanceof Error && error.message.includes(\"status 404\"))) {\n return;\n }\n throw error;\n }\n },\n async reconnect(sandboxId: string): Promise<void> {\n const client = await getClient();\n try {\n await client.getSprite(sandboxId);\n } catch (error) {\n if (isSpriteNotFoundError(error)) {\n throw new SandboxDestroyedError(sandboxId, \"sprites\", { cause: error });\n }\n throw error;\n }\n },\n async getUrl(sandboxId: string): Promise<string> {\n const client = await getClient();\n const sprite = await client.getSprite(sandboxId);\n const url = (sprite as { url?: string }).url;\n if (!url) {\n throw new Error(`sprites API did not return a URL for sprite: ${sandboxId}`);\n }\n return url;\n },\n async ensureServer(sandboxId: string): Promise<void> {\n const client = await getClient();\n await ensureService(client, sandboxId, serviceName, agentPort, serviceStartDuration, await getServerEnv());\n },\n async getToken(): Promise<string> {\n return await resolveToken(options.token);\n },\n };\n\n return provider;\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { S as SandboxProvider } from '../types-DLlJOfyX.js';
1
+ import { S as SandboxProvider } from '../types-DdcvY5CI.js';
2
2
 
3
3
  interface VercelProviderOptions {
4
4
  create?: Record<string, unknown> | (() => Record<string, unknown> | Promise<Record<string, unknown>>);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_AGENTS,
3
3
  SANDBOX_AGENT_INSTALL_SCRIPT
4
- } from "../chunk-TWTMX66J.js";
4
+ } from "../chunk-7BNDCDDU.js";
5
5
 
6
6
  // src/providers/vercel.ts
7
7
  import { Sandbox } from "@vercel/sandbox";
@@ -25,6 +25,7 @@ function vercel(options = {}) {
25
25
  const agentPort = options.agentPort ?? DEFAULT_AGENT_PORT;
26
26
  return {
27
27
  name: "vercel",
28
+ defaultCwd: "/home/vercel-sandbox",
28
29
  async create() {
29
30
  const sandbox = await Sandbox.create(await resolveCreateOptions(options.create, agentPort));
30
31
  await runVercelCommand(sandbox, "sh", ["-c", `curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`]);