Previously, Space on a thinking cell hid it entirely from the transcript.
Now Space toggles between folded (summary preview) and unfolded (full
content) for thinking cells, while other cells retain the existing
hide/show behavior.
Changes:
- Add folded_thinking HashSet to App for per-cell fold tracking
- Add lines_with_options_folded / lines_with_copy_metadata_folded that
accept an explicit folded flag, overriding the global verbose setting
- Update transcript cache to pass fold state during rendering
- Update Space key handler to toggle fold for thinking cells
- Update affordance text to mention Space for expanding folded thinking
Closes#2348
Clearing active_turn immediately breaks is_interrupt_requested detection
in monitor_turn, causing turn status to be Completed instead of Interrupted.
Let monitor_turn handle the cleanup after it detects the interrupt flag
and performs full finalization with correct status, usage, and error.
- Change 'not loaded' to 'not found' in submit_user_input and
cancel_user_input so map_thread_err correctly maps to 404
- Use map_thread_err in submit_user_input API endpoint for
consistent error response (404 for missing thread, 409 for
conflict, etc.) instead of always returning 500
The monitor_turn loop already handles full turn finalization when the
engine shuts down after cancellation, including saving turn status,
usage, error, emitting turn.completed, and clearing active_turn.
Having interrupt_turn also save turn status and emit turn.completed
causes duplicate SSE events and loses usage/error data that
monitor_turn would have captured from TurnComplete.
Keep only the active_turn cleanup so the 409 error is resolved while
monitor_turn remains the single source of truth for turn completion.
Add SSE event forwarding for UserInputRequired, REST endpoint for submitting user input responses, timeout protection for await_user_input, and fix interrupt_turn to clear active_turn immediately.
The DNS-resolution SSRF guard in `validate_dns_resolved_ip` rejects any
hostname that resolves into a restricted IP range. Under a transparent-proxy
/ TUN setup running in `fake-ip` mode, the local resolver maps *every*
hostname to a reserved placeholder range (commonly `198.18.0.0/15`), so the
guard rejects all outbound `fetch_url` requests even though the proxy will
route them correctly.
Add a narrowly-scoped, opt-in trust list on `NetworkPolicyDecider`:
- `with_trusted_fakeip_cidrs(&["198.18.0.0/15"])` registers IPv4 CIDR ranges
to treat as benign fake-ip placeholders (default: empty — no behavior
change unless the embedder configures it).
- `is_trusted_fakeip_addr(ip)` matches only those configured ranges.
`validate_dns_resolved_ip` now allows a resolved IP if it is either in a
configured fake-ip range or the host is on the existing trusted-proxy list.
Real private/loopback/link-local/cloud-metadata IPs match neither and stay
blocked, so this does not widen SSRF exposure for default configurations.
Includes CIDR parsing/containment helpers and a unit test covering the
placeholder-allowed / real-private-blocked / nothing-configured cases.
Bing wraps every SERP result URL in a `/ck/a?...&u=<base64>` click-tracking
redirect, and in the raw HTML the separators are `&` entities.
normalize_bing_url parsed the href without decoding entities first, so
extract_query_param looked for `u` while the actual key was `amp;u`. The
base64 redirect target was never recovered: every result collapsed to a
`bing.com` root domain, is_likely_spam_results rejected the whole batch,
and Bing — the default backend — returned zero results.
Decode HTML entities before extracting the redirect target. Adds a
regression test.
The header bar was reported to appear vertically centered on macOS
Terminal.app with large blank space above and below. While the existing
Constraint::Min(1) layout with default Flex::Start should place the
header at row 0, some ratatui/flex interactions can produce unexpected
centering on certain terminal sizes.
Restructure the render layout into a defensive two-pass system:
1. First pass: split the terminal into header (Length(1)) + body (Min(1))
with explicit Flex::Start, pinning the header to the absolute top.
2. Second pass: split the body area for chat, preview, composer, footer.
This guarantees the header is never vertically centered regardless of
ratatui Flex defaults or terminal dimensions.
Fixes#1834
EngineConfig.instructions was Vec<PathBuf>, which forces embedders that
compute instructions at runtime to stage content to a disk file just to
satisfy the path API. That has two awkward side-effects:
1. The disk file looks like editable config but gets overwritten on
every launch, confusing for users browsing the install dir.
2. Multi-engine setups need per-engine paths to avoid `rehydrate`
re-reading the wrong session's content across concurrent engines.
Add an `InstructionSource` enum (`File(PathBuf)` / `Inline { name,
content }`) covering both shapes. `render_instructions_block` dispatches:
File sources read disk (original behavior preserved), Inline sources use
the content directly with `name` becoming the `<instructions source=...>`
attribute.
`From<PathBuf> for InstructionSource` is provided so the existing CLI /
runtime call sites upgrade with a single `.into_iter().map(Into::into).
collect()` chain — no behavior change for callers passing paths.
New test `render_instructions_block_handles_inline_source` covers Inline
empty / oversize-truncate / File+Inline mixed-ordering. The 5 existing
`render_instructions_block_*` tests are updated to use `.into()` on
`PathBuf` and continue to assert File-variant behavior.
Deduplicate failures per tool name, clear stale failures when
the same tool succeeds, and cap visible failures at 2 so old
failures don't crowd the sidebar after the task moves on.
Adopt Gemini code-assist review on PR #1831:
- mode_plan: Yellow -> Magenta. Plan chip now contrasts with
status_warning (still Yellow) so the two never visually collide
in the status row.
- status_ready: Reset -> DarkGray. Ready chip now reads as a
distinct subdued accent instead of blending into body text
(which also resolves to Reset on this theme).
No surface change otherwise -- backgrounds and body text still use
Color::Reset to inherit the host terminal's color scheme.
Adds a new selectable theme `terminal` (alongside System / Whale / Whale
Light / Grayscale / Catppuccin / Tokyo Night / Dracula / Gruvbox) that
paints every surface with `Color::Reset` instead of any RGB so the
host terminal's own background, foreground, and palette show through.
The existing `system` theme only chose between two RGB themes (Whale dark
or Whale Light) based on COLORFGBG / macOS appearance — useful, but it
still painted brand-colored RGB surfaces. Users with custom terminal
themes (Solarized, Nord, transparent backgrounds, custom Ghostty/iTerm
schemes) had no way to make the TUI respect their terminal palette.
Implementation:
- New `TERMINAL_UI_THEME` const where every `*_bg` and most text slots
are `Color::Reset`, and accents (mode_agent/yolo/plan, status_working,
status_warning) use ANSI named colors so they also inherit the user's
terminal palette rather than DeepSeek brand RGB.
- `ThemeId::Terminal` plumbed through `from_name` / `name` /
`display_name` / `tagline` / `ui_theme` / `SELECTABLE_THEMES`, and
registered in `normalize_theme_name` with aliases `term`,
`transparent`, `follow-terminal`, `inherit` so existing
user-friendly config strings just work.
- `theme_remap_active(Terminal) → true` so the existing per-cell remap
in `ColorCompatBackend` rewrites every hard-coded palette constant
(`DEEPSEEK_INK`, `DEEPSEEK_SLATE`, `BORDER_COLOR`, `TEXT_BODY`, …) to
`Color::Reset`. Without this, the many render sites that reach for
the named palette constants directly would still paint brand RGB.
- `theme_green` / `theme_red` return `Color::Green` / `Color::Red`
for Terminal so diff "+"/"−" stay green/red but follow the user's
terminal palette.
- `theme_diff_added_bg` / `theme_diff_deleted_bg` return `Color::Reset`
for Terminal — diff highlight is conveyed by foreground color only.
- The new theme is the second entry in `SELECTABLE_THEMES` (right after
System) so it surfaces prominently in the `/theme` picker.
theme_picker tests: the new theme is inserted in row 2 of
`SELECTABLE_THEMES`, which shifts the indices three existing tests
relied on — `arrow_down_previews_next_theme`,
`enter_commits_with_persist_true`, and `digit_jumps_to_row` — so those
expectations are updated to match the new ordering. No production
behavior change in those tests, just index arithmetic.
Default (`theme = "system"`) is unchanged; existing users see no
difference. Users who want full terminal pass-through opt in via
`/theme` or `theme = "terminal"` in settings.toml.
- find_exe(): fall back to known install dirs when PATH lookup fails
(C:\Program Files\PowerShell\7, System32\WindowsPowerShell\v1.0)
- Encoding prefix: use idiomatic [Console]::OutputEncoding for PowerShell
instead of cmd.exe chcp 65001 >NUL
- Execution logging: write exec via <ShellKind> entries to
SHELL_DISPATCHER_LOG when set
- System prompt: use ShellDispatcher detection instead of raw $SHELL
so model knows it has PowerShell and generates native cmdlets
- display_command(): strip PowerShell encoding prefix for display
- Add tests for find_exe PATH + known-dir fallback
Refs #1779
Add `codewhale update --check` so users can compare the installed version with
the latest release without downloading or replacing binaries.
Surface the same release check in `codewhale doctor`, and share release lookup,
mirror handling, timeout, and version comparison logic between update and doctor.