| 2026-07-13 |

tui: unify syntax highlighting under Theme.code_theme; highlight filesystem read output
...
All syntax-highlighted code in the TUI now resolves one Pygments style per
theme from a single point: Theme.code_theme (gnexus-dark=dracula,
gnexus-light=paraiso-light). Previously the dracula/github-light name was
duplicated in artifact.py and markdown_content.py, and the light theme's
"github-light" is not a real Pygments style (only github-dark exists), so
rich silently fell back to "default" and light-mode code was never
highlighted — fixed by switching to paraiso-light.
New renderers/syntax.py::highlight_code() is the shared Syntax factory
(always theme.code_theme + background_color=theme.surface.hex); artifact.py
and the new filesystem read path build through it, and
_theme_aware_code_theme now reads Theme.code_theme via ThemeRegistry.
filesystem FilesystemToolResultRenderer._render_read: the file body is now
syntax-highlighted via highlight_code with the language guessed from the
read path (guess_language). The server's "{num:>width}: {line}" prefix is
stripped (_strip_number_prefix) so Syntax renders its own line-number column
and multi-line constructs (triple-quoted strings, block comments) highlight
correctly across line boundaries; numbered=False renders without numbers.
The header plaque (accent path) and the large-file warning stay as Text;
body is Group(header, [warning,] Text, Syntax). Unknown extensions fall back
to the "text" lexer (plain).
Diff content keeps marker-only coloring (combining Pygments token styles
with the +/- tint is non-trivial); grep/list/info/find unchanged.
Tests: tests/clients/test_code_theme.py pins the single-point contract
(markdown/artifact/read all resolve theme.code_theme, dark != light);
test_filesystem_renderer read tests rewritten for the Group+Syntax body,
plus language-guess and numbered=False coverage. Full suite: 932 passed.
Eugene Sukhodolskiy
committed
13 hours ago
|
renderers: colour diff line numbers + read line numbers, keep content neutral
...
Standard for diff and read output: the line number (and the +/- marker for
diffs) is the coloured anchor; the content itself reads plainly.
diff: "{num} {marker} {content}" with num+marker in the marker colour
(green/red), content neutral. Fixed the number-column regex to "^( +)(\d+)|"
so files with more than 9 lines (width > 1) still match — the old
single-space pattern silently fell back to whole-line colouring.
read: "{num}: {content}" with the number in the accent colour, content
neutral (was dim number).
Applied to both clients: the TUI diff/filesystem renderers and the webclient
ToolCard (renderDiff / renderRead). The model-facing text from the server is
unchanged — this is display-only.
Eugene Sukhodolskiy
committed
18 hours ago
|
| 2026-07-12 |

