Terminal Emulator
Relevant source files
The following files were used as context for generating this wiki page:
The Terminal Emulator is a core component of the Bolt workbench, providing a browser-based command-line interface that allows users and the AI assistant to interact directly with a sandboxed Node.js environment. It leverages the StackBlitz WebContainer API to execute shell commands, manage packages, and run development servers entirely within the user's browser tab.
Integrated into the Editor Panel, the terminal supports multiple concurrent sessions, allowing for a flexible development workflow where users can monitor logs, run tests, and execute scripts simultaneously. It features a themeable UI that synchronizes with the overall application state and supports standard terminal capabilities such as cursor blinking and automatic resizing.
Sources: README.md:12-18, app/components/workbench/EditorPanel.tsx:162-235, app/lib/stores/terminal.ts:7-12
Architecture and Integration
The terminal system is built using a layered architecture that connects the React UI component to the underlying WebContainer runtime through a centralized state management store.
Component Structure
The primary UI entry point is the Terminal component, which wraps the xterm.js library. It utilizes the FitAddon for responsive sizing and the WebLinksAddon for interactive URL detection.
The diagram above illustrates the flow from the React UI components down to the WebContainer shell process.
Sources: app/components/workbench/terminal/Terminal.tsx:21-55, app/lib/stores/terminal.ts:24-30
State Management
Terminal state is managed by the TerminalStore, which tracks active terminal instances and their associated WebContainer processes. The WorkbenchStore acts as a facade, providing high-level methods to toggle the terminal's visibility and handle resizing events.
| Class/Store | Responsibility | Key Properties/Methods |
|---|---|---|
TerminalStore | Manages WebContainer process lifecycle and terminal mapping. | attachTerminal(), onTerminalResize() |
WorkbenchStore | Coordinates terminal visibility within the workbench layout. | toggleTerminal(), showTerminal atom |
Terminal (Component) | Renders the terminal UI and handles xterm.js lifecycle. | onTerminalReady, reloadStyles() |
Sources: app/lib/stores/terminal.ts:7-15, app/lib/stores/workbench.ts:38-70
Implementation Details
Initialization and Lifecycle
When a Terminal component mounts, it initializes a new XTerm instance with specific configurations, including font family (Menlo, courier-new, monospace) and font size (12). It then triggers an onTerminalReady callback, which the WorkbenchStore uses to "attach" the terminal to a shell process.
The sequence diagram shows the initialization flow and how the UI connects to the runtime shell.
Sources: app/components/workbench/terminal/Terminal.tsx:28-54, app/lib/stores/terminal.ts:24-31
Multi-Terminal Support
The EditorPanel supports up to 3 concurrent terminal instances. Users can add new terminals via a plus icon, and each terminal maintains its own independent process within the WebContainer.
- Max Terminals: 3
- Default Size: 25% of the workbench height
- Active Terminal State: Managed via local React state (
activeTerminal)
Sources: app/components/workbench/EditorPanel.tsx:43-45, app/components/workbench/EditorPanel.tsx:162-200
Theme and Styling
The terminal theme is dynamically updated to match the application's light or dark mode. It uses CSS variables defined in variables.scss to map terminal colors (black, red, green, yellow, blue, magenta, cyan, white) to the project's design system.
/* Example Terminal Variable Mapping */
--bolt-terminal-background: var(--bolt-elements-terminals-background);
--bolt-terminal-foreground: #eff0eb;
--bolt-terminal-green: #5af78e;
Sources: app/styles/variables.scss:102-120, app/styles/variables.scss:215-233, app/components/workbench/terminal/Terminal.tsx:75-81
Configuration and API
The terminal is configured through props and store actions to handle various states, such as read-only mode during AI code generation.
Terminal Props
| Prop | Type | Description |
|---|---|---|
theme | Theme | Current application theme (light/dark). |
readonly | boolean | If true, disables input and hides the cursor. |
onTerminalReady | (terminal: XTerm) => void | Callback triggered when xterm.js is initialized. |
onTerminalResize | (cols, rows) => void | Callback triggered by the ResizeObserver. |
Sources: app/components/workbench/terminal/Terminal.tsx:16-22, app/components/workbench/terminal/Terminal.tsx:64-73
Shell Interaction
Shell processes are spawned using a utility function newShellProcess. If the shell fails to spawn, the terminal writes a red error message to the buffer.
async attachTerminal(terminal: ITerminal) {
try {
const shellProcess = await newShellProcess(await this.#webcontainer, terminal);
this.#terminals.push({ terminal, process: shellProcess });
} catch (error: any) {
terminal.write(coloredText.red('Failed to spawn shell\n\n') + error.message);
}
}
Sources: app/lib/stores/terminal.ts:24-33
Summary
The Terminal Emulator provides a high-fidelity development environment within the browser by bridging the xterm.js UI with StackBlitz WebContainers. Through the TerminalStore and WorkbenchStore, the system ensures that multiple terminal sessions are correctly synchronized with their underlying processes and the application's visual state.