mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix: ESC cancels secret/sudo prompts, clearer skip messaging (#9902)
- Add ESC key binding (eager) for secret_state and sudo_state modal prompts — fires immediately, same behavior as Ctrl+C cancel - Update placeholder text: 'Enter to submit · ESC to skip' (was 'Enter to skip' which was confusing — Enter on empty looked like submitting nothing rather than intentionally skipping) - Update widget body text: 'ESC or Ctrl+C to skip' - Change feedback message from 'Secret entry cancelled' to 'Secret entry skipped' — more accurate for the action taken - getpass fallback prompt also updated for non-TUI mode
This commit is contained in:
parent
55ce76b372
commit
1e5e1e822b
2 changed files with 24 additions and 6 deletions
24
cli.py
24
cli.py
|
|
@ -8631,6 +8631,24 @@ class HermesCLI:
|
||||||
self._should_exit = True
|
self._should_exit = True
|
||||||
event.app.exit()
|
event.app.exit()
|
||||||
|
|
||||||
|
_modal_prompt_active = Condition(
|
||||||
|
lambda: bool(self._secret_state or self._sudo_state)
|
||||||
|
)
|
||||||
|
|
||||||
|
@kb.add('escape', filter=_modal_prompt_active, eager=True)
|
||||||
|
def handle_escape_modal(event):
|
||||||
|
"""ESC cancels active secret/sudo prompts."""
|
||||||
|
if self._secret_state:
|
||||||
|
self._cancel_secret_capture()
|
||||||
|
event.app.current_buffer.reset()
|
||||||
|
event.app.invalidate()
|
||||||
|
return
|
||||||
|
if self._sudo_state:
|
||||||
|
self._sudo_state["response_queue"].put("")
|
||||||
|
self._sudo_state = None
|
||||||
|
event.app.invalidate()
|
||||||
|
return
|
||||||
|
|
||||||
@kb.add('c-z')
|
@kb.add('c-z')
|
||||||
def handle_ctrl_z(event):
|
def handle_ctrl_z(event):
|
||||||
"""Handle Ctrl+Z - suspend process to background (Unix only)."""
|
"""Handle Ctrl+Z - suspend process to background (Unix only)."""
|
||||||
|
|
@ -8928,9 +8946,9 @@ class HermesCLI:
|
||||||
if cli_ref._voice_processing:
|
if cli_ref._voice_processing:
|
||||||
return "transcribing..."
|
return "transcribing..."
|
||||||
if cli_ref._sudo_state:
|
if cli_ref._sudo_state:
|
||||||
return "type password (hidden), Enter to skip"
|
return "type password (hidden), Enter to submit · ESC to skip"
|
||||||
if cli_ref._secret_state:
|
if cli_ref._secret_state:
|
||||||
return "type secret (hidden), Enter to skip"
|
return "type secret (hidden), Enter to submit · ESC to skip"
|
||||||
if cli_ref._approval_state:
|
if cli_ref._approval_state:
|
||||||
return ""
|
return ""
|
||||||
if cli_ref._clarify_freetext:
|
if cli_ref._clarify_freetext:
|
||||||
|
|
@ -9173,7 +9191,7 @@ class HermesCLI:
|
||||||
prompt = state.get("prompt") or f"Enter value for {state.get('var_name', 'secret')}"
|
prompt = state.get("prompt") or f"Enter value for {state.get('var_name', 'secret')}"
|
||||||
metadata = state.get("metadata") or {}
|
metadata = state.get("metadata") or {}
|
||||||
help_text = metadata.get("help")
|
help_text = metadata.get("help")
|
||||||
body = 'Enter secret below (hidden), or press Enter to skip'
|
body = 'Enter secret below (hidden), ESC or Ctrl+C to skip'
|
||||||
content_lines = [prompt, body]
|
content_lines = [prompt, body]
|
||||||
if help_text:
|
if help_text:
|
||||||
content_lines.insert(1, str(help_text))
|
content_lines.insert(1, str(help_text))
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,12 @@ def prompt_for_secret(cli, var_name: str, prompt: str, metadata=None) -> dict:
|
||||||
if not hasattr(cli, "_secret_deadline"):
|
if not hasattr(cli, "_secret_deadline"):
|
||||||
cli._secret_deadline = 0
|
cli._secret_deadline = 0
|
||||||
try:
|
try:
|
||||||
value = getpass.getpass(f"{prompt} (hidden, Enter to skip): ")
|
value = getpass.getpass(f"{prompt} (hidden, ESC or empty Enter to skip): ")
|
||||||
except (EOFError, KeyboardInterrupt):
|
except (EOFError, KeyboardInterrupt):
|
||||||
value = ""
|
value = ""
|
||||||
|
|
||||||
if not value:
|
if not value:
|
||||||
cprint(f"\n{_DIM} ⏭ Secret entry cancelled{_RST}")
|
cprint(f"\n{_DIM} ⏭ Secret entry skipped{_RST}")
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"reason": "cancelled",
|
"reason": "cancelled",
|
||||||
|
|
@ -133,7 +133,7 @@ def prompt_for_secret(cli, var_name: str, prompt: str, metadata=None) -> dict:
|
||||||
cli._app.invalidate()
|
cli._app.invalidate()
|
||||||
|
|
||||||
if not value:
|
if not value:
|
||||||
cprint(f"\n{_DIM} ⏭ Secret entry cancelled{_RST}")
|
cprint(f"\n{_DIM} ⏭ Secret entry skipped{_RST}")
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"reason": "cancelled",
|
"reason": "cancelled",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue