70 nested closures (every prompt_toolkit key handler and handler factory, the
clarify/sudo/secret/approval/model-picker/command-palette/stash display
renderers, hint/placeholder/spinner callables, process_loop, spinner_loop,
_signal_handler, wake-startup) become HermesCLI._tui_* methods; run() only
binds them (kb.add(...)(self._tui_x)). The run() locals they closed over are
published on self at their original binding sites (_tui_multiline_shortcuts,
the four paste list-cells; process_loop reads self._app). Then four zero-
back-ref prologue regions become _tui_print_startup, _tui_init_run_state,
_tui_build_key_bindings -> kb and _tui_build_layout(kb) -> (layout, style).
All moved bodies verified AST-identical modulo cli_ref->self and the free-var
rewrites; unresolved-free-name check on every new method is empty. Source-
inspection tests repointed: getsource(run) -> _tui_process_loop, AST lookup of
handle_enter -> _tui_handle_enter.
handle_enter dispatches /steer and /model inline on the UI thread while
the agent is running, calling buffer.reset() then returning. Unlike every
other early-return branch in the handler, these two skipped
event.app.invalidate(). process_command() prints through patch_stdout
(scrolls output above the prompt without redrawing the input line), so the
just-cleared input area could keep showing the submitted '/steer <text>'
until an unrelated redraw fired — looking unsent and inviting an accidental
re-submit.
Add event.app.invalidate() after reset in both inline branches to match
the sibling branches. AST regression test pins the invariant: every
reset-then-return branch in handle_enter must invalidate first.
Fixes#34569