Skip to content

TUI refactor: modular tui/ module, compact banner, tool timeline, theme system#2

Merged
jaikoo merged 15 commits intomainfrom
feat/tui-refactor
Apr 26, 2026
Merged

TUI refactor: modular tui/ module, compact banner, tool timeline, theme system#2
jaikoo merged 15 commits intomainfrom
feat/tui-refactor

Conversation

@jaikoo
Copy link
Copy Markdown

@jaikoo jaikoo commented Apr 26, 2026

Summary

Extracted the monolithic main.rs (13,106 lines) into separate modules and built out a full TUI subsystem with 9 new modules and 45 new tests.

Commits (14)

Phase 0: Module Extraction (base work)

  • 456f9a0 — Extract format/ module from main.rs (8 submodules: tool_fmt, status, model, permissions, sessions, cost, errors, slash_help)
  • abe38d5 — Extract app.rs, args.rs, cli_commands.rs from main.rs + add status bar
    • main.rs reduced from 13,106 → 5,776 lines

Phase 2-10: TUI Module Buildout

  • Phase 2 (54e478c) — Collapsible tool output (10-line default, tui/tool_panel.rs)
  • Phase 3 (e4f710e) — Enhanced permission prompt with box-drawing/a=allow-all/v=view (tui/permission.rs)
  • Phase 4 (6d37234) — ANSI-colored git diff visualization (tui/diff_view.rs)
  • Phase 5 (6da3fba) — Thinking indicator with animated dot-wave (tui/thinking.rs)
  • Phase 6 (302d672) — Compact startup banner (BannerStyle::Full|Compact|None)
  • Phase 8 (1f6b6e2) — Terminal resize-awareness (tui/terminal.rs)
  • Phase 9 (911f096) — Tool call timeline (tui/timeline.rs)
  • Phase 10 (e210500) — Theme system with semantic color tokens (tui/theme.rs)

Integration & Fixes

  • b15b7ec — Wire ToolCallTimeline, TerminalSize, and Theme into runtime
  • ea89f52 — Unicode-safe truncation, Theme migration across 5 modules
  • 11a557b — Fix truncate_str byte-length → char-count
  • 78a8f3e — Theme migration in format/tool_fmt.rs (96 insertions)

Stats

  • 230 tests passing (0 regressions)
  • 9 new tui/ modules, 1,332 lines of TUI code
  • 45 new tests across all modules
  • main.rs: 56% reduction (13,106 → 5,776 lines)
  • Zero clippy warnings in rusty-claude-cli crate

Not wired yet (future PRs)

  1. complete_tool() on ToolCallTimeline — needs Arc<Mutex<>> sharing between AnthropicRuntimeClient and CliToolExecutor
  2. BannerStyle::from_config() — needs startup_banner field in runtime::RuntimeConfig
  3. Theme migration in app.rs banner area (brand-specific ANSI codes, low priority)

code-yeongyu and others added 15 commits April 25, 2026 18:10
Extract 88 format/reporting functions into format/ submodules:
- format/tool_fmt.rs: tool call/result formatting, truncation
- format/status.rs: status reports, git workspace summary
- format/model.rs: model aliases, provenance, resolution
- format/permissions.rs: permission mode parsing/reporting
- format/sessions.rs: session management, history formatting
- format/cost.rs: cost and compact reports
- format/errors.rs: error classification, suggestions
- format/slash_help.rs: help rendering, completions

main.rs reduced from 13,106 to 11,119 lines (-1,987).
All 213 tests pass (179 unit + 34 e2e).
… status bar

Phase 0.2-0.6: Extracted ~7,300 lines from main.rs (13,106 → 5,776 lines)
- app.rs: LiveCli, BuiltRuntime, RuntimeMcpState, CliPermissionPrompter,
  CliToolExecutor, AnthropicRuntimeClient, build_runtime, run_repl
- args.rs: CliAction, CliOutputFormat, parse_args
- cli_commands.rs: 50+ subcommand runners (doctor, resume, export, diff, etc.)
- Made shared types pub(crate), fixed cross-module references

Phase 1: Added tui/status_bar.rs with StatusBarState and StatusBar
- Raw ANSI escape sequences for trait-object compatibility
- Renders model, permission mode, message count, tokens, cost, elapsed time
- Wired into consume_stream on MessageDelta (Usage) events
- Unit tests for truncation, formatting, render output

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Replace direct truncate_output_for_display calls with collapse_tool_output()
from tui/tool_panel module. Tool output now defaults to 10 visible lines
(down from 60) per the TUI design doc. Includes DISPLAY_TRUNCATION_NOTICE
appended to collapsed output, ToolDisplayConfig for customization.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/permission.rs with:
- describe_tool_action() — plain-English descriptions per tool type
- format_enhanced_permission_prompt() — box-drawing borders, ANSI styling
- parse_permission_response() — parses y/n/a/v responses
- PermissionDecision enum (Allow, Deny, AllowAll, ViewInput)
- 11 unit tests

