Skip to content

Frontend: AgentTerminal component — XTerm.js interactive terminal for session workspace #506

@frankbria

Description

@frankbria

Parent Issue

Part of #500

Context

Interactive sessions need a terminal view so users can inspect the workspace, run tests, or verify changes made by the agent. This component provides an XTerm.js-based terminal wired to a backend WebSocket endpoint that shells into the session's workspace directory.

Backend Prerequisite

A simple terminal WebSocket endpoint is needed:

WS /ws/sessions/{id}/terminal?token=<JWT>

This shells a bash process in the session's workspace_path. The backend work is small (~30 lines using asyncio.create_subprocess_exec + WebSocket relay). It can be done in this same issue or as a quick addition to the API built in #502.

What to Build

1. Backend terminal endpoint (small — add to codeframe/ui/routers/session_chat_ws.py)

@router.websocket("/ws/sessions/{session_id}/terminal")
async def session_terminal(websocket: WebSocket, session_id: str, ...):
    # Authenticate JWT
    # Load session, get workspace_path
    # Spawn bash in workspace_path via asyncio.create_subprocess_exec
    # Relay stdin↔stdout between WebSocket and subprocess
    # Handle resize events: {"type": "resize", "cols": 120, "rows": 40}
    # Clean up subprocess on disconnect

2. Frontend component: web-ui/src/components/sessions/AgentTerminal.tsx

Props:

interface AgentTerminalProps {
  sessionId: string;
  className?: string;
}

Implementation:

  1. Install xterm and xterm-addon-fit (check if already in package.json; add if not)
  2. Mount XTerm.js instance on a <div ref> on component mount
  3. Connect WebSocket to /ws/sessions/{sessionId}/terminal?token=<JWT>
  4. Relay terminal input (user keystrokes) → WS → subprocess stdin
  5. Relay subprocess stdout → WS → terminal.write(data)
  6. On window/container resize: fit addon → send { type: "resize", cols, rows } over WS
  7. On WS disconnect: show reconnecting overlay, auto-retry (max 3 attempts)
  8. On unmount: close WS and dispose XTerm instance

Styling:

  • Dark background (#0a0a0c matching the app theme)
  • Purple cursor (brand primary color)
  • Monospace font (use existing JetBrains Mono CSS variable if available, or fallback to monospace)
  • Fit to container with FitAddon — no fixed height
  • Connection status overlay on disconnect: semi-transparent dark overlay with "Reconnecting..." message

Acceptance Criteria

  • Terminal renders in the component container with correct dark theme
  • Keystrokes are relayed to the backend subprocess in real-time
  • Subprocess output appears in the terminal
  • Terminal resizes correctly when container size changes
  • Disconnect shows overlay; reconnects automatically
  • XTerm instance is properly disposed on unmount (no memory leaks)
  • Working ls, cat, git status in the session workspace

Notes

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions