20 KiB
VibeTunnel Codebase Map
A comprehensive navigation guide for the VibeTunnel web terminal system.
Project Overview
VibeTunnel is a web-based terminal multiplexer with distributed architecture support. It provides:
- PTY-based terminal sessions via node-pty
- Real-time terminal streaming via SSE (asciinema cast files)
- Binary-optimized buffer synchronization (current viewport via WebSocket)
- Distributed HQ/remote server architecture
- Web UI with full terminal emulation
Directory Structure
web/
├── src/
│ ├── server/ # Node.js Express server
│ │ ├── middleware/ # Auth and other middleware
│ │ ├── pty/ # PTY management
│ │ ├── routes/ # API endpoints
│ │ ├── services/ # Core services
│ │ ├── server.ts # Server loader
│ │ └── fwd.ts # CLI forwarding tool
│ ├── client/ # Lit-based web UI
│ │ ├── assets/ # Static files (fonts, icons, html)
│ │ ├── components/ # UI components
│ │ ├── services/ # Client services
│ │ └── utils/ # Client utilities
│ ├── test/ # Test files
│ └── index.ts # Main entry point
├── scripts/ # Build scripts
└── public/ # Built static assets (generated)
Server Architecture (src/server/)
Core Components
Entry Points
index.ts(1-25): Main entry point, chooses between server and forward modesserver/server.ts(1-4): Simple loader for modular serverserver/index.ts(1-49): Server initialization, cleanup intervals, graceful shutdownserver/app.ts(198-404): Express app factory, CLI parsing, mode configuration
Server Modes
- Normal Mode: Standalone terminal server
- HQ Mode (
--hq): Central server managing remotes - Remote Mode (
--hq-url): Registers with HQ server
Authentication (middleware/auth.ts)
- Basic Auth: Username/password (46-55)
- Bearer Token: HQ↔Remote communication (28-44)
- Health endpoint bypass (14-16)
Session Management
PTY Manager (pty/pty-manager.ts)
createSession()(155-287): Spawns PTY processes- Supports
forwardToStdoutoption for direct stdout forwarding - Supports
onExitcallback for handling process termination - Automatic alias resolution: Uses
ProcessUtils.resolveCommand()to detect and run aliases through shell
- Supports
sendInput()(515-588): Handles keyboard inputkillSession()(687-764): SIGTERM→SIGKILL escalationresizeSession()(638-681): Terminal dimension changes- Control pipe support using file watching on all platforms (414-475)
shutdown()(937-974): Clean termination of all active sessions- Proper TypeScript types throughout (no "as any" assertions)
Process Utils (pty/process-utils.ts)
resolveCommand()(168-242): Detects if command exists in PATH or needs shell execution- Uses
which(Unix) orwhere(Windows) to check command existence - Returns appropriate shell command with args for aliases/builtins
- Platform-specific shell argument handling
- Uses
getUserShell()(219-281): Determines user's preferred shell- Checks
$SHELLenvironment variable first - Windows: Checks for pwsh, PowerShell, Git Bash, then cmd.exe
- Unix: Checks common shell paths (/bin/zsh, /bin/bash, etc.)
- Checks
Session Manager (pty/session-manager.ts)
- Session persistence in
~/.vibetunnel/control/ listSessions()(155-224): Filesystem-based discoveryupdateZombieSessions()(231-257): Dead process cleanup
Terminal Manager (services/terminal-manager.ts)
- Headless xterm.js for server-side state (40-69)
getBufferSnapshot()(255-323): Captures terminal bufferencodeSnapshot()(328-555): Binary protocol encoding- Debounced buffer notifications (627-642)
API Routes (routes/)
Sessions (sessions.ts)
GET /api/sessions(40-120): List with HQ aggregation- Returns array of
SessionEntryWithIdobjects with additional fields:- All fields from
SessionEntryWithId(see types.ts) source: 'local' | 'remote'- For remote sessions:
remoteId,remoteName,remoteUrl
- All fields from
- Returns array of
POST /api/sessions(123-199): Create local/remoteDELETE /api/sessions/:id(270-323): Kill sessionGET /api/sessions/:id/stream(517-627): SSE streaming of asciinema cast filesPOST /api/sessions/:id/input(630-695): Send inputPOST /api/sessions/:id/resize(698-767): Resize terminalGET /api/sessions/:id/buffer(569-631): Binary snapshot of current terminal viewGET /api/sessions/:id/text(504-654): Plain text of current terminal view- Optional
?stylesquery parameter adds style markup - Style format:
[style fg="color" bg="color" bold italic ...]text[/style] - Colors: indexed (0-255) as
"15", RGB as"255,128,0" - Attributes: bold, dim, italic, underline, inverse, invisible, strikethrough
- Optional
GET /api/sessions/activity(255-311): Activity status for all sessions- Returns:
{ [sessionId]: ActivityStatus }where ActivityStatus includes:isActive: boolean - Currently generating outputtimestamp: string - Last update timesession: SessionInfo object (see types.ts)
- In HQ mode: aggregates activity from all remote servers
- Returns:
GET /api/sessions/:id/activity(314-370): Activity status for specific session- Returns:
ActivityStatusobject (same format as above) - In HQ mode: forwards to appropriate remote server
- Returns:
Remotes (remotes.ts) - HQ Mode Only
GET /api/remotes(15-27): List registered serversPOST /api/remotes/register(30-52): Remote registrationDELETE /api/remotes/:id(55-69): Unregister remote
Logs (logs.ts)
POST /api/logs/client(24-56): Client-side log submission- Accepts:
{ level, module, args } - Prefixes module with
CLIENT:for identification
- Accepts:
GET /api/logs/raw(59-76): Stream raw log fileGET /api/logs/info(79-104): Log file metadataDELETE /api/logs/clear(107-121): Clear log file
Binary Buffer Protocol
Note: "Buffer" refers to the current terminal display state (visible viewport) without scrollback history - just what's currently shown at the bottom of the terminal. This is used for rendering terminal previews in the session list.
Format (terminal-manager.ts:361-555)
Header (32 bytes):
- Magic: 0x5654 "VT" (2 bytes)
- Version: 0x01 (1 byte)
- Flags: reserved (1 byte)
- Dimensions: cols, rows (8 bytes)
- Cursor: X, Y, viewport (12 bytes)
- Reserved (4 bytes)
Rows: 0xFE=empty, 0xFD=content
Cells: Variable-length with type byte
SSE Streaming and Asciinema Files
File Writing (pty/asciinema-writer.ts)
- AsciinemaWriter (separate file) writes cast files to
~/.vibetunnel/control/[sessionId]/stream-out - Used by PtyManager when creating sessions
- Records in asciinema v2 format with custom extensions:
- Standard:
[timestamp, "o", output]for terminal output - Standard:
[timestamp, "i", input]for user input - Standard:
[timestamp, "r", "colsxrows"]for resize events - Custom:
["exit", exitCode, sessionId]when process terminates
- Standard:
SSE Streaming (routes/sessions.ts:517-627)
- Streams asciinema cast files from disk in real-time
- StreamWatcher monitors file changes and broadcasts to clients
- Replays existing content first (timestamps zeroed)
- Watches for new content and streams incrementally
- Closes connections on exit event
Client Playback (client/utils/cast-converter.ts)
- Parses asciinema v2 format
- Handles custom exit event to dispatch
session-exit - Supports batch loading and real-time streaming
WebSocket (services/buffer-aggregator.ts)
- Client connections (31-68)
- Message handling (69-127)
- Local session buffers (131-195)
- Remote session proxy (200-232)
- Binary message format (136-164)
Activity Monitoring (services/activity-monitor.ts)
Overview
Monitors all terminal sessions for activity by watching stream-out file changes.
- Works for ALL sessions regardless of creation method (server or fwd.ts)
- No performance impact on terminal output
- File-based persistence for cross-process access
Implementation
start()(26-37): Begins monitoring with 100ms check intervalscanSessions()(61-98): Discovers and monitors session directorieshandleFileChange()(146-168): Detects output by file size increaseupdateActivityStates()(173-182): Marks inactive after 500ms timeoutwriteActivityStatus()(187-198): Persists toactivity.jsonper session
Activity Status Format
{
"isActive": boolean,
"timestamp": "ISO 8601 date string",
"session": { // SessionInfo object from session.json
"cmdline": ["command", "args"],
"name": "session name",
"cwd": "/working/directory",
"pid": 12345,
"status": "starting" | "running" | "exited",
"exit_code": 0,
"started_at": "ISO 8601 date string",
"term": "xterm-256color",
"spawn_type": "pty"
}
}
HQ Mode Components
Remote Registry (services/remote-registry.ts)
- Health checks every 15s (118-146)
- Session ownership tracking (82-96)
- Bearer token authentication
HQ Client (services/hq-client.ts)
- Registration with HQ (29-58)
- Unregister on shutdown (60-72)
Logging Infrastructure (utils/logger.ts)
Server Logger
- Unified logging with file and console output
- Log levels: log, warn, error, debug
- File output to
~/.vibetunnel/log.txt - Formatted timestamps and module names
- Debug mode toggle
- Style guide compliance (see LOGGING_STYLE_GUIDE.md)
Client Logger (client/utils/logger.ts)
- Mirrors server logger interface
- Logs to browser console
- Sends logs to
/api/logs/clientendpoint - Objects formatted as JSON before sending
- Integrates with server logging system
Client Architecture (src/client/)
Core Components
Entry Points
app-entry.ts- Main application entry pointtest-terminals-entry.ts- Test terminals entry pointstyles.css- Global styles
Main Application Component
app.ts- Lit-based SPA (15-331)- URL-based routing
?session=<id> - Global keyboard handlers
- Error/success message handling (74-90)
- Events fired:
toggle-nav- Toggle navigationnavigate-to-list- Navigate to session listerror- Display error messagesuccess- Display success messagenavigate- Navigate to specific session
- Events listened: Various events from child components
- URL-based routing
Component Event Architecture
Terminal Components
terminal.ts - Custom DOM terminal renderer (17-1000+)
Full terminal implementation with xterm.js for rendering and input handling.
- Virtual scrolling (537-555)
- Touch/momentum support
- URL highlighting integration
- Copy/paste handling
- Events fired:
terminal-ready- When terminal is initialized and readyterminal-input- When user types (detail: string)terminal-resize- When terminal is resized (detail: { cols: number, rows: number })url-clicked- When a URL is clicked (detail: string)
session-view.ts - Full-screen terminal view (29-1331)
Full-screen terminal view for an active session. Handles terminal I/O, streaming updates via SSE, file browser integration, and mobile overlays.
- SSE streaming (275-333)
- Mobile input overlays
- Resize synchronization
- Events fired:
navigate-to-list- When navigating back to session listerror- When an error occurs (detail: string)warning- When a warning occurs (detail: string)
- Events listened:
session-exit- From SSE stream when session exitsterminal-ready- From terminal component when readyfile-selected- From file browser when file is selectedbrowser-cancel- From file browser when cancelled
vibe-terminal-buffer.ts - Terminal buffer display (25-268)
Displays a read-only terminal buffer snapshot with automatic resizing. Subscribes to buffer updates via WebSocket and renders the terminal content.
- Events fired:
content-changed- When terminal content changes (no detail)
Session Management Components
session-list.ts - Active sessions list view (61-700+)
Main session list view showing all active terminal sessions with real-time updates, search/filtering, and session management capabilities.
- Events fired:
navigate- When clicking on a session (detail: { sessionId: string })error- When an error occurs (detail: string)success- When an operation succeeds (detail: string)session-created- When a new session is created (detail: Session)session-updated- When a session is updated (detail: Session)sessions-changed- When the session list changestoggle-create-form- When toggling the create form
- Events listened:
session-created- From create formcancel- From create formerror- From create form
session-card.ts - Individual session card (31-420+)
Individual session card component showing terminal preview and session controls. Displays a live terminal buffer preview and detects activity changes.
- Events fired:
view-session- When viewing a session (detail: Session)kill-session- When killing a session (detail: Session)copy-session-id- When copying session ID (detail: Session)
- Events listened:
content-changed- From vibe-terminal-buffer component
session-create-form.ts - New session creation form (27-381)
Modal dialog for creating new terminal sessions. Provides command input, working directory selection, and options for spawning in native terminal.
- Events fired:
session-created- When session is successfully created (detail: { sessionId: string, message?: string })cancel- When form is cancellederror- When creation fails (detail: string)
- Events listened:
file-selected- From file browser when directory is selectedbrowser-cancel- From file browser when cancelled
UI Components
app-header.ts - Application header (15-280+)
Main application header with logo, title, navigation controls, and session status.
- Events fired:
toggle-nav- Toggle navigation menunavigate-to-list- Navigate to session listtoggle-create-form- Toggle session create formtoggle-theme- Toggle dark/light themeopen-settings- Open settings modal
file-browser.ts - File browser component (48-665)
Modal file browser for navigating the filesystem and selecting files/directories. Supports Git status display, file preview with Monaco editor, and diff viewing.
- Events fired:
insert-path- When inserting a file path into terminal (detail: { path: string, type: 'file' | 'directory' })open-in-editor- When opening a file in external editor (detail: { path: string })directory-selected- When a directory is selected in 'select' mode (detail: string)browser-cancel- When the browser is cancelled or closed
log-viewer.ts - System log viewer (1-432)
Real-time log viewer with filtering and search capabilities.
- SSE-style polling every 2 seconds
- Client/server log distinction
- Log level filtering
- Relative timestamps
- Mobile-responsive layout
- Mac-style auto-hiding scrollbars
- Features:
- Filter by log level (error, warn, log, debug)
- Toggle client/server logs
- Search/filter by text
- Auto-scroll (smart - only when near bottom)
- Download logs
- Clear logs
Icon Components
vibe-logo.ts- Application logoterminal-icon.ts- Terminal iconcopy-icon.ts- Copy icon
Services
Buffer Subscription (services/buffer-subscription-service.ts)
- WebSocket client (30-87)
- Binary protocol decoder (163-208)
- Auto-reconnection with backoff
Utils
Cast Converter (utils/cast-converter.ts)
- Asciinema v2 parser (31-82)
- SSE stream handler (294-427)
- Batch loading (221-283)
Terminal Renderer (utils/terminal-renderer.ts)
- Binary buffer decoder (279-424)
- HTML generation
- Style mapping
Additional Utilities
url-highlighter.ts- URL detection and highlightingxterm-colors.ts- Terminal color definitionsterminal-preferences.ts- Terminal preference management
Forward Tool (src/server/fwd.ts)
Purpose
Simplified CLI tool that spawns PTY sessions using VibeTunnel infrastructure.
Key Features
- Interactive terminal forwarding with colorful output (chalk)
- Session creation with pre-generated IDs support
- Graceful cleanup on exit
- Automatic shell alias support via ProcessUtils.resolveCommand()
Usage
npx tsx src/fwd.ts [--session-id <id>] <command> [args...]
# Examples with aliases
npx tsx src/fwd.ts claude-danger # Automatically resolved through shell
Integration Points
- Uses PtyManager for all session management
- Control pipe and stdin forwarding handled by PtyManager
- Automatic cleanup via PtyManager's shutdown() method
Key Files Quick Reference
Server Core
src/index.ts: Main entry pointsrc/server/server.ts: Server loadersrc/server/app.ts: App configuration, CLI parsingsrc/server/middleware/auth.ts: Authentication logicsrc/server/routes/sessions.ts: Session API endpointssrc/server/pty/pty-manager.ts: PTY process management with file-watching control pipessrc/server/pty/asciinema-writer.ts: Cast file writersrc/server/services/terminal-manager.ts: Terminal state & binary protocolsrc/server/services/buffer-aggregator.ts: WebSocket buffer distributionsrc/server/services/stream-watcher.ts: SSE file streamingsrc/server/services/activity-monitor.ts: Session activity detectionsrc/server/fwd.ts: Simplified CLI forwarding tool
Client Core
src/client/app-entry.ts: Application entry pointsrc/client/app.ts: Main SPA componentsrc/client/components/terminal.ts: Terminal renderersrc/client/components/session-view.ts: Session viewersrc/client/components/session-list.ts: Session list viewsrc/client/services/buffer-subscription-service.ts: WebSocket clientsrc/client/utils/cast-converter.ts: Asciinema parsersrc/client/assets/: Static files (fonts, icons, HTML)
Configuration
- Environment:
PORT,VIBETUNNEL_USERNAME,VIBETUNNEL_PASSWORD,VIBETUNNEL_DEBUG - CLI:
--port,--username,--password,--hq,--hq-url,--name - Express static:
.htmlextension handling for clean URLs - Debug logging: Set
VIBETUNNEL_DEBUG=1orVIBETUNNEL_DEBUG=true
Protocols
- REST API: Session CRUD, terminal I/O, activity status
- SSE: Real-time streaming of asciinema cast files from disk
- WebSocket: Binary buffer updates (current terminal viewport)
- Control pipes: External session control
Session Data Storage
Each session has a directory in ~/.vibetunnel/control/[sessionId]/ containing:
session.json: Session metadatastream-out: Asciinema cast file with terminal outputstdin: Input pipe for sending keystrokescontrol: Control pipe for resize/kill commandsactivity.json: Activity status (written by ActivityMonitor)
Development Notes
Architecture Changes (Recent)
- PTY Manager now uses file watching for control pipes on all platforms (not just FIFO)
- No global exit handlers - clean shutdown via
shutdown()method - Simplified fwd.ts - control pipe and stdin forwarding handled by PTY Manager
- Added proper TypeScript types throughout (removed all "as any" assertions)
- Cleaned up logging and added colorful output messages using chalk
- Unified logging infrastructure:
- Server-wide adoption of structured logger
- Client-side logger with server integration
- Centralized log viewer at
/logs - Consistent style guide (LOGGING_STYLE_GUIDE.md)
- Express enhancements:
- Auto
.htmlextension resolution for static files
- Auto
Build System
pnpm run dev: Auto-rebuilds TypeScriptpnpm run build: Full build including Node.js SEA executable- ESBuild: Fast bundling
- Node.js SEA: Creates standalone executable (Node.js 20+ required)
- Vitest: Testing framework
- Assets: Copied from
src/client/assets/topublic/during build
Testing
- Unit tests:
pnpm test - E2E tests:
pnpm run test:e2e - Integration:
pnpm run test:integration
Key Dependencies
- node-pty: Cross-platform PTY
- @xterm/headless: Terminal emulation
- Lit: Web components
- Express: HTTP server
- TailwindCSS: Styling