filesystem: show real file line numbers in unified diffs
...
_number_diff parses @@ hunk headers and prefixes each content line with its
real file line number: removed/context lines use the old (from) number,
added lines use the new (to) number, in `{marker} {num}│ {content}` form
(marker first so existing startswith highlighting stays valid; column
right-aligned to the largest line number). Hunk/file headers and the
`\ No newline` marker are left unchanged.
Applied in _unified_diff (covers edit / edit_lines / smart_edit) and the
`diff` action — a single server-side change, so both the TUI and the web
client receive numbered diffs in the tool result text.
TUI highlight_unified_diff renders the `{marker} {num}│` column dim and the
content in the marker color, so the number reads as meta, not as part of the
added/removed text. Lines without the prefix (standalone `diff` event, older
callers) are still colored whole.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
filesystem edit: render red/green diff in TUI without changing model context
...
edit is now the primary editing method, yet its output was a dry one-line
status ("Edited …: replaced X B with Y B") while edit_lines/smart_edit showed a
highlighted unified diff. Carry the unified diff in ToolResult.metadata["diff"]
(kept out of the model-facing output, so the agent's context is unchanged) and
render it in the TUI: dim summary line plus highlighted diff (green +, red -,
dim @@). Falls back to plain text when no diff metadata is present.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
tui: move filesystem tool_started info into the card body
...
Previously the action and primary path were crammed into the title
("→ filesystem read src/main.py") and the body only held the extra args,
so for simple actions (info/delete/mkdir/exists) the card body was empty.
Title is now compact ("→ filesystem <action>"). The body always carries
the information: "path: <path>" (accent) leads, "destination: <dest>"
(accent) follows for move/copy/diff, then the per-action args (range/
content/old+new/operations/instruction/pattern/question …) as before.
The card is never empty.
Tests updated: title carries action only (path is in the body),
destination lands in the body for move/copy/diff, info shows path in body,
path value is styled accent. 42 filesystem-renderer tests total. Full
suite 827 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

tui: styled filesystem tool_started card — compact args, action in title
...
The generic ToolStartedRenderer dumped all of args as JSON, so filesystem
cards showed "→ filesystem" with no action in the title and the full
content/old/new text for write/edit/smart_edit flooding the card.
New FilesystemToolStartedRenderer (clients/terminal/tui/renderers/filesystem.py):
- Title carries the action and primary path: "→ filesystem read src/main.py";
move/copy/diff also append "→ <destination>".
- Body is a compact per-action summary instead of JSON:
- read: range (offset–limit) + numbered flag
- write/append: content preview (first line + "(+N lines)" hint, not full)
- edit: old + new previews
- edit_lines: operations count + op kinds (replace/delete/insert, first 5)
- smart_edit: instruction preview
- grep: pattern + glob + regex flag
- find/find_up: pattern
- query: question preview
- list: recursive flag
- info/delete/mkdir/exists: empty body (path is in the title)
- Body keys render dim, values in text.
- Sub-agent cards indented, matching ToolStartedRenderer.
Registered before the generic ToolStartedRenderer (first-match wins). The
filesystem tool, WS protocol, and events are untouched.
13 new tests cover accepts, title (action/path/destination), empty body for
info, and per-action body summaries (read/write/edit/edit_lines/grep/
smart_edit/query), content preview truncation, subagent indent, and body key
styling. 42 filesystem-renderer tests total. Full suite 827 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
tui: styled filesystem find + find_up output — stage 3
...
find: the "[N matches for 'pattern' in path ⠠ …]" header plaque is dim
(warning color on ⠠ truncated); "No matches for …" renders dim; each match
line "{path} ({size})" renders the path in text, " (" and the size in
dim, and the "<dir>" marker in info.
find_up: a resolved path renders in accent; "not found (searched: …)"
renders dim.
Fallback narrowed to write/edit/append/move/copy/delete/mkdir/exists/
query/unknown. 5 new tests (find header/matches/truncated/no-matches,
find_up found/not-found); 29 filesystem-renderer tests total. Full suite
814 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

tui: styled filesystem read + info output — stage 2
...
read: the "[path | N lines | size]" header plaque is now dim with the
path highlighted in accent (offset/limit plaque "… lines A–B of N …"
likewise); the "⚠ Large file …" warning line renders in warning color; the
file body renders in text (was dim — readable now) with no syntax
highlighting (rejected by design); numbered reads dim the line numbers and
render line content in text. read errors (not_found, file_too_large) render
in tool_error.
info: each "key: value" line highlights the key (incl. colon) in accent,
the alignment padding in dim, and the value in text.
Fallback narrowed to write/edit/append/move/copy/delete/mkdir/exists/find/
find_up/query/unknown (statuses and find/query intentionally untouched).
Diff/list/grep from stage 1 unchanged.
6 new tests (read plaque/offset/warn/numbered/error, info keys+values);
24 filesystem-renderer tests total. Full suite 809 passed, 1 skipped.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

tui: styled filesystem tool output (diff / list / grep) — stage 1
...
The TUI rendered every tool result as a single dim Text in a Panel — no
special handling for filesystem, so unified diffs from edit_lines/smart_edit/
diff were shown as plain grey text (the existing DiffRenderer only fires on
type:"diff", which filesystem never emits), directory listings were an
unaligned text blob, and grep matches had no pattern highlighting.
New FilesystemToolResultRenderer (clients/terminal/tui/renderers/filesystem.py)
intercepts filesystem tool_call events by tool=="filesystem" + args.action:
- diff / edit_lines / smart_edit: reuse a shared highlight_unified_diff()
helper (extracted from DiffRenderer) — + green, - red, @@ dim; the
"Applied …" summary line of edit_lines/smart_edit is separated from the
diff body via a Group; "Files are identical." renders dim.
- list: header plaque dim (warning color on ⚠ truncated); directories
shown as "▸ name/ (n items)" in info color; files as name (text) +
size (accent) + time (dim), preserving the tool's fixed-width alignment;
"?" entries in warning; "(empty directory)" dim.
- grep: header plaque dim; "rel:line:" location dim; matched pattern
occurrences highlighted in accent (case-insensitive, re.escape'd);
"No matches …" dim.
- read / info / write / edit / append / move / copy / delete / mkdir /
exists / find / find_up / query / unknown: plain dim fallback (unchanged
for now — stage 2). Errors (success=False): plain in tool_error color.
Registered before the generic ToolResultRenderer (first-match wins). The
filesystem tool, WS protocol, events, and webclient are untouched.
22 new tests in tests/clients/test_filesystem_renderer.py cover accepts,
diff/edit_lines/identical/error, list (dir/file/truncated), grep
(pattern/no-matches/no-pattern-arg), fallback, title+status, subagent
indent. DiffRenderer behavior unchanged (existing test still passes).
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|