Commit Graph

949 Commits

Author SHA1 Message Date
Hunter Bown 25f070919c test(tui): gate ANSI-byte recover_terminal_modes asserts to non-windows
Crossterm routes the same logical commands through the WinAPI console
backend on Windows, so EnableFocusChange / Push keyboard flags /
EnableMouseCapture / EnableBracketedPaste never reach the writer as
ANSI bytes there. Gate the byte-level test with cfg(not(windows)) and
add a windows-only smoke test that just exercises the function for
panic-freedom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:43:58 -05:00
Hunter Bown 8bf7bf8ba6 fix(mcp): collapse SSE message match arm to satisfy clippy
The "message" arm wrapped its work in `if !data.trim().is_empty()`,
which clippy::collapsible_match flags. Move the predicate into a
match guard so the inner branch is the only body.

No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:43:44 -05:00
Hunter Bown c916960b23 feat(tools): expose recall archive in parent registry 2026-05-09 13:33:49 -05:00
Hunter Bown 3d45476d4f refactor(config): drop unwired context per-model field 2026-05-09 13:31:56 -05:00
Hunter Bown d109a26f35 refactor(cycle): remove stale per-model config comment 2026-05-09 13:29:18 -05:00
Hunter Bown d67752f36a docs(codemap): soften cycle manager classification 2026-05-09 13:27:57 -05:00
Hunter Bown dcf7b66ad8 refactor(mcp): centralize json-rpc framing 2026-05-09 12:34:53 -05:00
Hunter Bown b78c2f8483 refactor(update): replace curl downloads with reqwest 2026-05-09 12:34:53 -05:00
Hunter Bown 6f963adc10 fix(update): verify release assets from checksum manifest 2026-05-09 12:34:53 -05:00
Hunter Bown a6ec43ece4 refactor(tui): unify terminal-mode recovery in recover_terminal_modes()
Extract the common "re-arm keyboard enhancement, mouse capture, bracketed
paste, and focus events" sequence used by app startup, FocusGained
recovery, and resume_terminal into a single best-effort helper.

The FocusGained handler previously only re-pushed keyboard enhancement
flags + (after v0.8.24) mouse capture, missing bracketed paste and focus
events. Each new mode added at startup was a fresh gap waiting to be
discovered when a user Cmd+Tabbed away. Co-locating the four flags in
one canonical helper means future mode additions are one edit, not three.

Adds a unit test that pins the gating (mouse + bracketed paste honor
their booleans; keyboard + focus are unconditional) by writing into an
in-memory buffer and asserting on the CSI sequences crossterm emits.

Test: cargo test -p deepseek-tui --bin deepseek-tui --locked
2026-05-09 12:34:53 -05:00
Hunter Bown 42cccee02d fix(markdown): wrap long table cells instead of truncating with
The previous render_table_row truncated cell content with `…` whenever
a cell's display width exceeded `(terminal_width - 7) / num_cols`. In
narrow terminals or with verbose English/Chinese instructional tables
(common in LLM responses), users would see only the first ~30
characters of meaningful content per cell with the rest silently lost
— not visible by scrolling, not recoverable.

Replace the truncation with a word-wrapping renderer that preserves
the full cell content across multiple visual lines while keeping the
column separators (`│`) aligned on every wrapped continuation line.
The row's visual height becomes the height of the tallest column;
shorter columns get blank-padded continuation rows so column edges
stay aligned.

Algorithm:
- wrap_cell_text splits on whitespace and packs words greedily until
  the next word wouldn't fit; words wider than col_width are
  hard-broken at character boundaries so wrapping always makes
  progress (URLs, paths).
- render_table_row pre-wraps every cell, computes the row height as
  max(cell_segments_len), then emits N visual lines with each cell's
  segment-or-empty padded to col_width and separated by `│`.

