-
Notifications
You must be signed in to change notification settings - Fork 3.3k
fix(ui): reduce minimum terminal width for sidebar visibility #3371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| The optional `fuzz` parameter was required to attempt the leading-indentation fuzzy fallback when exact search found zero matches. This forced the model to make two calls on every edit that needed fuzzy matching (first without fuzz -> error -> second with fuzz: true), causing a round-trip delay. | ||
|
|
||
| Fix: remove the `fuzz` gate from the count == 0 branch. The tool now automatically retries with indentation-tolerant fuzzy matching when exact search produces no results. The `fuzz` parameter is kept in the schema for backward compatibility but marked deprecated. | ||
|
|
||
| Changes: | ||
| - crates/tui/src/tools/file.rs: `if count == 0 && fuzz` -> `if count == 0` (always retry fuzzy fallback) | ||
| - crates/tui/src/tools/file.rs: removed dead `else if count == 0 { error }` branch | ||
| - crates/tui/src/tools/file.rs: updated description to note automatic fuzzy fallback | ||
| - crates/tui/src/tools/file.rs: marked fuzz parameter as deprecated in schema |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import re | ||
|
|
||
| file_path = r'C:\project\F_project1\CodeWhale\crates\tui\src\core\engine.rs' | ||
|
Comment on lines
+1
to
+3
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The script uses a hardcoded Windows absolute path ( import os\nimport re\n\nfile_path = os.path.join(os.path.dirname(__file__), 'crates', 'tui', 'src', 'core', 'engine.rs') |
||
| with open(file_path, 'r', encoding='utf-8') as f: | ||
| content = f.read() | ||
|
|
||
| # 1. Add helper function after runtime_prompt_text | ||
| marker = ' </runtime_prompt>"\n )\n}\n\n/// Spawn the engine' | ||
| helper_fn = ''' </runtime_prompt>" | ||
| ) | ||
| } | ||
|
|
||
| /// Check if a user message contains real user input (not just runtime metadata). | ||
| /// Returns true if the message has actual user text content beyond internal tags. | ||
| fn has_real_user_content(text: &str) -> bool { | ||
| // Strip known internal tags and check if meaningful content remains | ||
| let stripped = text | ||
| .replace("<turn_meta>", "") | ||
| .replace("</turn_meta>", "") | ||
| .replace("<runtime_prompt", "") | ||
| .replace("</runtime_prompt>", "") | ||
| .replace("<codewhale:runtime_event", "") | ||
| .replace("</codewhale:runtime_event>", ""); | ||
|
|
||
| // Check if there's non-whitespace content after stripping tags | ||
| let trimmed = stripped.trim(); | ||
| !trimmed.is_empty() && trimmed.len() > 10 // Allow for minimal metadata | ||
| } | ||
|
|
||
| /// Spawn the engine''' | ||
|
|
||
| if marker in content: | ||
| content = content.replace(marker, helper_fn) | ||
| print("OK: helper function added") | ||
| else: | ||
| print("WARN: marker not found for helper function") | ||
|
|
||
| with open(file_path, 'w', encoding='utf-8') as f: | ||
| f.write(content) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| ## Summary | ||
|
|
||
| Auto-collapse completed sub-agents in the Agents sidebar panel. Non-running agents now show only a single line (label), freeing vertical space for active agents. | ||
|
|
||
| ## Problem | ||
|
|
||
| Completed/failed/interrupted/cancelled sub-agents each occupied **2 lines** in the sidebar (label + detail line), wasting space that could be used for running agents or other content. With many agents, the sidebar became unnecessarily crowded. | ||
|
|
||
| ## Solution | ||
|
|
||
| In `subagent_panel_lines()`, check the agent status before rendering the detail line. If the agent is not running (i.e. completed, failed, interrupted, cancelled), skip the detail line entirely and only render the single-line label. | ||
|
|
||
| **Before:** | ||
| ``` | ||
| ✓ explore foo ← 2 lines per agent | ||
| abc123 · 3 steps · 12.3s | ||
| ✗ build failed ← 2 lines per agent | ||
| def456 · 7 steps · 45.6s | ||
| ● analysis running ← 2 lines per agent | ||
| ghi789 · 2 steps · 5.1s · parsing output... | ||
| ``` | ||
|
|
||
| **After:** | ||
| ``` | ||
| ✓ explore foo ← 1 line (collapsed) | ||
| ✗ build failed ← 1 line (collapsed) | ||
| ● analysis running ← 2 lines (expanded: label + detail) | ||
| ghi789 · 2 steps · 5.1s · parsing output... | ||
| ``` | ||
|
|
||
| ## File changed | ||
|
|
||
| `crates/tui/src/tui/sidebar.rs` — 5 lines added: `is_completed` check + early `continue` before the detail line. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| ## Bug | ||
|
|
||
| When `assistant_text` contains CJK characters (3-byte UTF-8), the byte slice | ||
| `&assistant_text[..SUMMARY_LIMIT.saturating_sub(3)]` (byte 277) can land in | ||
| the middle of a multi-byte sequence, causing a panic: | ||
|
|
||
| ``` | ||
| byte index 277 is not a char boundary (it is inside a 3-byte UTF-8 sequence) | ||
| ``` | ||
|
|
||
| ## Fix | ||
|
|
||
| Replace the raw byte-index slice with `truncate_with_ellipsis()` which already | ||
| finds the nearest safe char boundary via `char_indices()`. | ||
|
|
||
| ## Change | ||
|
|
||
| ```diff | ||
| -format!("{}...", &assistant_text[..SUMMARY_LIMIT.saturating_sub(3)]) | ||
| +crate::utils::truncate_with_ellipsis(&assistant_text, SUMMARY_LIMIT, "...") | ||
| ``` | ||
|
|
||
| 1 line changed. | ||
|
|
||
| ## Files | ||
|
|
||
| - crates/tui/src/runtime_threads.rs:1437 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| The optional `fuzz` parameter was required to attempt the leading-indentation fuzzy fallback when exact search found zero matches. This forced the model to make two calls on every edit that needed fuzzy matching (first without fuzz -> error -> second with fuzz: true), causing a round-trip delay. | ||
|
|
||
| Fix: remove the `fuzz` gate from the count == 0 branch. The tool now automatically retries with indentation-tolerant fuzzy matching when exact search produces no results. The `fuzz` parameter is kept in the schema for backward compatibility but marked deprecated. | ||
|
|
||
| Changes: | ||
| - crates/tui/src/tools/file.rs: `if count == 0 && fuzz` -> `if count == 0` (always retry fuzzy fallback) | ||
| - crates/tui/src/tools/file.rs: removed dead `else if count == 0 { error }` branch | ||
| - crates/tui/src/tools/file.rs: updated description to note automatic fuzzy fallback | ||
| - crates/tui/src/tools/file.rs: marked fuzz parameter as deprecated in schema |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| ## Problem | ||
|
|
||
| Pasting large text into the CodeWhale TUI composer (e.g. pasting a 20KB log file or code block) immediately converts it to an `@.deepseek/pastes/paste-xxx.md` mention. The user's text vanishes from the composer and is replaced by a cryptic `@file` reference they did not ask for. This is confusing — the user expected to see their pasted text and be able to review/edit it before sending. | ||
|
|
||
| ## Root Cause | ||
|
|
||
| `insert_paste_text()` calls `consolidate_large_input_if_oversized()` at paste time, which checks if `char_count(input) > MAX_SUBMITTED_INPUT_CHARS` (16,000 chars). When exceeded, it immediately writes the text to a paste file and replaces the composer input with `@.deepseek/pastes/paste-xxx.md`. | ||
|
|
||
| The consolidation is useful at submit time (safety net), but at paste time it is surprising and confusing. | ||
|
|
||
| ## Fix | ||
|
|
||
| 1. **Remove the immediate consolidation from `insert_paste_text()`** — the text now stays in the composer as-is after pasting. | ||
| 2. **Keep the consolidation as a safety net at submit time** — the same logic already runs when the user presses Enter, so the model still gets the `@file` reference if needed. | ||
| 3. **Improve the toast message** — explain what happened when the submit-time consolidation fires. | ||
|
|
||
| The user now sees their full pasted text in the composer and can review/edit before sending. The consolidation only triggers when they press Enter if the text is still over the 16K char limit. | ||
|
|
||
| ## Files | ||
|
|
||
| - `crates/tui/src/tui/app.rs`: commented out `self.consolidate_large_input_if_oversized()` in `insert_paste_text`, updated toast message |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| RLM sessions that produce large stdout/stderr (e.g. reading a local log file, dumping a large JSON table, or printing diagnostic output) currently inline the full preview into the parent tool result. On long-running RLM sessions this bloat accumulates and pressures the parent context window. | ||
|
|
||
| Fix: when `rlm_eval` stdout or stderr exceeds 1000 characters, the full body is stored as a `var_handle` in the handle store. The tool result returns a short inline note (`"N chars; retrieve via handle_read"`) plus `stdout_handle` / `stderr_handle` fields containing the handle reference. The model calls `handle_read` for bounded projections. | ||
|
|
||
| Changes: | ||
| - `rlm.rs`: Added `STDOUT_HANDLE_THRESHOLD_CHARS` constant | ||
| - `rlm.rs`: Added `route_output()` helper that stores large text as a var_handle | ||
| - `rlm.rs`: Modified `rlm_eval` execute to route stdout/stderr >= 1k chars into handles | ||
| - `rlm.rs`: Updated description to document the new handle-routing behavior |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| ## Summary | ||
|
|
||
| Validate terminal-safe voice shortcut and STT helper setup for the voice input feature shipping in v0.8.45/v0.8.46. | ||
|
|
||
| ## Completed | ||
|
|
||
| - **`voice_input.rs`**: Added `diagnose_voice_setup()` async function that checks: | ||
| - Missing/invalid `voice_input_command` config | ||
| - Inexecutable binary (spawns `--version` as probe) | ||
| - Permission/spawn failures with clear error messages | ||
| - **`voice_input.rs`**: Added `terminal_detection_tests` module with: | ||
| - `chord_likely_reaches_tui()` heuristic function documenting known-consumed chords | ||
| - Tests for common chords (Ctrl-K consumed, Ctrl-L/Ctrl-C safe) | ||
| - Candidate shortcut test matrix (F2, F3, Alt-Space, Ctrl-] etc.) | ||
| - **`docs/VOICE_INPUT_TERMINALS.md`**: Terminal compatibility matrix documenting Ctrl-K behavior across 13 terminal emulators + STT helper setup checklist + recommended safe chords | ||
| - **`docs/KEYBINDINGS.md`**: Added Voice input section documenting the Ctrl-K caveat with cross-reference to the new terminal matrix doc | ||
|
|
||
| ## Not completed (needs manual verification) | ||
|
|
||
| - **Actual terminal testing** on macOS Terminal.app, iTerm2, Ghostty, Warp, Windows Terminal, Linux terminals | ||
| - **Final default chord selection** — the matrix lists candidates but the final binding needs human verification | ||
| - **Manual QA checklist** for terminals that consume modifier keys | ||
| - **Compilation verification** — changes made to a feature branch (work/v0.8.45-flash) without Rust CI available | ||
|
|
||
| ## Files changed | ||
|
|
||
| ``` | ||
| crates/tui/src/tui/voice_input.rs | 110 +++++++++++++++++ | ||
| docs/KEYBINDINGS.md | 22 ++++ | ||
| docs/VOICE_INPUT_TERMINALS.md | 87 +++++++++++++ | ||
| 3 files changed, 219 insertions(+) | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| ## Summary | ||
|
|
||
| Add real-time incremental output display for shell execution commands. The TUI now displays shell output **while the command is still running**, instead of hiding all output until completion. | ||
|
|
||
| ## Changes | ||
|
|
||
| - **`ExecCell`**: Added `live_output: Option<String>` field to store incremental output during execution | ||
| - **`history.rs`**: Modified render logic to show `live_output` when `output` is not yet available (priority: final output > live output > hints) | ||
| - **`app.rs`**: Added `poll_shell_progress()` method that polls `ShellManager` during idle frames and updates matching `ExecCell` entries | ||
| - **`ui.rs`**: Wired `poll_shell_progress()` into the event loop after `tick_quit_armed()` | ||
| - **All ExecCell construction sites**: Added `live_output: None` to 8 files | ||
|
|
||
| ## How it works | ||
|
|
||
| 1. During idle frames, the TUI polls `ShellManager.list_jobs()` for running shell processes | ||
| 2. Running exec cells are matched to shell jobs by command prefix | ||
| 3. Live output (tail of stdout/stderr) is written to `ExecCell.live_output` | ||
| 4. The renderer displays it in the transcript immediately | ||
|
|
||
| ## Files changed | ||
| ``` | ||
| crates/tui/src/tui/active_cell.rs | 1 + | ||
| crates/tui/src/tui/app.rs | 69 +++++++++++++++++++++++++++++ | ||
| crates/tui/src/tui/history.rs | 11 ++++ | ||
| crates/tui/src/tui/sidebar.rs | 5 ++ | ||
| crates/tui/src/tui/tool_routing.rs | 2 + | ||
| crates/tui/src/tui/transcript.rs | 1 + | ||
| crates/tui/src/tui/ui.rs | 2 + | ||
| crates/tui/src/tui/ui/tests.rs | 3 + | ||
| ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reducing
SIDEBAR_VISIBLE_MIN_WIDTHto60introduces a bug where the sidebar is displayed but remains completely empty.\n\nInsidebar_width_for_chat_area(line 170), the sidebar width is calculated as:\nlet sidebar_width = preferred_sidebar.max(24).min(chat_width.saturating_sub(40));\nFor achat_widthof60,chat_width.saturating_sub(40)is20. Thus,sidebar_widthbecomes20.\n\nHowever, inrender_sidebar(crates/tui/src/tui/sidebar.rs), there is an early return check:\nif area.width < 24 || area.height < 8 { ... return; }\nSince20 < 24, the sidebar content is not rendered, leaving a blank background block that unnecessarily squeezes the chat area.\n\nTo ensure the sidebar has at least the minimum required width of24while keeping the chat area at its minimum of40, the minimum terminal width should be64(24 + 40).