@e2b/cli@2.14.0
4967 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a16dcdfc0c |
feat(cli): rename --team flag to --project and add E2B_PROJECT_ID env var (#1580)
Renames the `--team` flag to `-t, --project` on `template list`, `template publish`, `template unpublish`, and `template delete`. `--team` keeps working as a hidden alias that prints a deprecation warning to stderr. The project ID can now also be set via the new `E2B_PROJECT_ID` environment variable, with `E2B_TEAM_ID` still supported as a fallback. Resolution precedence: `--project` > `--team` > `E2B_PROJECT_ID` > `E2B_TEAM_ID` > `~/.e2b/config.json`. ## Usage ```sh e2b template list --project <project-id> # new flag (also -t) e2b template list --team <project-id> # still works, warns: "The --team flag is deprecated, use --project instead." E2B_PROJECT_ID=<project-id> e2b template list # new env var E2B_TEAM_ID=<project-id> e2b template list # still supported ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>@e2b/cli@2.14.0 |
||
|
|
f10989813c |
fix(js-sdk): drop bare require calls that crash edge runtimes at import (#1583)
Fixes #1579. Bare `require` references in the SDK's ESM source made tsdown emit an eager `createRequire(import.meta.url)` shim at module scope in `dist/index.mjs`, which throws in Cloudflare Workers (workerd) where `import.meta.url` is undefined in bundled code — so `import 'e2b'` crashed before any API call. `sha256` now uses WebCrypto directly (the `node:crypto` fallback was dead code, since package engines require Node ≥ 20.18.1 and `globalThis.crypto` exists on all supported runtimes), and `getCallerDirectory` loads `fileURLToPath` via a static top-level `import url from 'node:url'`, matching the existing sibling `node:fs`/`node:os`/`node:path` imports in the same file. `dynamicRequire` is removed entirely (no remaining callers), and a new bundle test (`tests/bundle/edgeCompat.test.ts`) fails the suite if a `require` shim ever reappears in `dist/index.mjs` — it skips locally when `dist/` hasn't been built and throws in CI, where the workflow always builds first. Verified against the issue's repro in real workerd via wrangler: `e2b@2.35.1` reproduces the crash, while this build imports cleanly and runs a full sandbox lifecycle from inside a Worker. Also verified: chromium browser test, Bun runtime test, signing/secure tests (WebCrypto signatures accepted end-to-end), and the full template suite (134 tests) against live infra. ### Usage No API changes — importing the SDK in a Cloudflare Worker (with `nodejs_compat`) now works again: ```ts import { Sandbox } from 'e2b' export default { async fetch(request: Request, env: Env) { const sandbox = await Sandbox.create({ apiKey: env.E2B_API_KEY }) const result = await sandbox.commands.run('echo hello from workerd') await sandbox.kill() return Response.json({ stdout: result.stdout }) }, } ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>e2b@2.35.2 |
||
|
|
0ad6c212cf | chore: change codeowners (#1582) | ||
|
|
43db96a0ef | [skip ci] Release new versions | ||
|
|
e5a4bd655d | Use undici8.8 when on node >= 22.19 (#1575) @e2b/cli@2.13.4 e2b@2.35.1 | ||
|
|
04827ab163 |
chore(cli): remove dead e2b.toml write path (#1569)
## Description The CLI no longer writes `e2b.toml` anywhere, so this removes the dead code around it: - `saveConfig` and its `getConfigHeader` helper in `packages/cli/src/config/index.ts` had zero callers — removed along with now-unused imports. - The `team_id` field is dropped from the config schema and the unused `localConfigTeamId` parameter from `resolveTeamId` — nothing consumed it since the legacy `template build` command was removed. Team resolution is now: `--team` flag → `E2B_TEAM_ID` env → `~/.e2b/config.json` (the last only when `E2B_API_KEY` isn't set). yup ignores unknown keys, so legacy tomls containing `team_id` still parse. Parsing (`loadConfig`, `deleteConfig`, `getConfigPath`) is intentionally kept as the backward-compatibility read path for legacy projects: `template migrate` (its whole purpose), `template publish`, `template delete`, and `sandbox create`. No user-facing behavior changes; includes a `@e2b/cli` patch changeset. ## Test Format, lint, and typecheck pass; CLI tests: 88 passed, 8 skipped (one pre-existing backend integration suite fails only due to missing `E2B_API_KEY` in the environment). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c0fe6081bd |
feat(cli): rename user-visible "team" wording to "project" in terminal output (#1577)
## Summary Copy-only rename of the remaining user-visible "team" strings to "project" in the CLI (EN-1891) — part of the Teams → Projects rename, following the dashboard copy pass. 12 string literals across `auth login`, `auth info`, `auth configure`, and `template publish`; no flag, env var, config key, API call, or exit-code behavior changes. Explicitly untouched (owned by other PRs): `--team` flag + help text (#1571), `~/.e2b/config.json` keys (#1570), `e2b.toml` `team_id` (#1569), internal identifiers and API `Team` types. Best merged after #1569–#1571 to keep their rebases trivial. ## Usage examples ``` $ e2b auth login Logged in as you@e2b.dev with selected project Your Project $ e2b auth info You are logged in as you@e2b.dev, Selected project: Your Project (a1b2c3d4) $ e2b auth configure ? Select project Your Project (a1b2c3d4) (currently selected project) Project Your Project (a1b2c3d4) selected. $ e2b template publish ⚠️ This will make the template public to everyone outside your project ``` ## Testing - No new tests — strings only, not functionality (per review). Existing suite passes except the pre-existing backend-integration suites that need live sandbox access (fail identically on main). - Patch changeset included. |
||
|
|
4990471484 |
fix(cli): sort sandbox list by timestamp instead of locale date string (#1573)
Fixes #1572 ## Problem `e2b sandbox list` sorted rows *after* converting `startedAt` to a locale string, so ordering was lexicographic over strings like `"9/1/2026, 10:00:00 AM"`. In en-US, `"9/..."` sorts after `"10/..."`, so September sandboxes appeared after October ones — chronological order broke at any single-digit/double-digit month or day boundary. ## Fix Sort by the raw `startedAt` timestamp (with the existing sandbox-ID tiebreak) before formatting for display. The row-building logic is extracted into an exported `buildTableRows` helper and covered by unit tests, including the September/October regression case. The input array is no longer mutated in place. ## Example ``` $ e2b sandbox list --state paused Paused sandboxes Sandbox ID ... Started at sbx-sep ... 9/1/2026, 12:00:00 PM ← previously listed after October sbx-oct ... 10/1/2026, 11:00:00 AM ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://app.blacksmith.sh/e2b-dev/codesmith/E2B/pr/1573"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v2.svg"><img alt="View with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v2.svg"></picture></a> <a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1787240223&installation_model_id=14389&pr_number=1573&repository=e2b-dev%2FE2B&return_to=https%3A%2F%2Fgithub.com%2Fe2b-dev%2FE2B%2Fpull%2F1573&signature=85af1311c0e7aa33bbe8ea331f8bb86f82e89ab6e8ec39b29ab776c3a1466cc1"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with Codesmith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"></picture></a> <sup>Need help on this PR? Tag <code>/codesmith</code> with what you need. Autofix is disabled.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
be1ffa19f6 |
chore(deps): remove dead pnpm overrides and add CLI changeset (#1561)
Follow-up to #1559 with two changes. First, it removes four `pnpm.overrides` entries whose targets are no longer in the dependency graph at all — `@next/eslint-plugin-next>glob` (the parent package is gone), `yaml@2.x`, `@tootallnate/once`, and `flatted`; the lockfile change is header-only and no resolved package versions change, verified with a clean `pnpm audit`. The remaining overrides are kept because no parent's declared range excludes the vulnerable versions, so they are the only enforcement of the patched floors. Second, it adds a patch changeset for `@e2b/cli`: the CLI bundles all runtime dependencies into `dist/index.js` at build time (tsdown `alwaysBundle`), so the patched transitive deps from #1559 (e.g. brace-expansion 5.0.7 via the glob/minimatch chains) only reach users through a new release. No changeset is needed for the `e2b` SDK or Python SDK since they publish dependency ranges that resolve fresh at user install time. Supersedes #1560. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f6cb5a0da7 |
fix(deps): resolve open Dependabot alerts via pnpm overrides (#1559)
Fixes all 6 open [Dependabot alerts](https://github.com/e2b-dev/E2B/security/dependabot) plus 2 advisories surfaced by `pnpm audit`, by bumping vulnerable transitive dependencies through `pnpm.overrides`: vite 6.4.2→6.4.3 (`server.fs.deny` bypass, NTLMv2 hash disclosure), js-yaml 3.14.2→3.15.0 / 4.1.1→4.3.0 (merge-key DoS), @babel/core 7.27.1→7.29.7 (arbitrary file read via `sourceMappingURL`), brace-expansion 1.1.12→1.1.16 / 5.0.5→5.0.7 (DoS), and underscore 1.13.6→1.13.8 (recursion DoS). Vite required a manual lockfile version+integrity rewrite because pnpm does not re-resolve auto-installed optional peers (vite enters the graph via vitest) when an override changes. Only brace-expansion@5 is in a runtime dependency chain (`glob` in the SDK/CLI); all other bumps are dev tooling, no package manifests changed, so no changeset is needed. Verified with a clean `pnpm audit`, passing lint/typecheck/format/builds, and a live vitest smoke test against a real sandbox. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
36639f5321 |
feat(cli): remove per-command tag from integration attribution (#1557)
## Description Removes the `e2b-cli-command/<command>` token (added in #1544) from the CLI's User-Agent integration attribution, so CLI traffic is attributed only by tool and version. This also lets `connectionConfig` and `client` in `packages/cli/src/api.ts` go back to plain `const` exports, deleting the per-command config/client rebuild machinery and the `preAction` hook that drove it. The attribution test now only checks the SDK and CLI tags, and a patch changeset for `@e2b/cli` is included. User-Agent sent by `e2b sandbox list`, before and after: ``` before: e2b-js-sdk/2.9.0 (Node.js/22.11.0) e2b-cli/2.13.3 e2b-cli-command/sandbox.list after: e2b-js-sdk/2.9.0 (Node.js/22.11.0) e2b-cli/2.13.3 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
50de0af442 | [skip ci] Release new versions | ||
|
|
95e4dc2832 |
feat(sdk): add sandbox fork to JS and Python SDKs (#1554)
## Summary
Adds SDK support for the new `POST /sandboxes/{sandboxID}/fork` endpoint
(e2b-dev/infra#3202): checkpoint a running sandbox in place (briefly
paused, snapshotted with full memory state, and resumed — its ID and
expiration stay untouched) and boot `count` new sandboxes from that
snapshot.
- **spec**: adds `SandboxForkRequest` / `SandboxForkResult` schemas and
the `/sandboxes/{sandboxID}/fork` path (mirroring the infra spec); JS
and Python API clients regenerated via `make codegen`.
- **js-sdk**: `sandbox.fork(opts)` instance method and
`Sandbox.fork(sandboxId, opts)` static method. Returns
`Promise<Array<Sandbox | Error>>` — one entry per requested fork, each
either a connected `Sandbox` instance or an `Error` describing why that
fork failed to start (`Promise.allSettled`-style, matching the per-fork
results of the API). Per-fork error codes go through the same code→class
mapping as other API errors (extracted from `handleApiError` into
`apiErrorFromCode`), so e.g. a per-fork 429 (sandbox limit) surfaces as
`RateLimitError`. `SandboxForkOpts` extends the full `ConnectionOpts`
(like `SandboxConnectOpts`), so `proxy`, `logger`, `apiUrl`, etc. work
with fork-by-ID. `timeoutMs` defaults to 5 minutes like
`create`/`connect`; `count` defaults to 1 and is validated client-side
(`InvalidArgumentError` for `count < 1`); a whole-request 404 maps to
`SandboxNotFoundError` (the source sandbox is the missing resource —
same semantics as `pause`/`connect`/`setTimeout`), carrying the API
error message when present; per-fork 404 error codes map to generic
`NotFoundError` (the missing resource is fork-internal, e.g. the
snapshot).
- **python-sdk**: `sandbox.fork(timeout=..., count=...)` /
`Sandbox.fork(sandbox_id, ...)` and the `AsyncSandbox` equivalents (same
`@class_method_variant` instance/static pattern as `connect`/`pause`),
returning `List[Union[Sandbox, Exception]]`. Per-fork errors map through
the shared `api_exception_from_code` (extracted from
`handle_api_exception`). `timeout` is in seconds per Python SDK
convention; an explicit `timeout=0` is preserved. Whole-request 404
raises `SandboxNotFoundException`; per-fork 404 codes map to generic
`NotFoundException`.
- **changesets**: minor bumps for `e2b` and `@e2b/python-sdk`.
## Usage
JS:
```ts
const sandbox = await Sandbox.create()
const [fork1, fork2] = await sandbox.fork({ count: 2, timeoutMs: 60_000 })
if (fork1 instanceof Sandbox) {
await fork1.commands.run('echo "hello from fork"')
}
// or by ID
const forks = await Sandbox.fork(sandbox.sandboxId, { count: 2 })
```
Python (sync / async):
```python
sandbox = Sandbox.create()
fork1, fork2 = sandbox.fork(count=2, timeout=60)
if isinstance(fork1, Sandbox):
fork1.commands.run('echo "hello from fork"')
# or by ID
forks = Sandbox.fork(sandbox.sandbox_id, count=2)
```
```python
sandbox = await AsyncSandbox.create()
fork1, fork2 = await sandbox.fork(count=2)
```
## Notes
- The JS option is named `timeoutMs` (milliseconds) to match
`SandboxOpts.timeoutMs` / `SandboxConnectOpts.timeoutMs`; the API
receives seconds via `timeoutToSeconds` as elsewhere.
- Failed forks are returned as error **values** in the array rather than
rejected promises, so a partial failure doesn't throw away the
successful forks and there are no unhandled-rejection hazards. A
per-fork error message includes the API error code only when the API
returned one.
## Test plan
- [x] `pnpm run format`, `pnpm run lint`, `pnpm run typecheck` pass at
the repo root (`ty` diagnostics identical to baseline)
- [x] Offline tests pass: `count < 1` → `InvalidArgumentError` /
`InvalidArgumentException` in JS, Python sync, and Python async;
`handleApiError` suite passes after the `apiErrorFromCode` extraction
(plus a behavior-parity check of the Python `handle_api_exception`
refactor)
- [ ] Integration tests (single fork with FS state inheritance +
independence, multi-fork with unique IDs, fork-by-ID, fork of killed
sandbox → `SandboxNotFoundError`) are written but currently fail against
prod with 404 because the fork endpoint (e2b-dev/infra#3202) is not
deployed yet — they should pass once it lands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
e2b@2.35.0
@e2b/python-sdk@2.34.0
|
||
|
|
e68b876689 |
fix(ci): notify success on releases that skip CLI tests (#1484)
## What `report-success` (the **Release Succeeded** Slack notification) silently skips on releases that don't bump the CLI — even when the release publishes successfully. ## Why The job used: ```yaml report-success: needs: [preflight, publish] if: needs.publish.result == 'success' ``` That `if` contains no status-check function (`always()`, `!cancelled()`, `failure()`, `success()`). When `cli-tests` is skipped — which happens whenever the changeset releases the SDKs but not the CLI (`cli-tests` has `if: needs.preflight.outputs.cli == 'true'`) — GitHub Actions **skip propagation** cascades through the dependency graph and skips `report-success` too, before its condition is meaningfully evaluated. So no success notification fires. The `publish` job avoids this exact trap because its `if` already starts with `(!cancelled())`, which is why `publish` runs (and succeeds) regardless. `report-success` just lacked the same guard. ### Evidence `report-success` skipped **iff** `cli-tests` skipped, across recent releases: | Run | `cli-tests` | `report-success` | |-----|-------------|------------------| | [28189674867](https://github.com/e2b-dev/E2B/actions/runs/28189674867) | skipped | **skipped** ❌ | | 27978450216 | skipped | **skipped** ❌ | | 28150204186 | ran ✅ | fired ✅ | | 27843301597 | ran ✅ | fired ✅ | ## Fix ```diff report-success: needs: [preflight, publish] - if: needs.publish.result == 'success' + if: (!cancelled()) && needs.publish.result == 'success' ``` `(!cancelled())` disables skip propagation so the condition is always evaluated, while `needs.publish.result == 'success'` preserves the original intent: notify only when the publish actually succeeded. `report-failure` (`if: failure()`) and `report-start` are unaffected — both already evaluate correctly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8c87016a57 | [skip ci] Release new versions | ||
|
|
2c77fc00bb |
feat(sdk): add name filter to snapshot list (#1523)
Adds an optional `name` filter to `Sandbox.listSnapshots()` / `Sandbox.list_snapshots()`, mirroring the infra snapshots list endpoint ([e2b-dev/infra#3184](https://github.com/e2b-dev/infra/pull/3184)). The filter accepts a snapshot name or ID, optionally tag-qualified (e.g. `"my-snapshot"`, `"my-team/my-snapshot"` or `"my-snapshot:v1"`); unknown names return an empty list. It's a flat top-level option alongside the existing `sandboxId` filter (non-breaking) and can be combined with it — the backend applies both with AND, matching the `metadata`+`state` behavior of `Sandbox.list()`. Applied equivalently across the OpenAPI spec, generated clients, and the JS + Python sync/async SDKs, with tests and a changeset. ## Usage ```ts // JS/TS const paginator = Sandbox.listSnapshots({ name: 'my-snapshot' }) const snapshots = await paginator.nextItems() // combine filters (snapshots from a sandbox matching a name) Sandbox.listSnapshots({ sandboxId: 'sandbox-id', name: 'my-snapshot' }) ``` ```python # Python (sync) paginator = Sandbox.list_snapshots(name="my-snapshot") snapshots = paginator.next_items() # Python (async) paginator = AsyncSandbox.list_snapshots(name="my-snapshot") snapshots = await paginator.next_items() ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>@e2b/python-sdk@2.33.0 e2b@2.34.0 |
||
|
|
78a91ab72f | [skip ci] Release new versions | ||
|
|
7474d904a2 |
fix(python-sdk): correct inverted no_install_recommends docstring (#1533)
Promotes the merged #1532 (by @anxkhn) from the staging branch `fix/no-install-recommends-docstring` into `main`. `TemplateBuilder.apt_install()` documents its `no_install_recommends` parameter as "Whether to install recommended packages", but the generated command does the opposite. In `packages/python-sdk/e2b/template/main.py` the command adds apt-get's `--no-install-recommends` flag when the argument is `True`: ```python f"... apt-get install -y {'--no-install-recommends ' if no_install_recommends else ''}..." ``` `--no-install-recommends` tells apt to *skip* recommended packages, so `no_install_recommends=True` skips them rather than installing them. A user who follows the docstring gets the inverse of the documented behavior. The parameter name and apt-get's own semantics confirm the code is correct and the docstring was wrong; this rewords the docstring line to match the real behavior. The `--no-install-recommends` flag was introduced in #983; the docstring has been inverted since then. This is Python-only. The JS twin `aptInstall` applies the same flag but has no per-parameter JSDoc for `noInstallRecommends` (it appears only inside an `@example`), so there is nothing contradictory to fix on the JS side. There is a single Python definition (no sync/async mirror for the template builder). No behavior change; documentation-only, plus a `@e2b/python-sdk: patch` changeset. ### Usage ```python from e2b import Template template = Template().from_image("ubuntu:22.04") # Install recommended packages as well (apt-get default): template.apt_install("vim") # Skip recommended packages (adds apt-get's --no-install-recommends): template.apt_install("vim", no_install_recommends=True) ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> Co-authored-by: Anas Khan <anxkhn28@gmail.com>@e2b/cli@2.13.3 @e2b/python-sdk@2.32.1 e2b@2.33.1 |
||
|
|
99e536f6eb |
fix(python-sdk): stop leaking per-call proxy pools in volume content clients (#1534)
The Python volume content client factories passed both `proxy` and the shared cached `transport` to httpx, so with a proxy configured (e.g. `Volume.connect(volume_id, proxy="http://user:pass@127.0.0.1:8080")`), every volume operation mounted a fresh, never-closed proxy transport that bypassed the cached connection pool. The client-level `proxy` argument is now dropped — the proxy is already baked into the cached transport, so proxied requests keep working but reuse one pooled transport per thread/event loop. The volume transports also gained connect-level retries (`E2B_CONNECTION_RETRIES`, default 3), matching the core API and envd transports. Includes a changeset for a `@e2b/python-sdk` patch release. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a4e07a6ab2 |
feat(cli): attribute CLI traffic with e2b-cli and per-command tags (#1544)
Follow-up promised in #1524 (original attempt #1525, closed while blocked on the backend User-Agent parser, since fixed by e2b-dev/infra#3149, which now iterates User-Agent tokens and ignores unrecognized ones — so the extra tags are safe on template builds). Sets `ConnectionConfig.setIntegration('e2b-cli/<version>')` at the top of `src/api.ts` before the shared connection config is built at import time, and a commander `preAction` hook extends the tag with the canonical invoked command (alias `ls` reports as `list`), rebuilding the shared config and client since they capture the User-Agent at construction. Every CLI request then carries: ``` User-Agent: e2b-js-sdk/2.32.0 e2b-cli/2.13.1 e2b-cli-command/sandbox.list ``` Tests drive the built CLI (`sandbox list` and the `ls` alias) against a local stub API server and assert the received User-Agent, which also guards that the bundle keeps shipping the workspace SDK where `setIntegration` exists. Includes a patch changeset for `@e2b/cli`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
347ebe8ad8 |
fix(cli): correct memory-mb help default and use non-deprecated pause (#1510)
Fixes two small CLI issues. The `e2b template create --memory-mb` help text claimed a default of 512 MB, but the real default is 1024 MB — the help now reflects that. The `e2b sandbox pause` command was calling the deprecated `Sandbox.betaPause()` alias and now calls `Sandbox.pause()` directly. ## Usage ```sh e2b template create --help # --memory-mb now shows "The default value is 1024." e2b sandbox pause <sandboxID> # behaves the same, no longer uses the deprecated method ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
64e9bc02b6 |
fix(js-sdk): unpin useDefineForClassFields — make caller-directory resolution emit-invariant (#1539)
Follow-up to #1536, which pinned `useDefineForClassFields: false` in the js-sdk tsconfig because raising `target` to `es2022` flips the default to `true`, and that broke the template builder. This PR fixes the root cause and removes the pin, so the SDK now compiles with the standard es2022 `[[Define]]` class-field semantics. ## Root cause `TemplateBase` resolved its default `fileContextPath` in a **class field initializer**: ```ts private fileContextPath: PathLike = runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.') ``` With native class fields (define semantics), V8 evaluates field initializers in an extra `<instance_members_initializer>` stack frame: ``` at getCallerDirectory (utils.ts) at <instance_members_initializer> (index.ts) ← extra frame under define semantics at new TemplateBase (index.ts) at Template (index.ts) at user code ← fixed-depth walk lands one frame short ``` `getCallerDirectory` walks the stack at a fixed depth, so it landed on the SDK's own `src/template` directory instead of the caller's — `.copy('folder/*', …)` then globbed against the wrong base dir (`Error: No files found in .../src/template/...`), and the resulting client-side failure mis-attributed build-step stack traces (the two `stacktrace.test.ts` failures were cascades of this one bug). ## Fix Move the default resolution into the constructor body, where the stack shape is identical under both emits: ```ts constructor(options?: TemplateOptions) { this.fileContextPath = options?.fileContextPath ?? (runtime === 'browser' ? '.' : (getCallerDirectory(STACK_TRACE_DEPTH) ?? '.')) ``` The call is now emit-invariant (same `STACK_TRACE_DEPTH`), so the tsconfig pin is removed. The method-level `getCallerFrame` call sites were never affected — method bodies don't change shape with class-field semantics. Only the js-sdk is touched: the Python SDKs resolve the caller via `inspect` and don't have this failure mode, and the CLI bundle doesn't include `TemplateBase`. ## Usage example Fixes relative-path resolution for SDK consumers whose toolchain emits native class fields (e.g. esbuild/vitest with `target: es2022+`): ```ts // user-project/scripts/template.ts const template = Template() .fromBaseImage() .copy('assets/*', '/app/assets') // now resolves against user-project/scripts/, // not the SDK's own directory ``` ## Verification - `tests/template/stacktrace.test.ts` — 30/30 pass with the flag defaulted (`true`), and still 30/30 when explicitly set back to `false` (emit-invariance) - `tests/template/build.test.ts` — 4/4 pass against the real backend (real `.copy` glob + build) - Smoke-tested built `dist/index.mjs` and `dist/index.js` from an external directory: `fileContextPath` resolves to the importing script's directory in both - Unit project A/B: identical results with and without this change (remaining failures are pre-existing `E2B_API_KEY`-gated live tests) - `pnpm run typecheck`, `lint`, `format` ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
423a1b7302 |
ci: seed codegen image cache from main instead of per-PR scopes (#1549)
## Why `generated_files.yml` only runs on `pull_request`, so its `cache-to: type=gha,mode=max` wrote buildkit blobs into per-PR scopes that other PRs cannot read — every new PR cold-built the codegen image (235–365s in 11 of 17 runs over the past week vs ~65s warm), and ~6 GB of duplicate blobs pushed the repo's Actions cache to 9.9 GB of the 10 GB limit, evicting the Playwright and pnpm caches that #1538 relies on. ## What Adds `codegen_image_cache.yml`, which builds the image on pushes to `main` touching its actual inputs (`codegen.Dockerfile`, `packages/connect-python/**`, or the workflow itself) and exports the cache to main's scope, readable by all PRs; it also supports `workflow_dispatch` for manual re-seeding. The PR-side build in `generated_files.yml` keeps `cache-from` but drops `cache-to`. Merging this PR triggers the first seed automatically, since the new workflow file matches its own paths filter. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
dbc6bfa161 | [skip ci] Release new versions | ||
|
|
09e12b3f65 |
feat(sdk): set-once integration attribution via ConnectionConfig.setIntegration (#1524)
Replaces the per-call `integration` connection option with a set-once, process-wide setter — `ConnectionConfig.setIntegration()` in JS and `ConnectionConfig.set_integration()` in Python — so integrations wrapping the SDK tag themselves once at startup and every request carries the identifier in the `User-Agent` header, with no threading through individual SDK calls. The setter is internal and hidden from generated docs; the `integration` option is removed from `ConnectionConfigOpts` (kept as a deprecated alias of `ConnectionOpts`) and from the Python constructor, and the round-trip machinery from #1459 is no longer needed since rebuilt configs read the process-wide value. User-Agent handling now follows a single rule in both SDKs via one shared helper per SDK: an explicitly provided `User-Agent` always wins, otherwise the SDK sends its own tagged with the current integration — and SDK-built values are recomputed whenever a config is rebuilt, so clearing or changing the integration propagates. Tests cover attribution, clearing, config rebuilds, and custom User-Agent precedence in both SDKs, with changesets for `e2b` and `@e2b/python-sdk` (minor). CLI attribution using this setter will follow in a separate PR. Usage (internal integrations only): ```ts import { ConnectionConfig } from 'e2b' ConnectionConfig.setIntegration('e2b-code-interpreter/0.1.0') // once at startup ``` ```python from e2b import ConnectionConfig ConnectionConfig.set_integration("e2b-code-interpreter/0.1.0") # once at startup ``` A caller-supplied `User-Agent` (via `headers`/`apiHeaders`) is preserved in both SDKs: ```ts const sbx = await Sandbox.create({ apiHeaders: { 'User-Agent': 'my-app/1.0' } }) // requests carry: my-app/1.0 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>@e2b/cli@2.13.2 @e2b/python-sdk@2.32.0 e2b@2.33.0 |
||
|
|
07041ccffc |
test: skip live volume tests unless ENABLE_VOLUME_TESTS is set (#1526)
Live volume tests create real volumes against the API; this gates them
behind an `ENABLE_VOLUME_TESTS` env var so they skip by default. In the
JS SDK, the `volumeTest` fixture is chained with
`.skipIf(process.env.ENABLE_VOLUME_TESTS === undefined)`, skipping all
of `tests/volume/file.test.ts`. In the Python SDK, the `volume` and
`async_volume` fixtures call `pytest.skip` when the env var is unset,
gating `tests/{sync/volume_sync,async/volume_async}/test_file.py`.
Mocked and unit volume tests (msw-based `volume.test.ts`,
`test_volume.py`, `test_volume_content.py`, `test_volume_client.py`,
`test_volume_connection_config.py`) still run unconditionally. To run
the live tests: `ENABLE_VOLUME_TESTS=1 pnpm run test` or
`ENABLE_VOLUME_TESTS=1 poetry run pytest`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
0bd06d86d2 |
chore(js-sdk,cli): modernize tsconfig and adopt TypeScript 7 (side-by-side) (#1536)
Supersedes #1516 (same modernization at TypeScript 6.0). Rebased onto `main` now that the build runs on **tsdown** (#1515). ## What & why Adopt **TypeScript 7** for both packages and modernize the compiler config. TypeScript 7.0's native compiler [ships no programmatic API yet](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) (it lands in 7.1), so anything built on the TS compiler API breaks on it — here that's tsdown's `.d.ts` generation and the codegen scripts (`openapi-typescript`, `json-schema-to-typescript`). Per the official guidance, TS 7 is installed **side-by-side** with TS 6: ```json "@typescript/native": "npm:typescript@^7.0.2", // native tsc — used for type-checking "typescript": "npm:@typescript/typescript6@^6.0.2" // TS6 w/ compiler API — used by tooling ``` - `tsc --noEmit` (typecheck) → **native TypeScript 7.0.2** (verified: `tsc --version` → 7.0.2) - `import 'typescript'` → **TypeScript 6.0** *with* the compiler API → tsdown dts + codegen keep working - Bonus: tsdown's dts no longer prints the "TypeScript 7.0 does not yet have a stable API and is experimental" warning (it's on the 6.0 API now) **Internal build-config change only — no public API or runtime behavior changes.** ## Compiler options: before → after ### `packages/js-sdk/tsconfig.json` | option | before | after | |---|---|---| | `target` | `es6` | `es2022` | | `lib` | `["dom","ESNext"]` | `["dom","es2022"]` | | `module` | _(unset)_ | `esnext` | | `moduleResolution` | `node` | `bundler` | | `allowJs` | `true` | **removed** (no `.js` sources) | | `allowSyntheticDefaultImports` | `true` | **removed** (implied by `esModuleInterop`) | | `useDefineForClassFields` | _(false, implied by es6)_ | **`false` (now explicit)** — see note | ### `packages/cli/tsconfig.json` | option | before | after | |---|---|---| | `moduleResolution` | `node` | `bundler` | | `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `noImplicitThis`, `alwaysStrict` | `true` | **removed** (implied by `strict`) | | `downlevelIteration` | `true` | **removed** (removed in TS 7; no-op at `es2022`) | | `baseUrl` | `"."` | **removed** (removed in TS 7) | | `paths` | `{ e2b }` | `{ src, "src/*", e2b }` (replaces `baseUrl` for the existing `src/...` import style) | | `outDir` | `"dist"` | **removed** (unused under `tsc --noEmit`) | | `exclude` | _(none)_ | `["dist","node_modules"]` (so the built bundle is never type-checked) | `target`/`lib` for the CLI were already `es2022`. ## Notes / decisions - **Why side-by-side, not a plain `typescript@7` bump:** TS 7.0 is the native (Go) compiler rewrite — feature-identical to 6.0 for type-checking, no programmatic API until 7.1. A plain bump crashed both codegen tools (`Cannot read properties of undefined (reading 'createKeywordTypeNode')`). Side-by-side gives native-TS-7 checking while keeping the TS-6 API for tooling. Once 7.1 ships the API and the tools update, this collapses back to a single `typescript@7` dep. - **`useDefineForClassFields: false` is pinned explicitly.** Raising js-sdk's `target` to `es2022` flips this default to `true`, changing class-field emit and shifting stack frames. The template builder resolves the caller's directory and per-step traces via **fixed-depth** stack walking (`getCallerDirectory` in `src/template/index.ts`), so the extra frames threw it off by one — resolving `.copy('folder/*', …)` against the wrong base dir and mis-attributing build steps (`tests/template/build.test.ts` + `stacktrace.test.ts`). Pinning `false` keeps the exact pre-existing field semantics (es6 already implied `false`); adopting `define` semantics should be a separate, deliberately tested change. - **Target stays at `es2022`, not `es2023`.** `engines` still allow Node 20 (`>=20.18.1 <21 || >=22`). - **`moduleResolution: "bundler"`** typechecks + builds cleanly in both packages. The CLI's `baseUrl`-based bare imports (`from 'src/user'`, `from 'src'`) are preserved via `paths`; the bundled output still resolves them (build verified, binary smoke-tested). ## Not done (intentionally) - **`verbatimModuleSyntax`** — ~177 `import type` conversions; left as a follow-up. - **Shared `tsconfig.base.json`** — the two configs diverge too much to factor out cleanly. ## Verification - `pnpm run typecheck` ✅ both packages, on **native TS 7.0.2** - `pnpm run build` ✅ both packages (js-sdk ESM + CJS + **DTS**; cli CJS; binary smoke-tested) - codegen ✅ `openapi-typescript` + `json2ts` run and produce identical output (idempotent) - `pnpm run lint` ✅ both packages - `pnpm run test` — `template/build` + `template/stacktrace` now pass (`stacktrace` verified locally 30/30); remaining local failures are all `E2B_API_KEY`-gated live tests, unaffected by this change 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
504c60999f |
ci: key Playwright browser cache on Playwright version (#1538)
## Why The Playwright browser cache in `js_sdk_tests.yml` keyed on the Node version + a hash of `packages/js-sdk/package.json`. Node bumps (e.g. #1515) and release-bot version bumps rotated the key, so PRs kept re-downloading Chromium — ~3 minutes per Windows job, twice per run (staging + production) — e.g. [this run](https://github.com/e2b-dev/E2B/actions/runs/29036879724/job/86183938330?pr=1536). The churn also created a fresh ~250 MB cache entry per OS on every release. ## What Browser binaries depend only on the Playwright version, so the cache is now keyed on the installed Playwright version (read from `node_modules` after `pnpm install`), and the two OS-conditional cache steps are collapsed into one. The key only rotates when Playwright itself is upgraded, which is exactly when a re-download is needed. On a cache hit, the `pretest` `playwright install` becomes a no-op skip instead of a download. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
9a638ae907 |
docs(readme): add UTM tracking to e2b.dev links (#1537)
Adds UTM parameters to the e2b.dev link(s) in the README so GitHub-referral traffic is attributed per repo. `utm_source=github&utm_medium=referral&utm_campaign=readme&utm_content=<repo>` Applies to apex e2b.dev links (root and subpaths). Subdomains and already-tagged links are untouched, and URL anchors are preserved. |
||
|
|
49367c8491 |
build: switch from tsup to tsdown (#1515)
Switches the build tooling for `packages/js-sdk` and `packages/cli` from `tsup` (esbuild) to `tsdown` (rolldown), replacing each `tsup.config.js` with a `tsdown.config.ts` and updating the `build`/`dev` scripts and devDependencies. The published artifact layout is intentionally unchanged — the SDK still ships `dist/index.js` (CJS), `dist/index.mjs` (ESM) and `dist/index.d.ts`/`.d.mts`, and the CLI still ships an executable `dist/index.js` plus `dist/templates` — kept identical via `fixedExtension: false`. CLI dependency bundling is preserved by mapping the old `noExternal` to tsdown's `deps.alwaysBundle` (still excluding the ESM-only, dynamically-imported `inquirer`), and template copying moves from an `onSuccess` shell step to tsdown's `copy` option. Also aligns Node versions: `engines.node` for both packages is set to `20 || >=22`, the CLI build targets `node20`, and the pinned `nodejs` in `.tool-versions` is bumped to `22.11.0`. The large `pnpm-lock.yaml` diff is expected — it swaps the tsup/esbuild dependency tree for tsdown's rolldown tree (no lockfile format change). ## Verification - Both packages build cleanly with output filenames identical to the previous tsup builds. - `typecheck`, `lint` (oxlint) and `build` pass for both packages; the built CLI runs (`--version`). - Built js-sdk imports correctly in both CJS (`require`) and ESM (`import`), exposing the default `Sandbox` export and all named exports. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e6c4e7e9d5 |
chore(js): modernize Connect/Protobuf and React test deps (#1512)
## What Modernizes the JS SDK's dependencies while remaining fully compatible with the current supported Node range (`>=20.18.1`) — no engine changes and no breaking impact for consumers. - **`@connectrpc/connect` / `@connectrpc/connect-web`:** `2.0.0-rc.3` → `^2.1.2` (off the pre-release pin onto the stable line, and switched to a `^` range). - **`@bufbuild/protobuf`:** `^2.6.2` → `^2.12.1`. - **React test deps:** `react` / `@types/react` → `^19.2.0`, and `react-dom` / `@types/react-dom` added at `^19.2.0` (previously auto-installed as v18 peers). Dev/test-only — no runtime impact. - **CI:** standardized `actions/setup-node` (mixed v3/v4/v6) to `v6` across all workflows; the three `@v3` uses were on the deprecated Node16 action runtime. No public SDK API changes — the sandbox filesystem and command RPCs use the same Connect transport configuration. ## Why undici / Node floor were dropped from this PR An earlier revision also bumped `undici` 7 → 8 and raised the Node floor to `>=22.19.0`. Usage data shows **Node 20 is still the single largest SDK runtime (~39% of sandbox creations)**, so dropping it would break the largest consumer segment via `engine-strict` install failures. undici 8 was the *only* change forcing Node 22, and undici `7.28.0` (already the latest 7.x) supports Node 20 — so undici stays at `^7.28.0` and the engine floor is unchanged. undici 8 is a good candidate for a future major once Node 20 usage declines. ## Verification - typecheck, lint (oxlint), and build pass - 22 mocked Connect/undici transport unit tests pass - 106 live filesystem/command tests pass over connectrpc `2.1.2` + undici `7.28.0` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0feb926937 | [skip ci] Release new versions | ||
|
|
5d84a8e7d2 |
chore(deps-dev): bump black from 23.7.0 to 26.3.1 in /packages/python-sdk in the uv group across 1 directory (#1530)
Bumps the uv group with 1 update in the /packages/python-sdk directory: [black](https://github.com/psf/black). Updates `black` from 23.7.0 to 26.3.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/psf/black/releases">black's releases</a>.</em></p> <blockquote> <h2>26.3.1</h2> <h3>Stable style</h3> <ul> <li>Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Always hash cache filename components derived from <code>--python-cell-magics</code> so custom magic names cannot affect cache paths (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3><em>Blackd</em></h3> <ul> <li>Disable browser-originated requests by default, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> </ul> <h2>26.3.0</h2> <h3>Stable style</h3> <ul> <li>Don't double-decode input, causing non-UTF-8 files to be corrupted (<a href="https://redirect.github.com/psf/black/issues/4964">#4964</a>)</li> <li>Fix crash on standalone comment in lambda default arguments (<a href="https://redirect.github.com/psf/black/issues/4993">#4993</a>)</li> <li>Preserve parentheses when <code># type: ignore</code> comments would be merged with other comments on the same line, preventing AST equivalence failures (<a href="https://redirect.github.com/psf/black/issues/4888">#4888</a>)</li> </ul> <h3>Preview style</h3> <ul> <li>Fix bug where <code>if</code> guards in <code>case</code> blocks were incorrectly split when the pattern had a trailing comma (<a href="https://redirect.github.com/psf/black/issues/4884">#4884</a>)</li> <li>Fix <code>string_processing</code> crashing on unassigned long string literals with trailing commas (one-item tuples) (<a href="https://redirect.github.com/psf/black/issues/4929">#4929</a>)</li> <li>Simplify implementation of the power operator "hugging" logic (<a href="https://redirect.github.com/psf/black/issues/4918">#4918</a>)</li> </ul> <h3>Packaging</h3> <ul> <li>Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments (<a href="https://redirect.github.com/psf/black/issues/4930">#4930</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Introduce winloop for windows as an alternative to uvloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Remove deprecated function <code>uvloop.install()</code> in favor of <code>uvloop.new_event_loop()</code> (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Rename <code>maybe_install_uvloop</code> function to <code>maybe_use_uvloop</code> to simplify loop installation and creation of either a uvloop/winloop evenloop or default eventloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> </ul> <h3>Output</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/psf/black/blob/main/CHANGES.md">black's changelog</a>.</em></p> <blockquote> <h2>Version 26.3.1</h2> <h3>Stable style</h3> <ul> <li>Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Always hash cache filename components derived from <code>--python-cell-magics</code> so custom magic names cannot affect cache paths (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> </ul> <h3><em>Blackd</em></h3> <ul> <li>Disable browser-originated requests by default, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> </ul> <h2>Version 26.3.0</h2> <h3>Stable style</h3> <ul> <li>Don't double-decode input, causing non-UTF-8 files to be corrupted (<a href="https://redirect.github.com/psf/black/issues/4964">#4964</a>)</li> <li>Fix crash on standalone comment in lambda default arguments (<a href="https://redirect.github.com/psf/black/issues/4993">#4993</a>)</li> <li>Preserve parentheses when <code># type: ignore</code> comments would be merged with other comments on the same line, preventing AST equivalence failures (<a href="https://redirect.github.com/psf/black/issues/4888">#4888</a>)</li> </ul> <h3>Preview style</h3> <ul> <li>Fix bug where <code>if</code> guards in <code>case</code> blocks were incorrectly split when the pattern had a trailing comma (<a href="https://redirect.github.com/psf/black/issues/4884">#4884</a>)</li> <li>Fix <code>string_processing</code> crashing on unassigned long string literals with trailing commas (one-item tuples) (<a href="https://redirect.github.com/psf/black/issues/4929">#4929</a>)</li> <li>Simplify implementation of the power operator "hugging" logic (<a href="https://redirect.github.com/psf/black/issues/4918">#4918</a>)</li> </ul> <h3>Packaging</h3> <ul> <li>Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments (<a href="https://redirect.github.com/psf/black/issues/4930">#4930</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Introduce winloop for windows as an alternative to uvloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Remove deprecated function <code>uvloop.install()</code> in favor of <code>uvloop.new_event_loop()</code> (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> <li>Rename <code>maybe_install_uvloop</code> function to <code>maybe_use_uvloop</code> to simplify loop installation and creation of either a uvloop/winloop eventloop or default eventloop (<a href="https://redirect.github.com/psf/black/issues/4996">#4996</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/psf/black/commit/c6755bb741b6481d6b3d3bb563c83fa060db96c9"><code>c6755bb</code></a> Prepare release 26.3.1 (<a href="https://redirect.github.com/psf/black/issues/5046">#5046</a>)</li> <li><a href="https://github.com/psf/black/commit/69973fd6950985fbeb1090d96da717dc4d8380b0"><code>69973fd</code></a> Harden blackd browser-facing request handling (<a href="https://redirect.github.com/psf/black/issues/5039">#5039</a>)</li> <li><a href="https://github.com/psf/black/commit/4937fe6cf241139ddbfc16b0bdbb5b422798909d"><code>4937fe6</code></a> Fix some shenanigans with the cache file and IPython (<a href="https://redirect.github.com/psf/black/issues/5038">#5038</a>)</li> <li><a href="https://github.com/psf/black/commit/2e641d174469c505d5ae905e75d4c769597e681f"><code>2e641d1</code></a> docs: remove outdated Black Playground references (<a href="https://redirect.github.com/psf/black/issues/5044">#5044</a>)</li> <li><a href="https://github.com/psf/black/commit/c014b22a2d5e0632587b47b81151658bddfa0b88"><code>c014b22</code></a> Remove unused internal code (<a href="https://redirect.github.com/psf/black/issues/5041">#5041</a>)</li> <li><a href="https://github.com/psf/black/commit/0dae20b2d009f2f03de8696d06b0c947d3abafc9"><code>0dae20b</code></a> Add new changelog (<a href="https://redirect.github.com/psf/black/issues/5036">#5036</a>)</li> <li><a href="https://github.com/psf/black/commit/c5c1cbddd92cecb554ac2a77a24139dd76831030"><code>c5c1cbd</code></a> Minor release patches (<a href="https://redirect.github.com/psf/black/issues/5035">#5035</a>)</li> <li><a href="https://github.com/psf/black/commit/7e5a828c37d71b6a6666e28eed444816def6a8f4"><code>7e5a828</code></a> docs: clarify relationship between Black style and PEP 8 (<a href="https://redirect.github.com/psf/black/issues/5025">#5025</a>)</li> <li><a href="https://github.com/psf/black/commit/69705deb8776e7c5e585668da106d1abe2cb8d77"><code>69705de</code></a> docs: add clearer pyproject configuration guidance (<a href="https://redirect.github.com/psf/black/issues/5026">#5026</a>)</li> <li><a href="https://github.com/psf/black/commit/35ea67920b7f6ac8e09be1c47278752b1e827f76"><code>35ea679</code></a> Prepare release 26.3.0 (<a href="https://redirect.github.com/psf/black/issues/5032">#5032</a>)</li> <li>Additional commits viewable in <a href="https://github.com/psf/black/compare/23.7.0...26.3.1">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/e2b-dev/E2B/network/alerts). </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mish Ushakov <10400064+mishushakov@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>@e2b/cli@2.13.1 @e2b/python-sdk@2.31.0 e2b@2.32.0 |
||
|
|
be4eb5fd96 |
chore(python-sdk): migrate from Poetry to uv (#1513)
Migrates the Python SDK's packaging and CI from Poetry to [uv](https://docs.astral.sh/uv/): `pyproject.toml` is converted to PEP 621 metadata using uv's native `uv_build` backend (verified to produce a byte-equivalent wheel containing both `e2b` and `e2b_connect`), `poetry.lock` is replaced with `uv.lock`, and the `Makefile`, `package.json` scripts, `.tool-versions`, `CLAUDE.md`, and all six GitHub workflows now use `uv` (`astral-sh/setup-uv` + `uv sync`/`build`/`version`/`publish`). It also drops the now-redundant explicit sync steps (since `uv run` auto-syncs) and removes the orphaned `pydoc-markdown` dev dependency, whose only consumer was deleted long ago — trimming 58 packages from the dev lockfile. ## Usage ```sh cd packages/python-sdk uv sync # install deps (replaces `poetry install`) uv run pytest # run tests uv build # build the wheel/sdist make lint # ruff (run via `uv run`) ``` No user-facing SDK change — packaging/tooling only — so no changeset is included; the published package contents are unchanged. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a6b1cf4bcf |
fix(python-sdk): strip colon-separated SGR escape codes in build logs (#1522)
### What Cherry-picks the fix from #1519. `strip_ansi_escape_codes` in the Python SDK only matched semicolon-separated CSI parameters, so colon-separated SGR sequences leaked literal escape garbage into template build-log messages. This widens the parameter class from `;` to `[;:]` so colon-separated sequences are stripped too, matching the JS SDK's `stripAnsi`. Modern terminals emit colon-separated SGR sequences: - 256-color: `\x1b[38:5:82m` - truecolor: `\x1b[38:2::255:0:0m` - curly underline: `\x1b[4:3m` The two SDKs share one source (chalk/ansi-regex) and the JS twin was already updated to support colons (`packages/js-sdk/src/utils.ts:95`, comment: "supports ; and :"); the Python port lagged behind. `strip_ansi_escape_codes` is consumed by `LogEntry.__post_init__` (`packages/python-sdk/e2b/template/logger.py`), so the leftover escape bytes showed up in Python build logs only. ### The one-line fix ```python # packages/python-sdk/e2b/template/utils.py:319 - r"(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))", + r"(?:(?:\d{1,4}(?:[;:]\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))", ``` ### Usage example (before / after) ```python from e2b.template.utils import strip_ansi_escape_codes # 256-color, colon-separated strip_ansi_escape_codes("\x1b[38:5:82mX\x1b[0m") # before: ":5:82mX" after: "X" # truecolor, colon-separated strip_ansi_escape_codes("\x1b[38:2::255:0:0mRED\x1b[0m") # before: ":2::255:0:0mRED" after: "RED" # semicolon variants already worked and still do strip_ansi_escape_codes("\x1b[38;5;82mX\x1b[0m") # "X" (unchanged) ``` ### Tests Unit tests at `packages/python-sdk/tests/shared/template/utils/test_strip_ansi_escape_codes.py` (no API key / sandbox): colon-256, colon-truecolor, curly-underline, plus basic/semicolon regressions. All 7 pass locally. ### Changeset `.changeset/python-strip-ansi-colon.md` (patch on `@e2b/python-sdk`). ### Notes Original PR: #1519 (by @anxkhn). Opened against a fresh branch off `main` per request, rather than merging #1519 directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> |
||
|
|
2b7dd17f10 |
feat(sdk): add gzip option to template copy layer (#1482)
Adds a `gzip` option to the template `.copy()` / `copyItems` layer that
controls whether copied files are gzipped before upload, threaded from
the copy call through the build-time tar stream in both the JS SDK and
the sync/async Python SDKs. It is enabled by default to preserve
existing behavior, so passing `gzip: false` (`gzip=False`) uploads an
uncompressed tar — useful for already-compressed payloads where gzip
adds CPU cost without shrinking the upload. The option name matches
node-tar's own `gzip` option and the existing sandbox filesystem `gzip`
kwarg. Gzip is deliberately excluded from the file cache hash, so
toggling it does not bust the build cache. Tests in both SDKs were
updated for the new argument and extended with `gzip: false` cases
asserting the archive is not gzipped yet still extracts, and a changeset
(`minor` for both packages) is included.
> [!NOTE]
> The server that extracts these uploaded archives lives in another repo
and must auto-detect compression (peek the gzip `0x1f 0x8b` magic)
rather than assuming gzip; confirm it handles plain tars before release.
## Usage
```ts
// JS/TS
template.copy('model.bin', '/app/', { gzip: false })
template.copyItems([{ src: 'a.bin', dest: '/app/', gzip: false }])
```
```python
# Python (sync & async)
template.copy('model.bin', '/app/', gzip=False)
template.copy_items([{ 'src': 'a.bin', 'dest': '/app/', 'gzip': False }])
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
a39db3bb36 |
chore: switch from eslint to oxlint (#1514)
Replaces ESLint (and its `@typescript-eslint/*` and `unused-imports` plugins) with [oxlint](https://oxc.rs) across the `js-sdk` and `cli` packages. A root `.oxlintrc.json` replaces the three `.eslintrc.cjs` files, the package `lint` scripts now run `oxlint`, the related devDependencies are swapped for `oxlint`, and the lint CI path filter is updated accordingly. Formatting rules (`quotes`/`semi`/`linebreak-style`) are dropped because Prettier already enforces them, and `no-unused-vars` is set to error to preserve the previous unused-imports check. The one behavior change is that `@typescript-eslint/member-ordering` has no oxlint equivalent and is no longer enforced. `lint`, `typecheck`, and `prettier` all pass clean for both packages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9b4a74388d |
chore(cli): remove unused dockerfile-ast dependency (#1509)
The CLI declared `dockerfile-ast` as a dependency but never imported it — all Dockerfile parsing in the CLI goes through the `e2b` SDK, which keeps its own (newer) `dockerfile-ast` dependency. This drops the redundant copy from `packages/cli/package.json`, removing `dockerfile-ast@0.6.1` and its sub-deps from the lockfile while `dockerfile-ast@0.7.1` (used by the js-sdk) stays. No behavior change; CLI typecheck and lint pass, and a `@e2b/cli` patch changeset is included. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c385566c29 |
fix(python-sdk): correct Sandbox.list() docstring (also lists paused) (#1511)
Integration branch PR for #1500. Merges the docstring fix into `main`. Once #1500 is merged into `python-sdk-list-docstring-base`, this PR will carry those changes into `main`. --------- Co-authored-by: Leinux <tristone13th@outlook.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d071bb78c8 |
fix(cli): use absolute import in generated Python build scripts (#1505)
Fixes the generated Python build scripts to use an absolute import (from template import template) instead of a relative one, which broke python build_dev.py with ImportError: attempted relative import with no known parent package since the files are emitted as flat siblings with no package. This reverts an unintended change from #954 that was flagged by Cursor Bugbot at the time but not addressed. Fixes #1477. |
||
|
|
2869febdee |
feat(cli): add config override flags to template migrate (#1494)
Adds override flags to `e2b template migrate` so the generated SDK files don't have to inherit everything from `e2b.toml`: `--name`/`-n` (template name), `--cmd`/`-c` (start command), `--ready-cmd` (ready command), `--cpu-count`, and `--memory-mb`. Each flag falls back to the corresponding config value when omitted, and `--memory-mb` is validated to be even. Includes tests covering the overrides and the odd-memory rejection, plus a changeset for `@e2b/cli`. ## Usage ```bash e2b template migrate \ --language typescript \ --name my-custom-name \ --cmd "node server.js" \ --ready-cmd "curl localhost:3000" \ --cpu-count 4 \ --memory-mb 2048 ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f160f08c7b |
Keep integration attribution on connection config (#1459)
moves integration attirbution to more private thing to avoid confusing people with first class kwargs |
||
|
|
42538836f3 |
ci: show skipped tests as skipped instead of green pass (#1486)
green passed tests is misleading. indicate when tests skipped. |
||
|
|
bb45f185f1 |
Introduce generic paginator base class for JS and Python SDKs (#1491)
Extracts the cursor-based pagination state machine into a reusable base
class — `Paginator` in the JS SDK's `utils`, `PaginatorBase` in
`e2b/utils.py` — that owns `hasNext`/`nextToken` and the `x-next-token`
header handling, and migrates the sandbox and snapshot paginators onto
it. Each concrete paginator now just implements `nextItems`/`next_items`
to fetch its own page, so future list endpoints (templates, builds,
etc.) can add pagination by subclassing without reimplementing the
bookkeeping. Applied equivalently to the JS SDK and both Python sync and
async implementations, with unit tests covering the shared base. There
are no public API changes — `Sandbox.list()` / `listSnapshots()` and the
existing paginator types behave identically.
## Usage (unchanged)
```ts
const paginator = Sandbox.list()
while (paginator.hasNext) {
const sandboxes = await paginator.nextItems()
console.log(sandboxes)
}
```
```python
paginator = Sandbox.list()
while paginator.has_next:
sandboxes = paginator.next_items()
print(sandboxes)
```
|
||
|
|
5c8c3ad7fc |
ci: split release workflow into production and candidate workflows (#1483)
## Why
GitHub Actions cannot conditionally show `workflow_dispatch` inputs
based on other inputs, so the single **Release** form always displayed
the six candidate-only fields even when running a production release —
confusing for anyone doing their first release.
## What
Split the combined workflow into two so each form matches its intent:
- **`release.yml` ("Release")** — production only; the `mode` dropdown
and all candidate fields are removed, leaving a form with no inputs.
- **`release-candidate.yml` ("Release candidate")** — new file
containing only the RC inputs (js-sdk, python-sdk, cli, tag, preid,
skip-tests), with the now-redundant "(candidate only)" label suffixes
dropped.
People choose by sidebar name instead of a dropdown, and the `mode ==/!=
'candidate'` job guards are gone since workflow selection does that job.
Two follow-ups from review to keep behavior intact across the split:
- **Concurrency:** both files use a shared literal group `release-${{
github.ref }}` (instead of `${{ github.workflow }}-…`) so production and
candidate releases on the same ref still serialize.
- **RC versioning:** `publish_candidates.yml` now derives RC version
suffixes from `github.run_id` instead of `github.run_number`.
`run_number` is per-workflow-file and would reset to 1 for the new
workflow, causing RC versions to go backwards (npm dist-tag downgrade /
publish collisions); `run_id` is globally unique and monotonic.
> [!NOTE]
> Any automation or docs that ran the old workflow with `-f
mode=candidate` must now target `release-candidate.yml` (no `mode`
field).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
bb1696871b |
Stream template build-context upload from disk instead of buffering in memory (#1435)
## Summary Template builds previously buffered the entire gzipped build-context tar archive in memory before uploading it. This PR spools the archive to a temporary file and streams it from disk during upload — in the JS SDK and both sync and async Python SDKs — so memory usage no longer scales with the size of the build context. The upload keeps an explicit `Content-Length` header (taken from the spooled file's size), which S3 presigned PUT URLs require — they reject `Transfer-Encoding: chunked` with `501 NotImplemented` (#1243). ## Changes - **JS** (`packages/js-sdk/src/template/`): `tarFileStream`/`tarFileStreamUpload` are replaced by `tarFileToStream`, which writes the archive to a temp file and returns a self-cleaning read stream plus its `size`. The spooled temp file deletes itself once the stream is closed (consumed, errored, or destroyed) via the stream's `close` event — mirroring the Python SDK's `tar_file_stream`. `buildApi` streams this body with `duplex: 'half'` and an explicit `Content-Length` from `size`; if `fetch` throws before consuming the body, it destroys the stream to trigger the same cleanup. There is no separate cleanup callback, so a cleanup failure can no longer mask the upload result. - **Python** (`packages/python-sdk/e2b/template/utils.py`, `template_async/build_api.py`, `template_sync/build_api.py`): `tar_file_stream` now writes to a `tempfile.TemporaryFile` instead of `io.BytesIO` and returns the file object positioned at the start; the upload streams from it with an explicit `Content-Length` and closes it (deleting the temp file) when done. - Tests updated for the new return shapes (JS `tarFileToStream.test.ts`, `uploadFile.test.ts`; Python upload/tar tests), including assertions that the spooled archive is removed on both the consume and destroy paths. ## Usage No API changes — `Template.build()` / template builds behave the same, just without holding the build context in memory: ```ts await Template.build(template, { alias: 'my-template' }) ``` ```python Template.build(template, alias="my-template") ``` Split out of #1433, which covers streaming for sandbox/volume file uploads and downloads. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
8b8a224f8b |
feat(python-sdk): add logger option for request/debug logging (#1409)
Adds a `logger` option (a standard library `logging.Logger`) to
`Sandbox.create`/`AsyncSandbox.create` and the static
`Sandbox.connect(sandbox_id, ...)`, wired into the API client, the envd
client, the volume content client, and the RPC (ConnectRPC) path. The
logger is stored on the sandbox and propagates to all of its later
operations — including control-plane calls like
`kill`/`pause`/`set_timeout`/`get_info` (via `get_api_params`) — so
logging keeps working after construction; mirroring the JS SDK, `logger`
is a construction-time option and not a public per-request parameter
those methods accept from the caller, and nothing is logged unless a
logger is supplied. The stdlib `logging.Logger` is used directly as the
adapter (no ported JS `Logger` interface), and log levels match JS:
requests at `INFO`, successful API and unary RPC responses at `INFO`,
streamed RPC messages at `DEBUG`, failed API responses (status >= 400)
at `ERROR`. The always-on module-level (`e2b.*`) request logging at the
transport layer was removed in favor of this opt-in client-layer
logging, and volume content operations continue to accept `logger` per
call via `VolumeApiParams` to match the JS Volume API. Includes a
changeset and unit tests in `tests/test_logging_option.py`.
## Usage
```python
import logging
from e2b import Sandbox
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("my-app.e2b")
sbx = Sandbox.create(logger=logger)
sbx.commands.run("echo hello") # RPC logged via `logger`
sbx.set_timeout(60) # control-plane call also logged via `logger`
```
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Matt Brockman <matt.brockman@e2b.dev>
|
||
|
|
ec260376dc | [skip ci] Release new versions | ||
|
|
de0c401626 | fix(sdk): correct filesystem watch handle callback and timeout behavior (#1480) @e2b/python-sdk@2.30.0 e2b@2.31.0 | ||
|
|
7e7e9514df |
feat(sdk): filesystem-only auto-pause via lifecycle.onTimeout object form (#1471)
## Filesystem-only auto-pause (`onTimeout` object form)
Adds an object form to the sandbox **lifecycle** `onTimeout`
(`on_timeout` in Python) that controls the snapshot kind taken when a
sandbox auto-pauses on timeout, via `keepMemory` (`keep_memory`).
`onTimeout` now accepts either the existing bare action (`'pause'` /
`'kill'`) or the object form `{ action, keepMemory }`. When `keepMemory`
is `false` (with `action: 'pause'`), a timeout auto-pause takes a
**filesystem-only** snapshot (no memory) instead of a full memory one,
so the sandbox cold-boots (reboots) from disk on resume — losing running
processes and open connections. Defaults to `true` (full memory
snapshot), so existing callers are unaffected. **The bare string form is
unchanged.**
It's the create-time / auto-pause counterpart to the explicit
`pause(keepMemory=false)` from #1465: same `keepMemory` naming, mapped
onto the `autoPauseMemory` create field.
### Type safety
The object form is a **discriminated union** on `action`: `keepMemory`
is only valid with `action: 'pause'`. Pairing it with `action: 'kill'`
is a **compile-time type error** (TS) / static error (`ty`), and is
additionally rejected at runtime (`InvalidArgumentError` /
`InvalidArgumentException`) for untyped callers.
### Behavior & validation
- `keepMemory` only applies to a `pause` action.
- **Incompatible with auto-resume** — auto-resume wakes a paused sandbox
on inbound traffic by restoring its memory snapshot in place; a
filesystem-only snapshot has no memory to restore (resuming cold-boots
it), so it must be resumed explicitly via `connect()`. Combining
`keepMemory: false` with `autoResume` is rejected client-side.
### Usage
```ts
// JS/TS — filesystem-only auto-pause on timeout
const sbx = await Sandbox.create({
lifecycle: { onTimeout: { action: 'pause', keepMemory: false } },
})
// bare string form still works (full memory snapshot)
const sbx2 = await Sandbox.create({ lifecycle: { onTimeout: 'pause' } })
```
```python
# Python
sbx = Sandbox.create(
lifecycle={"on_timeout": {"action": "pause", "keep_memory": False}}
)
```
### Changes
- `spec/openapi.yml`: `autoPauseMemory` on the create body (+
regenerated JS/Python clients).
- JS `SandboxOnTimeout` discriminated union (`'pause' | 'kill' | {
action: 'pause'; keepMemory? } | { action: 'kill' }`) and the Python
`SandboxOnTimeoutPause` / `SandboxOnTimeoutKill` TypedDicts, wired
through `createSandbox` / `_create_sandbox` (sync + async) to
`autoPauseMemory`, with the client-side guards.
- Tests: payload serialization + validation (offline, incl. the `action:
'kill'` type/runtime guard) and live cold-boot e2e in both SDKs;
changeset (`e2b` + `@e2b/python-sdk`, minor).
### Backend dependency
The live e2e tests exercise the real auto-pause→cold-boot path and
require the infra-side `autoPauseMemory` support (e2b-dev/infra#3055),
now merged and deployed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|