- Add CODEWHALE_RELEASE_BASE_URL as canonical env override for release
asset base URL (DEEPSEEK_TUI_RELEASE_BASE_URL and DEEPSEEK_RELEASE_BASE_URL
remain as legacy fallbacks).
- Add CODEWHALE_USE_CNB_MIRROR env var to auto-select the CNB (cnb.cool)
mirror for binary downloads, avoiding GitHub Releases timeouts in China.
- Update npm install scripts (artifacts.js) with the same env checks.
- Update Rust self-updater (update.rs) with new constants and env cascade.
Fixes#2222.
Update all three READMEs (en, zh-CN, ja-JP) to use the canonical
~/.codewhale paths for config, skills, and Docker volume mounts, with
legacy ~/.deepseek noted as a compatibility fallback. The state-root
migration has been underway since v0.8.44 — the docs now reflect it.
The /save command now writes to ~/.codewhale/sessions (or legacy
~/.deepseek/sessions) instead of the workspace root. Update the test
to set CODEWHALE_HOME to a temp directory and pre-create the sessions
subdirectory so resolve_state_dir picks the primary path.
Fixes the first failing test in #2223.
Steered/queued user messages were being inserted into app.history
before the active cell (holding streaming thinking/tool content) was
flushed, causing the user's message to render above (before) the
thinking block that chronologically preceded it.
Now call app.flush_active_cell() before app.add_message() in
steer_user_message(), matching the pattern used in MessageStarted
and MessageDelta handlers.
Fixes#2225.
- Add resolve_project_state_dir and ensure_project_state_dir to
codewhale-config, providing project-local .codewhale/.deepseek
resolution matching the home-directory pattern.
- Migrate snapshot paths to prefer ~/.codewhale/snapshots with
~/.deepseek/snapshots fallback (snapshot_base_with_home).
- Migrate skill_state.rs to use codewhale_config::ensure_state_dir
instead of hardcoded home.join(".deepseek").
- Update doc comments to reference canonical .codewhale paths.
Part of #2231 (state-root migration).
Add entries for deadlock fix (#1856), composer text selection (#2228),
and project context loading tracing (#2227). Add community credits for
@Fire-dtx and @imkingjh999.
Emit a tracing::info! line with the file path and byte size when a
project context file (AGENTS.md, CLAUDE.md, etc.) is successfully loaded.
This helps users and maintainers verify which file was used during
prompt assembly, addressing the confusion reported in #2227.
Add mouse drag selection and Shift+Arrow text selection in the composer
input box. Ctrl+C copies selected text; Ctrl+X cuts (or toggles mode if
no selection). Selection highlighting uses the theme's selection_bg color.
Mouse coordinate mapping accounts for wrapping, scroll offset, and padding.
Also fix Home, End, Ctrl+A, and Ctrl+E to clear the selection anchor
before jumping, matching the existing Left/Right behavior. Without these
calls a stale anchor silently reforms a selection and can cause unintended
deletions on the next keystroke.
Harvested from #2228.
Co-authored-by: imkingjh999 <imkingjh999@users.noreply.github.com>
Replace `Arc<RwLock<()>>` in ToolCallRuntime with `Arc<Semaphore>` to
eliminate the risk of a tool re-entering and deadlocking on the same lock.
Parallel tools now acquire then immediately drop the permit, allowing
concurrent execution after any in-flight serial tool finishes. Serial
tools hold the permit for the full duration.
Fixes#2157. Harvested from #1856.
Co-authored-by: Fire-dtx <58944505+Fire-dtx@users.noreply.github.com>
The wlcopy_helper_succeeds_when_binary_returns_zero test used
`true` as a stand-in for wl-copy, but `true` exits immediately
without reading stdin. On Linux CI runners the process exits
before the parent can write to the pipe, producing EPIPE and
failing the is_ok() assertion.
Switch to `cat` which reads stdin until EOF (when the pipe is
closed) and then exits 0, faithfully modelling a successful
wl-copy invocation.
The static website/ HTML files were the original codewhale.net surface
before the Next.js app under web/ took over. They have not been deployed
in some time and are now mirrored in the new dedicated site repo
(Hmbown/codewhalesites) only as far as history matters.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the dense 85-line 'What Is It' section with a tight 15-line
version using a three-column table:
- Start with trust — the 'A' preamble
- Clear jurisdiction — Constitution with nine tiers of authority
- Recursive improvement — V4 helps write the harness, loop tightens
All three languages (EN, zh-CN, ja-JP) updated. Contributors preserved.
- Sync root and crate CHANGELOG.md for version drift check
- Add community contributor credits to [0.8.46] section
- Remove stray '...' file that broke Windows git checkout
- config/src/lib.rs: remove undefined has_api_key variable (#2062 conflict)
- ui.rs: clone receipt before move into set_receipt_text
- footer_ui.rs: convert &str to String for if/else type consistency
- rlm.rs: use ref bindings to avoid partial moves of stdout/stderr_preview
- file.rs: prefix unused fuzz variable
- update.rs: remove redundant borrows
- tests.rs: allow print_stderr on catalog metrics test function
All clippy warnings resolved. CI should go green.
Issue 1600 asks for full rename UX: set a custom title, remove it back
to `(unnamed)`. The set side already shipped as `deepseek thread
set-name <id> <name>`, but there was no inverse — users who wanted to
drop a no-longer-relevant title had to either edit the SQLite store by
hand or set a placeholder string.
Add `deepseek thread clear-name <id>`, mirroring the existing
`SetName` arm in `run_thread_command`: look up the thread, set
`name = None`, refresh `updated_at`, upsert. Printed confirmation is
`cleared name for <id>` so it stays distinguishable from the
`renamed` line emitted by `set-name`.
Snapshot help test and the parser-matrix test both gain the new
subcommand. No state-store changes: `upsert_thread` already accepts
`name: None` and `thread list` already prints `(unnamed)` when the
field is empty, so the round-trip is complete with this CLI-only
change.
Co-authored-by: Claude <noreply@anthropic.com>
portable-pty 0.8.1 depends on nix 0.25.1, which lacks loongarch64 in
its ioctl cfg blocks, causing a build failure on LoongArch64 Linux.
portable-pty 0.9.0 depends on nix ^0.28, which fully supports
loongarch64. The public API surface used by CodeWhale is unchanged.
Closes#1945
The `effective_max_output_tokens` heuristic defaults to 64K for any model
not in the known-context-window table. This is fine for DeepSeek's hosted
API (1M context) but causes immediate HTTP 400s on self-hosted providers
with tight `max-model-len`.
Example: vLLM serving Qwen3.6 with `--max-model-len 65536` rejects
requests because 64000 (output) + ~1500 (input) exceeds the limit by 1
token.
This change lets the operator set `DEEPSEEK_MAX_OUTPUT_TOKENS=16384` (or
whatever fits their deployment) to override the heuristic. The env var
takes precedence over the model-table lookup when set to a positive
integer; otherwise the existing behavior is preserved.
No new config struct field — env-only override keeps the public API
unchanged. Useful for embedded users (e.g. pinvou3) who need to control
output budget without forking the engine config schema.
Co-authored-by: hexin <he.xin@h3c.com>
* feat: session token breakdown in footer and /status
Add accumulated session token tracking with input / cache-hit / output
breakdown. Rebased from PR #1666 onto post-rebrand main (v0.8.45).
Changes:
- SessionState: new total_input_tokens, total_cache_hit_tokens,
total_cache_miss_tokens, total_output_tokens fields
- Turn outcome handler: accumulate per-turn token breakdown
- StatusItem::Tokens: new footer chip, enabled by default
- Footer chip: "12K in · 8.1K cch · 2.5K out" format
- /status: expanded with session input/cache/output rows
- /clear and /load: reset accumulated breakdown
* fix: address review feedback — current_session_id, cache guarding, DRY helper
- Restore app.current_session_id assignment accidentally dropped in
apply_loaded_session during rebase (P1: breaks startup-resume and
session-sync paths)
- Guard cache-hit/miss accumulation behind is_some() so providers
that omit cache telemetry don't inflate miss totals
- Extract SessionState::reset_token_breakdown() to avoid duplicating
the four-field reset in core/session/ui call sites
- Hide the "cch" segment from the footer token chip when no cache
data has been recorded
- Show "not reported" in /status session-cache row instead of
"0 hit / 0 miss" when no cache telemetry is available
Adds Metaso AI Search as a new SearchProvider option alongside Bing,
DuckDuckGo, Tavily, and Bocha.
Co-authored-by: Zhao Xiaohong <zhaoxiaohong@metasota.ai>
grep_files runs its directory walk and per-file regex synchronously inside
the async execute(). On a large tree this pins the runtime worker for
minutes, so the turn loop can't observe the cancel token and the stop
button stays unresponsive — the same failure file_search fixed in #2035.
Mirror that fix: move the blocking walk onto spawn_blocking, bounded by a
30s hard timeout with a biased select on the cancel token, via a
run_blocking_grep helper that parallels run_blocking_file_search. Output
and the existing per-file/per-line cancel checks are unchanged.
Co-authored-by: hexin <he.xin@h3c.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(paste): preserve Enter suppression window after non-char keys during paste
* chore(paste): add debug_assert for buffer precondition in deactivate_keep_window
Documents the invariant that buffer must be flushed before calling deactivate_keep_window. The assert fires in debug builds only, catching future misuse without masking upstream bugs.
When the workspace is the user's home directory, the project-scope
config file (~/.deepseek/config.toml) is also the global config file.
Skip the merge to avoid redundant processing and a misleading
"project-scope config key ignored" warning on every launch from ~.
Fixes the home-directory false-positive in the #417 deny-list
check: the deny-list correctly refuses dangerous keys at project
scope, but when cwd == $HOME the project file *is* the global file
so the warning is noise.
The formula downloaded deepseek-macos-arm64 (the deprecation shim) as the
main binary. After the rebranding, deepseek is just a wrapper that spawns
codewhale, but codewhale was never installed — causing "codewhale not
found on PATH" for every Homebrew user.
Now the formula downloads codewhale-* as the primary binary and installs
all four artifacts: codewhale, codewhale-tui, deepseek (legacy shim), and
deepseek-tui (legacy TUI shim).
Closes#2104
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
When running in a Feishu thread-enabled group (话题群), every bot
response — status messages, approval prompts, streaming progress,
turn results — was sent via the Lark SDK's `create` API which spawns
a new standalone topic. The user sees a cluttered group with orphan
topics for each intermediate bot message.
Root cause: `sendText()` only called `client.im.message.create()`
with a bare `chat_id`, never passing any reply context. The Feishu
`reply` API was completely unused.
Fix (two changes, one site each):
1. **lib.mjs — incomingIdentity()**: expose `parentId`, `rootId`,
`threadId` from the raw Feishu message event so callers can
determine thread context. (Not consumed directly yet, but
available for future use.)
2. **index.mjs**:
- `handleIncomingMessage()`: store the latest incoming
`messageId` as `replyToMessageId` in the per-chat thread store.
- `sendText()`: look up `replyToMessageId` from the thread store;
when present, call `client.im.message.reply()` instead of
`create()`. This keeps ALL bot responses nested under the
original user message inside the same topic.
No config changes needed. New chats automatically start using the
reply path; existing chats without a `replyToMessageId` in the store
fall back to the old `create` behaviour.
/ 修复飞书话题群中 bot 消息新建独立话题的问题。所有回复改为使用 reply API
/ 在原话题内嵌套回复,而非通过 create API 创建新话题。
Three interrelated feedback issues resolved:
1. Windows desktop notifications (notifications.rs)
- resolve_method() now returns Method::Bel on Windows instead of
Method::Off, so windows_bell() (MessageBeep) fires a system
notification sound when a long turn completes.
2. Tool output summary truncation (history.rs)
- TOOL_TEXT_LIMIT increased from 180 to 300 characters, reducing
the chance that meaningful tool output is cut short in the
one-line summary shown in tool cards.
3. Turn completion status visibility (ui.rs)
- Added a push_status_toast(Info, 10s TTL) call alongside the
existing set_receipt_text() in the TurnComplete handler. The
receipt text is now visible in both the composer border (8s)
and the footer status bar (10s).
4. Footer working-time feedback (footer_ui.rs)
- Footer state label now includes elapsed seconds from
turn_started_at immediately, instead of waiting 30 seconds for
the stall_reason classification to kick in.
- When app.is_loading is true, the label shows elapsed time so
users see ongoing progress during model-loading phases.