From e1ac84ae44f981defe85ef1c8c14a1489c8b272a Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sun, 26 Apr 2026 11:56:41 -0500 Subject: [PATCH] =?UTF-8?q?release:=20v0.6.1=20=E2=80=94=20pricing=20updat?= =?UTF-8?q?e,=20remove=20light=20theme=20+=20theme=20setting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - V4 cache-hit input prices cut to 1/10th per DeepSeek pricing update: Pro promo 0.03625→0.003625, Pro base 0.145→0.0145, Flash 0.028→0.0028 - Remove the 'light' theme variant (Variant::Light, Theme::light(), test) - Remove the theme setting entirely — hardcode UI_THEME to whale/dark, drop the theme field from Settings, ConfigView, and config command - Bump workspace version 0.6.0 → 0.6.1 (Cargo.toml, npm pkg, CHANGELOG) - De-cringe the README: drop emojis, marketing fluff, unverified claims --- CHANGELOG.md | 11 ++++++++- Cargo.lock | 26 +++++++++++----------- Cargo.toml | 2 +- README.md | 28 +++++++++++------------ crates/tui/src/commands/config.rs | 5 ----- crates/tui/src/deepseek_theme.rs | 35 +++-------------------------- crates/tui/src/palette.rs | 37 ++++++------------------------- crates/tui/src/pricing.rs | 12 +++++----- crates/tui/src/settings.rs | 13 ----------- crates/tui/src/tui/app.rs | 2 +- crates/tui/src/tui/views/mod.rs | 7 ------ npm/deepseek-tui/package.json | 4 ++-- 12 files changed, 56 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eb27648..5fc7ab03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Test hygiene - **5 regression tests pin auto-scroll churn contract.** `mark_history_updated` does not scroll; tool-cell handlers only `mark_history_updated`; `add_message` and `flush_active_cell` gate on `user_scrolled_during_stream`; the per-stream lock clears at TurnComplete and when the user returns to the live tail. (P2.4) +## [0.6.1] - 2026-04-26 + +### Changed +- **V4 cache-hit input prices cut to 1/10th per DeepSeek's pricing update.** Pro promo 0.03625→0.003625, Pro base 0.145→0.0145, Flash 0.028→0.0028 per 1M tokens. Cache-miss and output rates unchanged. +- **Removed the "light" theme option.** It was never tested, looked bad, and the dark/whale palettes are the supported targets. Theme validation now accepts only `default`, `dark`, and `whale`. +- **System prompts redesigned with decomposition-first philosophy.** All five prompt tiers teach the model to `todo_write` before acting, `update_plan` for strategy, and sub-agents for parallel work. Inspired by the mismanaged-geniuses hypothesis (Zhang et al., 2026). + ## [0.6.0] - 2026-04-25 ### Added @@ -558,7 +565,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Hooks system and config profiles - Example skills and launch assets -[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.4.9...HEAD +[Unreleased]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.6.1...HEAD +[0.6.1]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.6.0...v0.6.1 +[0.6.0]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.4.9...v0.6.0 [0.4.9]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.4.8...v0.4.9 [0.4.8]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.3.33...v0.4.8 [0.3.33]: https://github.com/Hmbown/DeepSeek-TUI/compare/v0.3.32...v0.3.33 diff --git a/Cargo.lock b/Cargo.lock index 091f2c99..77ef7157 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -806,7 +806,7 @@ dependencies = [ [[package]] name = "deepseek-agent" -version = "0.6.0" +version = "0.6.1" dependencies = [ "deepseek-config", "serde", @@ -814,7 +814,7 @@ dependencies = [ [[package]] name = "deepseek-app-server" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "axum", @@ -837,7 +837,7 @@ dependencies = [ [[package]] name = "deepseek-config" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "dirs", @@ -848,7 +848,7 @@ dependencies = [ [[package]] name = "deepseek-core" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "chrono", @@ -867,7 +867,7 @@ dependencies = [ [[package]] name = "deepseek-execpolicy" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "deepseek-protocol", @@ -876,7 +876,7 @@ dependencies = [ [[package]] name = "deepseek-hooks" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "async-trait", @@ -890,7 +890,7 @@ dependencies = [ [[package]] name = "deepseek-mcp" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "deepseek-protocol", @@ -900,7 +900,7 @@ dependencies = [ [[package]] name = "deepseek-protocol" -version = "0.6.0" +version = "0.6.1" dependencies = [ "serde", "serde_json", @@ -908,7 +908,7 @@ dependencies = [ [[package]] name = "deepseek-state" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "chrono", @@ -920,7 +920,7 @@ dependencies = [ [[package]] name = "deepseek-tools" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "async-trait", @@ -933,7 +933,7 @@ dependencies = [ [[package]] name = "deepseek-tui" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "arboard", @@ -987,7 +987,7 @@ dependencies = [ [[package]] name = "deepseek-tui-cli" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "chrono", @@ -1005,7 +1005,7 @@ dependencies = [ [[package]] name = "deepseek-tui-core" -version = "0.6.0" +version = "0.6.1" [[package]] name = "deranged" diff --git a/Cargo.toml b/Cargo.toml index 7fc743b4..f485fd96 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.6.0" +version = "0.6.1" edition = "2024" license = "MIT" repository = "https://github.com/Hmbown/DeepSeek-TUI" diff --git a/README.md b/README.md index 38d729e2..9f409554 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,17 @@ DeepSeek TUI is a coding agent that runs entirely in your terminal. It gives Dee ### Key Features -- 🌊 **Native RLM** *(new in v0.6)* — `rlm_query` tool fans out 1–16 cheap `deepseek-v4-flash` children in parallel against the existing DeepSeek client. The model uses it for batched analysis, decomposition, or cheap parallel reasoning — one structured tool call, no external runtime -- 🧠 **Thinking-mode streaming** — watch DeepSeek's chain-of-thought as it reasons about your code -- 🔧 **Full tool suite** — file ops, shell execution, git, web search/browse, apply-patch, sub-agents, MCP servers, and more -- 🪟 **1M-token context** — feed entire codebases; automatic intelligent compaction when context fills up -- 🎛️ **Three interaction modes** — Plan (read-only explore), Agent (interactive with approval), YOLO (auto-approved). All three guided by decomposition-first system prompts that teach the model to `todo_write`, `update_plan`, and spawn sub-agents before acting -- ⚡ **Reasoning-effort tiers** — cycle through `off → high → max` with Shift+Tab -- 🔄 **Session save/resume** — checkpoint and resume long sessions, fork conversations -- 🌐 **HTTP/SSE runtime API** — `deepseek serve --http` for headless agent workflows -- 📦 **MCP protocol** — connect to Model Context Protocol servers for extended tooling -- 💰 **Live cost tracking** — per-turn and session-level token usage and cost estimates -- 🎨 **Dark & light themes** — with a DeepSeek-blue branded palette +- **Native RLM** (`rlm_query` tool) — fans out 1–16 cheap `deepseek-v4-flash` children in parallel against the existing DeepSeek client for batched analysis, decomposition, or parallel reasoning +- **Thinking-mode streaming** — shows DeepSeek's chain-of-thought as it reasons about your code +- **Full tool suite** — file ops, shell execution, git, web search/browse, apply-patch, sub-agents, MCP servers +- **1M-token context** — automatic intelligent compaction when context fills up +- **Three interaction modes** — Plan (read-only explore), Agent (interactive with approval), YOLO (auto-approved). Decomposition-first system prompts teach the model to `todo_write`, `update_plan`, and spawn sub-agents before acting +- **Reasoning-effort tiers** — cycle through `off → high → max` with Shift+Tab +- **Session save/resume** — checkpoint and resume long sessions +- **HTTP/SSE runtime API** — `deepseek serve --http` for headless agent workflows +- **MCP protocol** — connect to Model Context Protocol servers for extended tooling +- **Live cost tracking** — per-turn and session-level token usage and cost estimates +- **Dark theme** — DeepSeek-blue palette --- @@ -119,8 +119,8 @@ DeepSeek TUI targets **DeepSeek V4** models with 1M-token context windows by def | Model | Context | Input (cache hit) | Input (cache miss) | Output | |---|---|---|---|---| -| `deepseek-v4-pro` | 1M | $0.03625 / 1M* | $0.435 / 1M* | $0.87 / 1M* | -| `deepseek-v4-flash` | 1M | $0.028 / 1M | $0.14 / 1M | $0.28 / 1M | +| `deepseek-v4-pro` | 1M | $0.003625 / 1M* | $0.435 / 1M* | $0.87 / 1M* | +| `deepseek-v4-flash` | 1M | $0.0028 / 1M | $0.14 / 1M | $0.28 / 1M | Legacy aliases `deepseek-chat` and `deepseek-reasoner` silently map to `deepseek-v4-flash`. @@ -167,8 +167,6 @@ deepseek serve --http # HTTP/SSE API server | **Agent** 🤖 | Default interactive mode — multi-step tool use with approval gates; model outlines work via `todo_write` before requesting writes | | **YOLO** ⚡ | Auto-approve all tools in a trusted workspace; model still creates `todo_write`/`update_plan` to keep work visible and trackable | -All three modes are guided by decomposition-first system prompts: the model is taught to break work into verifiable tasks, track them in the sidebar, and fan out sub-agents for parallel work — "managing the geniuses" rather than just running single-shot prompts. - --- ## Configuration diff --git a/crates/tui/src/commands/config.rs b/crates/tui/src/commands/config.rs index 73657cab..c71d0c83 100644 --- a/crates/tui/src/commands/config.rs +++ b/crates/tui/src/commands/config.rs @@ -4,7 +4,6 @@ use std::path::{Path, PathBuf}; use super::CommandResult; use crate::config::{COMMON_DEEPSEEK_MODELS, clear_api_key, normalize_model_name}; -use crate::palette; use crate::settings::Settings; use crate::tui::app::{App, AppAction, AppMode, OnboardingState, SidebarFocus}; use crate::tui::approval::ApprovalMode; @@ -130,10 +129,6 @@ pub fn set_config_value(app: &mut App, key: &str, value: &str, persist: bool) -> action = Some(AppAction::UpdateCompaction(app.compaction_config())); } } - "theme" => { - app.ui_theme = palette::ui_theme(&settings.theme); - app.mark_history_updated(); - } "sidebar_width" | "sidebar" => { app.sidebar_width_percent = settings.sidebar_width_percent; app.mark_history_updated(); diff --git a/crates/tui/src/deepseek_theme.rs b/crates/tui/src/deepseek_theme.rs index 4564983e..640a3354 100644 --- a/crates/tui/src/deepseek_theme.rs +++ b/crates/tui/src/deepseek_theme.rs @@ -1,9 +1,9 @@ //! Whale/DeepSeek terminal theme tokens. //! //! A small, deliberately flat module that names the color, border, and -//! padding choices the TUI is already making. The dark variant matches the -//! values previously hard-coded against [`crate::palette`]; the light variant -//! is reserved for the future skin swap that issue #14 tracks. Visible output +//! padding choices the TUI is already making. All values match the dark +//! palette previously hard-coded against [`crate::palette`]; a single +//! source-of-truth change here can swap the skin later. Visible output //! is not changed by introducing this module. //! //! The only consumers today are the plan and tool cell renderers in @@ -21,9 +21,6 @@ use crate::tui::history::ToolStatus; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Variant { Dark, - /// Reserved for the future skin swap (issue #14). Not wired up yet. - #[allow(dead_code)] - Light, } /// Centralized visual tokens for sidebar, plan, and tool rendering. @@ -83,18 +80,6 @@ impl Theme { } } - /// The light variant. Same RGB values as `dark()` today so a future skin - /// swap is a single-source-of-truth change in this file. Out of scope: - /// actually picking a distinct light palette. - #[must_use] - #[allow(dead_code)] - pub const fn light() -> Self { - Self { - variant: Variant::Light, - ..Self::dark() - } - } - /// Pick the right tool accent for a given [`ToolStatus`]. #[must_use] pub const fn tool_status_color(self, status: ToolStatus) -> Color { @@ -167,20 +152,6 @@ mod tests { assert_eq!(theme.tool_failed_accent, palette::ACCENT_TOOL_ISSUE); } - #[test] - fn light_theme_keeps_dark_values_until_skin_swap() { - // The light variant exists so the future skin swap is a single-file - // change. It intentionally mirrors `dark()` today so introducing the - // module does not move pixels. - let dark = Theme::dark(); - let light = Theme::light(); - assert_eq!(light.variant, Variant::Light); - assert_eq!(light.section_border_color, dark.section_border_color); - assert_eq!(light.tool_running_accent, dark.tool_running_accent); - assert_eq!(light.tool_failed_accent, dark.tool_failed_accent); - assert_eq!(light.plan_in_progress_color, dark.plan_in_progress_color); - } - #[test] fn tool_status_color_maps_each_status() { let theme = Theme::dark(); diff --git a/crates/tui/src/palette.rs b/crates/tui/src/palette.rs index 4a439ed0..13f9f4e6 100644 --- a/crates/tui/src/palette.rs +++ b/crates/tui/src/palette.rs @@ -64,8 +64,6 @@ pub const ACCENT_PRIMARY: Color = DEEPSEEK_BLUE; // #3578E5 #[allow(dead_code)] pub const ACCENT_SECONDARY: Color = TEXT_ACCENT; // #6AAEF2 #[allow(dead_code)] -pub const BACKGROUND_LIGHT: Color = Color::Rgb(30, 47, 71); // #1E2F47 -#[allow(dead_code)] pub const BACKGROUND_DARK: Color = Color::Rgb(13, 26, 48); // #0D1A30 #[allow(dead_code)] pub const STATUS_NEUTRAL: Color = Color::Rgb(160, 160, 160); // #A0A0A0 @@ -103,6 +101,7 @@ pub const MODE_YOLO: Color = Color::Rgb(255, 100, 100); // Warning red pub const MODE_PLAN: Color = Color::Rgb(255, 170, 60); // Orange pub const SELECTION_BG: Color = Color::Rgb(26, 44, 74); +#[allow(dead_code)] pub const COMPOSER_BG: Color = DEEPSEEK_SLATE; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -113,31 +112,9 @@ pub struct UiTheme { pub header_bg: Color, } -pub fn ui_theme(name: &str) -> UiTheme { - match name.to_ascii_lowercase().as_str() { - "dark" => UiTheme { - name: "dark", - composer_bg: DEEPSEEK_INK, - selection_bg: SELECTION_BG, - header_bg: DEEPSEEK_INK, - }, - "light" => UiTheme { - name: "light", - composer_bg: Color::Rgb(26, 38, 58), - selection_bg: SELECTION_BG, - header_bg: DEEPSEEK_SLATE, - }, - "whale" => UiTheme { - name: "whale", - composer_bg: DEEPSEEK_SLATE, - selection_bg: SELECTION_BG, - header_bg: DEEPSEEK_INK, - }, - _ => UiTheme { - name: "default", - composer_bg: COMPOSER_BG, - selection_bg: SELECTION_BG, - header_bg: DEEPSEEK_INK, - }, - } -} +pub const UI_THEME: UiTheme = UiTheme { + name: "whale", + composer_bg: DEEPSEEK_SLATE, + selection_bg: SELECTION_BG, + header_bg: DEEPSEEK_INK, +}; diff --git a/crates/tui/src/pricing.rs b/crates/tui/src/pricing.rs index 1ac8a55a..4aefeeaa 100644 --- a/crates/tui/src/pricing.rs +++ b/crates/tui/src/pricing.rs @@ -39,13 +39,13 @@ fn pricing_for_model_at(model: &str, now: DateTime) -> Option // DeepSeek lists these as a limited-time 75% discount through // 2026-05-05 15:59 UTC. return Some(ModelPricing { - input_cache_hit_per_million: 0.03625, + input_cache_hit_per_million: 0.003625, input_cache_miss_per_million: 0.435, output_per_million: 0.87, }); } Some(ModelPricing { - input_cache_hit_per_million: 0.145, + input_cache_hit_per_million: 0.0145, input_cache_miss_per_million: 1.74, output_per_million: 3.48, }) @@ -53,7 +53,7 @@ fn pricing_for_model_at(model: &str, now: DateTime) -> Option // deepseek-v4-flash and legacy aliases (deepseek-chat, deepseek-reasoner, // deepseek-v3*) all price as v4-flash. Some(ModelPricing { - input_cache_hit_per_million: 0.028, + input_cache_hit_per_million: 0.0028, input_cache_miss_per_million: 0.14, output_per_million: 0.28, }) @@ -136,7 +136,7 @@ mod tests { .unwrap(); let pricing = pricing_for_model_at("deepseek-v4-pro", before_expiry).unwrap(); - assert_eq!(pricing.input_cache_hit_per_million, 0.03625); + assert_eq!(pricing.input_cache_hit_per_million, 0.003625); assert_eq!(pricing.input_cache_miss_per_million, 0.435); assert_eq!(pricing.output_per_million, 0.87); } @@ -146,7 +146,7 @@ mod tests { let after_expiry = Utc.with_ymd_and_hms(2026, 5, 5, 16, 0, 0).single().unwrap(); let pricing = pricing_for_model_at("deepseek-v4-pro", after_expiry).unwrap(); - assert_eq!(pricing.input_cache_hit_per_million, 0.145); + assert_eq!(pricing.input_cache_hit_per_million, 0.0145); assert_eq!(pricing.input_cache_miss_per_million, 1.74); assert_eq!(pricing.output_per_million, 3.48); } @@ -156,7 +156,7 @@ mod tests { let now = Utc.with_ymd_and_hms(2026, 4, 25, 0, 0, 0).single().unwrap(); let pricing = pricing_for_model_at("deepseek-v4-flash", now).unwrap(); - assert_eq!(pricing.input_cache_hit_per_million, 0.028); + assert_eq!(pricing.input_cache_hit_per_million, 0.0028); assert_eq!(pricing.input_cache_miss_per_million, 0.14); assert_eq!(pricing.output_per_million, 0.28); } diff --git a/crates/tui/src/settings.rs b/crates/tui/src/settings.rs index 5a4fa528..258b27b4 100644 --- a/crates/tui/src/settings.rs +++ b/crates/tui/src/settings.rs @@ -13,8 +13,6 @@ use crate::config::{expand_path, normalize_model_name}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(default)] pub struct Settings { - /// Color theme: "default", "dark", "light" - pub theme: String, /// Auto-compact conversations when they get long pub auto_compact: bool, /// Reduce status noise and collapse details more aggressively @@ -46,7 +44,6 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Self { - theme: "whale".to_string(), auto_compact: true, calm_mode: false, low_motion: false, @@ -130,14 +127,6 @@ impl Settings { /// Set a single setting by key pub fn set(&mut self, key: &str, value: &str) -> Result<()> { match key { - "theme" => { - if !["default", "dark", "light", "whale"].contains(&value) { - anyhow::bail!( - "Failed to update setting: invalid theme '{value}'. Expected: default, dark, light, whale." - ); - } - self.theme = value.to_string(); - } "auto_compact" | "compact" => { self.auto_compact = parse_bool(value)?; } @@ -252,7 +241,6 @@ impl Settings { let mut lines = Vec::new(); lines.push("Settings:".to_string()); lines.push("─────────────────────────────".to_string()); - lines.push(format!(" theme: {}", self.theme)); lines.push(format!(" auto_compact: {}", self.auto_compact)); lines.push(format!(" calm_mode: {}", self.calm_mode)); lines.push(format!(" low_motion: {}", self.low_motion)); @@ -284,7 +272,6 @@ impl Settings { #[allow(dead_code)] pub fn available_settings() -> Vec<(&'static str, &'static str)> { vec![ - ("theme", "Color theme: default, dark, light"), ("auto_compact", "Auto-compact conversations: on/off"), ("calm_mode", "Calmer UI defaults: on/off"), ("low_motion", "Reduce animation and redraw churn: on/off"), diff --git a/crates/tui/src/tui/app.rs b/crates/tui/src/tui/app.rs index 0f718854..e869a4d6 100644 --- a/crates/tui/src/tui/app.rs +++ b/crates/tui/src/tui/app.rs @@ -661,7 +661,7 @@ impl App { let sidebar_width_percent = settings.sidebar_width_percent; let sidebar_focus = SidebarFocus::from_setting(&settings.sidebar_focus); let max_input_history = settings.max_input_history; - let ui_theme = palette::ui_theme(&settings.theme); + let ui_theme = palette::UI_THEME; let model = settings.default_model.clone().unwrap_or(model); let compact_threshold = compaction_threshold_for_model_and_effort(&model, config.reasoning_effort()); diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index d9ab959a..f64ea7a7 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -363,12 +363,6 @@ impl ConfigView { editable: true, scope: ConfigScope::Saved, }, - ConfigRow { - key: "theme".to_string(), - value: settings.theme.clone(), - editable: true, - scope: ConfigScope::Saved, - }, ConfigRow { key: "sidebar_width".to_string(), value: settings.sidebar_width_percent.to_string(), @@ -597,7 +591,6 @@ fn config_hint_for_key(key: &str) -> &'static str { | "composer_border" => "on/off, true/false, yes/no, 1/0", "composer_density" | "transcript_spacing" => "compact | comfortable | spacious", "default_mode" => "agent | plan | yolo", - "theme" => "default | dark | light | whale", "sidebar_width" => "10..=50", "sidebar_focus" => "auto | plan | todos | tasks | agents", "max_history" => "integer (0 allowed)", diff --git a/npm/deepseek-tui/package.json b/npm/deepseek-tui/package.json index fef7c2d8..0db5f605 100644 --- a/npm/deepseek-tui/package.json +++ b/npm/deepseek-tui/package.json @@ -1,7 +1,7 @@ { "name": "deepseek-tui", - "version": "0.6.0", - "deepseekBinaryVersion": "0.6.0", + "version": "0.6.1", + "deepseekBinaryVersion": "0.6.1", "description": "Install and run deepseek and deepseek-tui binaries from GitHub release artifacts.", "author": "Hmbown", "license": "MIT",