fix(cli): prevent spinner ANSI escape codes from being printed verbatim

Fixes #2591

The "nanobot is thinking..." spinner was printing ANSI escape codes
literally in some terminals, causing garbled output like:
  ?[2K?[32m⠧?[0m ?[2mnanobot is thinking...?[0m

Root causes:
1. Console created without force_terminal=True, so Rich couldn't
   reliably detect terminal capabilities
2. Spinner continued running during user input prompt, conflicting
   with prompt_toolkit

Changes:
- Set force_terminal=True in _make_console() for proper ANSI handling
- Add stop_for_input() method to StreamRenderer
- Call stop_for_input() before reading user input in interactive mode
- Add tests for the new functionality
This commit is contained in:
Jiajun Xie
2026-04-05 16:50:49 +08:00
committed by Xubin Ren
parent 04a41e31ac
commit f86f226c17
3 changed files with 34 additions and 1 deletions
+26
View File
@@ -145,3 +145,29 @@ def test_response_renderable_without_metadata_keeps_markdown_path():
renderable = commands._response_renderable(help_text, render_markdown=True)
assert renderable.__class__.__name__ == "Markdown"
def test_stream_renderer_stop_for_input_stops_spinner():
"""stop_for_input should stop the active spinner to avoid prompt_toolkit conflicts."""
spinner = MagicMock()
mock_console = MagicMock()
mock_console.status.return_value = spinner
# Create renderer with mocked console
with patch.object(stream_mod, "_make_console", return_value=mock_console):
renderer = stream_mod.StreamRenderer(show_spinner=True)
# Verify spinner started
spinner.start.assert_called_once()
# Stop for input
renderer.stop_for_input()
# Verify spinner stopped
spinner.stop.assert_called_once()
def test_make_console_uses_force_terminal():
"""Console should be created with force_terminal=True for proper ANSI handling."""
console = stream_mod._make_console()
assert console._force_terminal is True