Commit Graph

728 Commits

Author SHA1 Message Date
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
Hunter Bown 432e68c35a docs(readme): clarify auto routing 2026-05-05 21:42:56 -05:00
Hunter Bown 82851aece4 fix(provider): complete vLLM integration on main 2026-05-05 21:27:02 -05:00
Agent007 a335ff5e4c feat(provider): add vLLM provider support (#737)
Add vLLM as a first-class OpenAI-compatible self-hosted provider with VLLM_BASE_URL, VLLM_API_KEY, and VLLM_MODEL wiring.
2026-05-05 21:22:24 -05:00
Hunter Bown 50780a5289 fix: restore auto model routing (#772)
Keep auto as a local routing mode, resolve concrete model/thinking before API requests, and wire auto routing through CLI, TUI, runtime threads, and subagents.
2026-05-05 21:22:03 -05:00
Hunter Bown 63e2234c6b fix(config): repair first-run auth and settings selection (#763)
* fix(auth): recover from env-only invalid API keys

Refs #759.

* fix(tui): repair config modal selection rendering

Refs #759.
2026-05-05 20:05:17 -05:00
Hunter Bown ab59ef8ff2 fix(cost): count V4 reasoning tokens in usage output (#762) 2026-05-05 19:57:25 -05:00
Hunter Bown f738f0175a docs(keybindings): fix Ctrl-S (stash not history search), add Alt-R, audit to v0.8.13
- Fix Ctrl-S: stash current draft, not reverse history search
- Add Alt-R: search prompt history
- Note bare Up/Down arrows now scroll transcript when composer is empty (v0.8.13)
- Remove phantom Alt+Up from audit notes
- Note tui.toml wiring still deferred
- Remove dated 'v0.8.11 follow-up' reference in header
2026-05-05 18:03:45 -05:00
Hunter Bown 401cf34827 docs(readme): fix single-binary claim, phantom Alt+Up, Rust version, add Homebrew + contributors
- Fix 'single binary' to 'self-contained binaries' (two binaries ship)
- Remove phantom Alt+Up shortcut (does not exist in key dispatch)
- Fix Rust version 1.85+ to 1.88+ in source install
- Add Homebrew install path to both READMEs
- Add v0.8.13 contributors: @dfwqdyl-ui (#729), @Oliver-ZPLiu (#738)
- Add LOCALIZATION.md to docs table in both READMEs
- Add missing usage commands to zh-CN (--version, resume, fork)
- Align zh-CN lede with English (prefix-cache aware, thinking-mode)
2026-05-05 18:02:33 -05:00
Hunter Bown b07fed8c9c docs(changelog): add scroll-fix entry for v0.8.13 2026-05-05 17:18:38 -05:00
Hunter Bown cc6c6c6053 fix(scroll): Up/Down arrows now scroll transcript when composer is empty
The should_scroll_with_arrows gate was hardcoded to false since the
initial commit, which meant bare Up/Down arrows always navigated
composer history — they never scrolled the transcript view. Users in
virtual terminals (Ghostty, Codex, Kitty-protocol terminals) were
especially affected because they couldn't use the specialized Cmd+Up
/ Alt+Up shortcuts.

The gate now returns true when the composer input is empty (or
whitespace-only), so bare arrows scroll the transcript. When text
is present, arrows still navigate composer history to recall
previous prompts.

Added 3 tests covering empty, whitespace-only, and text-filled
composer states.
2026-05-05 13:54:21 -05:00