diff --git a/apps/api/src/services/terminal_session.py b/apps/api/src/services/terminal_session.py index 6b5d349..755722d 100644 --- a/apps/api/src/services/terminal_session.py +++ b/apps/api/src/services/terminal_session.py @@ -142,11 +142,6 @@ class TerminalSession: if self._closed: logger.warning("Cannot resize: session is closed") return - - # Only resize if dimensions actually changed - if self._cols == cols and self._rows == rows: - return - self._cols = cols self._rows = rows logger.info(f"resize() called for session {self.session_id}: {cols}x{rows}") @@ -154,9 +149,12 @@ class TerminalSession: # Docker exec doesn't forward PTY resize to the container process, # so we need to explicitly set the size inside the container shell. - stty_cmd = f"stty cols {cols} rows {rows}\n".encode() - await self.write_input(stty_cmd) - logger.info(f"Sent stty command to container for session {self.session_id}: {cols}x{rows}") + # Only do this on the first resize to avoid interfering with user input. + if not getattr(self, '_stty_sent', False): + self._stty_sent = True + stty_cmd = f"stty cols {cols} rows {rows}\n".encode() + await self.write_input(stty_cmd) + logger.info(f"Sent stty command 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 2235ca9..38710d7 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -254,15 +254,16 @@ export const TerminalComponent: React.FC = ({ ws.send(data); }); - // Handle container resize with ResizeObserver (more reliable than window resize) + // Handle window resize with debounce let resizeTimeout: ReturnType; - const resizeObserver = new ResizeObserver(() => { + const handleResize = () => { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { fitTerminal(); - }, 100); - }); - resizeObserver.observe(container); + }, 250); + }; + + window.addEventListener("resize", handleResize); // Refit after mobile header auto-hides (3s delay + 0.3s transition) const headerHideTimeout = setTimeout(() => { @@ -297,7 +298,7 @@ export const TerminalComponent: React.FC = ({ return () => { clearTimeout(resizeTimeout); clearTimeout(headerHideTimeout); - resizeObserver.disconnect(); + window.removeEventListener("resize", handleResize); document.removeEventListener("visibilitychange", handleVisibilityChange); if (ws) { ws.close();