Adds two regression tests covering: long cells preserve content (no
`…`) and wrapped continuation lines retain column separators.
2026-05-09 12:34:53 -05:00
Duducoco e10e53d396 fix(client): stabilize reasoning_content replay for prompt cache (#1297)
* fix(client): stabilize reasoning_content replay for prompt cache

- stop gating assistant reasoning_content on whether a later user turn
  exists; the field now depends only on the stored message itself
- preserve historical message bytes across turns so DeepSeek's prefix
  cache stays warm on every text-reply follow-up
- add a byte-stability regression test and update the prior-non-tool
  reasoning test to assert the new contract

* style(client): rustfmt single-line let binding

- collapse a two-line `let mut has_reasoning = ...` into a single line
  so `cargo fmt --all -- --check` passes
2026-05-09 12:34:36 -05:00
jinpengxuan ebae6a07f6 fix: respect active provider credentials during onboarding (#1265) 2026-05-09 12:32:52 -05:00
heloanc 2e1cec79dd fix(tui): make Home/End keys move cursor in input box (#1246)
Previously, Home/End without modifiers scrolled the transcript
instead of moving the cursor to the start/end of the input line.
This is unexpected for most users who expect standard text editing
behavior.

Now:
- Home/End (no modifier) → move cursor to start/end of input
- Ctrl+Home/End → scroll transcript to top/bottom

Closes #1234

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-authored-by: heloanc <heloanc@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-05-09 12:30:17 -05:00
Hunter Bown e50eac0ce8 feat(mcp): support Streamable HTTP MCP endpoints with SSE fallback (#1300)
Closes #1266 (DeepWiki at https://mcp.deepwiki.com/mcp). URL-based MCP servers now try the modern Streamable HTTP transport first — POST JSON-RPC to the base URL with `Accept: application/json, text/event-stream`, accept either JSON or SSE response — and fall back to the older SSE endpoint-discovery flow on incompatible status codes (404/405/406/415/501). Existing SSE servers keep working via the fallback. Single-file change in `crates/tui/src/mcp.rs` with a tokio-based end-to-end test that exercises the full handshake.

Thanks @reidliu41.
2026-05-09 08:55:21 -05:00
Hunter Bown 65a4041112 fix(web): keep docs anchor scroll-margin overrideable (#1282)
Closes #1278. The docs page sets per-section `scroll-mt-32` (8rem) on each anchor section to clear the sticky nav, but the global `[id] { scroll-margin-top: 5rem }` rule loaded later with the same specificity, so 5rem won. Wrapping the global rule in `:where(...)` drops its specificity to 0, letting the page-level Tailwind utility win while still providing a fallback for anchors elsewhere on the site.

Thanks @Wenjunyun123.
2026-05-09 08:53:33 -05:00
Hunter Bown eaa68508f1 fix(i18n): use 终止 instead of 中止 in zh-Hans approval dialog (#1274)
Closes #1273. 中止 implies a temporarily-stoppable action; 终止 is the definitive 'end the turn' semantics that matches the English 'Abort the turn'. Updates two strings in the approval dialog (`option_abort` and the footer controls hint).

Thanks @Liu-Vince.
2026-05-09 08:53:22 -05:00
Hunter Bown 8ef903c60d fix(tui): align /config view columns by sizing key column from data (#1290)
Closes #1288. Long setting keys like `paste_burst_detection` were pushing Value and Scope columns out of alignment because the layout used a fixed 19-char minimum. Now the key column width is computed from the actual rows (with 19 as a floor) and shared between the header and each row. Header divider widens accordingly. Tests added.

Thanks @reidliu41.
2026-05-09 08:53:12 -05:00
reidliu41 e30583ab45 Support Streamable HTTP MCP endpoints
Add direct POST-based MCP transport for Streamable HTTP servers while keeping
  the existing SSE endpoint-discovery path as a fallback. Parse both JSON and
  text/event-stream responses so servers like DeepWiki can be validated and used.
2026-05-09 18:12:09 +08:00
reidliu41 9e7f100fe1 Fix config view column alignment
Size the config key column from the available setting keys so long keys like
  paste_burst_detection remain fully visible without pushing the value and scope
  columns out of alignment.

  Add a regression test covering long config keys and scope column alignment.
2026-05-09 16:22:42 +08:00
Hunter Bown cd27e6ceef chore(release): merge v0.8.24 (#1283)
Bugfix + community PR release. See CHANGELOG.md for full notes.
2026-05-09 02:41:48 -05:00
Hunter Bown 2c49b7e84b fix(release): bump per-crate Cargo.toml path-dep pins + npm package version to 0.8.24 2026-05-09 02:31:21 -05:00
Wenjunyun123 d633369b57 fix: preserve docs anchor offset 2026-05-09 15:28:46 +08:00
Hunter Bown 277621fba0 docs(release): credit contributors + document Project Context Pack default
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.
2026-05-09 02:26:41 -05:00
Hunter Bown 5f9f5ed558 fix(tui): re-arm mouse capture on FocusGained
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.
2026-05-09 02:17:22 -05:00
Vince cf51d8596d fix(i18n): use 终止 instead of 中止 in zh-Hans approval dialog
中止 implies a temporary pause that can be resumed; 终止 means a
definitive end, which matches the English "Abort the turn" / "abort"
semantics of this action.

Update both the option label ("终止本轮") and the Esc key footer hint
("Esc:终止") in the approval/elevation widget.

Fixes #1273
2026-05-09 14:20:04 +08:00
Hunter Bown 54ca5718d2 feat(cache): cache-aware prompt diagnostics and wire payload optimization (#1196)
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.
2026-05-09 00:20:13 -05:00
Hunter Bown 97d79862c2 chore(release): bump to 0.8.24, update CHANGELOG
Version bump: 0.8.23 → 0.8.24 in workspace Cargo.toml.

CHANGELOG entries for:
  - Workspace-local slash commands (#1259)
  - @-completion for gitignored dot-dirs
  - MCP paginated discovery via nextCursor (#1250, #1256, credit Liu-Vince)
  - Snapshot disk-space cap at 500 MB (#1112, credit Giggitycountless)
  - /clear resets Todos sidebar (#1258)
  - Language directive strengthened against project-context bias
  - Known issue: Windows flicker (#1260, #1251) — viewport-reset escape
    sequence on Windows conhost, investigation in progress
2026-05-09 00:12:33 -05:00
Hunter Bown 5670034d82 fix(todos): /clear now resets the Todos sidebar (#1258)
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.
2026-05-09 00:12:21 -05:00
Hunter Bown 097d0221c4 fix(prompts): explicitly mark project context as not a language signal (#1118, #1129)
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.
2026-05-09 00:12:12 -05:00
Hunter Bown b29d63b0c7 fix(snapshot): hard-cap side repo at 500 MB (#1112)
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).
2026-05-09 00:12:03 -05:00
Hunter Bown 808e981f56 fix(mcp): paginate tools/resources/prompts discovery via nextCursor (#1250, #1256)
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).
2026-05-09 00:11:51 -05:00
Hunter Bown 408708f13e fix(walk): include AI-tool dot-dirs in @-completion despite gitignore
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)
2026-05-09 00:11:40 -05:00
Hunter Bown 8dcb467bf5 feat(commands): scan workspace-local .deepseek/.cursor/.claude commands
Extend load_user_commands() to scan workspace-local command directories
in addition to the global ~/.deepseek/commands/. Precedence model
mirrors skills_directories(): project-local shadows global by name.

Scanned directories (in precedence order):
  1. <workspace>/.deepseek/commands/
  2. <workspace>/.claude/commands/   (Claude Code interop)
  3. <workspace>/.cursor/commands/   (Cursor interop)
  4. ~/.deepseek/commands/           (user-global fallback)

Workspace context threaded through:
  - try_dispatch_user_command (has App reference)
  - user_commands_matching (new workspace parameter)
  - all_command_names_matching (new workspace parameter)
  - slash_completion_hints (new workspace parameter)

Closes #1259
2026-05-09 00:11:28 -05:00
Hunter Bown 15f62e3e93 docs(readme): update What's New to v0.8.23 2026-05-08 22:21:01 -05:00
Hunter Bown cfb5f08ae5 fix(update): pass --ssl-no-revoke to curl on Windows (#1252)
Pre-tag fix for v0.8.23. Resolves Windows users hitting CRYPT_E_NO_REVOCATION_CHECK on `deepseek update`.
2026-05-08 21:07:56 -05:00
Hunter Bown 8f0bef9f15 fix(update): pass --ssl-no-revoke to curl on Windows
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.
2026-05-08 20:56:48 -05:00
Hunter Bown 73b5f5ea77 chore(release): merge v0.8.23 (#1245)
Security-focused release. Hardens child-process env, plan-mode tools, sub-agent approvals, MCP config paths, run_tests approval policy, fetch_url redirects (v0.8.22 backfill), runtime API auth. Fixes #1244 and the v0.8.21/v0.8.22 changelog gap. Thanks to @47Cid for responsible disclosure.
2026-05-08 19:51:25 -05:00
Hunter Bown 22414f15f7 fix(security): containment check for workspace-local skills dir
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.
2026-05-08 19:40:06 -05:00
Hunter Bown 51f2f04b47 Revert "Potential fix for pull request finding 'CodeQL / Uncontrolled data used in path expression'"
This reverts commit 326a1dacb9.
2026-05-08 19:38:14 -05:00
Hunter Bown 326a1dacb9 Potential fix for pull request finding 'CodeQL / Uncontrolled data used in path expression'
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-05-08 19:34:01 -05:00
Hunter Bown 43e572342a fix(tests): gate unix-only env_lock helper on cfg(unix)
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.
2026-05-08 19:06:31 -05:00
Hunter Bown 0ffa7bf720 docs(changelog): credit security disclosure across 0.8.22 + 0.8.23
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.
2026-05-08 18:58:01 -05:00
Hunter Bown 401c1f6cf8 fix(security): tighten approval policy for run_tests
`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.
2026-05-08 18:58:01 -05:00
Hunter Bown cd78b41fa3 test(release): replace hardcoded version assertion with CHANGELOG gate
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).
2026-05-08 18:21:21 -05:00
Hunter Bown 8e9957da5c chore(release): prepare v0.8.23
- 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.
2026-05-08 18:17:44 -05:00
Hunter Bown 77adb1030c fix(mcp): preserve spawn error chain and pass Node/proxy env (#1244)
`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.
2026-05-08 18:10:26 -05:00
Hunter Bown 07410521d7 fix(auth): default to file-backed secret store 2026-05-08 17:20:07 -05:00
Hunter Bown 9e6924c749 fix(security): narrow Plan mode tool surface 2026-05-08 14:47:16 -05:00
Hunter Bown 9dcbc94d51 test(skills): isolate command tests from global skills 2026-05-08 14:47:08 -05:00