- Full IDE with terminal integration using xterm.js - Session management with local and web sessions - HTML preview functionality - Multi-terminal support with session picker Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
13 KiB
Web-Based Terminal Integration for Claude Code CLI
Date: 2025-01-19 Status: Designed Author: Claude (with user collaboration)
Overview
Add full-featured web-based terminals to the Claude Code web interface, allowing users to open multiple terminal tabs that can run independently or attach to Claude Code sessions. Users get full interactive shell access with xterm.js, powered by node-pty and WebSocket communication.
Design Philosophy
Power + Simplicity: Provide full shell capabilities (as user already has SSH access) with intelligent defaults and easy restoration. No artificial restrictions - the user is the developer and knows what they're doing.
Core Features
1. Terminal Panel
- Location: Dedicated "🖥️ Terminal" tab in IDE navbar (next to Chat, Files, etc.)
- Multi-tab: Open unlimited terminals, switch between them
- Tab information: Shows session ID, mode, current directory
- Controls: New terminal, close, mode toggle, clear screen
2. Terminal Modes
- Session Mode (🔵): View Claude Code CLI output (stdio/stderr from session process)
- Shell Mode (🟢): Independent shell for running commands
- Mixed Mode (🟡): Both session output AND shell access (default)
3. Directory Selection
- Modal picker when creating new terminal
- Shows recent directories (last 5 used)
- Custom path input
- All terminals inherit chosen working directory
4. Session Attachment
- Attach any terminal to a Claude Code session
- See what Claude "sees" - file operations, tool output
- Switch between viewing session and running commands
- Perfect for debugging and understanding Claude's actions
5. Auto-Restore
- Always saves terminal setup automatically
- On page reload/refresh: all terminals close
- Shows: "📝 Previous session: 3 terminal(s) [Restore All] [Dismiss]"
- One-click restore recreates terminals with same configuration
- Fresh PTY processes, but same directories/sessions/modes
6. Security & Safety
- Warning modal on first terminal use (can be dismissed)
- Full shell access - no artificial restrictions (user has SSH anyway)
- All commands logged to
.claude-ide/terminal-logs.jsonl - No sudo blocking - user controls their own system
- Processes killed on page close (no orphans)
Architecture
Frontend Components
Terminal View (new tab)
├── Terminal Header
│ ├── Terminal Tabs (list of open terminals)
│ └── [+ New Terminal] button
└── Active Terminal Container
├── Terminal Toolbar
│ ├── Terminal info (ID, path, mode)
│ └── Controls (mode toggle, clear, close)
└── xterm.js Container
Backend Architecture
Frontend (xterm.js)
↓ WebSocket
TerminalController (Node.js)
↓ spawn + pty
Pseudo-terminal (node-pty)
↓ bidirectional I/O
├── Shell Process (bash/zsh)
└── OR Claude Session Process
Data Flow
Creating a Terminal:
- User clicks "+ New Terminal"
- Directory picker modal shows
- User selects directory
- POST
/claude/api/terminalswith{ workingDir, sessionId?, mode } - Backend creates PTY with shell in working directory
- Returns terminal ID
- Frontend opens WebSocket:
ws://host/claude/api/terminals/{id}/ws - xterm.js initializes, begins receiving/sending I/O
- If attached to session, pipe session output to PTY
Terminal I/O Loop:
User types in xterm.js
↓ WebSocket send
Backend receives message
↓ Write to PTY
Shell/Claude process executes
↓ PTY emits data
Backend reads PTY output
↓ WebSocket send
xterm.js displays data
Technical Implementation
New Dependencies
npm install xterm xterm-addon-fit xterm-addon-web-links node-pty @ws/websocket
Backend Files
/services/terminal-service.js - Core terminal management
class TerminalService {
constructor()
createServer(server) // Setup WebSocket server
createTerminal(options) // Create PTY with shell
handleConnection(terminalId, ws) // WebSocket I/O handling
attachToSession(terminal, session) // Pipe session output to PTY
closeTerminal(terminalId) // Kill PTY process
}
New API Endpoints:
POST /claude/api/terminals- Create terminalDELETE /claude/api/terminals/:id- Close terminalGET /claude/api/terminals- List active terminalsPOST /claude/api/terminals/:id/attach- Attach to sessionGET /claude/api/claude/terminal-restore- Get saved stateGET /claude/api/files/recent-dirs- Get recent directories
Frontend Files
/public/claude-ide/terminal.js - Terminal manager
class TerminalManager {
loadXTerm() // Load xterm CSS dynamically
createTerminal(options) // Create terminal UI + WebSocket
switchToTerminal(id) // Switch active terminal
closeTerminal(id) // Close terminal
setMode(id, mode) // Change session/shell/mixed mode
restoreTerminals(savedState) // Restore previous session
}
Modifications to /public/claude-ide/ide.js:
- Add terminal view handling
- Add restore prompt logic
- Integrate with existing navigation
Modifications to /public/claude-ide/index.html:
- Add Terminal tab to navbar
- Add terminal-view div to main content
Key Features Detail
Mode Switching
Session Mode:
- Shows only Claude Code CLI output
- Read-only view into what Claude does
- Useful for debugging tool usage, file operations
Shell Mode:
- Independent bash/zsh shell
- User types commands directly
- No session output shown
- Like opening a terminal anywhere else
Mixed Mode (Default):
- Shows both session output AND shell commands
- User can type commands while seeing Claude's work
- Perfect for development workflow
- Toggle which output is visible
Session Attachment
When attaching terminal to a session:
- Backend creates pipe from session.stdout to PTY input
- Session.stderr shown in red color
- Session messages appear interleaved with shell output
- User can interact with both simultaneously
Directory Picker
Shows recently used directories:
- Current session's working directory
- Last 5 directories used in any terminal
- Obsidian vault paths
- User can type custom path
State Persistence
Saved in .claude-ide/terminal-state.json:
{
"timestamp": "2025-01-19T14:30:00Z",
"terminals": [
{
"id": "term-1",
"workingDir": "/home/uroma/obsidian-vault",
"sessionId": "session-abc",
"mode": "mixed",
"order": 0
}
]
}
Restoration:
- On page load, check for saved state
- If found, show non-intrusive toast
- "Restore All" recreates terminals (new PTY processes)
- "Dismiss" ignores saved state
- Toast auto-dismisses after 30 seconds
Security Considerations
Logging
All commands logged to /home/uroma/obsidian-vault/.claude-ide/terminal-logs.jsonl:
{"timestamp":"2025-01-19T14:30:00Z","terminalId":"term-1","command":"ls -la","user":"uroma"}
First-Time Warning
Modal shown on first terminal use:
⚠️ Terminal Access
You're about to open a full shell terminal.
This gives you complete command-line access.
[ ] Don't show this warning again
[Cancel] [Open Terminal]
Resource Limits
- No hard limit on terminal count (practical limit ~10)
- Each terminal ~10-20MB memory
- All terminals killed on:
- Page close
- Browser crash
- Server restart
- User logout
UI Design
Terminal Panel Layout
┌─────────────────────────────────────────────────────────┐
│ 🖥️ Terminals [+ New] │
├─────────────────────────────────────────────────────────┤
│ ┌───────────────────────────────────────────────────┐ │
│ │ session-abc123 │ ▀ │ 🟡 Mixed │ ~/obsidian-vault │ │
│ │ [Close] [Split] │ │
│ ├───────────────────────────────────────────────────┤ │
│ │ $ npm test │ │
│ │ Tests running... │ │
│ │ ✓ Test 1 passed │ │
│ │ ✓ Test 2 passed │ │
│ │ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ [Terminal Tab 2] [Terminal Tab 3] │
└─────────────────────────────────────────────────────────┘
Keyboard Shortcuts
Ctrl+Shift+T- Open new terminalCtrl+Shift+W- Close current terminalCtrl+Tab- Next terminal tabCtrl+Shift+Tab- Previous terminal tabCtrl+Shift+M- Toggle terminal mode
Color Scheme
xterm.js theme matching existing IDE:
- Background:
#1a1a1a - Foreground:
#e0e0e0 - Cursor:
#4a9eff - Selection:
rgba(74, 158, 255, 0.3) - Session stderr: Red
\x1b[31m
Implementation Plan
Phase 1: Backend Setup
- Install dependencies:
xterm,node-pty,ws - Create
terminal-service.js - Add API endpoints to
server.js - Implement WebSocket server
- Test terminal creation and I/O
Phase 2: Frontend Terminal Panel
- Add terminal view to
index.html - Implement
terminal.jswith xterm.js integration - Create directory picker modal
- Implement tab management
- Add keyboard shortcuts
Phase 3: Session Integration
- Implement session attachment logic
- Add mode switching (session/shell/mixed)
- Pipe session output to PTY
- Test with active Claude Code sessions
Phase 4: Polish & Features
- Implement auto-save/restore
- Add first-time warning modal
- Implement command logging
- Add recent directories tracking
- Test edge cases
Phase 5: Testing
- Test multiple terminals simultaneously
- Test session attachment
- Test mode switching
- Test restore after page refresh
- Test with various commands (vim, htop, etc.)
Success Criteria
- ✅ Can open unlimited terminal tabs
- ✅ Each terminal runs in chosen directory
- ✅ Can attach terminal to Claude Code session
- ✅ Can switch between session/shell/mixed modes
- ✅ Terminal I/O is responsive (no lag)
- ✅ Terminals restore after page refresh
- ✅ All commands are logged
- ✅ Works with existing sessions
- ✅ Keyboard shortcuts work correctly
- ✅ No memory leaks or orphaned processes
Future Enhancements (Not in MVP)
- Split terminals - Divide terminal panes vertically/horizontally
- Terminal sharing - Share terminal URL with collaborators
- Command history - Show history of commands across terminals
- Search in terminal - Search/backscroll through output
- Download output - Save terminal output to file
- Multiple shells - Support zsh, fish, pwsh, etc.
- Custom fonts/themes - User-configurable appearance
Files to Create
/services/terminal-service.js- Terminal backend logic/public/claude-ide/terminal.js- Terminal frontend manager/public/claude-ide/terminal.css- Terminal panel styles/home/uroma/obsidian-vault/.claude-ide/terminal-logs.jsonl- Command log
Files to Modify
/server.js- Add terminal API endpoints/public/claude-ide/index.html- Add Terminal tab and view/public/claude-ide/ide.js- Add terminal view navigation
Dependencies
{
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0",
"xterm-addon-web-links": "^0.9.0",
"node-pty": "^1.0.0",
"ws": "^8.16.0"
}
Notes
- PTY processes cannot be serialized, so restoration creates new processes
- WebSocket reconnection is supported if network drops temporarily
- Process cleanup happens automatically on page close/navigation
- Memory usage per terminal is ~10-20MB (practical limit ~50 terminals)
- CPU usage is minimal when terminals are idle
- Security is maintained by session-based authentication
- Logging is for debugging and auditing, not surveillance
Design Status: ✅ Complete and approved Ready for Implementation: Yes Estimated Implementation Time: 3-4 days (5 phases)