ターミナル接続では、ブラウザーベースの UI がサンドボックスシェルと直接やり取りできます。exec() で個別のコマンドを実行するのではなく、bash シェルへの永続的な双方向チャネルを開きます。SSH やローカルのターミナルエミュレーターと同じモデルです。
ターミナル接続は WebSocket を使い、ブラウザーターミナル(xterm.js ↗ など)と、サンドボックスコンテナー内の擬似端末(PTY)プロセスの間で生バイトをストリームします。
Browser (xterm.js) <-- WebSocket --> Worker <-- proxy --> Container PTY (bash)- ブラウザーが Worker へ WebSocket アップグレードリクエストを送ります
- Worker が
sandbox.terminal(request)を呼び、アップグレードをコンテナーへプロキシします - コンテナーが PTY に接続した bash シェルを起動します
- 生バイトが双方向に流れます。キー入力が入り、ターミナル出力が出ます
これは exec() とは根本的に異なります。
exec()は 1 つのコマンドを完了まで実行し、結果を返しますterminal()は、ユーザーが対話的にコマンドを入力する永続シェルを開きます
コンテナーはターミナル出力をリングバッファに保持します。クライアントが切断して再接続すると、サーバーはバッファ済み出力を再生し、ターミナルは変わっていないように見えます。つまり:
- 短いネットワーク切断はユーザーに見えません
- 再接続したターミナルは、コマンドを再実行せずに以前の出力を表示します
- バッファには固定サイズがあるため、非常に古い出力は失われることがあります
バッファリングを扱うクライアント側コードは不要です。コンテナーが透過的に管理します。
ブラウザーベースのアプリケーションでは、ネットワーク切断はよく起きます。ターミナル接続は、上記のサーバー側バッファリングと、指数バックオフ付きのクライアント側再接続でこれに対応します。
xterm.js 向けの SandboxAddon は、これを自動で実装します。独自クライアントを作る場合、再接続ロジックは自分で実装します。サーバー側バッファリングは、接続するクライアントに依存しません。接続ライフサイクルの詳細は WebSocket プロトコルリファレンス を参照してください。
各 セッション は、独立したシェル状態を持つ独自のターミナルを持てます。
const devSession = await sandbox.createSession({
id: "dev",
cwd: "/workspace/frontend",
env: { NODE_ENV: "development" },
});
const testSession = await sandbox.createSession({
id: "test",
cwd: "/workspace",
env: { NODE_ENV: "test" },
});
// Each session's terminal has its own working directory,
// environment variables, and command history複数のブラウザークライアントを、同じセッションのターミナルへ同時に接続できます。全員が同じシェル出力を見られ、入力も送れます。独立したユーザーを分離するためではなく、1 つのワークスペース内での意図的な共同作業に使います。
ターミナル接続は、ターミナル I/O にバイナリ WebSocket フレーム(性能のため)、制御と状態メッセージに JSON テキストフレーム(構造のため)を使います。データパスを速く保ちつつ、ターミナルリサイズなどの操作では構造化された通信ができます。
プロトコル仕様の全体、接続ライフサイクルとメッセージ形式は Terminal API リファレンス を参照してください。
| 用途 | 方法 |
|---|---|
| コマンドを実行して結果を得る | exec() または execStream() |
| エンドユーザー向けの対話シェル | terminal() |
| リアルタイム出力のある長時間プロセス | startProcess() + streamProcessLogs() |
| 共同でのターミナル共有 | 共有セッションでの terminal() |
- Terminal API リファレンス — メソッドシグネチャと型
- ブラウザーターミナル — 手順付きセットアップガイド
- セッション管理 — セッションの仕組み
- アーキテクチャ — SDK 全体の設計