chore(release): prepare v0.8.37
This commit is contained in:
+48
-4
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" }
|
||||
)
|
||||
};
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
@@ -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'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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ const FALLBACK_STATS: RepoStats = {
|
||||
forks: 0,
|
||||
openIssues: 0,
|
||||
openPulls: 0,
|
||||
contributors: 69,
|
||||
contributors: 91,
|
||||
fetchedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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
@@ -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> = {
|
||||
|
||||
Reference in New Issue
Block a user