From b2a9f6beaa5a812d827dcc0d7c3426337b0eaddc Mon Sep 17 00:00:00 2001 From: teknium1 Date: Wed, 4 Mar 2026 13:39:48 -0800 Subject: [PATCH] feat: enable up/down arrow history navigation in CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TextArea uses multiline=True, so up/down arrows only moved the cursor within text — history browsing via FileHistory was attached but inaccessible. Two fixes: 1. Add up/down key bindings in normal input mode that call Buffer.auto_up()/auto_down(). These intelligently handle both: cursor movement when editing multi-line text, and history browsing when on the first/last line. 2. Pass append_to_history=True to buffer.reset() in the Enter handler so messages actually get saved to ~/.hermes_history. History persists across sessions via FileHistory. The bindings are filtered out during clarify, approval, and sudo prompts (which have their own up/down handlers). --- cli.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cli.py b/cli.py index 4079d89c..417d9f64 100755 --- a/cli.py +++ b/cli.py @@ -2378,7 +2378,7 @@ class HermesCLI: self._interrupt_queue.put(text) else: self._pending_input.put(text) - event.app.current_buffer.reset() + event.app.current_buffer.reset(append_to_history=True) @kb.add('escape', 'enter') def handle_alt_enter(event): @@ -2423,6 +2423,24 @@ class HermesCLI: self._approval_state["selected"] = min(max_idx, self._approval_state["selected"] + 1) event.app.invalidate() + # --- History navigation: up/down browse history in normal input mode --- + # The TextArea is multiline, so by default up/down only move the cursor. + # Buffer.auto_up/auto_down handle both: cursor movement when multi-line, + # history browsing when on the first/last line (or single-line input). + _normal_input = Condition( + lambda: not self._clarify_state and not self._approval_state and not self._sudo_state + ) + + @kb.add('up', filter=_normal_input) + def history_up(event): + """Up arrow: browse history when on first line, else move cursor up.""" + event.app.current_buffer.auto_up(count=event.arg) + + @kb.add('down', filter=_normal_input) + def history_down(event): + """Down arrow: browse history when on last line, else move cursor down.""" + event.app.current_buffer.auto_down(count=event.arg) + @kb.add('c-c') def handle_ctrl_c(event): """Handle Ctrl+C - cancel interactive prompts, interrupt agent, or exit.