Update CliPermissionPrompter in app.rs:
- Use enhanced prompt for display
- Support 'a' (allow all) — sets approve_all flag
- Support 'v' (view input) — prints raw input, then re-prompts

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/diff_view.rs with:
- parse_unified_diff() — git unified diff parser (DiffLine enum)
- render_colored_diff() — green additions, red deletions, cyan hunk headers
- render_diff_summary() — file-level +/- counts
- format_colored_diff() — full colored diff with summary header
- DiffCounts, count_diff_lines(), count_diff_files()
- 9 unit tests

Wire into cli_commands.rs:
- render_diff_report_for() now uses format_colored_diff()
- Staged/unstaged sections get ANSI coloring

Update mock_parity_harness assertions for new prompt text.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/thinking.rs with:
- ThinkingFrames — infinite cycled dot-wave animation frames (magenta)
- format_thinking_completed() — static 'Reasoned for X.Xs' line
- render_thinking_inline() — dim-colored reasoning indicator
- 5 unit tests

Update render_thinking_block_summary() in app.rs to delegate to the
new module, adding magenta ANSI coloring to all thinking summaries.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Replace monolithic startup_banner() with BannerStyle enum and dispatch:
- BannerStyle::Full — original ASCII art (opt-in)
- BannerStyle::Compact — 2-line banner (default)
- BannerStyle::None — empty banner (opt-out)

Add BannerStyle::from_config() for future config file integration.
Add compact_banner() and full_banner() methods to LiveCli.
All 220 tests pass.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/terminal.rs with:
- TerminalSize — thread-safe terminal-dimension tracker
- Periodic polling (1s interval) via crossterm::terminal::size()
- invalidate() for force-refresh on next read
- AtomicU16 storage, no locks on hot path (read path is lock-free)

StatusBar already consumes terminal_width; TerminalSize provides
a reusable shared instance for all TUI components.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/timeline.rs with:
- ToolCallTimeline — accumulator for tool events during a turn
- ToolCallEvent — per-call metadata (step, name, timing, error, truncation)
- start_tool() / complete_tool() builder API
- render() — numbered timeline with elapsed time and line counts
- 6 unit tests

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add tui/theme.rs with:
- Theme struct containing all semantic ANSI color constants
- DIM, SUCCESS, ERROR, HIGHLIGHT, THINKING, WARNING, MUTED, etc.
- Composite helpers: truncation_notice(), permission_border()
- 2 unit tests verifying non-empty constants and truncation notice format
- Single import point for all TUI modules to use consistent colors

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- Wire ToolCallTimeline into consume_stream: start_tool on ContentBlockStop,
  render at stream end when tools were used
- Replace direct crossterm::terminal::size() with TerminalSize tracker
  for periodic resize checking
- Import Theme in diff_view.rs, status_bar.rs, tool_panel.rs
- Use Theme::status_bar_fg() in StatusBar::render

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- status_bar.rs: content.len() -> content.chars().count() for unicode-safe truncation
- permission.rs: use Theme::WARNING, Theme::DIM, Theme::permission_border()
- diff_view.rs: use Theme::SUCCESS, Theme::ERROR, Theme::HIGHLIGHT, Theme::MUTED, Theme::DIM
- timeline.rs: use Theme::MUTED, Theme::SUCCESS_BOLD, Theme::ERROR_BRIGHT, Theme::HIGHLIGHT, Theme::DIM
- thinking.rs: use Theme::THINKING in format_thinking_completed and render_thinking_inline
- All 230 tests pass

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…ith Theme constants

All \x1b[...m escape sequences in tool_fmt.rs replaced with
Theme::DIM, RESET, SUCCESS_BOLD, ERROR_BRIGHT, WARNING,
HIGHLIGHT, ERROR, SUCCESS, MUTED, COMMAND_BG constants.
230 tests pass.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Resolve conflict in main.rs by:
- Removing inline CliAction, CliOutputFormat, LocalHelpTopic, parse_args
  (already extracted to args.rs by Phase 0)
- Adding CliAction::Rpc variant and --mode rpc parsing to args.rs
- Keeping all new mainline files (sdk crate, docs, API changes)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants