English | 中文
E2B implementation of the @deepseek-ai/dsh-subprocess seam. Load @deepseek-ai/dsh-e2b first, then this service in place of dsh-subprocess-local. Existing Bash, PTY, and LSP consumers then execute in the shared remote sandbox without E2B-specific capability packages.
| Key | Default | Meaning |
|---|---|---|
pollMs |
20 |
Remote status/liveness poll cadence in milliseconds; each tick is one control-plane request, so a larger value trades exit-observation latency for fewer requests. |
Sandbox.commands.run(..., { background: true }) starts remotely. pid is -1 until the wrapper publishes and the adapter validates its process-group id; stdin and ordinary observation wait for that publication. An owned startup signal aborts environment and private-state preparation before allocation; once allocation begins, cancellation waits for a provisional SDK handle it can clean.cwd and private runtimeRoot come from the shared owner; executable lookup verifies absolute paths or resolves a bare name against the sandbox PATH plus explicit overrides, and rejects relative paths containing separators like every subprocess provider.exec setsid --wait and records its actual process-group id plus private status files beneath ctx.e2b.runtimeRoot/processes. The handle waits for that file instead of treating the SDK command PID as its published identity. Termination signals the negative recorded id with SIGTERM, waits the caller's graceMs, then escalates to SIGKILL and the SDK kill fallback; TERM delivery or probe failures also force that escalation. Process-table probes treat groups containing only zombie or dead entries as quiescent. Force cleanup succeeds only after a bounded probe finds the group empty; otherwise waitForExit() exposes a retryable failure, while proven quiescence makes later termination a no-op. Publication and monitoring failures apply the same cleanup transaction before rejecting. Service disposal rejects new starts, terminates and joins every retained process group, then awaits SDK settlement and private cleanup before the sandbox owner disposes.DSH_* and credential-shaped (*KEY*, *SECRET*, *TOKEN*) names and restores every valid spec.env entry as an explicit caller opt-in. Empty names, =, and NUL framing violations reject before launch. Subsequent E2B command and PTY login shells receive a fresh randomized root-level HOME plus empty overrides for every scrubbed ambient name before user profiles can run; the requested argv receives the serialized environment afterward without changing the sandbox user's umask. Host ambient variables never enter the sandbox implicitly. Private environment files are removed after consumption, and failed command or terminal setup removes its private state before rejecting.graceMs, withholds its partial spill, and returns that status while retaining the remote group for waitForExit() and termination. Natural raw-pipe completion instead awaits lossless transport and preserves backpressure; explicit termination destroys the host pipes and releases blocked output before remote cleanup. Batch and streaming stdin use the SDK handle.spawnTerminal() uses E2B's byte PTY API, installs the exact argv and scrubbed environment through private mode-0600 files, reports the foreground process group, sends real signals, and tears down every live group in the remote terminal session through one retryable awaited terminate(); termination rejects new handle operations, aborts and joins in-flight writes, inspections, and signals, and treats zombie-only groups as quiescent. A private random output boundary discards the E2B bootstrap shell's prompt and echoed runner command while preserving every requested-process byte, including its first prompt. Terminal output is pushed to the handle's stream without awaiting host backpressure: a flowing consumer (the PTY backend attaches one at construction) folds bytes into its own bounded state, while a paused consumer buffers in host memory. PTY allocation is awaited through handle publication before cancellation is observed, so owned rollback can clean the published handle. Setup and teardown own the private state transaction, abort pending setup during service disposal, and fence publication; sandbox disposal or timeout bounds a setup rollback that also fails. Prompt detection, scrollback, readiness, and owner policy remain in dsh-terminal-bash.SandboxNotFoundError during process or terminal liveness, termination, rollback, or disconnect proves the remote execution world cannot retain work, so cleanup treats it as quiescent; unrelated failures remain observable.The default E2B base image supplies the runtime and Bash/GNU utilities this adapter invokes: node, bash, setsid, ps, awk, tr, env, base64, chmod, tee, head, rm, kill, id, and getent.
Indirectly, through Consumers such as the Bash executor behind dsh-tool-bash, which render remote output, exit facts, background deltas, and spill paths.
No direct invalidation; the named consumers own any request-prefix changes.
CommandHandle.stdout and .stderr accumulate the base64 transport even when this adapter exposes bounded raw-byte tails, so the subprocess seam's normal host-memory bound is not achieved and transport retention is larger than the source stream.pid remains -1 during remote startup; consumers that require a positive PID immediately, including the ACP child backend, cannot use this provider unchanged..dsh-e2b until the owner deletes the sandbox; this POC supplies no in-sandbox sweep.0700/0600 modes cannot isolate .dsh-e2b control files from concurrently running sandbox processes. A background process could rewrite pid/exit-code or read a not-yet-consumed environment file. The adapter validates published values and refuses group ids whose negative form is unsafe to signal (<= 1), but real isolation needs an E2B per-command user or an out-of-band control channel.SIGTERM or SIGKILL is reported only when no wrapper-published direct exit code wins; every unrequested SDK exit remains an exit code, including values equal to 128 + signal.