From 0fb419da374dc30b25bb362b702c9e655d8e9992 Mon Sep 17 00:00:00 2001 From: lim Date: Tue, 11 Nov 2025 15:46:13 +0000 Subject: [PATCH 1/8] add xterm --- components/terminal/terminal-display.tsx | 98 ++++-- components/terminal/xterm-terminal.tsx | 394 +++++++++++++++++++++++ hooks/use-terminal.ts | 142 ++++++++ lib/k8s/sandbox-manager.ts | 18 +- package.json | 5 + pnpm-lock.yaml | 56 ++++ 6 files changed, 688 insertions(+), 25 deletions(-) create mode 100644 components/terminal/xterm-terminal.tsx create mode 100644 hooks/use-terminal.ts diff --git a/components/terminal/terminal-display.tsx b/components/terminal/terminal-display.tsx index fa2656e..26e8ae9 100644 --- a/components/terminal/terminal-display.tsx +++ b/components/terminal/terminal-display.tsx @@ -1,8 +1,8 @@ /** * TerminalDisplay Component * - * Pure display component for terminal iframe - * VSCode Dark Modern theme style + * Display component for xterm.js terminal (no iframe) + * Direct WebSocket connection to ttyd backend */ 'use client'; @@ -19,8 +19,10 @@ import { } from '@/lib/util/status-colors'; import { cn } from '@/lib/utils'; +import { XtermTerminal } from './xterm-terminal'; + export interface TerminalDisplayProps { - /** ttyd URL */ + /** ttyd URL with authentication token */ ttydUrl?: string | null; /** Sandbox status */ status: string; @@ -29,40 +31,88 @@ export interface TerminalDisplayProps { } /** - * Display terminal iframe or status message - * Each terminal tab gets its own iframe with unique key to ensure separate WebSocket connections + * Display xterm.js terminal with direct WebSocket connection + * Each terminal tab gets independent WebSocket connection */ export function TerminalDisplay({ ttydUrl, status, tabId }: TerminalDisplayProps) { - const [iframeLoaded, setIframeLoaded] = useState(false); + const [terminalReady, setTerminalReady] = useState(false); + const [connectionStatus, setConnectionStatus] = useState<'connecting' | 'connected' | 'error'>( + 'connecting' + ); - // Only show terminal iframe if status is RUNNING and URL is available + // Only show terminal if status is RUNNING and ttyd URL is available if (status === 'RUNNING' && ttydUrl) { return (
- {/* Loading overlay */} - {!iframeLoaded && ( + {/* Loading overlay - show until terminal is ready and connected */} + {(connectionStatus === 'connecting' || !terminalReady) && (
- Connecting to terminal... + + {!terminalReady ? 'Loading terminal...' : 'Connecting to terminal...'} +
)} - {/* Terminal iframe - unique key per tab ensures separate WebSocket connection */} -