chore(release): prepare v0.8.37

This commit is contained in:
Hunter Bown
2026-05-14 14:37:14 -05:00
parent 9f3a1ec951
commit 4c32a316be
27 changed files with 694 additions and 681 deletions
+48 -4
View File
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.8.37] - 2026-05-14
### Added
- **Tencent Lighthouse + Feishu/Lark bridge setup.** Added a `/opt/whalebro`
@@ -17,9 +19,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Feishu/Lark + optional EdgeOne teaching path and added non-active CNB deploy
templates for a future Lighthouse deploy button. Feishu/Lighthouse branches
are now mirrored to CNB for Tencent-first bootstrap.
- **Homebrew tap automation is release-gated.** The release workflow can update
`Hmbown/homebrew-deepseek-tui` from the checksum manifest when a tap token is
configured, and skips cleanly before downloading release assets when no tap
token exists.
### Changed
- **Bing is the default `web_search` backend.** DuckDuckGo remains selectable
with `[search] provider = "duckduckgo"` and keeps its Bing fallback path.
### Fixed
- **First-run onboarding stays usable without an API key.** Missing-key startup
no longer aborts the TUI before onboarding can collect provider settings.
- **Streamable HTTP MCP sessions keep their server-issued session ID.** Custom
headers also apply to GET preflight requests, fixing authenticated MCP
servers that require both.
- **DeepSeek model completions use canonical IDs.** Alias completions now
resolve to stable DeepSeek model names before being written to config.
- **Terminal and child-process reliability is tighter.** Signal shutdown now
restores the terminal, child tasks preserve proxy environment variables, and
Windows Enter / CSI-u input handling avoids the prior event mismatch.
- **Long terminal text wraps instead of overflowing.** Streaming output, diff
rendering, and the pager now hard-wrap overlong no-whitespace and CJK runs.
- **Release and platform edges are safer.** The TUI no longer trips the Windows
Instant-underflow test path, unsupported desktop targets compile the external
URL opener, and legacy DeepSeek CN provider aliases deserialize to the
canonical DeepSeek provider.
- **Footer diagnostics are less cryptic.** Prefix-cache stability is no longer
shown in the default footer, and the opt-in `/statusline` chip now says
`cache prefix 100%` instead of the ambiguous `P 100%`.
- **Feishu/Lark bridge dependency installs are locked and audited.** The
bridge now ships a package lock, installs with `npm ci` on Lighthouse when
available, and overrides the Lark SDK's transitive `axios` dependency to a
@@ -33,10 +63,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
workflow now mirrors Feishu/Lighthouse release branches, so Tencent
Lighthouse bootstrap can use CNB before the release branch merges.
### Changed
### Thanks
- **Bing is the default `web_search` backend.** DuckDuckGo remains selectable
with `[search] provider = "duckduckgo"` and keeps its Bing fallback path.
Thanks to **ZzzPL ([@Oliver-ZPLiu](https://github.com/Oliver-ZPLiu))** for
the MCP Streamable HTTP and Homebrew automation fixes (#1643, #1631),
**Reid ([@reidliu41](https://github.com/reidliu41))** for CI, streaming wrap,
and model-completion fixes (#1603, #1628, #1601), **MidoriKurage
([@mdrkrg](https://github.com/mdrkrg))** for the onboarding crash fix (#1598),
**Gordon ([@gordonlu](https://github.com/gordonlu))** for the Windows Enter /
CSI-u fix (#1612), **Aitensa ([@Aitensa](https://github.com/Aitensa))** for
the CJK diff/pager wrap fix (#1622), **qiyan233
([@qiyan233](https://github.com/qiyan233))** for legacy DeepSeek CN provider
aliases (#1645), **jieshu666 ([@jieshu666](https://github.com/jieshu666))**
for the repaint-flicker reduction (#1563), **Vishnu
([@Vishnu1837](https://github.com/Vishnu1837))** for terminal restoration on
signals (#1586), and **axobase001
([@axobase001](https://github.com/axobase001))** for proxy environment
preservation in child tasks (#1608).
## [0.8.36] - 2026-05-14
@@ -4161,7 +4204,8 @@ Welcome — and thank you.
- Hooks system and config profiles
- Example skills and launch assets
[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.36...HEAD
[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.37...HEAD
[0.8.37]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.36...v0.8.37
[0.8.36]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.35...v0.8.36
[0.8.35]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.34...v0.8.35
[0.8.34]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.33...v0.8.34
Generated
+14 -14
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "deepseek-agent"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"deepseek-config",
"serde",
@@ -1168,7 +1168,7 @@ dependencies = [
[[package]]
name = "deepseek-app-server"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"axum",
@@ -1190,7 +1190,7 @@ dependencies = [
[[package]]
name = "deepseek-config"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"deepseek-secrets",
@@ -1202,7 +1202,7 @@ dependencies = [
[[package]]
name = "deepseek-core"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"chrono",
@@ -1220,7 +1220,7 @@ dependencies = [
[[package]]
name = "deepseek-execpolicy"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"deepseek-protocol",
@@ -1229,7 +1229,7 @@ dependencies = [
[[package]]
name = "deepseek-hooks"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"async-trait",
@@ -1243,7 +1243,7 @@ dependencies = [
[[package]]
name = "deepseek-mcp"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"serde",
@@ -1252,7 +1252,7 @@ dependencies = [
[[package]]
name = "deepseek-protocol"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"serde",
"serde_json",
@@ -1260,7 +1260,7 @@ dependencies = [
[[package]]
name = "deepseek-secrets"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"dirs",
"keyring",
@@ -1273,7 +1273,7 @@ dependencies = [
[[package]]
name = "deepseek-state"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"chrono",
@@ -1285,7 +1285,7 @@ dependencies = [
[[package]]
name = "deepseek-tools"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"async-trait",
@@ -1298,7 +1298,7 @@ dependencies = [
[[package]]
name = "deepseek-tui"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"arboard",
@@ -1361,7 +1361,7 @@ dependencies = [
[[package]]
name = "deepseek-tui-cli"
version = "0.8.36"
version = "0.8.37"
dependencies = [
"anyhow",
"chrono",
@@ -1386,7 +1386,7 @@ dependencies = [
[[package]]
name = "deepseek-tui-core"
version = "0.8.36"
version = "0.8.37"
[[package]]
name = "deltae"
+1 -1
View File
@@ -19,7 +19,7 @@ default-members = ["crates/cli", "crates/app-server", "crates/tui"]
resolver = "2"
[workspace.package]
version = "0.8.36"
version = "0.8.37"
edition = "2024"
# Rust 1.88 stabilized `let_chains` in `if`/`while` conditions, which the
# codebase relies on extensively. Cargo enforces this so users on older
+10 -5
View File
@@ -67,7 +67,7 @@ It is built around DeepSeek V4 (`deepseek-v4-pro` / `deepseek-v4-flash`), includ
- **Thinking-mode streaming** — see DeepSeek reasoning blocks as the model works
- **Full tool suite** — file ops, shell execution, git, web search/browse, apply-patch, sub-agents, MCP servers
- **1M-token context** — context tracking, manual or configured compaction, and prefix-cache telemetry
- **Prefix-cache stability tracking** — a footer chip surfaces how stable the cached prefix has been across recent turns so cost-busting edits are visible before they land
- **Prefix-cache stability tracking** — an optional `/statusline` footer chip surfaces how stable the cached prefix has been across recent turns so cost-busting edits are visible before they land
- **Three modes** — Plan (read-only explore), Agent (interactive with approval), YOLO (auto-approved)
- **Reasoning-effort tiers** — cycle through `off → high → max` with `Shift + Tab`
- **Session save/resume** — checkpoint and resume long-running sessions
@@ -491,7 +491,7 @@ This project ships with help from a growing community of contributors:
- **[loongmiaow-pixel](https://github.com/loongmiaow-pixel)** — Windows + China install documentation (#578)
- **[20bytes](https://github.com/20bytes)** — User memory docs and help polish (#569)
- **[staryxchen](https://github.com/staryxchen)** — glibc compatibility preflight (#556)
- **[Vishnu1837](https://github.com/Vishnu1837)** — glibc compatibility improvements (#565)
- **[Vishnu1837](https://github.com/Vishnu1837)** — glibc compatibility improvements and terminal restoration on SIGINT/SIGTERM (#565, #1586)
- **[shentoumengxin](https://github.com/shentoumengxin)** — Shell `cwd` boundary validation (#524)
- **[toi500](https://github.com/toi500)** — Windows paste fix report
- **[xsstomy](https://github.com/xsstomy)** — Terminal startup repaint report
@@ -502,8 +502,8 @@ This project ships with help from a growing community of contributors:
- **[wangfeng](mailto:wangfengcsu@qq.com)** — Pricing/discount info update (#692)
- **[zichen0116](https://github.com/zichen0116)** — CODE_OF_CONDUCT.md (#686)
- **[dfwqdyl-ui](https://github.com/dfwqdyl-ui)** — model ID case-sensitivity compatibility report (#729)
- **[Oliver-ZPLiu](https://github.com/Oliver-ZPLiu)** — stale `working...` state bug report and Windows clipboard fallback (#738, #850)
- **[reidliu41](https://github.com/reidliu41)** — resume hint, workspace trust persistence, Ollama provider support, and thinking-block stream finalization (#863, #870, #921, #1078)
- **[Oliver-ZPLiu](https://github.com/Oliver-ZPLiu)** — stale `working...` state bug report, Windows clipboard fallback, MCP Streamable HTTP session fixes, and Homebrew tap automation (#738, #850, #1643, #1631)
- **[reidliu41](https://github.com/reidliu41)** — resume hint, workspace trust persistence, Ollama provider support, thinking-block stream finalization, CI cache hardening, streaming wrap, and DeepSeek model completions (#863, #870, #921, #1078, #1603, #1628, #1601)
- **[xieshutao](https://github.com/xieshutao)** — plain Markdown skill fallback (#869)
- **[GK012](https://github.com/GK012)** — npm wrapper `--version` fallback (#885)
- **[y0sif](https://github.com/y0sif)** — parent turn-loop wakeup after direct child sub-agent completion (#901)
@@ -520,7 +520,7 @@ This project ships with help from a growing community of contributors:
- **Hafeez Pizofreude** — SSRF protection in `fetch_url` and Star History chart
- **Unic (YuniqueUnic)** — Schema-driven config UI (TUI + web)
- **Jason** — SSRF security hardening
- **[axobase001](https://github.com/axobase001)** — snapshot orphan cleanup, npm install guards, session telemetry fixes, model-scope cache clear, symlinked skill support, and npm mirror-escape-hatch guidance (#975, #1032, #1047, #1049, #1052, #1019, #1051, #1056)
- **[axobase001](https://github.com/axobase001)** — snapshot orphan cleanup, npm install guards, session telemetry fixes, model-scope cache clear, symlinked skill support, npm mirror-escape-hatch guidance, and proxy preservation for child tasks (#975, #1032, #1047, #1049, #1052, #1019, #1051, #1056, #1608)
- **[MengZ-super](https://github.com/MengZ-super)** — `/theme` command foundation and SSE gzip/brotli decompression (#1057, #1061)
- **[DI-HUO-MING-YI](https://github.com/DI-HUO-MING-YI)** — Plan-mode read-only sandbox safety fix (#1077)
- **[bevis-wong](https://github.com/bevis-wong)** — precise paste-Enter auto-submit reproducer (#1073)
@@ -530,6 +530,11 @@ This project ships with help from a growing community of contributors:
- **[Jefsky](https://github.com/Jefsky)** — DeepSeek endpoint correction report (#1079, #1084)
- **[wlon](https://github.com/wlon)** — NVIDIA NIM provider API-key preference diagnosis (#1081)
- **[Horace Liu](https://github.com/liuhq)** — Nix package support and install documentation (#1173)
- **[jieshu666](https://github.com/jieshu666)** — terminal repaint flicker reduction (#1563)
- **[gordonlu](https://github.com/gordonlu)** — Windows Enter / CSI-u input fix (#1612)
- **[mdrkrg](https://github.com/mdrkrg)** — first-run onboarding crash fix when the API key is missing (#1598)
- **[Aitensa](https://github.com/Aitensa)** — CJK wrapping propagation for diff and pager output (#1622)
- **[qiyan233](https://github.com/qiyan233)** — legacy DeepSeek CN provider alias compatibility (#1645)
---
+1 -1
View File
@@ -7,5 +7,5 @@ repository.workspace = true
description = "Model/provider registry and fallback strategy for DeepSeek workspace architecture"
[dependencies]
deepseek-config = { path = "../config", version = "0.8.36" }
deepseek-config = { path = "../config", version = "0.8.37" }
serde.workspace = true
+9 -9
View File
@@ -10,15 +10,15 @@ description = "Codex-style app-server transport for DeepSeek workspace architect
anyhow.workspace = true
axum.workspace = true
clap.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.36" }
deepseek-config = { path = "../config", version = "0.8.36" }
deepseek-core = { path = "../core", version = "0.8.36" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.36" }
deepseek-hooks = { path = "../hooks", version = "0.8.36" }
deepseek-mcp = { path = "../mcp", version = "0.8.36" }
deepseek-protocol = { path = "../protocol", version = "0.8.36" }
deepseek-state = { path = "../state", version = "0.8.36" }
deepseek-tools = { path = "../tools", version = "0.8.36" }
deepseek-agent = { path = "../agent", version = "0.8.37" }
deepseek-config = { path = "../config", version = "0.8.37" }
deepseek-core = { path = "../core", version = "0.8.37" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.37" }
deepseek-hooks = { path = "../hooks", version = "0.8.37" }
deepseek-mcp = { path = "../mcp", version = "0.8.37" }
deepseek-protocol = { path = "../protocol", version = "0.8.37" }
deepseek-state = { path = "../state", version = "0.8.37" }
deepseek-tools = { path = "../tools", version = "0.8.37" }
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
+7 -7
View File
@@ -14,13 +14,13 @@ path = "src/main.rs"
anyhow.workspace = true
clap.workspace = true
clap_complete.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.36" }
deepseek-app-server = { path = "../app-server", version = "0.8.36" }
deepseek-config = { path = "../config", version = "0.8.36" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.36" }
deepseek-mcp = { path = "../mcp", version = "0.8.36" }
deepseek-secrets = { path = "../secrets", version = "0.8.36" }
deepseek-state = { path = "../state", version = "0.8.36" }
deepseek-agent = { path = "../agent", version = "0.8.37" }
deepseek-app-server = { path = "../app-server", version = "0.8.37" }
deepseek-config = { path = "../config", version = "0.8.37" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.37" }
deepseek-mcp = { path = "../mcp", version = "0.8.37" }
deepseek-secrets = { path = "../secrets", version = "0.8.37" }
deepseek-state = { path = "../state", version = "0.8.37" }
chrono.workspace = true
dirs.workspace = true
serde.workspace = true
+1 -1
View File
@@ -8,7 +8,7 @@ description = "Config schema and precedence model for DeepSeek workspace archite
[dependencies]
anyhow.workspace = true
deepseek-secrets = { path = "../secrets", version = "0.8.36" }
deepseek-secrets = { path = "../secrets", version = "0.8.37" }
dirs.workspace = true
serde.workspace = true
toml.workspace = true
+8 -8
View File
@@ -9,13 +9,13 @@ description = "Core runtime boundaries for DeepSeek workspace architecture"
[dependencies]
anyhow.workspace = true
chrono.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.36" }
deepseek-config = { path = "../config", version = "0.8.36" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.36" }
deepseek-hooks = { path = "../hooks", version = "0.8.36" }
deepseek-mcp = { path = "../mcp", version = "0.8.36" }
deepseek-protocol = { path = "../protocol", version = "0.8.36" }
deepseek-state = { path = "../state", version = "0.8.36" }
deepseek-tools = { path = "../tools", version = "0.8.36" }
deepseek-agent = { path = "../agent", version = "0.8.37" }
deepseek-config = { path = "../config", version = "0.8.37" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.37" }
deepseek-hooks = { path = "../hooks", version = "0.8.37" }
deepseek-mcp = { path = "../mcp", version = "0.8.37" }
deepseek-protocol = { path = "../protocol", version = "0.8.37" }
deepseek-state = { path = "../state", version = "0.8.37" }
deepseek-tools = { path = "../tools", version = "0.8.37" }
serde_json.workspace = true
uuid.workspace = true
+1 -1
View File
@@ -8,5 +8,5 @@ description = "Execution policy and approval model parity for DeepSeek workspace
[dependencies]
anyhow.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.36" }
deepseek-protocol = { path = "../protocol", version = "0.8.37" }
serde.workspace = true
+1 -1
View File
@@ -10,7 +10,7 @@ description = "Hook dispatch and notifications parity for DeepSeek workspace arc
anyhow.workspace = true
async-trait.workspace = true
chrono.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.36" }
deepseek-protocol = { path = "../protocol", version = "0.8.37" }
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
+1 -1
View File
@@ -9,7 +9,7 @@ description = "Tool invocation lifecycle, schema validation, and scheduler paral
[dependencies]
anyhow.workspace = true
async-trait.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.36" }
deepseek-protocol = { path = "../protocol", version = "0.8.37" }
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
+48 -4
View File
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.8.37] - 2026-05-14
### Added
- **Tencent Lighthouse + Feishu/Lark bridge setup.** Added a `/opt/whalebro`
@@ -17,9 +19,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Feishu/Lark + optional EdgeOne teaching path and added non-active CNB deploy
templates for a future Lighthouse deploy button. Feishu/Lighthouse branches
are now mirrored to CNB for Tencent-first bootstrap.
- **Homebrew tap automation is release-gated.** The release workflow can update
`Hmbown/homebrew-deepseek-tui` from the checksum manifest when a tap token is
configured, and skips cleanly before downloading release assets when no tap
token exists.
### Changed
- **Bing is the default `web_search` backend.** DuckDuckGo remains selectable
with `[search] provider = "duckduckgo"` and keeps its Bing fallback path.
### Fixed
- **First-run onboarding stays usable without an API key.** Missing-key startup
no longer aborts the TUI before onboarding can collect provider settings.
- **Streamable HTTP MCP sessions keep their server-issued session ID.** Custom
headers also apply to GET preflight requests, fixing authenticated MCP
servers that require both.
- **DeepSeek model completions use canonical IDs.** Alias completions now
resolve to stable DeepSeek model names before being written to config.
- **Terminal and child-process reliability is tighter.** Signal shutdown now
restores the terminal, child tasks preserve proxy environment variables, and
Windows Enter / CSI-u input handling avoids the prior event mismatch.
- **Long terminal text wraps instead of overflowing.** Streaming output, diff
rendering, and the pager now hard-wrap overlong no-whitespace and CJK runs.
- **Release and platform edges are safer.** The TUI no longer trips the Windows
Instant-underflow test path, unsupported desktop targets compile the external
URL opener, and legacy DeepSeek CN provider aliases deserialize to the
canonical DeepSeek provider.
- **Footer diagnostics are less cryptic.** Prefix-cache stability is no longer
shown in the default footer, and the opt-in `/statusline` chip now says
`cache prefix 100%` instead of the ambiguous `P 100%`.
- **Feishu/Lark bridge dependency installs are locked and audited.** The
bridge now ships a package lock, installs with `npm ci` on Lighthouse when
available, and overrides the Lark SDK's transitive `axios` dependency to a
@@ -33,10 +63,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
workflow now mirrors Feishu/Lighthouse release branches, so Tencent
Lighthouse bootstrap can use CNB before the release branch merges.
### Changed
### Thanks
- **Bing is the default `web_search` backend.** DuckDuckGo remains selectable
with `[search] provider = "duckduckgo"` and keeps its Bing fallback path.
Thanks to **ZzzPL ([@Oliver-ZPLiu](https://github.com/Oliver-ZPLiu))** for
the MCP Streamable HTTP and Homebrew automation fixes (#1643, #1631),
**Reid ([@reidliu41](https://github.com/reidliu41))** for CI, streaming wrap,
and model-completion fixes (#1603, #1628, #1601), **MidoriKurage
([@mdrkrg](https://github.com/mdrkrg))** for the onboarding crash fix (#1598),
**Gordon ([@gordonlu](https://github.com/gordonlu))** for the Windows Enter /
CSI-u fix (#1612), **Aitensa ([@Aitensa](https://github.com/Aitensa))** for
the CJK diff/pager wrap fix (#1622), **qiyan233
([@qiyan233](https://github.com/qiyan233))** for legacy DeepSeek CN provider
aliases (#1645), **jieshu666 ([@jieshu666](https://github.com/jieshu666))**
for the repaint-flicker reduction (#1563), **Vishnu
([@Vishnu1837](https://github.com/Vishnu1837))** for terminal restoration on
signals (#1586), and **axobase001
([@axobase001](https://github.com/axobase001))** for proxy environment
preservation in child tasks (#1608).
## [0.8.36] - 2026-05-14
@@ -4161,7 +4204,8 @@ Welcome — and thank you.
- Hooks system and config profiles
- Example skills and launch assets
[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.36...HEAD
[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.37...HEAD
[0.8.37]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.36...v0.8.37
[0.8.36]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.35...v0.8.36
[0.8.35]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.34...v0.8.35
[0.8.34]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.8.33...v0.8.34
+2 -2
View File
@@ -21,8 +21,8 @@ path = "src/main.rs"
[dependencies]
anyhow = "1.0.100"
arboard = "3.4"
deepseek-secrets = { path = "../secrets", version = "0.8.36" }
deepseek-tools = { path = "../tools", version = "0.8.36" }
deepseek-secrets = { path = "../secrets", version = "0.8.37" }
deepseek-tools = { path = "../tools", version = "0.8.37" }
schemaui = { version = "0.12.0", default-features = false, optional = true }
async-stream = "0.3.6"
async-trait = "0.1"
+5 -5
View File
@@ -648,7 +648,7 @@ pub enum StatusItem {
Agents,
/// Reasoning-replay token count ("rsn 12.3k").
ReasoningReplay,
/// Prefix stability ("P 100%").
/// Prefix stability ("cache prefix 100%").
PrefixStability,
/// Cache hit rate ("cache 73%").
Cache,
@@ -663,9 +663,10 @@ pub enum StatusItem {
}
impl StatusItem {
/// Default footer composition matching v0.6.6 behaviour exactly. Used when
/// `tui.status_items` is missing from `config.toml` so upgraders see the
/// same footer they had before.
/// Default footer composition for the always-on status line. Used when
/// `tui.status_items` is missing from `config.toml` so upgraders see a
/// concise footer by default; diagnostic chips remain available via
/// `/statusline` without crowding the main UI.
#[must_use]
pub fn default_footer() -> Vec<StatusItem> {
vec![
@@ -676,7 +677,6 @@ impl StatusItem {
StatusItem::Coherence,
StatusItem::Agents,
StatusItem::ReasoningReplay,
StatusItem::PrefixStability,
StatusItem::Cache,
]
}
+4 -2
View File
@@ -510,8 +510,10 @@ pub(crate) fn footer_auxiliary_spans(app: &App, max_width: usize) -> Vec<Span<'s
let prefix_spans = app
.prefix_stability_pct
.map(|_| {
let (label, color) = format_helpers::prefix_stability_chip(app)
.unwrap_or(("P --".to_string(), ratatui::style::Color::DarkGray));
let (label, color) = format_helpers::prefix_stability_chip(app).unwrap_or((
"cache prefix --".to_string(),
ratatui::style::Color::DarkGray,
));
vec![Span::styled(label, Style::default().fg(color))]
})
.unwrap_or_default();
+3 -3
View File
@@ -29,7 +29,7 @@ pub(super) fn cache_warmup_result(usage: &Usage) -> String {
)
}
/// Format prefix stability info for the TUI footer chip.
/// Format prefix stability info for the opt-in TUI footer chip.
pub(super) fn prefix_stability_chip(app: &App) -> Option<(String, ratatui::style::Color)> {
let pct = app.prefix_stability_pct?;
let changes = app.prefix_change_count;
@@ -49,10 +49,10 @@ pub(super) fn prefix_stability_chip(app: &App) -> Option<(String, ratatui::style
};
let label = if changes == 0 {
format!("P {pct}%")
format!("cache prefix {pct}%")
} else {
format!(
"P {pct}% ({changes} change{})",
"cache prefix {pct}% ({changes} change{})",
if changes == 1 { "" } else { "s" }
)
};
+11 -12
View File
@@ -4980,18 +4980,17 @@ fn render_footer_from_with_default_items_renders_mode_and_model() {
}
#[test]
fn default_footer_includes_prefix_stability_before_cache() {
fn default_footer_keeps_prefix_stability_opt_in() {
let items = crate::config::StatusItem::default_footer();
let prefix = items
.iter()
.position(|item| *item == crate::config::StatusItem::PrefixStability)
.expect("default footer includes prefix stability");
let cache = items
.iter()
.position(|item| *item == crate::config::StatusItem::Cache)
.expect("default footer includes cache");
assert!(prefix < cache);
assert!(
!items.contains(&crate::config::StatusItem::PrefixStability),
"prefix stability is a diagnostic chip and should not crowd the default footer"
);
assert!(
items.contains(&crate::config::StatusItem::Cache),
"default footer should still include provider-reported cache hit rate"
);
}
#[test]
@@ -5002,7 +5001,7 @@ fn render_footer_from_prefix_stability_item_renders_cache_slot_chip() {
let props = render_footer_from(&app, &[crate::config::StatusItem::PrefixStability], None);
assert_eq!(spans_text(&props.cache), "P 100%");
assert_eq!(spans_text(&props.cache), "cache prefix 100%");
}
#[test]
@@ -5023,7 +5022,7 @@ fn render_footer_from_preserves_prefix_then_cache_order() {
None,
);
assert!(spans_text(&props.cache).starts_with("P 100% Cache: 90.0% hit"));
assert!(spans_text(&props.cache).starts_with("cache prefix 100% Cache: 90.0% hit"));
}
#[test]
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "deepseek-tui",
"version": "0.8.36",
"deepseekBinaryVersion": "0.8.36",
"version": "0.8.37",
"deepseekBinaryVersion": "0.8.37",
"description": "Install and run deepseek and deepseek-tui binaries from GitHub release artifacts.",
"author": "Hmbown",
"license": "MIT",
+371 -263
View File
@@ -1,7 +1,7 @@
import Link from "next/link";
import { GITEE_ENABLED } from "@/lib/i18n/config";
import { Seal } from "@/components/seal";
import { InstallTabs } from "@/components/install-tabs";
import { InstallCodeBlock } from "@/components/install-code-block";
import { InstallBinary } from "@/components/install-binary";
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;
@@ -9,288 +9,396 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s
return {
title: isZh ? "安装 · DeepSeek TUI" : "Install · DeepSeek TUI",
description: isZh
? "在 macOS、Linux 或 Windows 上通过 Cargo、npm、Homebrew tap 或预编译二进制安装 deepseek-tui。"
: "Install deepseek-tui on macOS, Linux, or Windows via Cargo, npm, the Homebrew tap, or pre-built binaries.",
? "通过 Cargo 安装 deepseek-tui。其他方式:npm、Homebrew、预编译二进制、Docker、国内镜像。"
: "Install deepseek-tui via Cargo. Other ways: npm, Homebrew, prebuilt binary, Docker, source.",
};
}
const CARGO_INSTALL = `cargo install deepseek-tui-cli --locked`;
const FIRST_RUN = `deepseek`;
const VERIFY = `deepseek --version
deepseek doctor`;
const SET_KEY_BASH = `export DEEPSEEK_API_KEY=sk-...`;
const SET_KEY_AUTH = `deepseek auth set --provider deepseek --api-key sk-...`;
const NPM_INSTALL = `npm install -g deepseek-tui`;
const TUNA_CONFIG = `# ~/.cargo/config.toml
[source.crates-io]
replace-with = "tuna"
[source.tuna]
registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"`;
const TUNA_INSTALL = `cargo install deepseek-tui-cli --locked`;
const NPMMIRROR = `npm config set registry https://registry.npmmirror.com
npm install -g deepseek-tui`;
const BREW = `brew tap Hmbown/deepseek-tui
brew install deepseek-tui`;
const DOCKER = `git clone https://github.com/Hmbown/deepseek-tui
cd deepseek-tui
docker build -t deepseek-tui .
docker run --rm -it \\
-e DEEPSEEK_API_KEY=$DEEPSEEK_API_KEY \\
-v ~/.deepseek:/home/deepseek/.deepseek \\
-v "$PWD:/work" -w /work \\
deepseek-tui`;
const FROM_SOURCE = `git clone https://github.com/Hmbown/deepseek-tui
cd deepseek-tui
cargo build --release --locked
# Install both binaries from the local checkout
cargo install --path crates/cli --locked # deepseek
cargo install --path crates/tui --locked # deepseek-tui`;
const CONFIG_TREE = `~/.deepseek/
config.toml api keys, model, hooks, profiles
mcp.json MCP server definitions
skills/ user skills (each with SKILL.md)
sessions/ checkpoints + offline queue
tasks/ background task store
audit.log credential / approval / elevation audit trail
./.deepseek/ project-scoped config (optional, per-repo)`;
const CONFIG_TREE_ZH = `~/.deepseek/
config.toml API
mcp.json MCP
skills/ SKILL.md
sessions/ + 线
tasks/
audit.log / /
./.deepseek/ `;
export default async function InstallPage({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;
const isZh = locale === "zh";
const copyLabel = isZh ? "复制" : "Copy";
const copiedLabel = isZh ? "已复制 ✓" : "Copied ✓";
return (
<>
{isZh ? (
<>
<section className="mx-auto max-w-[1400px] px-6 pt-12 pb-8">
<div className="flex items-baseline gap-4 mb-3">
<Seal char="装" />
<div className="eyebrow">Section 01 · </div>
{/* ① INSTALL */}
<section className="mx-auto max-w-[1100px] px-6 pt-12 pb-10">
<div className="flex items-baseline gap-4 mb-3">
<Seal char="装" />
<div className="eyebrow">{isZh ? "01 · 安装" : "01 · Install"}</div>
</div>
<h1 className="font-display tracking-crisp mb-6">
{isZh ? (
<> <span className="font-cjk text-indigo text-5xl ml-2">Install</span></>
) : (
<>Install <span className="font-cjk text-indigo text-5xl ml-2"></span></>
)}
</h1>
<div className="space-y-3">
<InstallCodeBlock cmd={CARGO_INSTALL} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<InstallCodeBlock cmd={FIRST_RUN} copyLabel={copyLabel} copiedLabel={copiedLabel} />
</div>
<p className="mt-4 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh ? (
<>
<code className="inline">deepseek</code> <code className="inline">~/.cargo/bin</code>
Rust 1.88+访{" "}
<a href="https://rustup.rs" className="body-link">rustup.rs</a>
Rust Homebrew
</>
) : (
<>
Compiles and installs <code className="inline">deepseek</code> to{" "}
<code className="inline">~/.cargo/bin</code>. Requires Rust 1.88+ install via{" "}
<a href="https://rustup.rs" className="body-link">rustup.rs</a> if you don&apos;t have it.
See <a href="#other-ways" className="body-link">Other ways to install</a> below for
npm, Homebrew, prebuilt binaries, or mainland China mirrors.
</>
)}
</p>
</section>
{/* ② VERIFY */}
<section className="mx-auto max-w-[1100px] px-6 py-10 hairline-t">
<div className="flex items-baseline gap-4 mb-5">
<Seal char="验" />
<div className="eyebrow">{isZh ? "02 · 验证" : "02 · Verify"}</div>
</div>
<InstallCodeBlock cmd={VERIFY} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="mt-4 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh ? (
<>
<code className="inline">deepseek doctor</code> API
MCP {" "}
<code className="inline">~/.deepseek/doctor.log</code>
</>
) : (
<>
<code className="inline">deepseek doctor</code> checks your API key, network,
sandbox availability, and MCP servers. Full report is written to{" "}
<code className="inline">~/.deepseek/doctor.log</code>.
</>
)}
</p>
</section>
{/* ③ FIRST RUN */}
<section className="mx-auto max-w-[1100px] px-6 py-10 hairline-t">
<div className="flex items-baseline gap-4 mb-5">
<Seal char="始" />
<div className="eyebrow">{isZh ? "03 · 首次运行" : "03 · First run"}</div>
</div>
<ol className="space-y-6 max-w-2xl">
<li>
<div className="font-display text-lg mb-2">
{isZh ? "① 获取 API 密钥" : "① Get an API key"}
</div>
<h1 className="font-display tracking-crisp">
<span className="font-cjk text-indigo text-5xl ml-2">Install</span>
</h1>
<p className="mt-5 max-w-3xl text-ink-soft text-lg leading-[1.9] tracking-wide">
<code className="inline">deepseek</code> 使 TUI
<code className="inline">doctor</code><code className="inline">mcp</code>
<code className="inline">serve</code><code className="inline">eval</code>
<p className="text-sm text-ink-soft leading-relaxed">
{isZh ? (
<>
{" "}
<a href="https://platform.deepseek.com" className="body-link">
platform.deepseek.com
</a>{" "}
<code className="inline">sk-...</code>
</>
) : (
<>
Sign up at{" "}
<a href="https://platform.deepseek.com" className="body-link">
platform.deepseek.com
</a>{" "}
and create a key (format: <code className="inline">sk-...</code>).
</>
)}
</p>
</section>
</li>
<InstallTabs />
<li>
<div className="font-display text-lg mb-2">
{isZh ? "② 设置密钥" : "② Set the key"}
</div>
<div className="space-y-2">
<InstallCodeBlock cmd={SET_KEY_BASH} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="text-xs text-ink-mute">
{isZh ? "或保存到 ~/.deepseek/config.toml" : "Or persist it to ~/.deepseek/config.toml:"}
</p>
<InstallCodeBlock cmd={SET_KEY_AUTH} copyLabel={copyLabel} copiedLabel={copiedLabel} />
</div>
</li>
{/* 国内镜像安装 */}
<section className="mx-auto max-w-[1400px] px-6 py-16">
<div className="flex items-baseline gap-4 mb-8 hairline-b pb-4">
<Seal char="镜" />
<h2 className="font-display">
<span className="font-cjk text-ink-mute text-xl ml-2"></span>
</h2>
<li>
<div className="font-display text-lg mb-2">
{isZh ? "③ 在项目目录中运行" : "③ Run it in a project"}
</div>
<InstallCodeBlock cmd={`cd path/to/project\ndeepseek`} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="mt-3 text-sm text-ink-soft leading-relaxed">
{isZh ? (
<>
Plan {" "}
<kbd className="font-mono text-xs px-1 hairline-t hairline-b hairline-l hairline-r">Tab</kbd>{" "}
Agent YOLO
</>
) : (
<>
Plan mode (read-only) is the default. Press{" "}
<kbd className="font-mono text-xs px-1 hairline-t hairline-b hairline-l hairline-r">Tab</kbd>{" "}
to switch to Agent mode (tool execution, per-action approval). Press again for
YOLO (auto-approve).
</>
)}
</p>
</li>
</ol>
</section>
{/* ④ OTHER WAYS TO INSTALL */}
<section id="other-ways" className="bg-paper-deep hairline-t hairline-b">
<div className="mx-auto max-w-[1100px] px-6 py-12">
<div className="flex items-baseline gap-4 mb-5">
<Seal char="备" />
<div className="eyebrow">{isZh ? "04 · 其他安装方式" : "04 · Other ways to install"}</div>
</div>
<h2 className="font-display text-3xl mb-2">
{isZh ? "其他安装方式" : "Other ways to install"}
</h2>
<p className="text-sm text-ink-soft max-w-2xl mb-10">
{isZh
? "如果上面的 Cargo 路径不适合你,从下面找到匹配你情况的一条。每条都安装同一个 deepseek 二进制。"
: "If the Cargo path above doesn't fit your setup, pick the row that matches your situation. Every path installs the same deepseek binary."}
</p>
<div className="space-y-10">
{/* No Rust toolchain */}
<div>
<div className="eyebrow mb-2 text-indigo">
{isZh ? "没有 Rust 工具链" : "No Rust toolchain"}
</div>
<InstallCodeBlock cmd={NPM_INSTALL} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="mt-3 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh ? (
<>
npm GitHub Releases Node 18+
<code className="inline">deepseek</code> {" "}
<code className="inline">deepseek-tui</code>
</>
) : (
<>
The npm wrapper downloads the prebuilt binary from GitHub Releases for your
platform. Requires Node 18+. Installs both <code className="inline">deepseek</code>{" "}
and <code className="inline">deepseek-tui</code> on PATH.
</>
)}
</p>
</div>
<div className="grid md:grid-cols-2 gap-0 col-rule hairline-t hairline-b min-w-0">
{/* npmmirror */}
<div className="p-6 min-w-0">
<h3 className="font-display text-lg mb-2">npmmirror </h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mb-3">
npm
</p>
<pre className="code-block text-[0.78rem]">
{`npm config set registry https://registry.npmmirror.com
npm install -g deepseek-tui`}
</pre>
{/* Mainland China network */}
<div>
<div className="eyebrow mb-2 text-indigo">
{isZh ? "中国大陆网络" : "Mainland China network"}
</div>
<p className="text-sm text-ink-soft leading-relaxed max-w-2xl mb-3">
{isZh ? (
<>
Cargo Tuna <code className="inline">~/.cargo/config.toml</code>
</>
) : (
<>
Cargo via Tsinghua Tuna mirror add to{" "}
<code className="inline">~/.cargo/config.toml</code>:
</>
)}
</p>
<InstallCodeBlock cmd={TUNA_CONFIG} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<div className="mt-3">
<InstallCodeBlock cmd={TUNA_INSTALL} copyLabel={copyLabel} copiedLabel={copiedLabel} />
</div>
{/* Tuna Cargo */}
<div className="p-6 min-w-0">
<h3 className="font-display text-lg mb-2">Tuna Cargo </h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mb-3">
<code className="inline">~/.cargo/config.toml</code> 使 Tuna
</p>
<pre className="code-block text-[0.78rem]">
{`[source.crates-io]
replace-with = "tuna"
<p className="text-sm text-ink-soft leading-relaxed max-w-2xl mt-6 mb-3">
{isZh ? "npm 经 npmmirror 镜像:" : "npm via npmmirror:"}
</p>
<InstallCodeBlock cmd={NPMMIRROR} copyLabel={copyLabel} copiedLabel={copiedLabel} />
[source.tuna]
registry = "sparse+https://mirrors.tuna.tsinghua.edu.cn/crates.io-index/"`}
</pre>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mt-3">
<code className="inline">cargo install deepseek-tui-cli --locked</code> <code className="inline">deepseek</code>
</p>
</div>
{/* Gitee 二进制 */}
{GITEE_ENABLED && <div className="p-6 min-w-0">
<h3 className="font-display text-lg mb-2">Gitee </h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mb-3">
Gitee 使
</p>
<Link href="https://gitee.com/Hmbown/deepseek-tui/releases" className="font-mono text-[0.78rem] text-indigo hover:underline">
gitee.com/Hmbown/deepseek-tui/releases
</Link>
</div>}
{/* API 端点 */}
<div className="p-6 min-w-0">
<h3 className="font-display text-lg mb-2"> API 访</h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mb-3">
DeepSeek
<code className="inline">https://api.deepseek.com</code>{" "}
<a href="https://api-docs.deepseek.com/" className="body-link"></a>
API key
</p>
<pre className="code-block text-[0.78rem]">
{`# 推荐:环境变量
export DEEPSEEK_API_KEY=sk-...
#
deepseek auth set --provider deepseek --api-key sk-...`}
</pre>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide mt-3">
{" "}
<code className="inline">DEEPSEEK_BASE_URL</code>
</p>
</div>
<p className="mt-4 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh ? (
<>
npm {" "}
<code className="inline">github.com/Hmbown/deepseek-tui/releases</code>{" "}
Cargo + Tuna GitHub
DeepSeek API<code className="inline">api.deepseek.com</code>
</>
) : (
<>
The npm wrapper still downloads the binary from{" "}
<code className="inline">github.com/Hmbown/deepseek-tui/releases</code>, which can
be slow over GFW. Cargo + Tuna routes around GitHub entirely. The DeepSeek API
at <code className="inline">api.deepseek.com</code> is reachable from mainland
China without a proxy.
</>
)}
</p>
</div>
{GITEE_ENABLED && <div className="mt-6">
<Link href="https://gitee.com/Hmbown/deepseek-tui" className="body-link">
Gitee
{/* Homebrew */}
<div>
<div className="eyebrow mb-2 text-indigo">
Homebrew{" "}
<span className="text-ink-mute font-mono normal-case tracking-normal">
· macOS / Linux
</span>
</div>
<InstallCodeBlock cmd={BREW} copyLabel={copyLabel} copiedLabel={copiedLabel} />
</div>
{/* Prebuilt binary */}
<div>
<div className="eyebrow mb-2 text-indigo">
{isZh ? "预编译二进制" : "Prebuilt binary"}{" "}
<span className="text-ink-mute font-mono normal-case tracking-normal">
{isZh ? "· 已自动检测" : "· auto-detected"}
</span>
</div>
<InstallBinary
copyLabel={copyLabel}
copiedLabel={copiedLabel}
verifyHeading={isZh ? "校验 SHA256" : "Verify checksum"}
/>
</div>
{/* Docker */}
<div>
<div className="eyebrow mb-2 text-indigo">Docker</div>
<InstallCodeBlock cmd={DOCKER} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="mt-3 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh
? "支持 multi-arch buildx。目前没有发布到镜像仓库,需要本地构建。"
: "Multi-arch buildx is supported. No image is published to a registry yet, so you build locally."}
</p>
</div>
{/* From source */}
<div>
<div className="eyebrow mb-2 text-indigo">
{isZh ? "从源码编译" : "From source"}
</div>
<InstallCodeBlock cmd={FROM_SOURCE} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<p className="mt-3 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh
? "适合本地修改 workspace 或贡献补丁。"
: "Useful for hacking on the workspace itself or contributing patches."}
</p>
</div>
</div>
</div>
</section>
{/* ⑤ WHERE CONFIG LIVES */}
<section className="mx-auto max-w-[1100px] px-6 py-12">
<div className="flex items-baseline gap-4 mb-5">
<Seal char="件" />
<div className="eyebrow">
{isZh ? "05 · 配置文件位置" : "05 · Where config lives"}
</div>
</div>
<h2 className="font-display text-3xl mb-6">
{isZh ? "配置文件位置" : "Where config lives"}
</h2>
<InstallCodeBlock
cmd={isZh ? CONFIG_TREE_ZH : CONFIG_TREE}
copyLabel={copyLabel}
copiedLabel={copiedLabel}
/>
<p className="mt-4 text-sm text-ink-soft leading-relaxed max-w-2xl">
{isZh ? (
<>
<code className="inline">~/.deepseek/</code>{" "}
<code className="inline">.deepseek/</code>
{" "}
<Link href={isZh ? "/zh/docs" : "/docs"} className="body-link">
{isZh ? "文档" : "the docs"}
</Link>
</div>}
</section>
{/* 安装后 */}
<section className="mx-auto max-w-[1400px] px-6 py-16">
<div className="flex items-baseline gap-4 mb-8 hairline-b pb-4">
<Seal char="后" />
<h2 className="font-display">
<span className="font-cjk text-ink-mute text-xl ml-2"></span>
</h2>
</div>
<ol className="grid md:grid-cols-3 gap-0 col-rule hairline-t hairline-b">
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2"></div>
<h3 className="font-display text-lg mb-2"> platform.deepseek.com </h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide">
<code className="inline">sk-...</code> API
<code className="inline"> deepseek auth</code>
<code className="inline"> ~/.deepseek/config.toml</code>
</p>
</li>
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2"></div>
<h3 className="font-display text-lg mb-2"></h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide">
<code className="inline">deepseek doctor</code>
MCP <code className="inline">~/.deepseek/doctor.log</code>
</p>
</li>
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2"></div>
<h3 className="font-display text-lg mb-2"></h3>
<p className="text-sm text-ink-soft leading-[1.9] tracking-wide">
<code className="inline">cd</code> <code className="inline">deepseek</code>
<em>"这个代码库是做什么的?"</em> Plan
<kbd className="font-mono text-xs px-1 hairline-t hairline-b hairline-l hairline-r">Tab</kbd> Agent
</p>
</li>
</ol>
</section>
{/* 配置 */}
<section className="bg-paper-deep hairline-t hairline-b">
<div className="mx-auto max-w-[1400px] px-6 py-16 grid lg:grid-cols-12 gap-10 min-w-0">
<div className="lg:col-span-5 min-w-0">
<div className="eyebrow mb-3"> · Config</div>
<h2 className="font-display text-3xl"></h2>
<p className="mt-4 text-ink-soft leading-[1.9] tracking-wide">
<code className="inline">~/.deepseek/</code>
<code className="inline">.deepseek/</code>
</p>
<div className="mt-6 space-y-3">
<Link href="/zh/docs" className="body-link inline-block"> </Link>
</div>
</div>
<div className="lg:col-span-7 min-w-0">
<pre className="code-block text-[0.78rem]">
{`~/.deepseek/
config.toml # API
mcp.json # MCP
skills/ # SKILL.md
sessions/ # + 线
tasks/ #
audit.log # / /
#
./.deepseek/ # `}
</pre>
</div>
</div>
</section>
</>
) : (
<>
<section className="mx-auto max-w-[1400px] px-6 pt-12 pb-8">
<div className="flex items-baseline gap-4 mb-3">
<Seal char="装" />
<div className="eyebrow">Section 01 · </div>
</div>
<h1 className="font-display tracking-crisp">
Install <span className="font-cjk text-indigo text-5xl ml-2"></span>
</h1>
<p className="mt-5 max-w-3xl text-ink-soft text-lg leading-relaxed">
Pick your platform below we auto-detect on first load. Every method gives you the same
binary: a single static <code className="inline">deepseek</code> executable that
dispatches to the TUI for interactive use and exposes subcommands like
<code className="inline">doctor</code>, <code className="inline">mcp</code>,
<code className="inline">serve</code>, <code className="inline">eval</code>.
</p>
</section>
<InstallTabs />
{/* AFTER INSTALL */}
<section className="mx-auto max-w-[1400px] px-6 py-16">
<div className="flex items-baseline gap-4 mb-8 hairline-b pb-4">
<Seal char="后" />
<h2 className="font-display">
After install <span className="font-cjk text-ink-mute text-xl ml-2"></span>
</h2>
</div>
<ol className="grid md:grid-cols-3 gap-0 col-rule hairline-t hairline-b">
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2">Get a key</div>
<h3 className="font-display text-lg mb-2">Sign up at platform.deepseek.com</h3>
<p className="text-sm text-ink-soft leading-relaxed">
You'll get an <code className="inline">sk-...</code> API key. Paste it once and
<code className="inline"> deepseek auth</code> will store it in
<code className="inline"> ~/.deepseek/config.toml</code>.
</p>
</li>
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2">Run doctor</div>
<h3 className="font-display text-lg mb-2">Verify your setup</h3>
<p className="text-sm text-ink-soft leading-relaxed">
<code className="inline">deepseek doctor</code> checks your key, network,
sandbox availability, MCP servers, and writes a report to{" "}
<code className="inline">~/.deepseek/doctor.log</code>.
</p>
</li>
<li className="p-6">
<div className="font-display text-3xl text-indigo mb-2"></div>
<div className="eyebrow mb-2">Try it out</div>
<h3 className="font-display text-lg mb-2">First prompt</h3>
<p className="text-sm text-ink-soft leading-relaxed">
<code className="inline">cd</code> into a project, run <code className="inline">deepseek</code>,
and ask: <em>"What does this codebase do?"</em> Plan mode is read-only by default
press <kbd className="font-mono text-xs px-1 hairline-t hairline-b hairline-l hairline-r">Tab</kbd> to switch to Agent mode.
</p>
</li>
</ol>
</section>
{/* CONFIG */}
<section className="bg-paper-deep hairline-t hairline-b">
<div className="mx-auto max-w-[1400px] px-6 py-16 grid lg:grid-cols-12 gap-10 min-w-0">
<div className="lg:col-span-5 min-w-0">
<div className="eyebrow mb-3">Config files · </div>
<h2 className="font-display text-3xl">Where things live</h2>
<p className="mt-4 text-ink-soft leading-relaxed">
All configuration goes under <code className="inline">~/.deepseek/</code>. Per-project
overrides via project-scoped <code className="inline">.deepseek/</code> config at the repo root.
</p>
<div className="mt-6 space-y-3">
<Link href="/docs" className="body-link inline-block">Full configuration reference </Link>
</div>
</div>
<div className="lg:col-span-7 min-w-0">
<pre className="code-block text-[0.78rem]">
{`~/.deepseek/
config.toml # api keys, model, hooks, profiles
mcp.json # MCP server definitions
skills/ # user skills (each with SKILL.md)
sessions/ # checkpoints + offline queue
tasks/ # background task store
audit.log # credential / approval / elevation audit trail
# project-local
./.deepseek/ # project-scoped config (optional)`}
</pre>
</div>
</div>
</section>
</>
)}
</>
) : (
<>
All user-level configuration goes under <code className="inline">~/.deepseek/</code>.
Per-project overrides live in <code className="inline">.deepseek/</code> at the repo
root. Full field reference in{" "}
<Link href="/docs" className="body-link">the docs</Link>.
</>
)}
</p>
</section>
</>
);
}
+1 -1
View File
@@ -17,7 +17,7 @@ const FALLBACK_STATS: RepoStats = {
forks: 0,
openIssues: 0,
openPulls: 0,
contributors: 69,
contributors: 91,
fetchedAt: new Date().toISOString(),
};
+1
View File
@@ -98,6 +98,7 @@ export function Footer({ locale = "en" }: { locale?: Locale }) {
<div className="eyebrow mb-2 text-ink-mute"> / Mirror</div>
<div className="flex flex-wrap gap-3 text-xs">
{GITEE_ENABLED && <a href="https://gitee.com/Hmbown/deepseek-tui" className="text-indigo hover:underline" target="_blank" rel="noopener">Gitee </a>}
<a href="https://cnb.cool/deepseek-tui.com/DeepSeek-TUI" className="text-indigo hover:underline" target="_blank" rel="noopener">CNB </a>
<a href="https://npmmirror.com/package/deepseek-tui" className="text-indigo hover:underline" target="_blank" rel="noopener">npmmirror</a>
<a href="https://mirrors.tuna.tsinghua.edu.cn/help/crates.io-index.html" className="text-indigo hover:underline" target="_blank" rel="noopener">Tuna crates.io</a>
</div>
+107
View File
@@ -0,0 +1,107 @@
"use client";
import { useEffect, useState } from "react";
import { InstallCodeBlock } from "./install-code-block";
type Arch = "macos-arm64" | "macos-x64" | "linux-x64" | "linux-arm64" | "windows-x64";
const SNIPPETS: Record<Arch, string> = {
"macos-arm64": `curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-macos-arm64
chmod +x deepseek
xattr -d com.apple.quarantine deepseek 2>/dev/null || true
sudo mv deepseek /usr/local/bin/`,
"macos-x64": `curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-macos-x64
chmod +x deepseek
xattr -d com.apple.quarantine deepseek 2>/dev/null || true
sudo mv deepseek /usr/local/bin/`,
"linux-x64": `curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-linux-x64
chmod +x deepseek
sudo mv deepseek /usr/local/bin/`,
"linux-arm64": `curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-linux-arm64
chmod +x deepseek
sudo mv deepseek /usr/local/bin/`,
"windows-x64": `# PowerShell
$ErrorActionPreference = "Stop"
$dest = "$Env:USERPROFILE\\bin"
New-Item -ItemType Directory -Force $dest | Out-Null
Invoke-WebRequest \`
-Uri https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-windows-x64.exe \`
-OutFile "$dest\\deepseek.exe"
$Env:Path = "$dest;$Env:Path"`,
};
const VERIFY: Record<Arch, string> = {
"macos-arm64": `curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
shasum -a 256 -c deepseek-artifacts-sha256.txt --ignore-missing`,
"macos-x64": `curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
shasum -a 256 -c deepseek-artifacts-sha256.txt --ignore-missing`,
"linux-x64": `curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
sha256sum -c deepseek-artifacts-sha256.txt --ignore-missing`,
"linux-arm64": `curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
sha256sum -c deepseek-artifacts-sha256.txt --ignore-missing`,
"windows-x64": `# PowerShell
Get-FileHash "$Env:USERPROFILE\\bin\\deepseek.exe" -Algorithm SHA256`,
};
const LABELS: Record<Arch, string> = {
"macos-arm64": "macOS · Apple Silicon",
"macos-x64": "macOS · Intel",
"linux-x64": "Linux · x64",
"linux-arm64": "Linux · arm64",
"windows-x64": "Windows · x64",
};
function detect(): Arch {
if (typeof navigator === "undefined") return "macos-arm64";
const ua = navigator.userAgent.toLowerCase();
if (ua.includes("win")) return "windows-x64";
if (ua.includes("linux")) {
if (ua.includes("aarch64") || ua.includes("arm64")) return "linux-arm64";
return "linux-x64";
}
// mac: most modern macs are arm64; Intel users can switch tab
return "macos-arm64";
}
interface Props {
copyLabel?: string;
copiedLabel?: string;
verifyHeading?: string;
}
export function InstallBinary({ copyLabel, copiedLabel, verifyHeading = "Verify checksum" }: Props) {
const [arch, setArch] = useState<Arch>("macos-arm64");
useEffect(() => { setArch(detect()); }, []);
return (
<div>
<div className="flex flex-wrap gap-0 mb-3 hairline-t hairline-b hairline-l hairline-r">
{(Object.keys(SNIPPETS) as Arch[]).map((a, i) => (
<button
key={a}
onClick={() => setArch(a)}
className={`px-3 py-1.5 font-mono text-[0.7rem] tracking-wider transition-colors ${
i > 0 ? "hairline-l" : ""
} ${arch === a ? "bg-ink text-paper" : "bg-paper hover:bg-paper-deep"}`}
>
{LABELS[a]}
</button>
))}
</div>
<InstallCodeBlock cmd={SNIPPETS[arch]} copyLabel={copyLabel} copiedLabel={copiedLabel} />
<div className="mt-4">
<div className="eyebrow mb-2">{verifyHeading}</div>
<InstallCodeBlock cmd={VERIFY[arch]} copyLabel={copyLabel} copiedLabel={copiedLabel} />
</div>
</div>
);
}
+34
View File
@@ -0,0 +1,34 @@
"use client";
import { useState } from "react";
interface Props {
cmd: string;
copyLabel?: string;
copiedLabel?: string;
}
export function InstallCodeBlock({ cmd, copyLabel = "Copy", copiedLabel = "Copied ✓" }: Props) {
const [copied, setCopied] = useState(false);
const copy = () => {
if (typeof navigator !== "undefined" && navigator.clipboard) {
navigator.clipboard.writeText(cmd);
setCopied(true);
setTimeout(() => setCopied(false), 1400);
}
};
return (
<div className="relative">
<button
onClick={copy}
aria-label={copied ? copiedLabel : copyLabel}
className="absolute top-3 right-3 z-10 px-3 py-1 bg-paper hairline-t hairline-b hairline-l hairline-r font-mono text-[0.7rem] uppercase tracking-wider hover:bg-indigo hover:text-paper transition-colors"
>
{copied ? copiedLabel : copyLabel}
</button>
<pre className="code-block text-[0.78rem] m-0 max-w-full pr-20">{cmd}</pre>
</div>
);
}
-331
View File
@@ -1,331 +0,0 @@
"use client";
import { useEffect, useState } from "react";
type OS = "macos" | "linux" | "windows" | "any";
interface Method {
id: string;
os: OS;
label: string;
cn: string;
recommended?: boolean;
comingSoon?: boolean;
prereq: string;
cmd: string;
}
const METHODS: Method[] = [
// ─── macOS ────────────────────────────────────────────────
{
id: "cargo-mac",
os: "macos",
label: "Cargo (recommended)",
cn: "Cargo · 推荐",
recommended: true,
prereq: "Rust 1.88+ — install via rustup.rs if needed",
cmd: `# Install the dispatcher (provides \`deepseek\`)
cargo install deepseek-tui-cli --locked
# Optional: also install the raw TUI binary (\`deepseek-tui\`)
cargo install deepseek-tui --locked
# Set your API key (one-time)
export DEEPSEEK_API_KEY=sk-...
echo 'export DEEPSEEK_API_KEY=sk-...' >> ~/.zshrc
# Run it
deepseek`,
},
{
id: "npm-mac",
os: "macos",
label: "npm wrapper",
cn: "npm 包",
prereq: "Node.js 18+",
cmd: `npm install -g deepseek-tui
# Provides both binaries on PATH:
deepseek # canonical dispatcher
deepseek-tui # raw TUI binary`,
},
{
id: "binary-mac",
os: "macos",
label: "Pre-built binary",
cn: "二进制",
prereq: "Apple Silicon (arm64) or Intel (x64). Releases ship raw binaries — no archive to extract.",
cmd: `# Apple Silicon
curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-macos-arm64
chmod +x deepseek
xattr -d com.apple.quarantine deepseek 2>/dev/null || true
sudo mv deepseek /usr/local/bin/
# Intel
curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-macos-x64
chmod +x deepseek
xattr -d com.apple.quarantine deepseek 2>/dev/null || true
sudo mv deepseek /usr/local/bin/
# Verify checksum (optional but recommended)
curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
shasum -a 256 -c deepseek-artifacts-sha256.txt --ignore-missing
deepseek`,
},
{
id: "brew",
os: "macos",
label: "Homebrew",
cn: "Homebrew",
prereq: "Homebrew on macOS or Linux; installs the dispatcher and companion TUI from the official Hmbown tap.",
cmd: `brew tap Hmbown/deepseek-tui
brew install deepseek-tui
deepseek --version
deepseek`,
},
// ─── Linux ────────────────────────────────────────────────
{
id: "cargo-linux",
os: "linux",
label: "Cargo (recommended)",
cn: "Cargo · 推荐",
recommended: true,
prereq: "Rust 1.88+; on Debian/Ubuntu: apt install build-essential pkg-config libssl-dev",
cmd: `cargo install deepseek-tui-cli --locked
export DEEPSEEK_API_KEY=sk-...
deepseek`,
},
{
id: "npm-linux",
os: "linux",
label: "npm wrapper",
cn: "npm 包",
prereq: "Node.js 18+",
cmd: `npm install -g deepseek-tui
deepseek`,
},
{
id: "binary-linux",
os: "linux",
label: "Pre-built binary",
cn: "二进制",
prereq: "x86_64 or aarch64 glibc. Releases ship raw binaries — no archive to extract.",
cmd: `# x86_64
curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-linux-x64
chmod +x deepseek
sudo mv deepseek /usr/local/bin/
# arm64
curl -fsSL -o deepseek \\
https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-linux-arm64
chmod +x deepseek
sudo mv deepseek /usr/local/bin/
# Verify checksum (optional but recommended)
curl -fsSL -O https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-artifacts-sha256.txt
sha256sum -c deepseek-artifacts-sha256.txt --ignore-missing
deepseek`,
},
// ─── Windows ──────────────────────────────────────────────
{
id: "cargo-win",
os: "windows",
label: "Cargo (recommended)",
cn: "Cargo · 推荐",
recommended: true,
prereq: "Rust 1.88+ via rustup-init.exe",
cmd: `cargo install deepseek-tui-cli --locked
$env:DEEPSEEK_API_KEY = "sk-..."
deepseek`,
},
{
id: "npm-win",
os: "windows",
label: "npm wrapper",
cn: "npm 包",
prereq: "Node.js 18+",
cmd: `npm install -g deepseek-tui
deepseek`,
},
{
id: "binary-win",
os: "windows",
label: "Pre-built binary",
cn: "二进制",
prereq: "Windows 10+ x64. Releases ship a raw .exe — no archive to extract.",
cmd: `# PowerShell
$ErrorActionPreference = "Stop"
$dest = "$Env:USERPROFILE\\bin"
New-Item -ItemType Directory -Force $dest | Out-Null
Invoke-WebRequest \`
-Uri https://github.com/Hmbown/deepseek-tui/releases/latest/download/deepseek-windows-x64.exe \`
-OutFile "$dest\\deepseek.exe"
# Add to PATH for this session (persist via System Properties Environment Variables)
$Env:Path = "$dest;$Env:Path"
$Env:DEEPSEEK_API_KEY = "sk-..."
deepseek`,
},
{
id: "scoop",
os: "windows",
label: "Scoop",
cn: "Scoop",
comingSoon: true,
prereq: "Scoop manifest not yet published — use Cargo or the pre-built .exe above.",
cmd: `# Coming soon — no Scoop manifest yet.
# Working alternatives on Windows:
# - Cargo (recommended above)
# - Pre-built deepseek-windows-x64.exe (above)
#
# Track progress:
# https://github.com/Hmbown/deepseek-tui/issues`,
},
// ─── Any (cross-platform) ────────────────────────────────
{
id: "docker",
os: "any",
label: "Docker",
cn: "Docker",
prereq: "Dockerfile ships with the repo (multi-arch buildx). No prebuilt image is published to a registry yet.",
cmd: `git clone https://github.com/Hmbown/deepseek-tui
cd deepseek-tui
# Build for your local arch
docker build -t deepseek-tui .
# Or multi-arch via buildx
docker buildx build --platform linux/amd64,linux/arm64 -t deepseek-tui .
# Run interactively, mounting your config + a project
docker run --rm -it \\
-e DEEPSEEK_API_KEY=$DEEPSEEK_API_KEY \\
-v ~/.deepseek:/home/deepseek/.deepseek \\
-v "$PWD:/work" -w /work \\
deepseek-tui`,
},
{
id: "from-source",
os: "any",
label: "Build from source",
cn: "源码编译",
prereq: "Rust 1.88+ and a git checkout — useful for hacking on the workspace itself.",
cmd: `git clone https://github.com/Hmbown/deepseek-tui
cd deepseek-tui
# Builds both \`deepseek\` and \`deepseek-tui\` into ./target/release/
cargo build --release --locked
# Run without installing
./target/release/deepseek
# Or install both binaries from your local checkout
cargo install --path crates/cli --locked # provides \`deepseek\`
cargo install --path crates/tui --locked # provides \`deepseek-tui\``,
},
];
const OS_LABEL: Record<OS, { en: string; cn: string }> = {
macos: { en: "macOS", cn: "苹果" },
linux: { en: "Linux", cn: "Linux" },
windows: { en: "Windows", cn: "视窗" },
any: { en: "Any platform", cn: "通用" },
};
function detectOS(): OS {
if (typeof navigator === "undefined") return "macos";
const ua = navigator.userAgent.toLowerCase();
if (ua.includes("mac")) return "macos";
if (ua.includes("win")) return "windows";
if (ua.includes("linux")) return "linux";
return "macos";
}
export function InstallTabs() {
const [os, setOS] = useState<OS>("macos");
const [copied, setCopied] = useState<string | null>(null);
useEffect(() => { setOS(detectOS()); }, []);
// Show OS-specific methods + universal ones (Docker status / source build).
// On the "Any" tab, only show universal ones.
const methods = METHODS.filter((m) => (os === "any" ? m.os === "any" : m.os === os || m.os === "any"));
const copy = (id: string, text: string) => {
navigator.clipboard?.writeText(text);
setCopied(id);
setTimeout(() => setCopied(null), 1400);
};
return (
<div>
{/* OS selector */}
<div className="hairline-t hairline-b grid grid-cols-4">
{(["macos", "linux", "windows", "any"] as OS[]).map((o) => {
const active = os === o;
return (
<button
key={o}
onClick={() => setOS(o)}
className={`px-4 py-4 text-left transition-colors hairline-l first:border-l-0 ${
active ? "bg-ink text-paper" : "bg-paper hover:bg-paper-deep"
}`}
>
<div className={`eyebrow mb-1 ${active ? "text-paper-deep/70" : ""}`}>
{active ? "▼ " : ""}Detected · {o === detectOS() ? "auto" : "switch"}
</div>
<div className="font-display text-lg leading-tight">{OS_LABEL[o].en}</div>
<div className={`font-cjk text-xs ${active ? "text-paper-deep/80" : "text-ink-mute"}`}>
{OS_LABEL[o].cn}
</div>
</button>
);
})}
</div>
{/* methods */}
<div className="hairline-b">
{methods.map((m, i) => (
<div key={m.id} className={i > 0 ? "hairline-t" : ""}>
<div className="grid lg:grid-cols-12 gap-0 min-w-0">
<div className={`min-w-0 lg:col-span-4 p-6 hairline-r-0 lg:hairline-r bg-paper ${m.comingSoon ? "opacity-70" : ""}`}>
<div className="flex items-center gap-2 mb-2 flex-wrap">
{m.recommended && <span className="pill pill-hot">Recommended</span>}
{m.comingSoon && <span className="pill pill-ghost">Coming soon</span>}
<span className="eyebrow">Method 0{i + 1}</span>
</div>
<h3 className="font-display text-xl mb-1">{m.label}</h3>
<div className="font-cjk text-sm text-ink-mute mb-3">{m.cn}</div>
<div className="text-xs text-ink-soft leading-relaxed">
<strong className="text-ink">Prereq:</strong> {m.prereq}
</div>
</div>
<div className={`min-w-0 lg:col-span-8 p-6 bg-paper-deep relative ${m.comingSoon ? "opacity-80" : ""}`}>
{!m.comingSoon && (
<button
onClick={() => copy(m.id, m.cmd)}
className="absolute top-7 right-7 z-10 px-3 py-1 bg-paper hairline-t hairline-b hairline-l hairline-r font-mono text-[0.7rem] uppercase tracking-wider hover:bg-indigo hover:text-paper transition-colors"
>
{copied === m.id ? "Copied ✓" : "Copy"}
</button>
)}
<pre className="code-block text-[0.78rem] m-0 max-w-full">{m.cmd}</pre>
</div>
</div>
</div>
))}
</div>
</div>
);
}
+2 -2
View File
@@ -18,8 +18,8 @@ export interface RepoFacts {
}
export const FACTS: RepoFacts = {
"generatedAt": "2026-05-13T06:15:45.167Z",
"version": "0.8.35",
"generatedAt": "2026-05-14T19:34:46.542Z",
"version": "0.8.37",
"crates": [
"agent",
"app-server",
+1 -1
View File
@@ -2,7 +2,7 @@ import type { FeedItem, RepoStats } from "./types";
const REPO = process.env.GITHUB_REPO ?? "Hmbown/deepseek-tui";
const GH = "https://api.github.com";
const MIN_KNOWN_CONTRIBUTORS = 69;
const MIN_KNOWN_CONTRIBUTORS = 91;
function headers(token?: string): HeadersInit {
const h: Record<string, string> = {