From 3092038e407dd246ace605b822f4e92aaea58a42 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 19:44:21 +0200 Subject: [PATCH] debug: add console logging for terminal resize debugging --- apps/api/src/services/terminal_session.py | 13 +++++++++++ apps/web/src/components/terminal.tsx | 27 +++++++++++++---------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/apps/api/src/services/terminal_session.py b/apps/api/src/services/terminal_session.py index b87110f..4302a25 100644 --- a/apps/api/src/services/terminal_session.py +++ b/apps/api/src/services/terminal_session.py @@ -164,6 +164,19 @@ class TerminalSession: ).encode() await self.write_input(stty_cmd) logger.debug(f"Sent stty resize to container for session {self.session_id}: {cols}x{rows}") + + # Docker exec doesn't forward PTY resize to the container process, + # so we need to explicitly set the size inside the container shell. + # Send on every resize so the container shell always matches the frontend. + # Use ANSI escape sequences to hide the command from view: + # - \x1b[?25l: hide cursor + # - \x1b[A\x1b[2K: move up and clear line + # - \x1b[?25h: show cursor + stty_cmd = ( + f"\x1b[?25lstty cols {cols} rows {rows}\n\x1b[A\x1b[2K\x1b[?25h" + ).encode() + await self.write_input(stty_cmd) + logger.debug(f"Sent stty resize to container for session {self.session_id}: {cols}x{rows}") async def reset(self) -> None: """Reset the session by killing the process and clearing state.""" diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index e126688..6e13cad 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -216,26 +216,29 @@ export const TerminalComponent: React.FC = ({ // Fit terminal and notify backend const fitTerminal = () => { - if (!fitAddonRef.current || !termRef.current) return; + if (!fitAddonRef.current || !termRef.current) { + console.log('[Terminal] fitTerminal: refs not ready'); + return; + } const oldCols = termRef.current.cols; const oldRows = termRef.current.rows; - // Force layout recalculation before fit - if (container) { - void container.offsetWidth; - void container.offsetHeight; - } + console.log('[Terminal] fitTerminal called, container dims:', container?.offsetWidth, container?.offsetHeight); fitAddonRef.current.fit(); const { cols, rows } = termRef.current; - if (cols !== oldCols || rows !== oldRows) { - // Delay refresh to next frame so renderer can process resize first - requestAnimationFrame(() => { - termRef.current?.refresh(0, rows - 1); - }); - } + console.log('[Terminal] fitTerminal result:', cols, rows, '(was:', oldCols, oldRows + ')'); + + // Always refresh on initial load or when dimensions change + requestAnimationFrame(() => { + termRef.current?.refresh(0, rows - 1); + }); + if (ws.readyState === WebSocket.OPEN) { + console.log('[Terminal] Sending resize:', cols, rows); ws.send(JSON.stringify({ type: "resize", cols, rows })); + } else { + console.log('[Terminal] WebSocket not open, state:', ws.readyState); } };