diff --git a/cli.py b/cli.py index a5fe488d59..53dba6825c 100644 --- a/cli.py +++ b/cli.py @@ -2635,7 +2635,7 @@ class HermesCLI(CLIProcessNotificationsMixin, CLIAgentSetupMixin, CLICommandsMix self._stream_table_buf: list[str] = [] self._in_stream_table = False self._pending_edit_snapshots = {} - self._last_input_mode_recovery = self._last_termios_drift_check = 0.0 + self._last_input_mode_recovery = self._last_termios_drift_check = None # None = never; monotonic epoch is arbitrary self._input_mode_recovery_notice_shown = self._termios_drift_notice_shown = False def _init_model_routing(self, model, toolsets, provider, reasoning, api_key, base_url, max_turns, run_budget, checkpoints, pass_session_id, ignore_rules): diff --git a/hermes_cli/cli_terminal_mixin.py b/hermes_cli/cli_terminal_mixin.py index 8fe300e5e0..3115df2b16 100644 --- a/hermes_cli/cli_terminal_mixin.py +++ b/hermes_cli/cli_terminal_mixin.py @@ -367,8 +367,10 @@ class CLITerminalMixin: CLI_CONFIG, _DIM, _RST, _TERMINAL_INPUT_MODE_RESET_SEQ, _cli_multiline_shortcuts_enabled, _cprint, _enable_extended_enter_keys, logger) now = time.monotonic() - # Rate-limit to avoid thrashing if a terminal floods reports. - if now - self._last_input_mode_recovery < 0.5: + # Rate-limit to avoid thrashing if a terminal floods reports. None = never + # (monotonic epoch is arbitrary, see _invalidate). + last = self._last_input_mode_recovery + if last is not None and now - last < 0.5: return self._last_input_mode_recovery = now app = getattr(self, "_app", None) @@ -408,7 +410,8 @@ class CLITerminalMixin: if getattr(app, "_running_in_terminal", False): return now = time.monotonic() - if now - self._last_termios_drift_check < 1.0: + last = self._last_termios_drift_check # None = never (monotonic epoch is arbitrary) + if last is not None and now - last < 1.0: return self._last_termios_drift_check = now try: diff --git a/tests/hermes_cli/test_cli_force_redraw.py b/tests/hermes_cli/test_cli_force_redraw.py index 849e82bc25..344fa4621c 100644 --- a/tests/hermes_cli/test_cli_force_redraw.py +++ b/tests/hermes_cli/test_cli_force_redraw.py @@ -444,3 +444,16 @@ class TestFocusRegainRedraw: bare_cli._schedule_focus_regain_redraw(min_interval=60.0) assert calls == ["redraw"] + + def test_first_invalidate_fires_even_with_small_monotonic_clock( + self, bare_cli, monkeypatch + ): + """Same class as above for the streaming/spinner repaint throttle.""" + app = MagicMock() + bare_cli._app = app + bare_cli._last_invalidate = None + monkeypatch.setattr(cli_mod.time, "monotonic", lambda: 0.1) + + bare_cli._invalidate(min_interval=0.25) + + app.invalidate.assert_called_once()