Skip bare separator and dot tokens during @-mention completion so Windows and WSL2 workspaces do not trigger an eager filesystem walk on the UI thread.
Rename the 14 workspace member crates from `deepseek-*` (and
`deepseek-tui-*`) to `codewhale-*`. Internal-only — binary names
(`deepseek` and `deepseek-tui`) are intentionally untouched in this
phase; they move in the next phase along with the deprecation shims.
Affects:
- 14 `[package] name = "..."` declarations.
- All inter-crate `[dependencies]` entries that referenced the old
package names.
- All `use deepseek_*::...` statements rewritten to `use codewhale_*`.
- Cargo.lock regenerated.
CI workflows and release scripts that pass `-p deepseek-*` still
reference the old names; those move with the binary rename phase so
that pair lands together.
Local gates green: `cargo check --workspace --all-targets --locked`,
`cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets
--all-features --locked -- -D warnings`, `cargo test --workspace
--all-features --locked` (3226+ pass, 0 fail).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per gemini-code-assist review on #1749: End on a newline character
should stay at the end of the current line (idempotent), not skip
to the next line. Removes the non-standard skip-past-newline logic
and updates the associated tests.
Plain Home and End now navigate within the current line instead of
jumping to the absolute start/end of the entire input. Ctrl+A and
Ctrl+E remain as absolute start/end shortcuts.
- Add move_cursor_line_start() / move_cursor_line_end() to App
- Wire Home -> move_cursor_line_start(), End -> move_cursor_line_end()
- On single-line input the new methods behave identically to the
absolute versions (no behaviour change)
- End on a newline character skips to the end of the next line
- 14 tests covering multiline, singleline, and edge cases
Address gemini-code-assist review on PR #1744 (two MEDIUM):
- cmd detection used program.eq_ignore_ascii_case("cmd"), which fails
for a full path (C:\Windows\System32\cmd.exe) or a .exe suffix, so the
raw_arg quoting fix would not apply. Use Path::file_stem() instead
(fully-qualified std::path::Path -> no unused import off-Windows).
- Strengthen the Windows block of issue_1691_quoted_commit_message_round_trips
to assert argv content equals spec.args, not just arg count, so the
raw_arg payload (quotes preserved, no extra escaping) is actually
verified. sandbox/mod.rs already asserts content -- left untouched.
Windows paths are cfg-gated (compile-checked on macOS, executed on
Windows CI). macOS build + clippy clean.
Refs #1691.
git commit -m "feat: complete sub-pages" failed on Windows with
'pathspec sub-pages" did not match' because the quoted -m message was
split on spaces. Root cause is not a tokenizer bug: CommandSpec::shell()
builds 'cmd /C "chcp 65001 >/dev/null & <command>"' and std::process::Command
applies MSVCRT escaping (" -> \"); cmd.exe does not use MSVCRT parsing,
so the quoting is destroyed and git receives feat:/complete/sub-pages"
as separate pathspecs. The Unix sh -c path was already correct.
Add a cfg-split push_shell_args() replacing cmd.args() at the 3 std
spawn sites in shell.rs. On Windows, for the cmd /C <payload> shape
only, pass /C and payload via CommandExt::raw_arg so the string reaches
cmd.exe verbatim (as a terminal does); other programs keep normal
escaping. Non-Windows is a faithful pass-through (byte-for-byte
unchanged). portable_pty path intentionally untouched (out of scope).
The Unix path is provably unchanged (tested); the Windows raw_arg
runtime correctness is only verifiable on a Windows runner -- flagged in
the PR for Windows CI verification per the #1736 Windows policy.
Refs #1691, #1736.
Address gemini-code-assist review on PR #1742 (MEDIUM): the status was
emitted at the assistant-persist site, but the same turn can still
CONTINUE for pending steers or sub-agent completions -- the user would
see a spurious 'turn ended without output' notice immediately before the
turn resumed.
Capture thinking_only_no_sendable at the persist site (no emission
there) and decide at the end of the tool_uses.is_empty() path, just
before the terminal break -- reachable only when there were no pending
steers, no sub-agent completions, and we were not holding for running
children. Extend should_emit_thinking_only_status with steers_pending
and holding_for_subagents (false if either), recomputed live at the
decision point as defense-in-depth. Unit test updated with the two new
no-emit cases.
Refs #1727.
When a model streams a turn with only a reasoning block (empty content,
no tool_calls -- e.g. gpt-oss via ollama's harmony->OpenAI shim mapping
to reasoning_content), has_sendable_assistant_content is false: the
if-only persist branch was skipped, NO event was emitted, and the turn
fell through to break. The UI spinner hung with no reply and no error.
Add an else-if at the same persist site that, only on a clean end
(tool_uses empty, turn_error.is_none(), not cancelled), warns and emits
an Event::status notice telling the user the turn ended and they can
retry. No assistant message is persisted (prior behavior preserved); no
retry/re-prompt/placeholder policy is added (out of scope). Guard
ordering extracted into a pure should_emit_thinking_only_status() helper
with a unit test, matching the existing should_hold_turn_for_subagents
style. Maintainer audit #1736 confirms #1727 is not shipped in v0.8.39
and release-blocking.
Refs #1727, #1736.
Address gemini-code-assist review on PR #1743:
- HIGH: should_replay_reasoning_content_for_provider was made model-aware
in the previous commit, but handle_chat_completion_stream still computed
is_reasoning_model = requires_reasoning_content(model) &&
provider_accepts_reasoning_content(provider). On the openai provider +
a DeepSeek model that was false during SSE parsing, so reasoning tokens
were stored as content (not reasoning_content) and the next request
still 400'd -- the fix was incomplete. Extract is_reasoning_model_for_stream()
and route the stream call site through it; add an equivalence test
locking it to the replay predicate so the two paths can't drift.
- MEDIUM: rename generic_openai_provider_drops_deepseek_reasoning_content
-> generic_openai_provider_drops_reasoning_content_for_non_deepseek_models
(now uses gpt-4o; old name was misleading).
Non-DeepSeek models on any provider are unaffected (#1542 not regressed).
Refs #1739, #1694, #1542.