From f3ccab1f6067d188cdffb35b7a6ad46292a2ca2f Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Tue, 8 Sep 2026 03:14:17 -0700 Subject: [PATCH] test: define passive one-line subagent dock contract --- tests/cli/test_subagent_dock_collapse.py | 92 ++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 tests/cli/test_subagent_dock_collapse.py diff --git a/tests/cli/test_subagent_dock_collapse.py b/tests/cli/test_subagent_dock_collapse.py new file mode 100644 index 0000000000..4a054b1998 --- /dev/null +++ b/tests/cli/test_subagent_dock_collapse.py @@ -0,0 +1,92 @@ +"""Collapsing the passive dock never takes space or focus from the editor.""" +import asyncio +from types import SimpleNamespace + + +def test_collapsed_dock_reserves_one_shaded_row_without_changing_editor(): + from prompt_toolkit.application import Application + from prompt_toolkit.data_structures import Size + from prompt_toolkit.document import Document + from prompt_toolkit.input import create_pipe_input + from prompt_toolkit.layout import HSplit, Layout + from prompt_toolkit.output import DummyOutput + from prompt_toolkit.styles import Style + from prompt_toolkit.widgets import TextArea + from hermes_cli import cli_subagent_monitor as dock + from hermes_cli.skin_engine import get_prompt_toolkit_style_overrides + + cli = SimpleNamespace(agent=None) + dock.install_dock(cli) + monitor = cli._subagent_monitor + monitor.entries = [dict(subagent_id=str(i), goal='Worker 界 ' * 20, + elapsed=12, last_tool='terminal', status='running') for i in range(6)] + submitted = [] + editor = TextArea(height=1, multiline=False, + accept_handler=lambda buffer: submitted.append(buffer.text)) + output = DummyOutput() + + async def run(): + with create_pipe_input() as pipe: + app = Application(layout=Layout(HSplit([cli._subagent_dock_widget, editor]), + focused_element=editor), input=pipe, output=output, + style=Style.from_dict(get_prompt_toolkit_style_overrides())) + cli._invalidate = app.invalidate + painted = asyncio.Event() + app.after_render += lambda _: painted.set() + output.get_size = lambda: Size(rows=30, columns=100) + task = asyncio.create_task(app.run_async()) + await asyncio.wait_for(painted.wait(), 3) + try: + def height(): + return app.renderer._last_screen.visible_windows_to_write_positions[editor.window].ypos + + preview_height = height() + assert preview_height > 1 + editor.buffer.document = Document('keep this draft', 5) + dock.toggle_dock(cli) + for columns, rows in [(100, 30), (80, 20), (40, 14)]: + output.get_size = lambda: Size(rows=rows, columns=columns) + painted.clear() + app.invalidate() + await asyncio.wait_for(painted.wait(), 3) + assert height() == 1 + assert app.layout.has_focus(editor) + assert (editor.text, editor.buffer.cursor_position) == ('keep this draft', 5) + screen = app.renderer._last_screen + for x in (0, columns // 2, columns - 1): + attrs = app._merged_style.get_attrs_for_style_str(screen.data_buffer[0][x].style) + assert attrs.bgcolor and attrs.color != attrs.bgcolor + painted.clear() + pipe.send_text('X\r') + await asyncio.wait_for(painted.wait(), 3) + assert submitted == ['keep Xthis draft'] + assert height() == 1 + output.get_size = lambda: Size(rows=30, columns=100) + painted.clear() + dock.toggle_dock(cli) + await asyncio.wait_for(painted.wait(), 3) + assert height() == preview_height + finally: + app.exit() + await task + asyncio.run(run()) + + +def test_collapsed_summary_prioritizes_live_count_and_controls_at_small_widths(): + from prompt_toolkit.utils import get_cwidth + from hermes_cli.cli_subagent_monitor import SubagentMonitor + + monitor = SubagentMonitor(SimpleNamespace()) + monitor.entries = [dict(goal='Inspect 界 ' * 40, elapsed=12, + last_tool='terminal', status='running') for _ in range(6)] + monitor.collapsed = True + for width in (100, 80, 40, 24, 10, 1): + text = monitor.dock_text(columns=width, rows=20) + assert len(text.splitlines()) == 1 + assert get_cwidth(text) <= width + if width >= 24: + assert '6 live' in text and 'F6' in text and 'F7' in text + if width >= 80: + assert 'last: terminal' in text and 'F6 expand' in text and 'F7 restore' in text + monitor.entries.clear() + assert monitor.dock_text(columns=80, rows=20) == ''