From b4873a5de7005d3417b01153dadcfa57d086a845 Mon Sep 17 00:00:00 2001 From: teknium1 Date: Fri, 6 Mar 2026 05:27:11 -0800 Subject: [PATCH] fix(setup): Escape skips instead of exiting, add control hints to all prompts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously pressing Escape in any setup wizard menu called sys.exit(1), killing the entire wizard with no way to recover. Now: - prompt_choice: Escape keeps the current default and moves on (prints 'Skipped (keeping current)'). Shows '↑/↓ Navigate Enter Select Esc Skip Ctrl+C Exit' hint. - prompt_checklist: Escape returns pre-selected items instead of empty list. Shows 'SPACE Toggle ENTER Confirm ESC Skip Ctrl+C Exit'. - prompt_yes_no: now catches KeyboardInterrupt/EOFError properly. - Fallback number prompts also show control hints. Ctrl+C still exits the wizard cleanly. --- hermes_cli/setup.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index 44e5e7e7..ef3a521d 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -72,7 +72,11 @@ def prompt(question: str, default: str = None, password: bool = False) -> str: sys.exit(1) def prompt_choice(question: str, choices: list, default: int = 0) -> int: - """Prompt for a choice from a list with arrow key navigation.""" + """Prompt for a choice from a list with arrow key navigation. + + Escape keeps the current default (skips the question). + Ctrl+C exits the wizard. + """ print(color(question, Colors.YELLOW)) # Try to use interactive menu if available @@ -88,6 +92,8 @@ def prompt_choice(question: str, choices: list, default: int = 0) -> int: ) menu_choices = [f" {_emoji_re.sub('', choice).strip()}" for choice in choices] + print_info(" ↑/↓ Navigate Enter Select Esc Skip Ctrl+C Exit") + terminal_menu = TerminalMenu( menu_choices, cursor_index=default, @@ -99,9 +105,10 @@ def prompt_choice(question: str, choices: list, default: int = 0) -> int: ) idx = terminal_menu.show() - if idx is None: # User pressed Escape or Ctrl+C + if idx is None: # User pressed Escape — keep current value + print_info(f" Skipped (keeping current)") print() - sys.exit(1) + return default print() # Add newline after selection return idx @@ -118,6 +125,8 @@ def prompt_choice(question: str, choices: list, default: int = 0) -> int: else: print(f" {marker} {choice}") + print_info(f" Enter for default ({default + 1}) Ctrl+C to exit") + while True: try: value = input(color(f" Select [1-{len(choices)}] ({default + 1}): ", Colors.DIM)) @@ -134,11 +143,15 @@ def prompt_choice(question: str, choices: list, default: int = 0) -> int: sys.exit(1) def prompt_yes_no(question: str, default: bool = True) -> bool: - """Prompt for yes/no.""" + """Prompt for yes/no. Ctrl+C exits, empty input returns default.""" default_str = "Y/n" if default else "y/N" while True: - value = input(color(f"{question} [{default_str}]: ", Colors.YELLOW)).strip().lower() + try: + value = input(color(f"{question} [{default_str}]: ", Colors.YELLOW)).strip().lower() + except (KeyboardInterrupt, EOFError): + print() + sys.exit(1) if not value: return default @@ -168,7 +181,7 @@ def prompt_checklist(title: str, items: list, pre_selected: list = None) -> list pre_selected = [] print(color(title, Colors.YELLOW)) - print_info("SPACE to toggle, ENTER to confirm.") + print_info(" SPACE Toggle ENTER Confirm ESC Skip Ctrl+C Exit") print() try: @@ -204,7 +217,8 @@ def prompt_checklist(title: str, items: list, pre_selected: list = None) -> list terminal_menu.show() if terminal_menu.chosen_menu_entries is None: - return [] + print_info(" Skipped (keeping current)") + return list(pre_selected) selected = list(terminal_menu.chosen_menu_indices or []) return selected