diff --git a/clients/terminal/tui/renderers/filesystem.py b/clients/terminal/tui/renderers/filesystem.py index 0ea5922..293c43c 100644 --- a/clients/terminal/tui/renderers/filesystem.py +++ b/clients/terminal/tui/renderers/filesystem.py @@ -333,7 +333,7 @@ if last < len(text): out.append(text[last:], style=theme.text.hex) -# Actions whose title carries "path → destination". +# Actions that take a destination path (shown in the body alongside the path). _DEST_ACTIONS = {"move", "copy", "diff"} _PREVIEW_MAX = 60 @@ -355,10 +355,11 @@ class FilesystemToolStartedRenderer(ContentRenderer): """Styled ``tool_started`` card for ``filesystem``. - Title: ``→ filesystem `` (plus ``→ `` for - move/copy/diff). Body: a compact, human-readable summary of the key - arguments per action — large ``content`` / ``old`` / ``new`` / - ``instruction`` / ``question`` values are previewed, not dumped in full. + Title: ``→ filesystem `` (compact — the action alone). Body: the + primary ``path`` (and ``destination`` for move/copy/diff) plus a compact, + human-readable summary of the key per-action arguments — large ``content`` + / ``old`` / ``new`` / ``instruction`` / ``question`` values are previewed, + not dumped in full, so the card is never empty. """ def accepts(self, msg: dict) -> bool: @@ -368,14 +369,8 @@ theme = get_active_theme() args = msg.get("args") or {} action = args.get("action", "?") - path = args.get("path") title = f"→ filesystem {action}" - if path: - title += f" {path}" - if action in _DEST_ACTIONS and args.get("destination"): - title += f" → {args['destination']}" - body = self._summarize(action, args, theme) panel = Panel( body if body.plain else Text(""), @@ -398,6 +393,13 @@ out.append(": ", style=theme.text_dim.hex) out.append(str(value), style=value_style) + # Primary path and (for move/copy/diff) destination lead the body. + path = args.get("path") + if path: + kv("path", str(path), theme.accent.hex) + if action in _DEST_ACTIONS and args.get("destination"): + kv("destination", str(args["destination"]), theme.accent.hex) + if action == "read": offset = args.get("offset") limit = args.get("limit") @@ -430,6 +432,4 @@ kv("regex", "true") elif action == "query": kv("question", _preview(args.get("question", ""))) - # move/copy/diff: destination is in the title. - # info/delete/mkdir/exists: only the path, which is in the title. return out diff --git a/tests/clients/test_filesystem_renderer.py b/tests/clients/test_filesystem_renderer.py index dfe4ff2..aee354c 100644 --- a/tests/clients/test_filesystem_renderer.py +++ b/tests/clients/test_filesystem_renderer.py @@ -586,36 +586,41 @@ assert not renderer.accepts({"type": "tool_call", "tool": "filesystem", "args": {}}) -def test_started_title_carries_action_and_path() -> None: +def test_started_title_carries_action_only() -> None: set_active_theme("gnexus-dark") renderer = FilesystemToolStartedRenderer() panel = renderer.render(_started_msg({"action": "read", "path": "src/main.py"})) title = str(panel.title) assert "filesystem" in title assert "read" in title - assert "src/main.py" in title + # Path is in the body, not the title. + assert "src/main.py" not in title + body = _body(panel) + assert "src/main.py" in body.plain -def test_started_title_carries_destination_for_move_copy_diff() -> None: +def test_started_destination_in_body_for_move_copy_diff() -> None: set_active_theme("gnexus-dark") renderer = FilesystemToolStartedRenderer() move = renderer.render(_started_msg({"action": "move", "path": "a.py", "destination": "b.py"})) - assert "→" in str(move.title) - assert "b.py" in str(move.title) + assert "b.py" not in str(move.title) + assert "b.py" in _body(move).plain diff = renderer.render(_started_msg({"action": "diff", "path": "a.py", "destination": "b.py"})) - assert "b.py" in str(diff.title) - # Non-destination actions do not add the arrow. + assert "b.py" in _body(diff).plain + # Non-destination actions do not add a destination line. read = renderer.render(_started_msg({"action": "read", "path": "a.py", "destination": "x"})) - assert "→ x" not in str(read.title) + # "destination" key is absent; "x" may appear only if path == "x" (it isn't). + assert "destination" not in _body(read).plain -def test_started_info_has_empty_body() -> None: +def test_started_info_shows_path_in_body() -> None: set_active_theme("gnexus-dark") renderer = FilesystemToolStartedRenderer() panel = renderer.render(_started_msg({"action": "info", "path": "a.py"})) body = _body(panel) assert isinstance(body, Text) - assert body.plain == "" + assert "path" in body.plain + assert "a.py" in body.plain def test_started_read_shows_range_and_numbered() -> None: @@ -728,3 +733,5 @@ assert _span_styles_at(body, "pattern") == {theme.text_dim.hex} # Pattern value is in text. assert theme.text.hex in _span_styles_at(body, "TODO") + # Path value is in accent. + assert _span_styles_at(body, "src") == {theme.accent.hex}