mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix: flush stdin after curses/terminal menus to prevent escape sequence leakage (#7167)
After curses.wrapper() or simple_term_menu exits, endwin() restores the terminal but does NOT drain the OS input buffer. Leftover escape-sequence bytes from arrow key navigation remain buffered and get silently consumed by the next input()/getpass.getpass() call. This caused a user-reported bug where selecting Z.AI/GLM as provider wrote ^[^[ (two ESC chars) into .env as the API key, because the buffered escape bytes were consumed by getpass before the user could type anything. Fix: add flush_stdin() helper using termios.tcflush(TCIFLUSH) and call it after every curses.wrapper() and simple_term_menu .show() return across all interactive menu sites: - hermes_cli/curses_ui.py (curses_checklist) - hermes_cli/setup.py (_curses_prompt_choice) - hermes_cli/tools_config.py (_prompt_choice) - hermes_cli/auth.py (_prompt_model_selection) - hermes_cli/main.py (3 simple_term_menu usages)
This commit is contained in:
parent
49da1ff1b1
commit
f3ae1d765d
5 changed files with 35 additions and 0 deletions
|
|
@ -10,6 +10,28 @@ from typing import Callable, List, Optional, Set
|
|||
from hermes_cli.colors import Colors, color
|
||||
|
||||
|
||||
def flush_stdin() -> None:
|
||||
"""Flush any stray bytes from the stdin input buffer.
|
||||
|
||||
Must be called after ``curses.wrapper()`` (or any terminal-mode library
|
||||
like simple_term_menu) returns, **before** the next ``input()`` /
|
||||
``getpass.getpass()`` call. ``curses.endwin()`` restores the terminal
|
||||
but does NOT drain the OS input buffer — leftover escape-sequence bytes
|
||||
(from arrow keys, terminal mode-switch responses, or rapid keypresses)
|
||||
remain buffered and silently get consumed by the next ``input()`` call,
|
||||
corrupting user data (e.g. writing ``^[^[`` into .env files).
|
||||
|
||||
On non-TTY stdin (piped, redirected) or Windows, this is a no-op.
|
||||
"""
|
||||
try:
|
||||
if not sys.stdin.isatty():
|
||||
return
|
||||
import termios
|
||||
termios.tcflush(sys.stdin, termios.TCIFLUSH)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def curses_checklist(
|
||||
title: str,
|
||||
items: List[str],
|
||||
|
|
@ -131,6 +153,7 @@ def curses_checklist(
|
|||
return
|
||||
|
||||
curses.wrapper(_draw)
|
||||
flush_stdin()
|
||||
return result_holder[0] if result_holder[0] is not None else cancel_returns
|
||||
|
||||
except Exception:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue