Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds Commands.start/4 which spawns a HandleServer GenServer owning the
envd Start server-stream via Req into: :self. The server folds events
through Commands.Fold and delivers {ref, _} messages to the subscriber,
blocking start/4 on :await_start until the first envd pid event arrives.
CommandHandle wraps the server pid, ref, envd pid, and context, exposing
pid/1, kill/1, send_stdin/2, close_stdin/1, and disconnect/1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds Commands.start/4 (background) returning a message-streaming CommandHandle (wait/kill/send_stdin/close_stdin/disconnect/pid), plus connect/4 reconnect, list/2, and by-pid control RPCs. run/4 unchanged, refactored onto shared Commands.Fold + Envd.Rpc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a pty branch to Fold.apply_event/2 that decodes the base64 chunk
and emits {:pty, bytes} without accumulating into the CommandResult.
Widens the output/0 type to include :pty. Three new tests cover the
happy path, end-event after pty data, and invalid-base64 error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r{}}
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds pseudo-terminal (PTY) support to
E2bEx, reaching feature parity with the JS/Python SDKs'ptynamespace. This is Phase 3 of the Commands parity roadmap (Phases 1 & 2 — streaming + background execution — already landed).E2bEx.Pty—create/3(launches an interactive/bin/bash -i -lon a PTY of:cols×:rows),connect/4(reconnect by pid), and by-pidsend_input/5/resize/5/kill/4.E2bEx.Pty.Handle—pid/1,send_input/2,resize/2,kill/1,wait/1,disconnect/1. Distinct struct exposing only PTY-valid ops; backed by the sameCommands.HandleServer.{ref, {:pty, bytes}}channel (not stdout/stderr), ending with a terminal{:exit, %CommandResult{}}/{:error, %Error{}}.wait/1returns an exit-code-only%CommandResult{}(PTY output is not buffered).Internals
Commands.Foldgains an emit-onlyptydata-event branch (decodesdata.pty, emits{:pty, _}, accumulates nothing).Envd.Rpcgainssend_pty_input/3(theptyinput channel) andresize/3(theUpdateRPC).Commands.HandleServeris reused unchanged — PTY just hands it a different request map.Notable decisions
Pty.list— neither SDK has one; listing stays onCommands.create/3raisesArgumentErroron missing:cols/:rows(a programmer error, likeClient.newwithout:api_key).runanalog, matching the SDKs).receive_timeoutconstant; collapsing streaming-request construction intoRpc) are intentionally deferred to keep this diff PTY-only.Spec:
docs/superpowers/specs/2026-06-11-e2b-pty-design.md· Plan:docs/superpowers/plans/2026-06-11-e2b-pty.mdTest Plan
mix test— 142 tests, 0 failuresmix compile --warnings-as-errors— cleanpty.size,Updateresize,SendInputinput.pty,data.ptydecode) verified against the envd proto and JS SDKsend_pty_input/resize(+ non-2xx error);Pty.create/connectstreaming; by-pid controls;Handle.wait(drain, crash) /disconnect; pre-start context error🤖 Generated with Claude Code
Added:
mix e2b.terminal(interactive terminal)This PR now also includes a raw interactive terminal built on the PTY layer above (merged from
feat/pty-terminal):mix e2b.terminal SANDBOX_ID(or--template <tmpl>to create/attach/kill-on-exit) — opens a real terminal into a sandbox PTY from a normal shell: arrow keys, tab-completion,vim/htop, Ctrl-C all work.E2bEx.Pty.Terminal.run/2— the reusable session orchestrator (output loop + linked stdin reader + size-poll + crash handling), over injectable IO hooks so it's fully unit-tested (Bypass-backed, no real tty).E2bEx.Pty.InputBatcher— coalesces stdin bytes (and multi-byte escape sequences) into onesend_inputper ~10ms window.Ports the E2B CLI's
terminal.ts, accommodating two BEAM constraints: raw mode viastty </dev/tty(nosetRawMode), and resize via polling (OTP can't trapSIGWINCH). Allstty/tty side effects are quarantined in the Mix task; the orchestration logic is pure and tested.Note: the raw-terminal path itself (
stty//dev/tty) is the one piece not automatically tested — it's manual-smoke-only (mix e2b.terminal --template base).Test Plan (terminal)
mix test— 153 tests, 0 failuresmix compile --warnings-as-errorsclean;mix help e2b.terminallists the taskmix e2b.terminal --template baseopens a working shell; window resize propagates;exitrestores the local terminal