@agentproto/sandbox-e2b 0.2.0 → 0.2.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.
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -24,6 +24,7 @@ function readE2bConfig(spec) {
|
|
|
24
24
|
daemonReadyTimeoutMs: typeof config.daemonReadyTimeoutMs === "number" ? config.daemonReadyTimeoutMs : void 0,
|
|
25
25
|
pollIntervalMs: typeof config.pollIntervalMs === "number" ? config.pollIntervalMs : void 0,
|
|
26
26
|
updateCliOnBoot: typeof config.updateCliOnBoot === "boolean" ? config.updateCliOnBoot : void 0,
|
|
27
|
+
cliVersion: typeof config.cliVersion === "string" ? config.cliVersion : void 0,
|
|
27
28
|
installPackages: Array.isArray(config.installPackages) ? config.installPackages.filter((p) => typeof p === "string" && p.length > 0) : void 0,
|
|
28
29
|
updateCliTimeoutMs: typeof config.updateCliTimeoutMs === "number" ? config.updateCliTimeoutMs : void 0
|
|
29
30
|
};
|
|
@@ -37,7 +38,8 @@ async function ensureDaemonHealthy(sandbox, host, port, workspace, config, env)
|
|
|
37
38
|
if (alreadyUp) return;
|
|
38
39
|
if (config.updateCliOnBoot ?? true) {
|
|
39
40
|
const extras = (config.installPackages ?? []).map((spec) => ` '${spec.replace(/'/g, "")}'`).join("");
|
|
40
|
-
|
|
41
|
+
const cli = `@agentproto/cli@${config.cliVersion ?? "latest"}`;
|
|
42
|
+
await sandbox.commands.run(`sudo npm i -g ${cli}${extras}`, {
|
|
41
43
|
envs: env,
|
|
42
44
|
timeoutMs: config.updateCliTimeoutMs ?? UPDATE_CLI_TIMEOUT_MS
|
|
43
45
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * e2b `SandboxProvider` — boots the pre-built `agentproto-workstation`\n * template, ensures the agentproto daemon is listening on it, and exposes\n * the daemon's `/mcp` endpoint via `sandbox.getHost()` so\n * `createSandboxAgentSessionHost` (`@agentproto/sandbox`) can hand it\n * straight to `connectDaemonAgentSessionHost`.\n *\n * `getHost(port)` returns a publicly reachable hostname for that port\n * directly — e2b's per-sandbox auth token (`SandboxOpts.secure`) gates the\n * SDK's own control-plane (envd) traffic, not arbitrary listening ports the\n * sandbox process opens, so no extra auth header is threaded through here.\n * The daemon's OWN origin allowlist is a separate gate, though: it defaults\n * to `localhost:*`, which rejects a connection from this host process\n * against the sandbox's public `https://<getHost>` origin. `--allow-origin`\n * is passed the sandbox's own getHost origin to open that gate.\n *\n * The workstation template MAY already autostart the daemon; since that\n * can't be verified without a live template, this provider checks health\n * first and only issues the start command when the daemon isn't already\n * responding — correct either way. When it does start the daemon, it first\n * updates the baked `@agentproto/cli` (the pre-built template can lag\n * behind — verified stale against a live template) so callers aren't stuck\n * on whatever agentproto version the template was last baked with.\n */\n\nimport { Sandbox } from \"e2b\"\nimport type { BootedSandbox, SandboxBootOpts, SandboxProvider, SandboxSpec } from \"@agentproto/sandbox\"\n\n/** Pre-built template that bakes @agentproto/cli + adapters + node + git. */\nexport const DEFAULT_TEMPLATE = \"53ybr99wdfgoebi9nee8\"\n\n/** `serve.ts`'s default port (`DEFAULT_MCP_URL` in `@agentproto/harness`). */\nconst DEFAULT_PORT = 18790\n/**\n * Default sandbox LIFETIME. e2b's own default is 5 minutes (`SandboxOpts.\n * timeoutMs @default 300_000`) — lethal for real agent work: boot (~30s) +\n * `npm i -g` (~90s) + a multi-minute agent turn crosses 5:00 mid-turn, e2b\n * reaps the VM, and the next request cold-boots it WITHOUT the daemon —\n * surfacing as the baffling `\"The sandbox is running but port is not open\"`\n * 502 (observed live killing a PR-review turn). 45 minutes covers any\n * plausible session; `config.timeoutMs` still overrides in either direction.\n */\nconst DEFAULT_SANDBOX_TIMEOUT_MS = 45 * 60_000\nconst DEFAULT_WORKSPACE = \"/home/user\"\nconst HEALTH_PROBE_TIMEOUT_MS = 3_000\nconst DAEMON_READY_TIMEOUT_MS = 30_000\nconst POLL_INTERVAL_MS = 500\nconst UPDATE_CLI_TIMEOUT_MS = 120_000\n\ninterface E2bSandboxConfig {\n /** Template name or id. Defaults to the `agentproto-workstation` template. */\n template?: string\n /** Port the agentproto daemon listens on inside the sandbox. Default 18790. */\n port?: number\n /** `--workspace` passed to `agentproto serve`. Default `/home/user`. */\n workspace?: string\n /** Sandbox lifetime cap, forwarded to `Sandbox.create`. */\n timeoutMs?: number\n /** How long to wait for the health probe before assuming the daemon isn't autostarted. */\n healthProbeTimeoutMs?: number\n /** How long to wait for the daemon to become healthy after starting it. */\n daemonReadyTimeoutMs?: number\n /** Delay between health-probe attempts. */\n pollIntervalMs?: number\n /** Run `npm i -g @agentproto/cli@latest` before starting the daemon, so a\n * stale template bake doesn't pin callers to an old agentproto version.\n * Default true. Only runs when this provider is the one starting the\n * daemon (skipped when the health probe finds it already autostarted). */\n updateCliOnBoot?: boolean\n /** Extra npm package specs installed globally ALONGSIDE the CLI update\n * (single `npm i -g` invocation). Load-bearing for adapters: the CLI\n * update replaces the global install, LOSING any template-baked\n * `@agentproto/adapter-*` packages (verified against a live template) —\n * so the adapter the caller intends to spawn must be (re)installed in the\n * same breath, e.g. `[\"@agentproto/adapter-claude-sdk@latest\"]` (plus\n * `\"@anthropic-ai/claude-code@latest\"` for the claude-code adapter's\n * underlying CLI). Ignored when `updateCliOnBoot` is false or the daemon\n * was already autostarted healthy. */\n installPackages?: string[]\n /** Timeout for the `npm i -g` update command. Default 120s. */\n updateCliTimeoutMs?: number\n}\n\nfunction readE2bConfig(spec: SandboxSpec): E2bSandboxConfig {\n const config = (spec.config ?? {}) as Record<string, unknown>\n return {\n template: typeof config.template === \"string\" ? config.template : undefined,\n port: typeof config.port === \"number\" ? config.port : undefined,\n workspace: typeof config.workspace === \"string\" ? config.workspace : undefined,\n timeoutMs: typeof config.timeoutMs === \"number\" ? config.timeoutMs : undefined,\n healthProbeTimeoutMs:\n typeof config.healthProbeTimeoutMs === \"number\" ? config.healthProbeTimeoutMs : undefined,\n daemonReadyTimeoutMs:\n typeof config.daemonReadyTimeoutMs === \"number\" ? config.daemonReadyTimeoutMs : undefined,\n pollIntervalMs: typeof config.pollIntervalMs === \"number\" ? config.pollIntervalMs : undefined,\n updateCliOnBoot: typeof config.updateCliOnBoot === \"boolean\" ? config.updateCliOnBoot : undefined,\n installPackages: Array.isArray(config.installPackages)\n ? config.installPackages.filter((p): p is string => typeof p === \"string\" && p.length > 0)\n : undefined,\n updateCliTimeoutMs:\n typeof config.updateCliTimeoutMs === \"number\" ? config.updateCliTimeoutMs : undefined,\n }\n}\n\n/**\n * Probe health, and — if the daemon isn't already up — update the (possibly\n * stale) baked CLI and start it, then re-probe. Shared by `boot` (a fresh\n * template's autostart may not have fired yet) and `connect` (a resumed box\n * may wake with a dead daemon process — see PR3 risk \"stale daemon on\n * reconnect\"). Throws (after killing the sandbox) if the daemon never comes\n * up.\n */\nasync function ensureDaemonHealthy(\n sandbox: Sandbox,\n host: string,\n port: number,\n workspace: string,\n config: E2bSandboxConfig,\n env: Record<string, string>,\n): Promise<void> {\n const healthUrl = `https://${host}/health`\n const healthProbeTimeoutMs = config.healthProbeTimeoutMs ?? HEALTH_PROBE_TIMEOUT_MS\n const daemonReadyTimeoutMs = config.daemonReadyTimeoutMs ?? DAEMON_READY_TIMEOUT_MS\n const pollIntervalMs = config.pollIntervalMs ?? POLL_INTERVAL_MS\n\n const alreadyUp = await probeHealth(healthUrl, healthProbeTimeoutMs, pollIntervalMs)\n if (alreadyUp) return\n\n if (config.updateCliOnBoot ?? true) {\n // One `npm i -g` for the CLI update AND any caller-declared extras\n // (`installPackages` — typically the adapter about to be spawned). The\n // CLI update alone replaces the global install and LOSES template-baked\n // adapters, so the two must land in the same invocation. Extras are\n // single-quoted (with any quote chars stripped) since they arrive from\n // caller-authored spec config.\n const extras = (config.installPackages ?? [])\n .map(spec => ` '${spec.replace(/'/g, \"\")}'`)\n .join(\"\")\n await sandbox.commands.run(`sudo npm i -g @agentproto/cli@latest${extras}`, {\n envs: env,\n timeoutMs: config.updateCliTimeoutMs ?? UPDATE_CLI_TIMEOUT_MS,\n })\n }\n await sandbox.commands.run(\n `agentproto serve --port ${port} --bind 0.0.0.0 --workspace ${workspace} --allow-origin https://${host}`,\n // timeoutMs: 0 disables e2b's per-command timeout — which DEFAULTS TO 60\n // SECONDS and applies to `background: true` commands too, silently\n // SIGKILLing the daemon one minute after boot. That was the root cause of\n // every long agent turn dying with \"sandbox is running but port is not\n // open\" (502) / `MCP error -32001` while short (<60s) probe turns passed\n // — verified live: the daemon's port went dead at exactly serve+60s with\n // the VM healthy and memory flat. The daemon must live as long as the\n // SANDBOX (lifetime cap above), not as long as a shell command.\n { background: true, envs: env, timeoutMs: 0 },\n )\n const ready = await probeHealth(healthUrl, daemonReadyTimeoutMs, pollIntervalMs)\n if (!ready) {\n await sandbox.kill()\n throw new Error(\n `@agentproto/sandbox-e2b: agentproto daemon did not become healthy at ${healthUrl} ` +\n `within ${daemonReadyTimeoutMs}ms (sandbox ${sandbox.sandboxId}).`,\n )\n }\n}\n\n/** Wrap a healthy sandbox handle into the `BootedSandbox` shape common to\n * `boot` and `connect`. `pause()` always keeps the full memory snapshot\n * (`keepMemory: true`, the SDK default) — a filesystem-only pause would\n * cold-boot the box on resume, dropping the running agentproto daemon and\n * any open connections (PR3 risk \"e2b pause loses in-memory state\"). */\nfunction toBootedSandbox(sandbox: Awaited<ReturnType<typeof Sandbox.create>>, host: string): BootedSandbox {\n return {\n mcpUrl: `https://${host}/mcp`,\n sandboxId: sandbox.sandboxId,\n async stop(): Promise<void> {\n await sandbox.kill()\n },\n async pause(): Promise<void> {\n await sandbox.pause({ keepMemory: true })\n },\n }\n}\n\n/** `e2bSandboxProvider.boot`/`.connect` — see module docs. */\nexport const e2bSandboxProvider: SandboxProvider = {\n async boot(spec: SandboxSpec, opts: SandboxBootOpts): Promise<BootedSandbox> {\n const config = readE2bConfig(spec)\n const template = config.template ?? DEFAULT_TEMPLATE\n const port = config.port ?? DEFAULT_PORT\n const workspace = config.workspace ?? DEFAULT_WORKSPACE\n\n const sandbox = await Sandbox.create(template, {\n apiKey: process.env.E2B_API_KEY,\n envs: opts.env,\n timeoutMs: config.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS,\n })\n\n const host = sandbox.getHost(port)\n await ensureDaemonHealthy(sandbox, host, port, workspace, config, opts.env)\n return toBootedSandbox(sandbox, host)\n },\n\n async connect(sandboxId: string, spec: SandboxSpec, opts: SandboxBootOpts): Promise<BootedSandbox> {\n const config = readE2bConfig(spec)\n const port = config.port ?? DEFAULT_PORT\n const workspace = config.workspace ?? DEFAULT_WORKSPACE\n\n const sandbox = await Sandbox.connect(sandboxId, { apiKey: process.env.E2B_API_KEY })\n // A resumed box keeps its ORIGINAL lifetime deadline — re-arm it so the\n // reconnected session gets the same runway a fresh boot gets (same\n // 5-minute-default trap as `boot`, see DEFAULT_SANDBOX_TIMEOUT_MS).\n await sandbox.setTimeout(config.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS)\n\n const host = sandbox.getHost(port)\n await ensureDaemonHealthy(sandbox, host, port, workspace, config, opts.env)\n return toBootedSandbox(sandbox, host)\n },\n}\n\n/** Poll `url` until it responds OK, or return false once `timeoutMs` elapses. */\nasync function probeHealth(url: string, timeoutMs: number, pollIntervalMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(pollIntervalMs) })\n if (res.ok) return true\n } catch {\n // not up yet — fall through to the deadline check\n }\n if (Date.now() >= deadline) return false\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * e2b `SandboxProvider` — boots the pre-built `agentproto-workstation`\n * template, ensures the agentproto daemon is listening on it, and exposes\n * the daemon's `/mcp` endpoint via `sandbox.getHost()` so\n * `createSandboxAgentSessionHost` (`@agentproto/sandbox`) can hand it\n * straight to `connectDaemonAgentSessionHost`.\n *\n * `getHost(port)` returns a publicly reachable hostname for that port\n * directly — e2b's per-sandbox auth token (`SandboxOpts.secure`) gates the\n * SDK's own control-plane (envd) traffic, not arbitrary listening ports the\n * sandbox process opens, so no extra auth header is threaded through here.\n * The daemon's OWN origin allowlist is a separate gate, though: it defaults\n * to `localhost:*`, which rejects a connection from this host process\n * against the sandbox's public `https://<getHost>` origin. `--allow-origin`\n * is passed the sandbox's own getHost origin to open that gate.\n *\n * The workstation template MAY already autostart the daemon; since that\n * can't be verified without a live template, this provider checks health\n * first and only issues the start command when the daemon isn't already\n * responding — correct either way. When it does start the daemon, it first\n * updates the baked `@agentproto/cli` (the pre-built template can lag\n * behind — verified stale against a live template) so callers aren't stuck\n * on whatever agentproto version the template was last baked with.\n */\n\nimport { Sandbox } from \"e2b\"\nimport type { BootedSandbox, SandboxBootOpts, SandboxProvider, SandboxSpec } from \"@agentproto/sandbox\"\n\n/** Pre-built template that bakes @agentproto/cli + adapters + node + git. */\nexport const DEFAULT_TEMPLATE = \"53ybr99wdfgoebi9nee8\"\n\n/** `serve.ts`'s default port (`DEFAULT_MCP_URL` in `@agentproto/harness`). */\nconst DEFAULT_PORT = 18790\n/**\n * Default sandbox LIFETIME. e2b's own default is 5 minutes (`SandboxOpts.\n * timeoutMs @default 300_000`) — lethal for real agent work: boot (~30s) +\n * `npm i -g` (~90s) + a multi-minute agent turn crosses 5:00 mid-turn, e2b\n * reaps the VM, and the next request cold-boots it WITHOUT the daemon —\n * surfacing as the baffling `\"The sandbox is running but port is not open\"`\n * 502 (observed live killing a PR-review turn). 45 minutes covers any\n * plausible session; `config.timeoutMs` still overrides in either direction.\n */\nconst DEFAULT_SANDBOX_TIMEOUT_MS = 45 * 60_000\nconst DEFAULT_WORKSPACE = \"/home/user\"\nconst HEALTH_PROBE_TIMEOUT_MS = 3_000\nconst DAEMON_READY_TIMEOUT_MS = 30_000\nconst POLL_INTERVAL_MS = 500\nconst UPDATE_CLI_TIMEOUT_MS = 120_000\n\ninterface E2bSandboxConfig {\n /** Template name or id. Defaults to the `agentproto-workstation` template. */\n template?: string\n /** Port the agentproto daemon listens on inside the sandbox. Default 18790. */\n port?: number\n /** `--workspace` passed to `agentproto serve`. Default `/home/user`. */\n workspace?: string\n /** Sandbox lifetime cap, forwarded to `Sandbox.create`. */\n timeoutMs?: number\n /** How long to wait for the health probe before assuming the daemon isn't autostarted. */\n healthProbeTimeoutMs?: number\n /** How long to wait for the daemon to become healthy after starting it. */\n daemonReadyTimeoutMs?: number\n /** Delay between health-probe attempts. */\n pollIntervalMs?: number\n /** Run `npm i -g @agentproto/cli@latest` before starting the daemon, so a\n * stale template bake doesn't pin callers to an old agentproto version.\n * Default true. Only runs when this provider is the one starting the\n * daemon (skipped when the health probe finds it already autostarted). */\n updateCliOnBoot?: boolean\n /** CLI version to install on boot, pinned instead of a floating `@latest`.\n * A broken `@agentproto/cli@latest` publish otherwise silently kills the\n * box on boot; pinning a known-good version (sourced from config, defaulting\n * to the repo's declared `cliVersion`) makes the boot install reproducible.\n * Produces `@agentproto/cli@<version>`; when unset, falls back to `@latest`. */\n cliVersion?: string\n /** Extra npm package specs installed globally ALONGSIDE the CLI update\n * (single `npm i -g` invocation). Load-bearing for adapters: the CLI\n * update replaces the global install, LOSING any template-baked\n * `@agentproto/adapter-*` packages (verified against a live template) —\n * so the adapter the caller intends to spawn must be (re)installed in the\n * same breath, e.g. `[\"@agentproto/adapter-claude-sdk@latest\"]` (plus\n * `\"@anthropic-ai/claude-code@latest\"` for the claude-code adapter's\n * underlying CLI). Ignored when `updateCliOnBoot` is false or the daemon\n * was already autostarted healthy. */\n installPackages?: string[]\n /** Timeout for the `npm i -g` update command. Default 120s. */\n updateCliTimeoutMs?: number\n}\n\nfunction readE2bConfig(spec: SandboxSpec): E2bSandboxConfig {\n const config = (spec.config ?? {}) as Record<string, unknown>\n return {\n template: typeof config.template === \"string\" ? config.template : undefined,\n port: typeof config.port === \"number\" ? config.port : undefined,\n workspace: typeof config.workspace === \"string\" ? config.workspace : undefined,\n timeoutMs: typeof config.timeoutMs === \"number\" ? config.timeoutMs : undefined,\n healthProbeTimeoutMs:\n typeof config.healthProbeTimeoutMs === \"number\" ? config.healthProbeTimeoutMs : undefined,\n daemonReadyTimeoutMs:\n typeof config.daemonReadyTimeoutMs === \"number\" ? config.daemonReadyTimeoutMs : undefined,\n pollIntervalMs: typeof config.pollIntervalMs === \"number\" ? config.pollIntervalMs : undefined,\n updateCliOnBoot: typeof config.updateCliOnBoot === \"boolean\" ? config.updateCliOnBoot : undefined,\n cliVersion: typeof config.cliVersion === \"string\" ? config.cliVersion : undefined,\n installPackages: Array.isArray(config.installPackages)\n ? config.installPackages.filter((p): p is string => typeof p === \"string\" && p.length > 0)\n : undefined,\n updateCliTimeoutMs:\n typeof config.updateCliTimeoutMs === \"number\" ? config.updateCliTimeoutMs : undefined,\n }\n}\n\n/**\n * Probe health, and — if the daemon isn't already up — update the (possibly\n * stale) baked CLI and start it, then re-probe. Shared by `boot` (a fresh\n * template's autostart may not have fired yet) and `connect` (a resumed box\n * may wake with a dead daemon process — see PR3 risk \"stale daemon on\n * reconnect\"). Throws (after killing the sandbox) if the daemon never comes\n * up.\n */\nasync function ensureDaemonHealthy(\n sandbox: Sandbox,\n host: string,\n port: number,\n workspace: string,\n config: E2bSandboxConfig,\n env: Record<string, string>,\n): Promise<void> {\n const healthUrl = `https://${host}/health`\n const healthProbeTimeoutMs = config.healthProbeTimeoutMs ?? HEALTH_PROBE_TIMEOUT_MS\n const daemonReadyTimeoutMs = config.daemonReadyTimeoutMs ?? DAEMON_READY_TIMEOUT_MS\n const pollIntervalMs = config.pollIntervalMs ?? POLL_INTERVAL_MS\n\n const alreadyUp = await probeHealth(healthUrl, healthProbeTimeoutMs, pollIntervalMs)\n if (alreadyUp) return\n\n if (config.updateCliOnBoot ?? true) {\n // One `npm i -g` for the CLI update AND any caller-declared extras\n // (`installPackages` — typically the adapter about to be spawned). The\n // CLI update alone replaces the global install and LOSES template-baked\n // adapters, so the two must land in the same invocation. Extras are\n // single-quoted (with any quote chars stripped) since they arrive from\n // caller-authored spec config.\n const extras = (config.installPackages ?? [])\n .map(spec => ` '${spec.replace(/'/g, \"\")}'`)\n .join(\"\")\n const cli = `@agentproto/cli@${config.cliVersion ?? \"latest\"}`\n await sandbox.commands.run(`sudo npm i -g ${cli}${extras}`, {\n envs: env,\n timeoutMs: config.updateCliTimeoutMs ?? UPDATE_CLI_TIMEOUT_MS,\n })\n }\n await sandbox.commands.run(\n `agentproto serve --port ${port} --bind 0.0.0.0 --workspace ${workspace} --allow-origin https://${host}`,\n // timeoutMs: 0 disables e2b's per-command timeout — which DEFAULTS TO 60\n // SECONDS and applies to `background: true` commands too, silently\n // SIGKILLing the daemon one minute after boot. That was the root cause of\n // every long agent turn dying with \"sandbox is running but port is not\n // open\" (502) / `MCP error -32001` while short (<60s) probe turns passed\n // — verified live: the daemon's port went dead at exactly serve+60s with\n // the VM healthy and memory flat. The daemon must live as long as the\n // SANDBOX (lifetime cap above), not as long as a shell command.\n { background: true, envs: env, timeoutMs: 0 },\n )\n const ready = await probeHealth(healthUrl, daemonReadyTimeoutMs, pollIntervalMs)\n if (!ready) {\n await sandbox.kill()\n throw new Error(\n `@agentproto/sandbox-e2b: agentproto daemon did not become healthy at ${healthUrl} ` +\n `within ${daemonReadyTimeoutMs}ms (sandbox ${sandbox.sandboxId}).`,\n )\n }\n}\n\n/** Wrap a healthy sandbox handle into the `BootedSandbox` shape common to\n * `boot` and `connect`. `pause()` always keeps the full memory snapshot\n * (`keepMemory: true`, the SDK default) — a filesystem-only pause would\n * cold-boot the box on resume, dropping the running agentproto daemon and\n * any open connections (PR3 risk \"e2b pause loses in-memory state\"). */\nfunction toBootedSandbox(sandbox: Awaited<ReturnType<typeof Sandbox.create>>, host: string): BootedSandbox {\n return {\n mcpUrl: `https://${host}/mcp`,\n sandboxId: sandbox.sandboxId,\n async stop(): Promise<void> {\n await sandbox.kill()\n },\n async pause(): Promise<void> {\n await sandbox.pause({ keepMemory: true })\n },\n }\n}\n\n/** `e2bSandboxProvider.boot`/`.connect` — see module docs. */\nexport const e2bSandboxProvider: SandboxProvider = {\n async boot(spec: SandboxSpec, opts: SandboxBootOpts): Promise<BootedSandbox> {\n const config = readE2bConfig(spec)\n const template = config.template ?? DEFAULT_TEMPLATE\n const port = config.port ?? DEFAULT_PORT\n const workspace = config.workspace ?? DEFAULT_WORKSPACE\n\n const sandbox = await Sandbox.create(template, {\n apiKey: process.env.E2B_API_KEY,\n envs: opts.env,\n timeoutMs: config.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS,\n })\n\n const host = sandbox.getHost(port)\n await ensureDaemonHealthy(sandbox, host, port, workspace, config, opts.env)\n return toBootedSandbox(sandbox, host)\n },\n\n async connect(sandboxId: string, spec: SandboxSpec, opts: SandboxBootOpts): Promise<BootedSandbox> {\n const config = readE2bConfig(spec)\n const port = config.port ?? DEFAULT_PORT\n const workspace = config.workspace ?? DEFAULT_WORKSPACE\n\n const sandbox = await Sandbox.connect(sandboxId, { apiKey: process.env.E2B_API_KEY })\n // A resumed box keeps its ORIGINAL lifetime deadline — re-arm it so the\n // reconnected session gets the same runway a fresh boot gets (same\n // 5-minute-default trap as `boot`, see DEFAULT_SANDBOX_TIMEOUT_MS).\n await sandbox.setTimeout(config.timeoutMs ?? DEFAULT_SANDBOX_TIMEOUT_MS)\n\n const host = sandbox.getHost(port)\n await ensureDaemonHealthy(sandbox, host, port, workspace, config, opts.env)\n return toBootedSandbox(sandbox, host)\n },\n}\n\n/** Poll `url` until it responds OK, or return false once `timeoutMs` elapses. */\nasync function probeHealth(url: string, timeoutMs: number, pollIntervalMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n for (;;) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(pollIntervalMs) })\n if (res.ok) return true\n } catch {\n // not up yet — fall through to the deadline check\n }\n if (Date.now() >= deadline) return false\n await new Promise(resolve => setTimeout(resolve, pollIntervalMs))\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentproto/sandbox-e2b",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "@agentproto/sandbox-e2b — e2b `SandboxProvider` for @agentproto/sandbox. Boots the `agentproto-workstation` e2b template, starts the agentproto daemon inside it, and exposes its MCP endpoint as a URL so any AgentSessionHost consumer (worktreeAgentWorkflow, worktree-agent CLI) can run a coding-agent step inside the sandbox.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agentproto",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"e2b": "^2.31.0",
|
|
45
|
-
"@agentproto/sandbox": "0.1.
|
|
45
|
+
"@agentproto/sandbox": "0.1.5"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^25.6.2",
|