diff --git a/cli.py b/cli.py index ab0b2ab774a..3a522f2f2a3 100644 --- a/cli.py +++ b/cli.py @@ -9654,7 +9654,10 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin): # Pre-wrap the mandatory content — command + choices must always render. cmd_wrapped = _wrap_panel_text(cmd_display, inner_text_width) if not show_full and "view" in choices and len(cmd_wrapped) > 4: - cmd_wrapped = cmd_wrapped[:3] + ["… (choose Show full command)"] + cmd_wrapped = cmd_wrapped[:3] + _wrap_panel_text( + "… (choose Show full command)", + inner_text_width, + ) # (choice_index, wrapped_line) so we can re-apply selected styling below choice_wrapped: list[tuple[int, str]] = [] @@ -9704,7 +9707,10 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin): max_cmd_rows = max(1, available - chrome_rows - len(choice_wrapped)) if len(cmd_wrapped) > max_cmd_rows: keep = max(1, max_cmd_rows - 1) if max_cmd_rows > 1 else 1 - cmd_wrapped = cmd_wrapped[:keep] + ["… (command truncated — use /logs or /debug for full text)"] + cmd_wrapped = cmd_wrapped[:keep] + _wrap_panel_text( + "… (command truncated — use /logs or /debug for full text)", + inner_text_width, + ) # Allocate any remaining rows to description. The extra -1 in full mode # accounts for the blank separator between choices and description. diff --git a/tests/cli/test_cli_approval_ui.py b/tests/cli/test_cli_approval_ui.py index aeae5d92af1..334811addaa 100644 --- a/tests/cli/test_cli_approval_ui.py +++ b/tests/cli/test_cli_approval_ui.py @@ -158,6 +158,30 @@ class TestCliApprovalUi: assert "keyring.gpg" in rendered assert "status=progress" in rendered + def test_approval_display_wraps_preview_hint_on_narrow_terminal(self): + cli = _make_cli_stub() + cli._approval_state = { + "command": "sudo " + ("very-long-command-segment-" * 8), + "description": "shell command via -c/-lc flag", + "choices": ["once", "session", "always", "deny", "view"], + "selected": 0, + "response_queue": queue.Queue(), + } + + import shutil as _shutil + + with patch("cli.shutil.get_terminal_size", + return_value=_shutil.os.terminal_size((30, 24))): + fragments = cli._get_approval_display_fragments() + + rendered = "".join(text for _style, text in fragments) + lines = rendered.splitlines() + border_width = len(lines[0]) + + assert "Show full" in rendered + assert "command)" in rendered + assert all(len(line) == border_width for line in lines) + def test_approval_display_shows_full_command_after_view(self): cli = _make_cli_stub() full_command = "sudo dd if=/tmp/in of=/usr/share/keyrings/githubcli-archive-keyring.gpg bs=4M status=progress"