diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index fe8e969..6403cc6 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -82,8 +82,10 @@ export const TerminalComponent: React.FC = ({ // Send current terminal size immediately on connect if (termRef.current) { const { cols, rows } = termRef.current; - // Send resize immediately on connect - ws.send(JSON.stringify({ type: "resize", cols, rows })); + // Only send if we have valid dimensions + if (cols > 0 && rows > 0) { + ws.send(JSON.stringify({ type: "resize", cols, rows })); + } } // Start heartbeat check @@ -227,13 +229,24 @@ export const TerminalComponent: React.FC = ({ // Define fitTerminal before connectWebSocket so it's available in onmessage const fitTerminal = () => { if (!fitAddonRef.current || !termRef.current) return; + // Ensure terminal is opened and has valid dimensions + if (termRef.current.cols === 0 || termRef.current.rows === 0) return; const oldCols = termRef.current.cols; const oldRows = termRef.current.rows; - fitAddonRef.current.fit(); + try { + fitAddonRef.current.fit(); + } catch { + // Ignore fit errors during initialization + return; + } const { cols, rows } = termRef.current; - // Force refresh if dimensions changed - if (cols !== oldCols || rows !== oldRows) { - termRef.current.refresh(0, rows - 1); + // Force refresh if dimensions changed and are valid + if ((cols !== oldCols || rows !== oldRows) && cols > 0 && rows > 0) { + try { + termRef.current.refresh(0, rows - 1); + } catch { + // Ignore refresh errors + } } const currentWs = wsRef.current; if (currentWs?.readyState === WebSocket.OPEN) { @@ -241,17 +254,23 @@ export const TerminalComponent: React.FC = ({ } }; - // Initial fit after layout settles - requestAnimationFrame(() => { - requestAnimationFrame(() => { - fitTerminal(); - }); - }); - - // Open xterm immediately + // Open xterm first (must happen before fit) term.open(container); ws = connectWebSocket(); + // Initial fit after layout settles (terminal must be opened first) + const doInitialFit = () => { + if (!container.isConnected) return; + // Ensure container has dimensions before fitting + if (container.clientWidth > 0 && container.clientHeight > 0) { + fitTerminal(); + } else { + // Container not ready yet, try again + requestAnimationFrame(doInitialFit); + } + }; + requestAnimationFrame(doInitialFit); + // Refit after font load (metrics may change) document.fonts.ready.then(() => { requestAnimationFrame(() => fitTerminal());