* test(web): add unit tests for pure helper functions
Add vitest configuration and tests for:
- relativeTime: time formatting (just now, minutes, hours, days, months, years)
- lastPageFromLink: GitHub Link header pagination parsing
These are the first tests for the web frontend. The test framework
(vitest) was already in package.json but had no config or test files.
* test(web): exercise real GitHub helpers
---------
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Co-authored-by: Hunter B <hmbown@gmail.com>
* refactor(tools): replace manual Display impl with thiserror derive
Replace the hand-rolled Display implementation for ToolError with
thiserror derive macros. The thiserror crate is already a workspace
dependency. Error messages remain identical (verified by existing
test tool_error_display_matches_legacy_text).
This reduces boilerplate and ensures consistency with other error
types in the codebase (secrets, state crates already use thiserror).
* chore: add thiserror to Cargo.lock
---------
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
* docs(core): add doc comments to all public types
Add doc comments to all public types in the core crate:
- InitialHistory enum and variants
- NewThread struct and fields
- JobStatus enum and variants
- JobRetryMetadata struct and fields
- JobHistoryEntry struct and fields
- JobRecord struct and fields
- JobManager struct
- ThreadManager struct
- Runtime struct
* docs(core): add doc comments to all public types
---------
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Add doc comments to all public structs, enums, traits, and methods:
- McpServerConfig, ToolFilter, McpServerDefinition
- McpStartupStatus, McpStartupUpdateEvent, McpStartupFailure, McpStartupCompleteEvent
- McpToolDescriptor, McpResourceDescriptor
- McpManagedClient trait and all its methods
- InMemoryMcpClient and its builder methods
- McpManager and all its public methods
- run_stdio_server function
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Harvests the UnixSocketHookSink work from #2333 while moving app-server socket configuration to the separate [hook_sinks] table, requiring an explicit socket path, and adding regression coverage for macOS-safe socket paths and lifecycle [hooks] preservation.
Prevent inline skill slash completions from opening while editing arguments for an existing slash command.
This keeps `/attach /path/to/image.png` usable without showing skill entries after the path slash, while
preserving inline skill completions in normal message text.
Adds a regression test for `/attach /`.
Hardens the tool override path from #2420 so a broken replacement override cannot silently fall through to the original built-in tool.
Validation:
- git diff --check
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/fix-plugin-override cargo test -p codewhale-tui tools::registry --all-features
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/fix-plugin-override cargo test -p codewhale-tui tools::plugin --all-features
Add Volcengine (火山引擎) as a new SearchProvider in web_search tool.
Uses Volcengine's Responses API with `tools: [{type: "web_search"}]`
and strict JSON prompt constraints to extract structured search results.
- Free tier: 20K queries/month per API key
- API key resolution: [search] api_key → VOLCENGINE_API_KEY →
VOLCENGINE_ARK_API_KEY → ARK_API_KEY env vars
- Select via `DEEPSEEK_SEARCH_PROVIDER=volcengine` or
`[search] provider = "volcengine"` in config.toml
Co-authored-by: Cursor <cursoragent@cursor.com>
Supersedes #2224.
Updates the transitive web lockfile entry for `qs` from 6.15.1 to 6.15.2 while keeping the current-main diff limited to the `node_modules/qs` metadata.
Validation:
- git diff --check
- npm --prefix web ci --ignore-scripts
- npm --prefix web run lint
Harvested from #2391 with thanks to @wplll.
Tracks a cache warmup key across provider, model, base URL, static prefix, tool catalog, project pack, and skills hashes; records base URL and tool catalog from completed turns; reports whether /cache inspect still matches the last warmup key; and computes the warmup key from the actual warmup request sent to the provider.
Validation:
- cargo fmt --all -- --check
- git diff --check
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/harvest-2391-rebase cargo test -p codewhale-tui warmup_status --all-features
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/harvest-2391-rebase cargo test -p codewhale-tui cache_inspect --all-features
Harvested from #2390 with thanks to @wplll.
Records the actual tool catalog used by the last model request, reports that catalog in /cache inspect JSON and text output, and includes review hardening for stale catalog clearing, JSON/verbose flag handling, and CJK-aware token estimates.
Validation:
- cargo fmt --all -- --check
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/harvest-2390 cargo test -p codewhale-tui cache_inspect --all-features
Harvested from #2377 with thanks to @buko.
Threads the parent MCP tool pool into child SubAgentRuntime construction and registers MCP-backed tools for child agents when MCP is enabled, while leaving the broader mention-browser/provider/config work for focused follow-ups.
Validation:
- cargo fmt --all -- --check
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-pr2377-target cargo test -p codewhale-tui tools::subagent
- CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/harvest-2377-recheck cargo test -p codewhale-tui tools::subagent --all-features
Harvested from #2343 with thanks to @lucaszhu-hue.
Registers AtlasCloud static model rows for Pro and Flash resolution, adds provider-hinted alias coverage, and updates neutral provider docs and env examples while leaving promotional assets/copy out.
Harvested from #2393 with thanks to @wplll.
Strengthens the tool-result dedup regression coverage by exercising repeated medium-sized outputs that are above the dedup threshold but below the truncation budget.
Harvested from #2392 with thanks to @wplll.
Makes project context pack path ordering deterministic across Unix and Windows-style separators while keeping README/config/source entries prioritized before general directory noise.
Harvested from #2402 with thanks to @axobase001.
Keeps `allow_shell` guidance visible for gated shell tools even when missing-tool suggestions exist, removes the nonexistent task_shell_cancel matcher, and broadens regression coverage.
Partially addresses #2328.
Harvested from #2415 with thanks to @axobase001.
Keeps the denser mobile QR renderer and replaces the fixed binding-warning sleep with health polling plus an explicit timeout failure path, so slow starts fail with the useful cause instead of drifting into misleading assertions.
Follow-up to #2403.
Harvested from #2408 with thanks to @axobase001.
Adds regression coverage proving tty:true shell commands receive a controlling terminal, with a longer wait margin so the test is stable on slower CI hosts.
Partially addresses #2372.
Harvested from #2405 with thanks to @axobase001.\n\nCompacts the statusline token chip to use the short label while preserving the existing token detail and adding focused coverage for the rendered label.\n\nPartially addresses #2309.
Harvested from #2400 with thanks to @axobase001.\n\nAligns the configuration docs around CODEWHALE_HOME while preserving the DEEPSEEK_HOME legacy alias and spelling out how legacy checkpoints can still be scanned during cleanup.\n\nCloses #2322.
Harvested from #2406 with thanks to @axobase001.
Adds auto-selected model and reasoning effort to turn metadata while keeping user text isolated in its own content block. Includes the comment cleanup requested in review.
Partially addresses #2380.
Harvested from #2407 with thanks to @axobase001.
Adds a first-time macOS Python FAQ and completes the virtualenv flow with the final run command.
Fixes#2351.
Harvested with thanks to @aboimpinto.
Includes the ExternalTool abstraction layer plus follow-up fixes for lossy REPL stdout handling and unquoted unicode git diff paths.
Validation included full CI and focused local checks for non-UTF8 REPL stdout, git_diff, and external_tool behavior.
* feat: add mobile smoke tests and QR code for mobile URL
#2396: Add scripts/mobile-smoke.sh that launches the compiled binary on
loopback ports and verifies the mobile surface through real HTTP requests:
- Token auth (401/200, Bearer, query param, approval 404)
- Insecure mode (no token required)
- Binding warnings (0.0.0.0, LAN URL hint)
Add mobile-smoke job to CI workflow.
#2397: Add --qr flag to 'codewhale serve --mobile' that renders a
terminal QR code for the mobile URL. Uses the LAN IP when available,
falls back to 127.0.0.1. Adds qrcode crate (pure Rust, no C deps).
* fix: address review feedback on mobile smoke tests
- Fix Test Group 3 subprocess capture: use temp file instead of command
substitution to avoid hanging and subshell variable isolation
- Allow BINARY path to be overridden via BINARY env var
- Add libdbus-1-dev system dependency to CI job for ubuntu build
* fix: pass auth header in mobile smoke status helper
* fix: send approval JSON in mobile smoke
---------
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Co-authored-by: Hunter B <hmbown@gmail.com>
* feat: add Claude theme — warm navy & coral palette
Add a new theme aligned with Claude Code's product surface colors:
deep navy surfaces (#181715), cream-tinted text (#faf9f5),
coral accent (#cc785c), and teal secondary (#5db8a6).
Includes cell-level remap pipeline registration and full
WCAG contrast QA compliance.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(theme): address review feedback on Claude theme
- Fix text_dim contrast: #615E58 → #72706A (2.77 → 3.62, passes WCAG AA)
- Fix error_fg/error_border contrast: #C64545 → #E06060 (3.70 → 5.13, passes AA)
- Use amber #E8A55A for accent_action (distinct from accent_primary coral)
- Fix theme_picker test expecting GruvboxDark as last theme
- Remove broken include_str!("../../../web-chat/index.html") reference
left by incomplete web-chat revert
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: revert version bump, keep theme-only changes
---------
Co-authored-by: Hu Qiantao <huqiantao@HudeMacBook-Air.local>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Hunter B <hmbown@gmail.com>
* fix(tui): init runtime log before EnterAlternateScreen, add Windows stderr redirect
Two root causes of verbose logging leaking into the TUI alt-screen:
1. EnterAlternateScreen was called BEFORE runtime_log::init(), so any
logging between alt-screen entry and redirect init leaked raw bytes
into the TUI buffer — causing the 'scroll demon' on all platforms.
2. redirect_stderr_to was #[cfg(unix)] only — Windows had no stderr
redirect at all, so every eprintln!/tracing call during the TUI
session wrote directly into the alt-screen buffer.
Fixes:
- Swap order: init runtime_log (with stderr redirect) BEFORE entering
the alt-screen, so the redirect is active from the start.
- Add #[cfg(windows)] redirect_stderr_to using SetStdHandle from the
already-available windows crate, with corresponding Drop impl to
restore the original handle.
Fixes#1909
* fix(tui): handle Windows stderr redirect API types
* docs(tui): update runtime log stderr redirect notes
* fix: propagate SetStdHandle error instead of using .context()
Use .map_err() with a descriptive message and cast target to isize
for the HANDLE constructor, so the error is properly propagated if
SetStdHandle fails.
Co-Authored-By: bot_apk <apk@cognition.ai>
* fix(tui): pass raw Windows stderr handle
* fix: use DuplicateHandle for Windows stderr redirect to avoid handle aliasing
The previous implementation used file.as_raw_handle() directly with
SetStdHandle, causing both _file and the process stderr table entry to
share the same HANDLE. If a third-party library called CloseHandle on
the stderr handle during the TUI session, it would silently invalidate
_file and cause a double-CloseHandle on guard drop.
Now we call DuplicateHandle before SetStdHandle to produce a truly
independent handle for the redirected stderr, mirroring the Unix path's
use of libc::dup. The duplicated handle is tracked in the guard struct
and properly closed on drop after the original stderr is restored.
Co-Authored-By: bot_apk <apk@cognition.ai>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: bot_apk <apk@cognition.ai>
* fix: Windows .bat launcher with correct JS escaping and codewhale rebrand
* fix: complete Windows bat release asset handling
---------
Co-authored-by: cy2311 <cy2311@users.noreply.github.com>
Co-authored-by: Hunter B <hmbown@gmail.com>