Terminal
bridge.terminal starts and manages an interactive local pseudo-terminal (PTY) session. The shell runs on the desktop user's machine; it does not mount, copy, or mirror the encrypted cloud workspace.
Adapter support
bridge.terminal.isSupported() is independent of localFiles:
Tauri macOS desktop — starts the account's login shell.
Mock adapter — provides deterministic terminal output for renderer tests. It does not execute shell commands.
REST, browser production, iOS, and other Tauri platforms — report unsupported. They never forward terminal requests to an HTTP endpoint or another shell.
The mock stream is useful for deterministic rendering checks. It does not establish that a native CLI, Japanese IME, or macOS WebKit input behavior works.
Bridge contract
interface TerminalSpawnOptions {
/** Absolute, existing local directory. Omitted means the user's home. */
cwd?: string;
/** Integers from 1 to 500. */
cols: number;
rows: number;
}
interface TerminalSession {
id: string;
/** Canonical local directory passed to the shell at startup. */
cwd: string;
shell: string;
}
type TerminalExitReason =
| "completed"
| "killed"
| "owner-expired"
| "disconnected"
| "output-stalled"
| "io-error";
type TerminalEvent =
| { type: "data"; sessionId: string; sequence: number; data: Uint8Array }
| {
type: "exit";
sessionId: string;
exitCode: number | null;
signal: string | null;
reason: TerminalExitReason;
};
interface TerminalAPI {
isSupported(): boolean;
spawn(
options: TerminalSpawnOptions,
onEvent: (event: TerminalEvent) => void | Promise<void>,
): Promise<TerminalSession>;
write(id: string, data: Uint8Array): Promise<void>;
resize(id: string, cols: number, rows: number): Promise<void>;
kill(id: string): Promise<void>;
}The bridge accepts only the working directory and initial dimensions at spawn. It does not accept a command string, shell override, or environment from the renderer. Users type into the started shell after the PTY opens.
cwd must be an absolute, existing local directory. The native backend canonicalizes it and uses the account's home directory when it is omitted. The returned cwd is the directory used to start the shell; it does not track later cd commands.
Byte stream and flow control
Native output is delivered over a Tauri Channel created before the child process starts. Output and exit events share one ordered stream, so final output is processed before exit. A data event contains raw bytes, not decoded text.
The listener can receive data or exit before the spawn() promise resolves, including an immediate shell exit. Create the consumer before calling spawn() and let it process events without waiting for the returned session ID.
The bridge processes listener callbacks in sequence and acknowledges each data packet only after its callback resolves. A terminal renderer should resolve the callback from the terminal emulator's write callback, including while the frame is hidden. Resolve pending callbacks during disposal; a callback waiting on a disposed emulator can otherwise hold the stream open.
Native packets are limited to 1 KiB. At most 32 output packets and 64 KiB are retained in flight per session. The bridge enforces the same byte/packet bounds before acknowledging more output. A sustained listener stall terminates visibly instead of accumulating unbounded output.
Ownership and lifecycle
The bridge acquires an owner generation for the calling main window. Native spawn is restricted to main and numeric main-* window labels; terminal pop-out is not supported. Each frame owns a separate session.
The renderer sends a heartbeat every 15 seconds. A session whose owner has not renewed for 180 seconds expires and its shell is reaped. Page navigation and native window destruction revoke ownership immediately. Long macOS sleep or background suspension can delay heartbeats past the grace period and end a session.
The renderer's module-scoped session cache must survive ordinary React remounts and explicitly retained temporary frames. Dispose a session when a provider replacement permanently removes the Terminal frame, when its workspace is torn down, or when its window/app closes. Native teardown also terminates foreground descendants and waits for process cleanup.
Sessions, terminal output, selected working directories, and typed commands are not serialized into layouts, persisted settings, or cloud workspace data. Restoring a saved Terminal frame must remain idle until the user starts a shell.
Limits and exit behavior
| Resource | Bound |
|---|---|
| Concurrent sessions | 32 |
| Columns and rows | 1–500 each |
Input per write | 64 KiB |
| Queued native input | 128 KiB and 32 queued entries |
| Output per packet | 1 KiB |
| Outstanding output | 32 packets and 64 KiB |
| Owner and output-stall grace | 180 seconds |
| Native cleanup wait | 3 seconds before returning an error |
The exit event reports exitCode, signal, and one of completed, killed, owner-expired, disconnected, output-stalled, or io-error. kill(id) is idempotent for an already completed or absent session after owner validation; it resolves after native cleanup rather than after the renderer paints.