Commit Graph

738 Commits

Author SHA1 Message Date
Reid 93cfb83a67 fix(tui): persist workspace trust in global config
fix(tui): persist workspace trust in global config
2026-05-06 10:24:55 -05:00
GK012 9a7cd9f937 fix(npm): add --version fallback in wrapper
fix(npm): add --version fallback in wrapper
2026-05-06 10:19:05 -05:00
Hunter Bown 7def57203f fix(tui): stop stealing Ctrl+E from composer
fix(tui): stop stealing Ctrl+E from composer
2026-05-06 10:13:00 -05:00
junskyeed d4185ede5a fix(engine): cap API request max_tokens
fix(engine): cap API request max_tokens without affecting internal context budget
2026-05-06 09:59:22 -05:00
xieshutao 686393dae3 fix(skills): accept plain markdown SKILL files (#869)
Accepts SKILL.md files without YAML frontmatter by using the first Markdown H1 heading as the skill name. This lets compatible plain Markdown skill files show up instead of being skipped with parse warnings.\n\nI added a small maintainer test commit to keep the command tests hermetic and cover both the plain-heading fallback and missing-heading warning path.\n\nVerification:\n- cargo test -p deepseek-tui skills --all-features\n- cargo fmt --all -- --check\n- git diff --check xieshutao/main...HEAD\n- cargo clippy -p deepseek-tui --all-targets --all-features -- -D warnings\n- GitGuardian Security Checks passed
2026-05-06 09:44:34 -05:00
ZzzPL 0f6b9ad26e fix(tui): add Windows clipboard fallback (#850)
Adds a PowerShell Set-Clipboard fallback on Windows when arboard clipboard writes are unavailable, before falling back to OSC 52.\n\nVerification:\n- cargo fmt --all -- --check\n- git diff --check origin/main...HEAD\n- cargo test -p deepseek-tui clipboard --all-features\n- cargo clippy -p deepseek-tui --all-targets --all-features -- -D warnings\n- contributor verified the same focused Windows checks on stable-x86_64-pc-windows-msvc\n\nNote: local x86_64-pc-windows-gnu cross-check is blocked on this macOS machine by missing x86_64-w64-mingw32-gcc.
2026-05-06 09:38:23 -05:00
Reid cdb82670d2 fix: show resume hint after TUI exit (#863)
Prints the canonical resume command after a successful TUI exit when a session id is available.\n\nVerified with local focused tests plus green CI.\n\nCloses #682.
2026-05-06 09:34:48 -05:00
Hunter Bown f932c4b9d2 fix: seed snapshot built-in excludes (#854) 2026-05-06 05:55:41 -05:00
Hunter Bown 2090792570 fix: explain dispatcher TUI spawn failures (#853) 2026-05-06 05:41:40 -05:00
John Doe a6a5e3aee8 fix(tui): cache @mention completions to fix cursor lag (#792) (#849)
* fix(tui): cache @mention completions to fix cursor lag (#792)

Cache file-mention completion results to avoid re-walking the filesystem
on every keystroke. The cache is invalidated when the partial text after
@, cursor position, or input content changes.

Fixes #792

* fix: keep mention completion cache stable on cursor moves

* style: satisfy mention cache clippy

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 05:28:56 -05:00
Hunter Bown a1a96d1afc fix: discover global agents skills (#848) 2026-05-06 05:21:02 -05:00
Hunter Bown 67eddd6344 fix: bound stream open waits (#847) 2026-05-06 05:16:44 -05:00
Duducoco 9b47ecfa4a feat(tui): show skills in slash command autocomplete menu (#808)
* feat(tui): show skills in slash command autocomplete menu

- add SlashMenuEntry struct with name, description, is_skill fields
- cache skill names/descriptions in App to avoid per-keystroke disk I/O
- render slash popup as two-column layout with precise Unicode width truncation
- include skill names in Tab autocomplete and visible_slash_menu_entries
- refresh skill cache after install/uninstall

* style(tui): apply rustfmt to slash menu and widgets

* fix: complete skills with valid slash command form

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 05:04:14 -05:00
Hunter Bown 9cf422d299 fix: fallback to OSC 52 for SSH clipboard copy (#845) 2026-05-06 04:54:06 -05:00
AGSaturn 8e987a4702 fix: preserve requested model ID casing in registry resolution (#733)
Previously, ModelRegistry::resolve() lowercased the requested model name
before looking it up in the alias map, and always returned the registry's
canonical (lowercase) model ID.  This broke third-party API providers
that enforce case-sensitive model name matching.

Now when the resolved model ID differs from the requested name only in
case (eq_ignore_ascii_case), the requested casing is preserved.

Closes #729

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 04:52:10 -05:00
Hunter Bown b62af3e047 fix: skip repeated language step after api key setup (#844) 2026-05-06 04:42:12 -05:00
Gerry Qi 7d798cfa66 fix(core): wrap fire-and-forget spawn_blocking calls with panic dump … (#810)
* fix(core): wrap fire-and-forget spawn_blocking calls with panic dump protection

* test(utils): cover supervised blocking panic handling

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 04:32:37 -05:00
zhouyf d5f4d89352 fix(web_run): decode percent-encoded UTF-8 bytes correctly (#840)
percent_decode in web_run.rs builds the result via `out.push(b as char)`,
mapping each decoded byte to its Latin-1 codepoint. For percent-encoded
multi-byte UTF-8 sequences (e.g. %E4%B8%AA = 个) this produces visible
mojibake: bytes E4 B8 AA become three Latin-1 chars `个` and the final
String is the UTF-8 encoding of those codepoints, not the original
character.

The sister module web_search.rs::percent_decode (line 490) already uses
the correct pattern: collect bytes into Vec<u8>, then finalize with
String::from_utf8_lossy. Align web_run.rs with that implementation.

Affects DuckDuckGo redirect URLs containing non-ASCII paths, where
normalize_search_url -> percent_decode previously corrupted the decoded
URL before it was shown to the model and to the user.

Add a regression test covering percent-encoded CJK input, raw UTF-8
input, and mixed ASCII+UTF-8.

Co-authored-by: Elowen <xrnc@outlook.com>
2026-05-06 04:28:30 -05:00
banqii 0a17f144c0 feat(skills): add .cursor/skills to skill discovery paths (#817)
* feat(skills): add .cursor/skills to skill discovery paths

    Adds Cursor IDE interop by scanning .cursor/skills alongside the
    existing .opencode/skills and .claude/skills directories (#432).
    Precedence: .agents/skills > skills > .opencode/skills >
    .claude/skills > .cursor/skills > ~/.deepseek/skills.

* test(skills): cover cursor skills discovery

---------

Co-authored-by: ornn.ban <ornn.ban@biuya.com>
Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 04:22:54 -05:00
Ziang Xie 6e2b854fdb fix(docker): remove misleading ENV, add explicit UID/GID, add .dockerignore (#827)
* fix(docker): remove misleading ENV, add explicit UID/GID, add .dockerignore

- Removed `ENV DEEPSEEK_API_KEY=""` and `ENV DEEPSEEK_NO_COLOR=""`:
  API keys should never be baked into image layers, even as empty strings.
  Added comments documenting runtime secret passing patterns.

- Added explicit UID/GID (1000:1000) for the `deepseek` user:
  Makes filesystem ownership unambiguous when mounting volumes and
  avoids the default auto-assigned UID shifting between hosts.

- Added `.dockerignore`:
  Prevents accidental inclusion of .env files, local runtime state,
  documentation, dev configs, and build artifacts into the build
  context, keeping the image smaller and avoiding secret leaks.

* fix(docker): keep nested build inputs in context

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 04:21:34 -05:00
kitty 719594636c feat(commands): add /rename command to set a custom session title (#836)
* feat(commands): add /rename command to set a custom session title

Adds a `/rename <new title>` slash command that lets users set a
human-readable name for the current session. The new title is
persisted immediately to the session JSON file so it appears in
the session picker on the next open.

- Max title length capped at 100 characters (char-count aware, handles CJK)
- Errors on missing/empty arg or no active session
- Inner `rename_with_manager` helper keeps unit tests fully isolated
  from ~/.deepseek/sessions
- Localized descriptions in en, ja, zh-Hans, pt-BR

* fix(rename): sync App state before saving to prevent data loss

Use update_session() to merge current in-memory messages and tokens
into the session before writing the renamed title, preventing stale
disk data from overwriting unsaved App state.

* style: format rename command

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 04:13:23 -05:00
Jason b86baa38ed fix(tools): enforce network policy in web_run (#800)
* fix(tools): enforce network policy in web_run

The web_run tool bypassed the network policy that fetch_url and
web_search respect. URL fetches (open/click) now check the configured
network policy before making outbound requests, consistent with other
network tools.

* fix: gate web run fetches by network policy

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 04:01:59 -05:00
zhouyf a212e44655 fix(tests): pin test app locale and provider to deterministic values (#825)
create_test_app() in commands/{core,debug,provider}.rs constructs App
via App::new, which reads system LANG. On a Chinese host this
auto-selects ZhHans for ui_locale (translating asserted strings) and
DeepseekCN for api_provider (which then differs from the
ApiProvider::Deepseek that tests pass to provider()).

Pin both fields after construction, matching the existing pattern in
home_dashboard_localizes_in_zh_hans which already sets app.ui_locale
to test Chinese rendering.

All 17 tests listed in the issue now pass on a host with
LANG=zh_CN.UTF-8.

Closes #791.

Co-authored-by: Elowen <xrnc@outlook.com>
2026-05-06 03:56:10 -05:00
Ziang Xie e2f596075f fix: write all config files with restrictive permissions (0o600) (#837)
* fix: write config files with restrictive permissions in all paths

Three config-file write paths in the TUI crate used `fs::write()` with
default permissions (typically 0644), leaving API keys world-readable:
- `save_api_key_to_config_file` (initial key storage)
- `save_api_key_for` (provider-specific key storage)
- `clear_api_keys_from_config_file` (logout/credential wipe)

Add a `write_config_file_secure` helper that uses `OpenOptions` with
mode 0o600 on Unix, and route all config writes through it. Also harden
`ensure_parent_dir` to strip group/other permissions from the config
directory.

* fix: harden tui config file permissions

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 03:51:48 -05:00
Ziang Xie df288c6734 fix: save config with restrictive permissions and improve secret redaction (#833)
* fix: save config with restrictive permissions and improve secret redaction

- Config files containing API keys were written with default permissions
  (typically 0644), making them world-readable on multi-user systems. Use
  OpenOptions with mode 0o600 on Unix to restrict access to the file owner.
- `redact_secret` threshold raised from 8 to 16 characters — previously a
  9-character secret would leak 8 of its 9 characters (4 prefix + 4
  suffix). Now secrets up to 16 chars are fully masked with "********".

* fix(config): keep secret saves warning-free on windows

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 03:42:27 -05:00
Hunter Bown 03e59c60ce fix(rlm): pin child calls to flash (#832) 2026-05-06 03:41:47 -05:00
Ziang Xie 69714819f8 fix: replace unreachable!() with proper error returns for DeepSeek providers (#835)
Three `unreachable!()` calls panicked if `save_api_key_for` or the API key
apply path ever received a DeepSeek/DeepseekCN variant past the early-return
guard. Replace them with explicit `Err` returns so a future refactor that
breaks the guard produces a recoverable error instead of a crash.
2026-05-06 03:38:30 -05:00
Ziang Xie 4994ce99f8 fix(command_safety): fix path_escapes_workspace false positive for double-dots in names (#824)
* fix(command_safety): fix path_escapes_workspace false positive for ".." in names

The path_escapes_workspace function used `path.contains("..")` to detect
directory traversal, which incorrectly flagged paths containing consecutive
dots in file or directory names (e.g., `foo..bar`, `dir..name/file.txt`).

Replace the substring matching with a component-level walk that tracks
nesting depth. Each `..` path component decrements the depth; if depth
ever goes negative the path has escaped the workspace. Non-`..` components
increment depth. This correctly:

- Flags genuine traversal like `../outside` and `./sub/../../etc/passwd`
- Ignores names with embedded double-dots like `some..file.txt`
- Allows safe intra-workspace `..` usage like `./subdir/../other`

* test(command_safety): cover absolute traversal paths

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 03:33:28 -05:00
Ziang Xie 026e9558a9 fix: replace std::thread::sleep with tokio::time::sleep in async context (#831)
The `execute` method of `ShellWaitTool` is async, but used
`std::thread::sleep` which blocks the tokio worker thread. Replace with
`tokio::time::sleep().await` so other tasks can make progress during the
50ms poll interval.
2026-05-06 03:29:43 -05:00
Hunter Bown 77b6d43088 chore(doctor): show resolved API endpoint (#823)
* chore(doctor): show resolved API endpoint

* test(tui): serialize markdown OSC8 parity render
2026-05-06 03:17:58 -05:00
Hunter Bown ab92892cc4 fix(session): scope latest resume to workspace (#830) 2026-05-06 03:16:44 -05:00
YuanSheng Wang 3e93143079 feat(tui): support Shift+Enter to insert newline in composer (#801)
* feat(tui): support Shift+Enter to insert newline in composer

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(tui): cover shift-enter newline handling

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 03:10:12 -05:00
Ziang Xie 950860768f fix(web_search): complete HTML entity decoding with numeric character references (#822)
* fix(web_search): complete HTML entity decoding with numeric character references

The decode_html_entities function only handled 7 named entities and lacked
support for decimal (&#NN;) and hex (&#xHH;) numeric character references,
which are common in search engine result snippets. This caused garbled text.

Replace the hard-coded replace chains with a regex-based decoder that
handles:
- All named entities (amp, lt, gt, quot, apos, nbsp, copy, reg, mdash,
  ndash, lsquo, rsquo, ldquo, rdquo, hellip)
- Decimal numeric references (&#65; → A)
- Hex numeric references (&#x41; → A)
- Unknown entities are passed through unchanged

* style(web_search): apply rustfmt

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 02:58:20 -05:00
Hunter Bown 58a0039c92 fix(install): avoid unstable file locking API (#821) 2026-05-06 02:53:30 -05:00
Hunter Bown a09a72572f fix(network): add allowlist slash command (#819) 2026-05-06 02:46:02 -05:00
Hunter Bown 1171c5e401 fix(skills): ignore symlinks outside selected install root (#814) 2026-05-06 02:36:57 -05:00
Zhang Yonglun 4408b59852 fix(config): the skills directory should be read recursively (#811) 2026-05-06 02:27:06 -05:00
ccomma 0d50cab251 fix: skip snapshots for dangerous workspaces (#804) 2026-05-06 02:14:59 -05:00
Hunter Bown a2ca64018e feat(cost): support yuan display (#806) 2026-05-06 01:36:46 -05:00
Jason 1981c09970 fix(snapshot): refuse to snapshot $HOME directory (#798)
* fix(snapshot): refuse to snapshot home directory (#793)

When the TUI is launched from $HOME, the snapshot system would run
`git add -A` on the entire home directory, consuming unbounded CPU and
disk. This manifests as a multi-GB side-repo under ~/.deepseek/snapshots
and makes the TUI appear frozen.

Add a guard in SnapshotRepo::open_or_init that compares the canonical
workspace path against the canonical home directory and returns an error
if they match. The error is non-fatal (snapshots are a safety net, not a
correctness gate) so the turn loop continues without snapshots.

Closes #793

* test(snapshot): fix home guard test portability

* test(snapshot): avoid env-dependent home guard test

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-06 01:08:05 -05:00
Hunter Bown 8c091cce98 fix(tui): reflect approval mode in agent prompts (#797) 2026-05-06 00:47:04 -05:00
wucm667 05db50d182 fix(config): accept provider-prefixed DeepSeek model IDs (#794)
Allow model IDs like accounts/fireworks/models/deepseek-v4-flash
by checking for /deepseek in addition to starts_with(deepseek).

Fixes #753

Signed-off-by: wucm667 <stevenwucongmin@gmail.com>
2026-05-06 00:30:37 -05:00
Agent007 cb3245a3a0 [Doc] Update README with deepseek-v4-pro pricing note (#776)
* Revise DeepSeek Pro pricing and service details

Update pricing and service notes for DeepSeek Pro.

* Update README with DeepSeek-V4-Pro pricing note

Added note about DeepSeek-V4-Pro service throughput and expected price reduction.

* Update README.zh-CN.md

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Update README.md

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Revise DeepSeek-V4-Pro pricing and service notes

Updated pricing and service throughput information for DeepSeek-V4-Pro.

* Update README.zh-CN.md

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-05-06 00:24:30 -05:00
Hunter Bown feaae514a6 fix(tui): recognize legacy ctrl-v paste input (#786) 2026-05-05 22:41:50 -05:00
Hunter Bown 3af6ef6f69 fix(tui): default mouse capture off on Windows (#785) 2026-05-05 22:40:31 -05:00
zxyasfas 0fded51824 docs: align Rust MSRV references with workspace (#739) 2026-05-05 22:39:50 -05:00
Hunter Bown ece6b88e79 feat(acp): add stdio adapter for editor agents (#782) 2026-05-05 22:30:17 -05:00
Reid 02456429ca Add shell completion setup examples (#742)
* Add shell completion setup examples

  Show actionable bash, zsh, and fish completion setup commands in the completion subcommand help, and cover them in the CLI help
  surface test.

* docs(cli): clarify completion setup examples

---------

Co-authored-by: Hunter Bown <hmbown@gmail.com>
2026-05-05 22:28:10 -05:00
Lawrence 76e5c90185 fix(tui): preserve UTF-8 while stripping ANSI
Preserve multi-byte UTF-8 characters when stripping ANSI/OSC8 sequences from transcript output.\n\nVerified locally with:\n- cargo fmt --all -- --check\n- cargo test -p deepseek-tui --bin deepseek-tui tui::osc8
2026-05-05 22:13:59 -05:00
Hunter Bown f31ad207dd docs(readme): clarify auto mode 2026-05-05 21:48:46 -05:00