diff --git a/gui/tabs/terminal_tab.py b/gui/tabs/terminal_tab.py index d8b4e3d..7787e5a 100644 --- a/gui/tabs/terminal_tab.py +++ b/gui/tabs/terminal_tab.py @@ -3,12 +3,16 @@ Terminal tab — persistent interactive SSH shell via ShellSession + TerminalWid """ import queue +import re import threading import time import customtkinter as ctk from core.ssh_client import ShellSession from core.i18n import t +# Regex to strip ANSI escape sequences +_ANSI_RE = re.compile(r'\x1b\[[0-9;]*[a-zA-Z]|\x1b\].*?\x07|\x1b[()][AB012]|\x1b\[?\d*[a-zA-Z]') + class TerminalTab(ctk.CTkFrame): def __init__(self, master, store, session_pool=None): @@ -161,14 +165,20 @@ class TerminalTab(ctk.CTkFrame): # Sudo auto-password: only check if not already sent if not self._sudo_sent and self._session: self._sudo_buffer += combined - self._sudo_buffer = self._sudo_buffer[-300:] + self._sudo_buffer = self._sudo_buffer[-500:] buf_str = self._sudo_buffer.decode("utf-8", errors="replace") - # Only match actual sudo password prompt — NOT log output - last_line = buf_str.rstrip().rsplit("\n", 1)[-1].strip() + # Strip ANSI escapes and normalize line endings + clean = _ANSI_RE.sub("", buf_str) + clean = clean.replace("\r\n", "\n").replace("\r", "\n") + last_line = clean.rstrip().rsplit("\n", 1)[-1].strip() if "[sudo] password for" in last_line: server = self.store.get_server(self._current_alias) if server and server.get("password"): - self._session.send(server["password"].encode() + b"\n") + # Small delay — let the PTY settle before sending + def _send_sudo_pass(): + if self._session and self._session.connected: + self._session.send(server["password"].encode() + b"\n") + self.after(200, _send_sudo_pass) self._sudo_sent = True self._sudo_buffer = b"" diff --git a/releases/ServerManager-v1.8.6-win-x64.exe b/releases/ServerManager-v1.8.6-win-x64.exe index 5e2a4f1..44e0dd0 100644 Binary files a/releases/ServerManager-v1.8.6-win-x64.exe and b/releases/ServerManager-v1.8.6-win-x64.exe differ