v1.8.6: fix sudo detection, terminal copy/paste

- Tighten sudo auto-password to only match "[sudo] password for" in last line (fixes journalctl hang)
- Remove state="disabled" from terminal widget (fixes copy/paste on Windows)
- Copy: Ctrl+C (with selection), Ctrl+Shift+C, right-click menu
- Paste: Ctrl+V, Ctrl+Shift+V, right-click menu

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-24 03:58:53 -05:00
parent f7c7fe731f
commit c597fe9e5d
4 changed files with 17 additions and 11 deletions

View File

@@ -156,19 +156,21 @@ class TerminalTab(ctk.CTkFrame):
pass
if chunks:
combined = b"".join(chunks)
self._sudo_buffer += combined
# Keep only last 200 bytes for pattern matching
self._sudo_buffer = self._sudo_buffer[-200:]
self._terminal.feed(combined)
if not self._sudo_sent:
buf_str = self._sudo_buffer.decode("utf-8", errors="replace").lower()
if "[sudo] password for" in buf_str or buf_str.rstrip().endswith("password:"):
# 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:]
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()
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")
self._sudo_sent = True
self._terminal.feed(combined)
self._sudo_buffer = b""
def _on_disconnected(self):
"""Called from SSH read thread."""

View File

@@ -522,7 +522,9 @@ class TerminalWidget(tk.Frame):
self._prev_cursor_y = cursor.y
self._prev_cursor_hidden = cursor_hidden
self._text.configure(state="disabled")
# Keep text widget in "normal" state — all input is handled
# by key bindings returning "break", so no user editing is possible.
# "disabled" state breaks mouse selection on Windows.
def _make_tags(self, fg, bg, bold, italic, underline, reverse,
strikethrough) -> tuple:
@@ -853,7 +855,9 @@ class TerminalWidget(tk.Frame):
"""Select all text in terminal."""
self._text.configure(state="normal")
self._text.tag_add("sel", "1.0", "end-1c")
self._text.configure(state="disabled")
# Keep text widget in "normal" state — all input is handled
# by key bindings returning "break", so no user editing is possible.
# "disabled" state breaks mouse selection on Windows.
def _on_mousewheel(self, event):
# Ctrl+wheel → zoom

Binary file not shown.

View File

@@ -1,6 +1,6 @@
"""Version info for ServerManager."""
__version__ = "1.8.5"
__version__ = "1.8.6"
__app_name__ = "ServerManager"
__author__ = "aibot777"
__description__ = "Desktop GUI for managing remote servers"