Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codewhale
Submodule codewhale added at 5dffec
6 changes: 6 additions & 0 deletions crates/tui/src/core/engine/tool_catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ pub(super) const DEFAULT_ACTIVE_NATIVE_TOOLS: &[&str] = &[
"apply_patch",
"checklist_write",
"edit_file",
"exec_interact",
"exec_shell",
"exec_shell_interact",
"exec_shell_wait",
"exec_wait",
"fetch_url",
"file_search",
"git_diff",
Expand All @@ -46,6 +50,8 @@ pub(super) const DEFAULT_ACTIVE_NATIVE_TOOLS: &[&str] = &[
"task_create",
"task_list",
"task_read",
"task_shell_start",
"task_shell_wait",
"update_plan",
"web_search",
"write_file",
Expand Down
2 changes: 1 addition & 1 deletion crates/tui/src/tui/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const DISPATCH_WATCHDOG_TIMEOUT: Duration = Duration::from_secs(30);
// the per-tool spinner pulse — keep this fast enough that the spout reads as
// motion (~12 fps) instead of teleport-frames.
const UI_STATUS_ANIMATION_MS: u64 = 80;
const SIDEBAR_VISIBLE_MIN_WIDTH: u16 = 100;
const SIDEBAR_VISIBLE_MIN_WIDTH: u16 = 60;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Reducing SIDEBAR_VISIBLE_MIN_WIDTH to 60 introduces a bug where the sidebar is displayed but remains completely empty.\n\nIn sidebar_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 a chat_width of 60, chat_width.saturating_sub(40) is 20. Thus, sidebar_width becomes 20.\n\nHowever, in render_sidebar (crates/tui/src/tui/sidebar.rs), there is an early return check:\nif area.width < 24 || area.height < 8 { ... return; }\nSince 20 < 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 of 24 while keeping the chat area at its minimum of 40, the minimum terminal width should be 64 (24 + 40).

Suggested change
const SIDEBAR_VISIBLE_MIN_WIDTH: u16 = 60;
const SIDEBAR_VISIBLE_MIN_WIDTH: u16 = 64;

const DEFAULT_TERMINAL_PROBE_TIMEOUT_MS: u64 = 500;
const PERIODIC_FULL_REPAINT_EVERY_N: u64 = 50;
const TURN_META_PREFIX: &str = "<turn_meta>";
Expand Down
9 changes: 9 additions & 0 deletions fix-edit_file-fuzz.patch
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
39 changes: 39 additions & 0 deletions fix_engine.py
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The script uses a hardcoded Windows absolute path (C:\\project\\F_project1\\...), which will fail on other environments (e.g., CI/CD pipelines or other developers' machines). If this script is intended to be part of the repository, please use a relative path. Otherwise, if it was committed accidentally, it should be removed.

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)
33 changes: 33 additions & 0 deletions pr-body-agents.md
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.
27 changes: 27 additions & 0 deletions pr-body-cjk.md
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
9 changes: 9 additions & 0 deletions pr-body-fuzz.md
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
21 changes: 21 additions & 0 deletions pr-body-paste.md
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
9 changes: 9 additions & 0 deletions pr-body-rlm.md
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
32 changes: 32 additions & 0 deletions pr-body-voice.md
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(+)
```
30 changes: 30 additions & 0 deletions pr-body.md
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 +
```
Empty file added shell-live-progress.patch
Empty file.