Chrome extension terminals were spawning successfully but only showing a blinking cursor. Typing worked (backend logs showed input being received), but no output was displayed in the terminal.
Message type mismatch in the background service worker
The backend sends terminal output with type 'terminal-output', but the background worker was only checking for 'output':
// β BROKEN - Only checked for 'output'
if (message.type === 'output') {
broadcastToClients({
type: 'TERMINAL_OUTPUT',
terminalId: message.terminalId,
data: message.data,
})
}This caused terminal output to be wrapped in WS_MESSAGE instead of TERMINAL_OUTPUT, so the Terminal component never received it.
File: extension/background/background.ts (line 39)
// β
FIXED - Check for both 'output' and 'terminal-output'
if (message.type === 'output' || message.type === 'terminal-output') {
console.log('π Terminal output received, broadcasting to clients:', message.terminalId?.slice(-8), message.data?.length, 'bytes')
broadcastToClients({
type: 'TERMINAL_OUTPUT',
terminalId: message.terminalId,
data: message.data,
})
}File: extension/components/Terminal.tsx
import { Unicode11Addon } from '@xterm/addon-unicode11'
const xterm = new XTerm({
// ... other options
allowProposedApi: true, // Required for Unicode11
})
const unicode11Addon = new Unicode11Addon()
xterm.loadAddon(unicode11Addon)
xterm.unicode.activeVersion = '11'Why: Fixes emoji width issues and improves TUI app rendering (htop, lazygit, etc.)
File: extension/sidepanel/sidepanel.tsx
- Removed redundant custom header (Chrome's sidepanel already provides one)
- Created compact toolbar with just: connection status, session count, spawn button, settings
- Removed footer that was covering tmux status bar
Before:
[Chrome Header: Terminal Tabs - Browser Edition]
[Custom Header: Terminal Tabs | Connected | Buttons]
[Session Tabs]
[Terminal View]
[Footer: 1 active session] β Covered tmux status bar
After:
[Chrome Header: Terminal Tabs - Browser Edition]
[Compact Toolbar: Connected | 1 session | + | βοΈ]
[Session Tabs]
[Terminal View] β Full height, tmux status bar visible
-
Backend logs showed terminals spawning successfully:
[success] Spawned terminal { id: '...' } -
Backend logs showed output being generated:
π¨ WS message received: terminal-output -
Background worker logs showed messages being received:
π¨ WS message received: terminal-output -
BUT Terminal component never logged receiving output:
// This never appeared: [Terminal] π TERMINAL_OUTPUT received: -
The message flow was broken at the background worker:
- Backend β WebSocket β Background Worker β
- Background Worker β Terminal Component β (wrong message type)
Backend (server.js)
β WebSocket sends: { type: 'terminal-output', terminalId: '...', data: '...' }
Background Worker (background.ts)
β Checks: message.type === 'output' || message.type === 'terminal-output' β
β Broadcasts: { type: 'TERMINAL_OUTPUT', terminalId: '...', data: '...' }
Terminal Component (Terminal.tsx)
β Receives via port connection
β Checks: message.type === 'TERMINAL_OUTPUT' β
β Writes to xterm: xtermRef.current.write(message.data)
Terminal Display β
Output visible!
extension/background/background.ts- Fixed output message type checkextension/components/Terminal.tsx- Added Unicode11 addonextension/sidepanel/sidepanel.tsx- Simplified header/footer
After the fix:
- β Terminal output displays correctly
- β Bash prompts appear
- β Command output shows
- β TUI apps render correctly (htop, lazygit, etc.)
- β Emojis display with correct width
- β Tmux status bar fully visible (no footer overlap)
- Always check message type strings exactly - Small differences like
'output'vs'terminal-output'can break the entire flow - Follow the message through each layer - Backend β WebSocket β Background Worker β Component
- Add debug logging at each step - Made it easy to see where the message flow broke
- The Unicode11 addon is essential for modern terminal apps with emojis/special characters
Date: November 17, 2025 Issue: Terminal spawned but showed only blinking cursor Fix: Message type mismatch in background worker Time to Debug: ~2 hours Result: Fully functional Chrome extension terminal! π