From 5c1086fe9ee8f997d40a2dd90458d80bee876fa7 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sat, 25 Apr 2026 07:59:01 -0500 Subject: [PATCH] release: deepseek-tui 0.4.7 Bump workspace version 0.4.6 -> 0.4.7 and ship the bug fix flagged by Devin on PR #18: an uncommented `DEEPSEEK_API_KEY=` line in .env.example caused `cp .env.example .env` to load an empty key, which `apply_env_overrides` then propagated into the config and `Config::validate()` rejected on startup with "api_key cannot be empty string". - .env.example: comment out the empty `DEEPSEEK_API_KEY=` placeholder. - crates/tui/src/config.rs: skip empty `DEEPSEEK_API_KEY` env values in `apply_env_overrides`, matching the facade's empty-string filter. - Add `apply_env_overrides_ignores_empty_api_key` regression test. - Bump Cargo.toml workspace version, npm wrapper version + binary version, and Cargo.lock. --- .env.example | 2 +- Cargo.lock | 26 ++++++++++++------------ Cargo.toml | 2 +- crates/tui/src/config.rs | 37 ++++++++++++++++++++++++++++++++++- npm/deepseek-tui/package.json | 4 ++-- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.env.example b/.env.example index 2bf024a3..d4084b2b 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ # DeepSeek API (default provider) # Get an API key from DeepSeek, then keep it local in `.env`. -DEEPSEEK_API_KEY= +# DEEPSEEK_API_KEY= # Global endpoint: # DEEPSEEK_BASE_URL=https://api.deepseek.com diff --git a/Cargo.lock b/Cargo.lock index bf6e5e22..57ccd367 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,7 +806,7 @@ dependencies = [ [[package]] name = "deepseek-agent" -version = "0.4.6" +version = "0.4.7" dependencies = [ "deepseek-config", "serde", @@ -814,7 +814,7 @@ dependencies = [ [[package]] name = "deepseek-app-server" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "axum", @@ -837,7 +837,7 @@ dependencies = [ [[package]] name = "deepseek-config" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "dirs", @@ -848,7 +848,7 @@ dependencies = [ [[package]] name = "deepseek-core" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "chrono", @@ -867,7 +867,7 @@ dependencies = [ [[package]] name = "deepseek-execpolicy" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "deepseek-protocol", @@ -876,7 +876,7 @@ dependencies = [ [[package]] name = "deepseek-hooks" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "async-trait", @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "deepseek-mcp" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "deepseek-protocol", @@ -900,7 +900,7 @@ dependencies = [ [[package]] name = "deepseek-protocol" -version = "0.4.6" +version = "0.4.7" dependencies = [ "serde", "serde_json", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "deepseek-state" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "chrono", @@ -920,7 +920,7 @@ dependencies = [ [[package]] name = "deepseek-tools" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "async-trait", @@ -933,7 +933,7 @@ dependencies = [ [[package]] name = "deepseek-tui" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "arboard", @@ -987,7 +987,7 @@ dependencies = [ [[package]] name = "deepseek-tui-cli" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "chrono", @@ -1005,7 +1005,7 @@ dependencies = [ [[package]] name = "deepseek-tui-core" -version = "0.4.6" +version = "0.4.7" [[package]] name = "deranged" diff --git a/Cargo.toml b/Cargo.toml index e5b95425..6b52b6ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ default-members = ["crates/cli", "crates/app-server", "crates/tui"] resolver = "2" [workspace.package] -version = "0.4.6" +version = "0.4.7" edition = "2024" license = "MIT" repository = "https://github.com/Hmbown/DeepSeek-TUI" diff --git a/crates/tui/src/config.rs b/crates/tui/src/config.rs index a4428279..d31cf2e6 100644 --- a/crates/tui/src/config.rs +++ b/crates/tui/src/config.rs @@ -728,7 +728,9 @@ fn apply_env_overrides(config: &mut Config) { if let Ok(value) = std::env::var("DEEPSEEK_PROVIDER") { config.provider = Some(value); } - if let Ok(value) = std::env::var("DEEPSEEK_API_KEY") { + if let Ok(value) = std::env::var("DEEPSEEK_API_KEY") + && !value.trim().is_empty() + { config.api_key = Some(value); } if let Ok(value) = std::env::var("DEEPSEEK_BASE_URL") { @@ -1554,6 +1556,39 @@ mod tests { Ok(()) } + #[test] + fn apply_env_overrides_ignores_empty_api_key() -> Result<()> { + let _lock = lock_test_env(); + let nanos = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos(); + let temp_root = env::temp_dir().join(format!( + "deepseek-tui-empty-key-{}-{}", + std::process::id(), + nanos + )); + fs::create_dir_all(&temp_root)?; + let _guard = EnvGuard::new(&temp_root); + + // Simulate a fresh user who copied .env.example to .env without + // filling in DEEPSEEK_API_KEY: dotenv loads it as the empty string. + // Safety: test-only environment mutation guarded by a global mutex. + unsafe { + env::set_var("DEEPSEEK_API_KEY", ""); + } + + let mut config = Config { + api_key: Some("from-config-file".to_string()), + ..Default::default() + }; + apply_env_overrides(&mut config); + + assert_eq!(config.api_key.as_deref(), Some("from-config-file")); + config.validate()?; + Ok(()) + } + #[test] fn normalize_model_name_handles_aliases_and_future_ids() { assert_eq!( diff --git a/npm/deepseek-tui/package.json b/npm/deepseek-tui/package.json index 36795de1..4458717c 100644 --- a/npm/deepseek-tui/package.json +++ b/npm/deepseek-tui/package.json @@ -1,7 +1,7 @@ { "name": "deepseek-tui", - "version": "0.4.6", - "deepseekBinaryVersion": "0.4.6", + "version": "0.4.7", + "deepseekBinaryVersion": "0.4.7", "description": "Install and run deepseek and deepseek-tui binaries from GitHub release artifacts.", "author": "Hmbown", "license": "MIT",