CHANGELOG additions:
- Top-line credit summary: wplll, Liu-Vince, Giggitycountless,
SamhandsomeLee, barjatiyasaurabh, tyculw, hongyuatcufe, ljlbit.
- New "Added" section properly documenting #1196 (cache-aware
diagnostics, /cache inspect, /cache warmup, payload optimization,
Project Context Pack). Calls out that the Pack is default-on, adds
~1–10 KB to every prompt, and how to opt out via
[context] project_pack = false.
- Per-item issue reporter credits across the Fixed section.
- Removed #1129 from the i18n entry — that's a separate bug we did
not actually fix (wrong env var name in HTTP system prompt).
README updates: rewrote the "What's New" section in both README.md
and README.zh-CN.md to v0.8.24 with all the same credits and the
project_pack opt-out note.
Pre-existing gap exposed during v0.8.24 testing: when the user clicks
away (Cmd+Tab, opens the screenshot tool, etc.) and clicks back, some
terminals drop the application's mouse-tracking mode. The
\`FocusGained\` handler at \`ui.rs::1599\` already re-pushed keyboard
enhancement flags to recover IME state — extend the same recovery to
\`EnableMouseCapture\` so wheel scroll keeps working after a focus
round-trip. Gated on \`app.use_mouse_capture\` so explicit
\`--no-mouse-capture\` users aren't re-enabled against their will.
Merge of PR #1196 by wplll. Adds:
Cache-aware prompt layering:
- PromptBuilder struct separates prompt construction from inspection
- System prompt split into named layers with stability classification
- Layers classified as static/history/dynamic for cache debugging
/cache inspect command:
- SHA-256 hashes of each rendered prompt layer
- Base static prefix hash vs full request prefix hash
- Static prefix stability status across turns
- First-divergence tracking from previous request
Wire payload optimization:
- Tool result budget: large outputs compacted before API request
- Tool result dedup: repeated outputs replaced by compact refs
- Turn metadata dedup: repeated <turn_meta> blocks deduplicated
- Wire-only: local session messages remain unchanged
Project context pack:
- Deterministic workspace summary injected into stable prefix
- Configurable via [context] project_pack = false
Cache warmup and improved footer cache display.
Thanks to wplll for the contribution.
Previously clear_todos() only cleared the plan_state — the SharedTodoList
was never touched. Now it clears both: the todo list (via try_lock on
self.todos) and the plan state. The caller in commands/core.rs already
called clear_todos() on /clear; it just had nothing to clear.
Adds a directive to the ## Language section telling the model that
project context (AGENTS.md, auto-generated instructions, file trees,
skill descriptions) is NOT a language signal. Chinese filenames in a
repo should not bias the model toward Chinese replies when the user
writes in English.
Adds a disk-space guard before each snapshot: if the snapshot directory
exceeds MAX_SNAPSHOT_SIZE_MB (500 MB), the oldest snapshots are pruned
aggressively to stay under PRUNE_TARGET_MB (400 MB). If pruning cannot
get under the limit, the history is wiped so the next snapshot starts
fresh.
The guard runs in snapshot() before git add/write-tree/commit-tree so
disk pressure is relieved BEFORE taking another snapshot.
Includes dir_size_mb() helper and regression tests.
Thanks to Giggitycountless for the original max_size_mb proposal
(PR #1131).
MCP servers are allowed by spec to paginate list responses. The old
implementation made a single request and stopped, silently dropping
subsequent pages. Servers that paginate at fewer items than their
total tool count (e.g. gbrain at 5 per page) would appear to expose
only those first few tools.
All four discovery methods now follow nextCursor until the server
signals no more pages, accumulating results across all pages:
- discover_tools
- discover_resources
- discover_resource_templates
- discover_prompts
Thanks to Liu-Vince for the original diagnosis and fix (PR #1256).
Files inside .deepseek/, .cursor/, .claude/, and .agents/ were invisible
to @-mention Tab-completion when those directories were listed in
.gitignore (the common case). The walk_for_completions and
build_file_index paths now walk these directories separately with
gitignore disabled, merging results into the main candidate list.
Also excludes .deepseek/snapshots/ from the dot-dir walk so the snapshot
side repo (which can reach hundreds of GB, see #1112) is never indexed.
The fix applies to:
- @-mention Tab-completion (walk_for_completions)
- Fuzzy file resolution (build_file_index)
- Ctrl+P file picker (collect_candidates)
Windows ships curl built against Schannel, which performs mandatory
certificate-revocation checks. When the user's network can't reach
OCSP/CRL responders (corporate firewalls, captive portals, IPv6
hiccups, some ISPs), the TLS handshake fails with
\`CRYPT_E_NO_REVOCATION_CHECK (0x80092012)\` and \`deepseek update\`
is unable to fetch \`api.github.com\` or download release assets.
Add \`--ssl-no-revoke\` to every curl invocation issued by the
self-update path on Windows. Other platforms (OpenSSL/LibreSSL on
macOS/Linux/BSD) continue to use no extra flags. Helper is a pure
function over the OS string, so both branches are unit-tested.
Replaces the autofix in 326a1da (reverted in 51f2f04b4), which mistakenly
required `workspace` to live under the global config's skills directory
and therefore caused `resolve_skills_dir` to *always* fall back to the
global skills dir — silently breaking workspace-local `.agents/skills`
and `./skills` loading.
Apply the right containment check instead: canonicalize the workspace
once, canonicalize each candidate, and require the candidate to
`.starts_with` the canonicalized workspace before returning it. A
`skills` symlink that escapes the workspace (e.g. to `/etc`) now causes
the candidate to be rejected and resolution to fall back to the
configured global skills directory, preserving real symlink-escape
defense without regressing the feature.
Adds three regression tests: positive case for `.agents/skills`,
positive case for the `./skills` fallback, and a Unix-only test that
constructs a symlink-escaping `skills` directory and asserts it is
rejected.
The env_lock helper and its Mutex/OnceLock imports are only used by a
`#[cfg(unix)]` env-mutating test. On Windows that test compiles out
entirely, leaving env_lock as dead code under `-Dwarnings`. Gate both
the import and the helper with `#[cfg(unix)]` so the Windows test job
compiles.
Adds a Security bullet to v0.8.23 for the run_tests approval-policy
change, and credits @47Cid as the reporter on both the v0.8.22
fetch_url hardening and the v0.8.23 run_tests hardening. Neutral
language — no attack-vector detail.
`run_tests` declares `ToolCapability::ExecutesCode` and runs `cargo test`,
which executes workspace code at test, build-script, and proc-macro time.
Match the default approval policy for code-executing tools by returning
`ApprovalRequirement::Required` explicitly instead of overriding to
`Auto`. Adds a regression test pinning the approval requirement.
The prior `package_version_is_current_hotfix_release` test was a
brittle hardcoded `assert_eq!(env!("CARGO_PKG_VERSION"), "0.8.22")`
that needed manual update on every release and only restated what
`scripts/release/check-versions.sh` already enforces.
Replace with `changelog_entry_exists_for_current_package_version`,
which reads `CHANGELOG.md` and asserts a `## [X.Y.Z]` entry exists
for the current `CARGO_PKG_VERSION`. No hardcoded version string —
this self-updates with the workspace version bump and gates against
the actual class of bug we just patched (the v0.8.21 / v0.8.22
backfill gap).
- Bump workspace version 0.8.22 → 0.8.23 across Cargo.toml, every per-crate
path-dependency pin, npm/deepseek-tui/package.json (both `version` and
`deepseekBinaryVersion`), and Cargo.lock.
- Add a 0.8.23 CHANGELOG entry covering the security hardening stack
(sanitized child env, plan-mode tool surface, sub-agent approvals,
symlink walks, runtime API auth, shell safety classification, MCP
config path traversal), the macOS Keychain prompt fix, the #1244 MCP
spawn error visibility + env passthrough work, the compact-thinking UX
change, and a Known issues callout for mid-run MCP stderr.
- Backfill missing CHANGELOG entries for v0.8.21 (community-heavy
release, contributors credited) and v0.8.22 (fetch_url redirect
validation). The gap was unintentional, so contributor work is being
reflected in-repo now.
- Add docs/RELEASE_CHECKLIST.md so future releases gate on the
CHANGELOG/version/preflight steps explicitly.
`cmd.spawn()` failures now show the underlying io::Error via `{err:#}`
instead of dropping the chain in the snapshot, the `mcp connect`/`mcp
validate` CLI commands, and the engine status event. Users now see
"No such file or directory (os error 2)" or similar instead of the
opaque "MCP stdio spawn failed (...)" wrapper.
MCP stdio launches also get a wider env allowlist than arbitrary shell
tools — NVM_DIR, NODE_OPTIONS, NODE_PATH, NODE_EXTRA_CA_CERTS,
NPM_CONFIG_*, VOLTA_HOME, COREPACK_HOME, PYTHONPATH, PYTHONHOME,
VIRTUAL_ENV, PIPX_*, POETRY_HOME, UV_*, GEM_HOME/PATH, BUNDLE_*,
JAVA_HOME, HTTP/HTTPS/NO/ALL/FTP_PROXY (case-insensitive), and
SSL_CERT_*/REQUESTS_CA_BUNDLE/CURL_CA_BUNDLE — so common `npx`,
`uvx`, and proxy-bound corporate setups don't break under the
v0.8.22 child-env scrub. Secret-bearing parent env (AWS_*, GITHUB_TOKEN,
*_API_KEY, …) stays scrubbed, and the strict allowlist remains in
force for shell tools and other non-MCP child spawns.
## Summary
- Prefer a writable named Docker volume for the container home data path.
- Document the non-root UID/GID ownership requirement for host bind mounts.
- Update README and Docker docs examples to avoid permission-denied first runs.
## Test plan
- git diff --check
- GitHub CI green: version drift, lint, ubuntu, macOS, Windows, npm wrapper smoke, GitGuardian
## Summary
- Move the pager exit hint to the front of the footer so q/Esc is immediately discoverable.
- Preserve the rest of the pager footer metadata and styling.
## Test plan
- cargo test -p deepseek-tui pager --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI green: version drift, lint, ubuntu, macOS, Windows, npm wrapper smoke, GitGuardian
## Summary
- carry markdown render metadata through the message renderer so fenced code lines are identified explicitly
- keep normal conversational continuation rails for prose, but replace the rail with alignment spaces before fenced code lines
- add a regression test for assistant code blocks so the visible U+258F rail does not appear inside code output
## Test plan
- cargo test -p deepseek-tui assistant_code_block_lines_do_not_get_transcript_rail --locked
- cargo fmt --all -- --check
- git diff --check origin/main..HEAD
- GitHub CI: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian
## Summary
- treat the macOS Option+V legacy glyph as the tool-details shortcut instead of inserting text
- show the platform-appropriate details shortcut label in active tool status/footer copy
- add regression coverage for macOS glyph handling and existing tool-details target behavior
## Test plan
- cargo test -p deepseek-tui macos_option_v_glyph_is_treated_as_details_shortcut_only_on_macos --locked
- cargo test -p deepseek-tui detail_target_prefers_visible_tool_card --locked
- cargo test -p deepseek-tui active_tool_status_label_summarizes_live_tool_group --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI: Version drift, Lint, Test (ubuntu-latest), Test (macos-latest), Test (windows-latest), npm wrapper smoke, GitGuardian
## Summary
- normalize empty or missing tool-call names to unknown_tool in streaming and non-streaming responses
- include source/id context in fallback warnings
- add regression coverage for empty streaming names and missing non-streaming names
## Test plan
- cargo test -p deepseek-tui decoder_uses_fallback_name_for_empty_streaming_tool_name --locked
- cargo test -p deepseek-tui non_streaming_response_uses_fallback_name_for_missing_tool_name --locked
- cargo fmt --all -- --check
- git diff --check
- GitHub CI: Version drift, Lint, Test (ubuntu-latest), Test (macos-latest), Test (windows-latest), npm wrapper smoke, GitGuardian
## Summary
- Add explicit ID, Status, Time, and Title headers to /task list output.
- Align task rows without changing task storage or execution behavior.
## Verification
- GitHub CI passed: lint, version drift, ubuntu/macos/windows tests, npm wrapper smoke, GitGuardian.