Skip to content

Commit 683febe

Browse files
Add PTY (pseudo-terminal) API documentation
Documentation for PR #310 which adds interactive terminal support. New documentation: - API reference: /sandbox/api/pty/ - How-to guide: /sandbox/guides/terminal-shells/ - Updated navigation and index pages Covers PTY creation, session attachment, terminal I/O, resizing, lifecycle management, and WebSocket transport for lower latency.
1 parent c4ab24a commit 683febe

File tree

4 files changed

+755
-0
lines changed

4 files changed

+755
-0
lines changed

src/content/docs/sandbox/api/index.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ The Sandbox SDK provides a comprehensive API for executing code, managing files,
6767
Create isolated execution contexts within a sandbox. Each session maintains its own shell state, environment variables, and working directory.
6868
</LinkTitleCard>
6969

70+
<LinkTitleCard
71+
title="PTY (Terminal)"
72+
href="/sandbox/api/pty/"
73+
icon="terminal"
74+
>
75+
Create interactive pseudo-terminal sessions for shells and terminal-based applications. Full terminal control with ANSI escape codes.
76+
</LinkTitleCard>
77+
7078
</CardGrid>
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
---
2+
title: PTY (Terminal)
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 9
6+
---
7+
8+
import { TypeScriptExample } from "~/components";
9+
10+
Create and manage interactive pseudo-terminal (PTY) sessions for shell access and terminal-based applications.
11+
12+
PTY sessions provide a full terminal environment with ANSI escape codes, terminal resizing, and proper signal handling. Use PTY for interactive shells, terminal-based editors, or applications that require terminal control.
13+
14+
## Methods
15+
16+
### `sandbox.pty.create()`
17+
18+
Create a new PTY session with a fresh terminal environment.
19+
20+
```ts
21+
const pty = await sandbox.pty.create(options?: CreatePtyOptions): Promise<Pty>
22+
```
23+
24+
**Parameters**:
25+
- `options` (optional):
26+
- `cols` - Terminal width in columns (default: `80`)
27+
- `rows` - Terminal height in rows (default: `24`)
28+
- `command` - Command to run (default: `['/bin/bash']`)
29+
- `cwd` - Working directory (default: `/home/user`)
30+
- `env` - Environment variables to set
31+
- `disconnectTimeout` - Milliseconds before orphaned PTY is killed (default: `30000`)
32+
33+
**Returns**: `Promise<Pty>` - PTY handle for interacting with the terminal
34+
35+
<TypeScriptExample>
36+
```ts
37+
// Create a default bash terminal
38+
const pty = await sandbox.pty.create({ cols: 80, rows: 24 });
39+
40+
// Listen for output
41+
pty.onData((data) => {
42+
console.log('Terminal output:', data);
43+
});
44+
45+
// Send commands
46+
await pty.write('ls -la\n');
47+
await pty.write('pwd\n');
48+
49+
// Wait for exit
50+
const { exitCode } = await pty.exited;
51+
console.log('Terminal exited with code:', exitCode);
52+
```
53+
</TypeScriptExample>
54+
55+
### `sandbox.pty.attach()`
56+
57+
Attach a PTY to an existing session, inheriting its working directory and environment variables.
58+
59+
```ts
60+
const pty = await sandbox.pty.attach(sessionId: string, options?: AttachPtyOptions): Promise<Pty>
61+
```
62+
63+
**Parameters**:
64+
- `sessionId` - Session ID to attach to
65+
- `options` (optional):
66+
- `cols` - Terminal width in columns (default: `80`)
67+
- `rows` - Terminal height in rows (default: `24`)
68+
- `command` - Command to run (default: `['/bin/bash']`)
69+
- `disconnectTimeout` - Milliseconds before orphaned PTY is killed (default: `30000`)
70+
71+
**Returns**: `Promise<Pty>` - PTY handle
72+
73+
<TypeScriptExample>
74+
```ts
75+
// Create a session and run some commands
76+
const session = await sandbox.sessions.create({ cwd: '/workspace' });
77+
await sandbox.exec('cd /workspace/project', { sessionId: session.id });
78+
79+
// Attach PTY to existing session - inherits /workspace/project cwd
80+
const pty = await sandbox.pty.attach(session.id, { cols: 100, rows: 30 });
81+
82+
// PTY starts in the session working directory
83+
pty.onData((data) => console.log(data));
84+
await pty.write('pwd\n'); // Outputs: /workspace/project
85+
```
86+
</TypeScriptExample>
87+
88+
### `sandbox.pty.getById()`
89+
90+
Reconnect to an existing PTY session by ID.
91+
92+
```ts
93+
const pty = await sandbox.pty.getById(id: string): Promise<Pty>
94+
```
95+
96+
**Parameters**:
97+
- `id` - PTY ID (e.g., `'pty_123'`)
98+
99+
**Returns**: `Promise<Pty>` - PTY handle
100+
101+
<TypeScriptExample>
102+
```ts
103+
// Store PTY ID for later reconnection
104+
const pty = await sandbox.pty.create();
105+
const ptyId = pty.id;
106+
107+
// Later: reconnect to the same PTY
108+
const reconnected = await sandbox.pty.getById(ptyId);
109+
reconnected.onData((data) => console.log(data));
110+
```
111+
</TypeScriptExample>
112+
113+
### `sandbox.pty.list()`
114+
115+
List all active PTY sessions in the sandbox.
116+
117+
```ts
118+
const ptys = await sandbox.pty.list(): Promise<PtyInfo[]>
119+
```
120+
121+
**Returns**: `Promise<PtyInfo[]>` - Array of PTY information objects with:
122+
- `id` - PTY identifier
123+
- `sessionId` - Associated session ID (if attached)
124+
- `cols` - Terminal width
125+
- `rows` - Terminal height
126+
- `command` - Command being run
127+
- `cwd` - Working directory
128+
- `state` - PTY state (`'running'` or `'exited'`)
129+
- `exitCode` - Exit code (if exited)
130+
- `createdAt` - Creation timestamp
131+
132+
<TypeScriptExample>
133+
```ts
134+
const ptys = await sandbox.pty.list();
135+
console.log(`Found ${ptys.length} active PTY sessions`);
136+
137+
for (const pty of ptys) {
138+
console.log(`PTY ${pty.id}: ${pty.state} (${pty.cols}x${pty.rows})`);
139+
}
140+
```
141+
</TypeScriptExample>
142+
143+
## PTY Handle
144+
145+
All `create()`, `attach()`, and `getById()` methods return a `Pty` handle with the following interface:
146+
147+
### Properties
148+
149+
- `id: string` - Unique PTY identifier
150+
- `sessionId?: string` - Associated session ID (if attached to session)
151+
- `exited: Promise<{ exitCode: number }>` - Promise that resolves when PTY exits
152+
153+
### Methods
154+
155+
#### `write()`
156+
157+
Send input to the PTY terminal.
158+
159+
```ts
160+
await pty.write(data: string): Promise<void>
161+
```
162+
163+
<TypeScriptExample>
164+
```ts
165+
// Interactive commands
166+
await pty.write('npm install\n');
167+
await pty.write('git status\n');
168+
169+
// Control sequences
170+
await pty.write('\x03'); // Ctrl+C
171+
await pty.write('\x04'); // Ctrl+D (EOF)
172+
```
173+
</TypeScriptExample>
174+
175+
#### `resize()`
176+
177+
Resize the terminal dimensions. The application running in the PTY receives a SIGWINCH signal.
178+
179+
```ts
180+
await pty.resize(cols: number, rows: number): Promise<void>
181+
```
182+
183+
<TypeScriptExample>
184+
```ts
185+
// Resize to match client terminal
186+
await pty.resize(120, 40);
187+
```
188+
</TypeScriptExample>
189+
190+
#### `kill()`
191+
192+
Terminate the PTY process.
193+
194+
```ts
195+
await pty.kill(signal?: string): Promise<void>
196+
```
197+
198+
<TypeScriptExample>
199+
```ts
200+
// Graceful termination
201+
await pty.kill('SIGTERM');
202+
203+
// Force kill
204+
await pty.kill('SIGKILL');
205+
206+
// Default signal (SIGTERM)
207+
await pty.kill();
208+
```
209+
</TypeScriptExample>
210+
211+
#### `onData()`
212+
213+
Register a callback to receive terminal output.
214+
215+
```ts
216+
const unsubscribe = pty.onData(callback: (data: string) => void): () => void
217+
```
218+
219+
Returns an unsubscribe function to stop receiving data.
220+
221+
<TypeScriptExample>
222+
```ts
223+
const unsubscribe = pty.onData((data) => {
224+
console.log('Terminal output:', data);
225+
});
226+
227+
// Later: stop listening
228+
unsubscribe();
229+
```
230+
</TypeScriptExample>
231+
232+
#### `onExit()`
233+
234+
Register a callback to handle PTY exit.
235+
236+
```ts
237+
const unsubscribe = pty.onExit(callback: (exitCode: number) => void): () => void
238+
```
239+
240+
Returns an unsubscribe function to remove the callback.
241+
242+
<TypeScriptExample>
243+
```ts
244+
pty.onExit((exitCode) => {
245+
console.log('PTY exited with code:', exitCode);
246+
});
247+
```
248+
</TypeScriptExample>
249+
250+
#### `close()`
251+
252+
Detach from the PTY without killing it. The PTY continues running until the `disconnectTimeout` expires.
253+
254+
```ts
255+
pty.close(): void
256+
```
257+
258+
<TypeScriptExample>
259+
```ts
260+
// Detach from PTY
261+
pty.close();
262+
263+
// PTY continues running for disconnectTimeout period
264+
// Can reconnect with getById() before timeout expires
265+
```
266+
</TypeScriptExample>
267+
268+
### Async Iteration
269+
270+
PTY handles support async iteration for scripting scenarios:
271+
272+
<TypeScriptExample>
273+
```ts
274+
const pty = await sandbox.pty.create();
275+
await pty.write('find / -name "*.log" 2>/dev/null\n');
276+
await pty.write('exit\n');
277+
278+
// Collect output using async iteration
279+
let output = '';
280+
for await (const chunk of pty) {
281+
output += chunk;
282+
}
283+
284+
console.log('Found log files:', output);
285+
```
286+
</TypeScriptExample>
287+
288+
## Transport Modes
289+
290+
PTY operations work with both HTTP and WebSocket transports:
291+
292+
**HTTP Transport** (default):
293+
- `write()` and `resize()` return promises that resolve when the container confirms the operation
294+
- `onData()` uses Server-Sent Events (SSE) for output streaming
295+
- Higher latency but works in all Workers environments
296+
297+
**WebSocket Transport** (opt-in):
298+
- `write()` and `resize()` send messages over WebSocket and resolve immediately
299+
- `onData()` receives output over the same WebSocket connection
300+
- Lower latency for real-time terminal interaction
301+
- Requires WebSocket support in your Worker environment
302+
303+
Enable WebSocket transport when creating the sandbox:
304+
305+
<TypeScriptExample>
306+
```ts
307+
import { getSandbox } from '@cloudflare/sandbox';
308+
309+
const sandbox = await getSandbox(env.Sandbox, 'my-sandbox', {
310+
useWebSocket: true
311+
});
312+
313+
// PTY operations now use WebSocket for lower latency
314+
const pty = await sandbox.pty.create({ cols: 80, rows: 24 });
315+
```
316+
</TypeScriptExample>
317+
318+
## Related Resources
319+
320+
- [Terminal Shells Guide](/sandbox/guides/terminal-shells/) - Build interactive terminal applications
321+
- [Commands API](/sandbox/api/commands/) - Execute one-off commands without PTY overhead
322+
- [Sessions API](/sandbox/api/sessions/) - Manage execution contexts

0 commit comments

Comments
 (0)