From 903e4537f4a5e915b01a75e0e189b256000c73d5 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sat, 23 May 2026 11:48:43 -0500 Subject: [PATCH] refactor(strings): rebrand user-facing strings to codewhale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename brand-bearing string literals across the TUI source and the system-prompt templates that ship inside the binary. The DeepSeek provider integration is again left intact: the `ApiProvider::Deepseek` enum variant, the `"deepseek"` provider name string returned by `ApiProvider`-to-string mappings, model IDs, the `~/.deepseek/` config directory and `DEEPSEEK_CONFIG_PATH` env var, the OS keyring key `"deepseek"`, the Ollama `deepseek-coder*` model defaults, the China preset alias `deepseek-china`, and the various provider list error messages all keep the legacy spelling. Touchpoints: - `crates/tui/src/prompts/*.md` and `*.txt`: brand language flipped to `codewhale`; the internal ``, ``, ``, `` XML-ish event tags rename in lockstep to `` so the model-facing format stays consistent. - `crates/tui/src/tools/subagent/mod.rs`: emits the new event tag. - `crates/tui/src/core/tool_parser.rs`: parses the new event tag. - `crates/tui/src/tools/subagent/tests.rs`, `crates/tui/tests/protocol_recovery.rs`, `crates/tui/src/prompts.rs`: test expectations updated to match the new tag and the new prompt text. - Status / display strings flipped to `codewhale`: `acp_server.rs`'s agent name + title, `config_ui.rs`'s config schema title, `share.rs`'s export title, `welcome.rs`'s onboarding banner, `commands/status.rs`, `core/engine*`, `tui/notifications.rs`, `tui/sidebar.rs`, `tui/widgets/header.rs`, `tui/widgets/mod.rs`, `tui/ui.rs`'s resume-hint, `main.rs`'s clap header and `Doctor` prose, `tui/ui/tests.rs` and other test assertions. - `crates/tui/src/logging.rs` test fixture: `deepseek_cli=debug` -> `codewhale_cli=debug` so the log-filter test references the renamed crate. - Tracing targets that were namespaced under the brand (`target: "deepseek::config"`) move to `target: "codewhale::config"`. - Test-fixture tempdir prefixes (`deepseek-tui-…` / `deepseek-…`) rename for consistency. Local gates green: `cargo check --workspace --all-targets --locked`, `cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings`, `cargo test --workspace --all-features --locked` (3226+ pass, 0 fail). Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/tui/src/acp_server.rs | 8 +- crates/tui/src/commands/config.rs | 16 +- crates/tui/src/commands/core.rs | 4 +- crates/tui/src/commands/share.rs | 12 +- crates/tui/src/commands/status.rs | 4 +- crates/tui/src/config.rs | 146 +++++++------- crates/tui/src/config_ui.rs | 14 +- crates/tui/src/core/engine.rs | 6 +- crates/tui/src/core/engine/streaming.rs | 4 +- crates/tui/src/core/engine/tests.rs | 6 +- crates/tui/src/core/engine/turn_loop.rs | 10 +- crates/tui/src/core/tool_parser.rs | 12 +- crates/tui/src/dependencies.rs | 2 +- crates/tui/src/localization.rs | 20 +- crates/tui/src/logging.rs | 2 +- crates/tui/src/main.rs | 186 +++++++++--------- crates/tui/src/mcp.rs | 4 +- crates/tui/src/prompts.rs | 14 +- crates/tui/src/prompts/agent.txt | 2 +- crates/tui/src/prompts/base.md | 10 +- crates/tui/src/prompts/base.txt | 2 +- crates/tui/src/tools/subagent/mod.rs | 18 +- crates/tui/src/tools/subagent/tests.rs | 26 +-- crates/tui/src/tui/notifications.rs | 22 +-- crates/tui/src/tui/onboarding/welcome.rs | 2 +- crates/tui/src/tui/sidebar.rs | 4 +- crates/tui/src/tui/ui.rs | 2 +- crates/tui/src/tui/ui/tests.rs | 16 +- crates/tui/src/tui/widgets/header.rs | 18 +- crates/tui/src/tui/widgets/mod.rs | 18 +- crates/tui/tests/protocol_recovery.rs | 4 +- .../tui/tests/support/qa_harness/harness.rs | 2 +- 32 files changed, 308 insertions(+), 308 deletions(-) diff --git a/crates/tui/src/acp_server.rs b/crates/tui/src/acp_server.rs index 1b2cbd38..72a110cf 100644 --- a/crates/tui/src/acp_server.rs +++ b/crates/tui/src/acp_server.rs @@ -143,7 +143,7 @@ impl AcpServer { .and_then(Value::as_str) .map(PathBuf::from) .unwrap_or_else(|| self.default_cwd.clone()); - let session_id = format!("deepseek-{}", uuid::Uuid::new_v4()); + let session_id = format!("codewhale-{}", uuid::Uuid::new_v4()); self.sessions.insert(session_id.clone(), AcpSession { cwd }); Ok(json!({ "sessionId": session_id })) } @@ -284,8 +284,8 @@ fn initialize_result(client_protocol_version: Option) -> Value { "sessionCapabilities": {} }, "agentInfo": { - "name": "deepseek", - "title": "DeepSeek TUI", + "name": "codewhale", + "title": "codewhale", "version": env!("CARGO_PKG_VERSION") }, "authMethods": [] @@ -423,7 +423,7 @@ mod tests { let result = initialize_result(Some(1)); assert_eq!(result["protocolVersion"], 1); - assert_eq!(result["agentInfo"]["name"], "deepseek"); + assert_eq!(result["agentInfo"]["name"], "codewhale"); assert_eq!(result["agentCapabilities"]["loadSession"], false); assert_eq!( result["agentCapabilities"]["promptCapabilities"]["embeddedContext"], diff --git a/crates/tui/src/commands/config.rs b/crates/tui/src/commands/config.rs index c84afec1..40ffe1dc 100644 --- a/crates/tui/src/commands/config.rs +++ b/crates/tui/src/commands/config.rs @@ -976,7 +976,7 @@ pub struct AutoRouteSelection { } pub const AUTO_MODEL_ROUTER_SYSTEM_PROMPT: &str = "\ -You are the DeepSeek TUI auto-routing classifier. Return only compact JSON: \ +You are the codewhale auto-routing classifier. Return only compact JSON: \ {\"model\":\"deepseek-v4-flash|deepseek-v4-pro\",\"thinking\":\"off|high|max\"}. \ Use deepseek-v4-flash for trivial, conversational, status, or single-step work. \ Use deepseek-v4-pro for coding, debugging, release work, multi-step tasks, high-risk decisions, \ @@ -1706,7 +1706,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-default-mode-test-{}-{}", + "codewhale-tui-default-mode-test-{}-{}", std::process::id(), nanos )); @@ -1731,7 +1731,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-cost-currency-test-{}-{}", + "codewhale-tui-cost-currency-test-{}-{}", std::process::id(), nanos )); @@ -1757,7 +1757,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-theme-command-test-{}-{}", + "codewhale-tui-theme-command-test-{}-{}", std::process::id(), nanos )); @@ -1780,7 +1780,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-theme-save-test-{}-{}", + "codewhale-tui-theme-save-test-{}-{}", std::process::id(), nanos )); @@ -1884,7 +1884,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-logout-test-{}-{}", + "codewhale-tui-logout-test-{}-{}", std::process::id(), nanos )); @@ -1933,7 +1933,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-statusline-persist-{}-{}", + "codewhale-statusline-persist-{}-{}", std::process::id(), nanos )); @@ -1964,7 +1964,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-statusline-preserve-{}-{}", + "codewhale-statusline-preserve-{}-{}", std::process::id(), nanos )); diff --git a/crates/tui/src/commands/core.rs b/crates/tui/src/commands/core.rs index 4820b1bd..9e8fd775 100644 --- a/crates/tui/src/commands/core.rs +++ b/crates/tui/src/commands/core.rs @@ -782,7 +782,7 @@ mod tests { let result = home_dashboard(&mut app); assert!(result.message.is_some()); let msg = result.message.unwrap(); - assert!(msg.contains("DeepSeek TUI Home Dashboard")); + assert!(msg.contains("codewhale Home Dashboard")); assert!(msg.contains("Model:")); assert!(msg.contains("Mode:")); assert!(msg.contains("Workspace:")); @@ -831,7 +831,7 @@ mod tests { !msg.lines() .any(|line| line.trim_start().starts_with("/set ")) ); - assert!(!msg.contains("/deepseek")); + assert!(!msg.contains("/codewhale")); } #[test] diff --git a/crates/tui/src/commands/share.rs b/crates/tui/src/commands/share.rs index 0ba38ca4..25c1db58 100644 --- a/crates/tui/src/commands/share.rs +++ b/crates/tui/src/commands/share.rs @@ -101,7 +101,7 @@ fn render_session_html(history_json: &str, model: &str, mode: &str) -> String { -DeepSeek TUI Session Export +codewhale Session Export -

DeepSeek TUI Session

+

codewhale Session

Model: {escaped_model} · Mode: {escaped_mode}
Exported: {timestamp}
{escaped_body}
"#, @@ -145,7 +145,7 @@ fn html_escape(s: &str) -> String { /// Write HTML to a secure temp file and keep it alive for upload. fn write_temp_html(html: &str) -> Result { let mut tmp = tempfile::Builder::new() - .prefix("deepseek-share-") + .prefix("codewhale-share-") .suffix(".html") .tempfile() .map_err(|e| format!("{e}"))?; @@ -164,7 +164,7 @@ async fn upload_gist(path: &Path) -> Result { "--filename", "session-export.html", "--desc", - "DeepSeek TUI Session Export", + "codewhale Session Export", ]) .output() .await @@ -194,7 +194,7 @@ mod tests { assert!(html.contains("deepseek-v4-pro")); assert!(html.contains("agent")); assert!(html.contains("[{}]")); - assert!(html.contains("DeepSeek TUI")); + assert!(html.contains("codewhale")); } #[test] diff --git a/crates/tui/src/commands/status.rs b/crates/tui/src/commands/status.rs index 55e84cdc..c721dec7 100644 --- a/crates/tui/src/commands/status.rs +++ b/crates/tui/src/commands/status.rs @@ -18,7 +18,7 @@ fn format_status(app: &App) -> String { let mut out = String::new(); let (context_used, context_max, context_percent) = context_usage(app); - let _ = writeln!(out, "DeepSeek TUI Status"); + let _ = writeln!(out, "codewhale Status"); let _ = writeln!(out, "==================="); let _ = writeln!(out); push_row(&mut out, "Version:", env!("CARGO_PKG_VERSION")); @@ -227,7 +227,7 @@ mod tests { let result = status(&mut app); let msg = result.message.expect("status message"); - assert!(msg.contains("DeepSeek TUI Status")); + assert!(msg.contains("codewhale Status")); assert!(msg.contains("Provider:")); assert!(msg.contains("Model:")); assert!(msg.contains("Directory:")); diff --git a/crates/tui/src/config.rs b/crates/tui/src/config.rs index 471534a9..663aae88 100644 --- a/crates/tui/src/config.rs +++ b/crates/tui/src/config.rs @@ -1,4 +1,4 @@ -//! Configuration loading and defaults for DeepSeek TUI. +//! Configuration loading and defaults for codewhale. use std::collections::HashMap; use std::fmt::Write; @@ -969,7 +969,7 @@ pub struct Config { #[serde(default)] pub hooks: Option, - /// Provider-specific credentials and defaults shared with the `deepseek` facade. + /// Provider-specific credentials and defaults shared with the `codewhale` facade. #[serde(default)] pub providers: Option, @@ -1024,7 +1024,7 @@ pub struct Config { #[serde(default)] pub subagents: Option, - /// Runtime API server tuning (`deepseek serve --http`). Currently only + /// Runtime API server tuning (`codewhale serve --http`). Currently only /// hosts the CORS allow-list extension (whalescale#255 / #561). When the /// table is absent, the daemon ships with localhost:3000 / localhost:1420 /// / tauri://localhost as the only allowed dev origins. @@ -1656,7 +1656,7 @@ impl Config { } // 1. Config file (provider-scoped slot). This intentionally wins - // over ambient env so `deepseek auth set` fixes stale shell exports. + // over ambient env so `codewhale auth set` fixes stale shell exports. if let Some(configured) = self .provider_config_for(provider) .and_then(|provider| provider.api_key.clone()) @@ -1683,7 +1683,7 @@ impl Config { \n\ 1. Get a key: https://platform.deepseek.com/api_keys\n\ 2. Save it (works in every folder, no OS prompts):\n\ - deepseek auth set --provider deepseek\n\ + codewhale auth set --provider deepseek\n\ \n\ Alternatives:\n\ • export DEEPSEEK_API_KEY= (current shell only;\n\ @@ -1692,33 +1692,33 @@ impl Config { • api_key = \"\" in ~/.deepseek/config.toml" ), ApiProvider::NvidiaNim => anyhow::bail!( - "NVIDIA NIM API key not found. Run 'deepseek auth set --provider nvidia-nim', \ + "NVIDIA NIM API key not found. Run 'codewhale auth set --provider nvidia-nim', \ set NVIDIA_API_KEY/NVIDIA_NIM_API_KEY, or save api_key in ~/.deepseek/config.toml \ with provider = \"nvidia-nim\"." ), ApiProvider::Openai => anyhow::bail!( - "OpenAI-compatible API key not found. Run 'deepseek auth set --provider openai', \ + "OpenAI-compatible API key not found. Run 'codewhale auth set --provider openai', \ set OPENAI_API_KEY, or add [providers.openai] api_key in ~/.deepseek/config.toml." ), ApiProvider::Atlascloud => anyhow::bail!( - "AtlasCloud API key not found. Run 'deepseek auth set --provider atlascloud', \ + "AtlasCloud API key not found. Run 'codewhale auth set --provider atlascloud', \ set ATLASCLOUD_API_KEY, or add [providers.atlascloud] api_key in ~/.deepseek/config.toml." ), ApiProvider::WanjieArk => anyhow::bail!( - "Wanjie Ark API key not found. Run 'deepseek auth set --provider wanjie-ark', \ + "Wanjie Ark API key not found. Run 'codewhale auth set --provider wanjie-ark', \ set WANJIE_ARK_API_KEY/WANJIE_API_KEY/WANJIE_MAAS_API_KEY, or add \ [providers.wanjie_ark] api_key in ~/.deepseek/config.toml." ), ApiProvider::Openrouter => anyhow::bail!( - "OpenRouter API key not found. Run 'deepseek auth set --provider openrouter', \ + "OpenRouter API key not found. Run 'codewhale auth set --provider openrouter', \ set OPENROUTER_API_KEY, or add [providers.openrouter] api_key in ~/.deepseek/config.toml." ), ApiProvider::Novita => anyhow::bail!( - "Novita API key not found. Run 'deepseek auth set --provider novita', \ + "Novita API key not found. Run 'codewhale auth set --provider novita', \ set NOVITA_API_KEY, or add [providers.novita] api_key in ~/.deepseek/config.toml." ), ApiProvider::Fireworks => anyhow::bail!( - "Fireworks AI API key not found. Run 'deepseek auth set --provider fireworks', \ + "Fireworks AI API key not found. Run 'codewhale auth set --provider fireworks', \ set FIREWORKS_API_KEY, or add [providers.fireworks] api_key in ~/.deepseek/config.toml." ), // Self-hosted deployments commonly run without auth on localhost. @@ -2120,7 +2120,7 @@ fn resolve_load_config_path(path: Option) -> Option { /// Create an inspectable config file on first interactive launch. /// -/// The file intentionally omits `api_key`; onboarding or `deepseek auth set` +/// The file intentionally omits `api_key`; onboarding or `codewhale auth set` /// writes that field after the user supplies a key. pub fn ensure_config_file_exists(path: Option) -> Result> { let config_path = path @@ -2133,9 +2133,9 @@ pub fn ensure_config_file_exists(path: Option) -> Result Result<()> { perms.set_mode(mode & !0o077); if let Err(err) = fs::set_permissions(parent, perms) { tracing::warn!( - target: "deepseek::config", + target: "codewhale::config", path = %parent.display(), error = %err, "could not tighten parent dir permissions; \ @@ -3166,7 +3166,7 @@ fn write_config_file_secure(path: &Path, content: &str) -> Result<()> { // system's native ACL model is doing the access control. if let Err(err) = file.set_permissions(fs::Permissions::from_mode(0o600)) { tracing::warn!( - target: "deepseek::config", + target: "codewhale::config", path = %path.display(), error = %err, "could not enforce 0o600 on config file; filesystem may \ @@ -3186,7 +3186,7 @@ fn write_config_file_secure(path: &Path, content: &str) -> Result<()> { /// the caller can show a confirmation message without leaking the key. #[derive(Debug, Clone, PartialEq, Eq)] pub enum SavedCredential { - /// Stored in **both** the OS keyring and the deepseek config file. + /// Stored in **both** the OS keyring and the codewhale config file. /// This is the default outcome on platforms with a working keyring /// backend: writing both layers defeats the /// `keyring → env → config-file` resolution-order shadow that @@ -3201,7 +3201,7 @@ pub enum SavedCredential { /// Absolute path to the config file that was also updated. path: PathBuf, }, - /// Stored in the deepseek config file only. Fallback when no + /// Stored in the codewhale config file only. Fallback when no /// keyring backend is reachable, or under `cfg(test)` so unit /// tests don't pollute the host keyring. ConfigFile(PathBuf), @@ -3324,7 +3324,7 @@ fn save_api_key_to_config_file(api_key: &str) -> Result { } else { // Create new minimal config format!( - r#"# DeepSeek TUI Configuration + r#"# codewhale Configuration # Get your API key from https://platform.deepseek.com # Or set DEEPSEEK_API_KEY environment variable @@ -4063,7 +4063,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-test-{}-{}", + "codewhale-tui-test-{}-{}", std::process::id(), nanos )); @@ -4099,7 +4099,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-first-run-config-{}-{}", + "codewhale-tui-first-run-config-{}-{}", std::process::id(), nanos )); @@ -4125,7 +4125,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-workspace-trust-{}-{}", + "codewhale-tui-workspace-trust-{}-{}", std::process::id(), nanos )); @@ -4161,7 +4161,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-existing-project-trust-{}-{}", + "codewhale-tui-existing-project-trust-{}-{}", std::process::id(), nanos )); @@ -4364,7 +4364,7 @@ mod tests { .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-clear-{}-{}", + "codewhale-tui-clear-{}-{}", std::process::id(), nanos )); @@ -4397,7 +4397,7 @@ api_key = "old-openrouter-key" ); assert!( !after.contains("old-provider-key"), - "provider-scoped deepseek key must be stripped: {after}" + "provider-scoped codewhale key must be stripped: {after}" ); assert!( !after.contains("old-openrouter-key"), @@ -4420,7 +4420,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-override-{}-{}", + "codewhale-tui-override-{}-{}", std::process::id(), nanos )); @@ -4446,7 +4446,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-config-over-env-{}-{}", + "codewhale-tui-config-over-env-{}-{}", std::process::id(), nanos )); @@ -4471,7 +4471,7 @@ api_key = "old-openrouter-key" fn active_provider_detects_env_only_api_key() -> Result<()> { let _lock = lock_test_env(); let temp_root = - env::temp_dir().join(format!("deepseek-tui-env-only-key-{}", std::process::id())); + env::temp_dir().join(format!("codewhale-tui-env-only-key-{}", std::process::id())); fs::create_dir_all(&temp_root)?; let _guard = EnvGuard::new(&temp_root); @@ -4501,7 +4501,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-sentinel-{}-{}", + "codewhale-tui-sentinel-{}-{}", std::process::id(), nanos )); @@ -4529,7 +4529,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-tilde-test-{}-{}", + "codewhale-tui-tilde-test-{}-{}", std::process::id(), nanos )); @@ -4558,7 +4558,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-load-tilde-test-{}-{}", + "codewhale-tui-load-tilde-test-{}-{}", std::process::id(), nanos )); @@ -4587,7 +4587,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-load-fallback-test-{}-{}", + "codewhale-tui-load-fallback-test-{}-{}", std::process::id(), nanos )); @@ -4646,7 +4646,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-api-key-test-{}-{}", + "codewhale-tui-api-key-test-{}-{}", std::process::id(), nanos )); @@ -4693,7 +4693,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-empty-key-{}-{}", + "codewhale-tui-empty-key-{}-{}", std::process::id(), nanos )); @@ -4726,7 +4726,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-env-key-not-config-{}-{}", + "codewhale-tui-env-key-not-config-{}-{}", std::process::id(), nanos )); @@ -4839,7 +4839,7 @@ api_key = "old-openrouter-key" #[test] fn normalize_model_name_rejects_invalid_or_non_deepseek_ids() { assert!(normalize_model_name("gpt-4o").is_none()); - assert!(normalize_model_name("deepseek v4").is_none()); + assert!(normalize_model_name("codewhale v4").is_none()); assert!(normalize_model_name("").is_none()); } @@ -4980,7 +4980,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-model-env-test-{}-{}", + "codewhale-tui-model-env-test-{}-{}", std::process::id(), nanos )); @@ -5009,7 +5009,7 @@ api_key = "old-openrouter-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-http-headers-root-{}-{}", + "codewhale-tui-http-headers-root-{}-{}", std::process::id(), nanos )); @@ -5073,7 +5073,7 @@ http_headers = { "X-Model-Provider-Id" = "tongyi" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-http-headers-env-{}-{}", + "codewhale-tui-http-headers-env-{}-{}", std::process::id(), nanos )); @@ -5127,7 +5127,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-model-alias-test-{}-{}", + "codewhale-tui-nim-model-alias-test-{}-{}", std::process::id(), nanos )); @@ -5171,7 +5171,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-env-test-{}-{}", + "codewhale-tui-nim-env-test-{}-{}", std::process::id(), nanos )); @@ -5200,7 +5200,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-base-url-alias-test-{}-{}", + "codewhale-tui-nim-base-url-alias-test-{}-{}", std::process::id(), nanos )); @@ -5227,7 +5227,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-forwarded-base-url-test-{}-{}", + "codewhale-tui-nim-forwarded-base-url-test-{}-{}", std::process::id(), nanos )); @@ -5285,7 +5285,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-atlascloud-env-test-{}-{}", + "codewhale-tui-atlascloud-env-test-{}-{}", std::process::id(), nanos )); @@ -5329,7 +5329,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-wanjie-env-test-{}-{}", + "codewhale-tui-wanjie-env-test-{}-{}", std::process::id(), nanos )); @@ -5359,7 +5359,7 @@ http_headers = { "X-Model-Provider-Id" = "from-file" } .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-wanjie-table-{}-{}", + "codewhale-tui-wanjie-table-{}-{}", std::process::id(), nanos )); @@ -5398,7 +5398,7 @@ model = "account-model-id" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-openai-table-{}-{}", + "codewhale-tui-openai-table-{}-{}", std::process::id(), nanos )); @@ -5429,7 +5429,7 @@ model = "glm-5" Ok(()) } - // Regression for issue #1714: `deepseek --provider openai --model + // Regression for issue #1714: `codewhale --provider openai --model // MiniMax-M2.7` forwards the choice via DEEPSEEK_MODEL (never // OPENAI_MODEL) and uses the DEFAULT base_url. The explicit custom model // must pass through verbatim instead of silently becoming a @@ -5442,7 +5442,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-1714-passthrough-{}-{}", + "codewhale-tui-1714-passthrough-{}-{}", std::process::id(), nanos )); @@ -5495,7 +5495,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-openai-env-test-{}-{}", + "codewhale-tui-openai-env-test-{}-{}", std::process::id(), nanos )); @@ -5529,7 +5529,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-openai-forwarded-base-url-test-{}-{}", + "codewhale-tui-openai-forwarded-base-url-test-{}-{}", std::process::id(), nanos )); @@ -5563,7 +5563,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-or-defaults-{}-{}", + "codewhale-tui-or-defaults-{}-{}", std::process::id(), nanos )); @@ -5589,7 +5589,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-novita-defaults-{}-{}", + "codewhale-tui-novita-defaults-{}-{}", std::process::id(), nanos )); @@ -5615,7 +5615,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-fireworks-defaults-{}-{}", + "codewhale-tui-fireworks-defaults-{}-{}", std::process::id(), nanos )); @@ -5641,7 +5641,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-sglang-defaults-{}-{}", + "codewhale-tui-sglang-defaults-{}-{}", std::process::id(), nanos )); @@ -5669,7 +5669,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-ollama-defaults-{}-{}", + "codewhale-tui-ollama-defaults-{}-{}", std::process::id(), nanos )); @@ -5697,7 +5697,7 @@ model = "glm-5" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-ollama-model-test-{}-{}", + "codewhale-tui-ollama-model-test-{}-{}", std::process::id(), nanos )); @@ -5731,7 +5731,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-self-hosted-base-url-test-{}-{}", + "codewhale-tui-self-hosted-base-url-test-{}-{}", std::process::id(), nanos )); @@ -5766,7 +5766,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-ollama-env-test-{}-{}", + "codewhale-tui-ollama-env-test-{}-{}", std::process::id(), nanos )); @@ -5795,7 +5795,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-or-env-key-{}-{}", + "codewhale-tui-or-env-key-{}-{}", std::process::id(), nanos )); @@ -5822,7 +5822,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-novita-env-key-{}-{}", + "codewhale-tui-novita-env-key-{}-{}", std::process::id(), nanos )); @@ -5849,7 +5849,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-or-base-url-{}-{}", + "codewhale-tui-or-base-url-{}-{}", std::process::id(), nanos )); @@ -5876,7 +5876,7 @@ model = "qwen2.5-coder:7b" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-or-table-{}-{}", + "codewhale-tui-or-table-{}-{}", std::process::id(), nanos )); @@ -5910,7 +5910,7 @@ base_url = "https://or-table.example/v1" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-or-custom-model-{}-{}", + "codewhale-tui-or-custom-model-{}-{}", std::process::id(), nanos )); @@ -5946,7 +5946,7 @@ model = "DeepSeek-V4-Pro" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-novita-table-{}-{}", + "codewhale-tui-novita-table-{}-{}", std::process::id(), nanos )); @@ -5979,7 +5979,7 @@ api_key = "novita-table-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-has-key-{}-{}", + "codewhale-tui-has-key-{}-{}", std::process::id(), nanos )); @@ -6036,7 +6036,7 @@ api_key = "novita-table-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-has-key-cn-{}-{}", + "codewhale-tui-has-key-cn-{}-{}", std::process::id(), nanos )); @@ -6073,7 +6073,7 @@ api_key = "novita-table-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-save-key-or-{}-{}", + "codewhale-tui-save-key-or-{}-{}", std::process::id(), nanos )); @@ -6161,7 +6161,7 @@ api_key = "novita-table-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-save-key-cn-{}-{}", + "codewhale-tui-save-key-cn-{}-{}", std::process::id(), nanos )); @@ -6188,7 +6188,7 @@ api_key = "novita-table-key" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-provider-table-test-{}-{}", + "codewhale-tui-nim-provider-table-test-{}-{}", std::process::id(), nanos )); @@ -6227,7 +6227,7 @@ model = "deepseek-v4-pro" .unwrap() .as_nanos(); let temp_root = env::temp_dir().join(format!( - "deepseek-tui-nim-root-key-precedence-test-{}-{}", + "codewhale-tui-nim-root-key-precedence-test-{}-{}", std::process::id(), nanos )); @@ -6238,7 +6238,7 @@ model = "deepseek-v4-pro" ensure_parent_dir(&config_path)?; fs::write( &config_path, - r#"api_key = "deepseek-root-key" + r#"api_key = "codewhale-root-key" provider = "nvidia-nim" [providers.nvidia_nim] diff --git a/crates/tui/src/config_ui.rs b/crates/tui/src/config_ui.rs index a0915dd8..7e400496 100644 --- a/crates/tui/src/config_ui.rs +++ b/crates/tui/src/config_ui.rs @@ -283,7 +283,7 @@ pub enum StatusItemValue { pub fn parse_mode(arg: Option<&str>) -> Result { let raw = arg.unwrap_or("").trim(); // Bare `/config` opens the legacy native modal — it matches the rest - // of the deepseek-tui navy chrome out of the box. Power users can + // of the codewhale-tui navy chrome out of the box. Power users can // opt into the schemaui-driven editor with `/config tui`, or the // browser surface with `/config web` (web feature only). if raw.is_empty() || raw.eq_ignore_ascii_case("native") { @@ -348,7 +348,7 @@ pub fn build_document(app: &App, config: &Config) -> Result { pub fn build_schema() -> Value { let mut schema = serde_json::to_value(schema_for!(ConfigUiDocument)).expect("config ui schema"); - schema["title"] = Value::String("DeepSeek TUI Config".to_string()); + schema["title"] = Value::String("codewhale Config".to_string()); schema["description"] = Value::String("Edit runtime and persisted TUI configuration.".to_string()); schema @@ -359,7 +359,7 @@ pub fn run_tui_editor(app: &App, config: &Config) -> Result { let document = build_document(app, config)?; let value = SchemaUI::new(serde_json::to_value(document.clone())?) .with_schema(build_schema()) - .with_title("DeepSeek TUI Config") + .with_title("codewhale Config") .with_description("Edit persisted settings and live runtime knobs.") .run(FrontendOptions::Tui( UiOptions::default() @@ -377,7 +377,7 @@ pub async fn start_web_editor(app: &App, config: &Config) -> Result, /// Receiver paired with `tx_subagent_completion`. Drained at the - /// turn-loop's empty-tool_uses branch to surface `` + /// turn-loop's empty-tool_uses branch to surface `` /// sentinels into the parent's transcript before deciding to end the turn. pub(super) rx_subagent_completion: mpsc::UnboundedReceiver, cancel_token: CancellationToken, @@ -378,8 +378,8 @@ impl Engine { Some(format!( "The rejected key came from {env_var}; no saved config key is present.\n\ - Run `deepseek auth status` to inspect credential sources, then \ - `deepseek auth set --provider {provider}` to save a valid key in ~/.deepseek/config.toml, \ + Run `codewhale auth status` to inspect credential sources, then \ + `codewhale auth set --provider {provider}` to save a valid key in ~/.deepseek/config.toml, \ or remove the stale export and open a fresh shell.", provider = provider.as_str() )) diff --git a/crates/tui/src/core/engine/streaming.rs b/crates/tui/src/core/engine/streaming.rs index 3c2a654c..0da4d5ae 100644 --- a/crates/tui/src/core/engine/streaming.rs +++ b/crates/tui/src/core/engine/streaming.rs @@ -88,7 +88,7 @@ pub(super) fn should_transparently_retry_stream( pub(crate) const TOOL_CALL_START_MARKERS: [&str; 5] = [ "[TOOL_CALL]", - "", @@ -96,7 +96,7 @@ pub(crate) const TOOL_CALL_START_MARKERS: [&str; 5] = [ pub(crate) const TOOL_CALL_END_MARKERS: [&str; 5] = [ "[/TOOL_CALL]", - "
", + "", "", "", "", diff --git a/crates/tui/src/core/engine/tests.rs b/crates/tui/src/core/engine/tests.rs index 78d50435..ca3c410a 100644 --- a/crates/tui/src/core/engine/tests.rs +++ b/crates/tui/src/core/engine/tests.rs @@ -94,8 +94,8 @@ fn env_only_auth_error_gets_recovery_hint() { assert!(message.contains("DEEPSEEK_API_KEY")); assert!(message.contains("no saved config key is present")); - assert!(message.contains("deepseek auth status")); - assert!(message.contains("deepseek auth set --provider deepseek")); + assert!(message.contains("codewhale auth status")); + assert!(message.contains("codewhale auth set --provider deepseek")); } #[test] @@ -1874,7 +1874,7 @@ fn filter_tool_call_delta_strips_bracket_marker() { fn filter_tool_call_delta_strips_deepseek_xml_marker() { let mut in_block = false; let visible = filter_tool_call_delta( - "before payload after", + "before payload after", &mut in_block, ); assert!(!in_block); diff --git a/crates/tui/src/core/engine/turn_loop.rs b/crates/tui/src/core/engine/turn_loop.rs index 1cfe8f09..e69104e3 100644 --- a/crates/tui/src/core/engine/turn_loop.rs +++ b/crates/tui/src/core/engine/turn_loop.rs @@ -924,7 +924,7 @@ impl Engine { // streaming with no tool calls — but if it has direct children // still running (or completions queued from children that // finished while we were inferring), surface their - // `` sentinels into the transcript and + // `` sentinels into the transcript and // resume instead of ending the turn. This fulfils the contract // already documented in `prompts/base.md`: the parent is // promised it'll see the sentinel when a child finishes. @@ -2010,13 +2010,13 @@ fn subagent_completion_runtime_message(payload: &str) -> Message { role: "system".to_string(), content: vec![ContentBlock::Text { text: format!( - "\n\ + "\n\ This is an internal runtime event, not user input. Use the sub-agent completion \ data below to continue coordinating the current task. Do not tell the user they \ pasted sentinels, do not explain the sentinel protocol, and do not quote the raw \ XML unless the user explicitly asks to debug sub-agent internals.\n\n\ {payload}\n\ -" +" ), cache_control: None, }], @@ -2109,7 +2109,7 @@ mod tests { #[test] fn subagent_completion_handoff_is_internal_system_message() { let message = subagent_completion_runtime_message( - "Build passed\n{\"agent_id\":\"agent_a\"}", + "Build passed\n{\"agent_id\":\"agent_a\"}", ); assert_eq!(message.role, "system"); @@ -2119,7 +2119,7 @@ mod tests { }; assert!(text.contains("internal runtime event, not user input")); assert!(text.contains("Do not tell the user they pasted sentinels")); - assert!(text.contains("")); + assert!(text.contains("")); assert!(text.contains("Build passed")); } diff --git a/crates/tui/src/core/tool_parser.rs b/crates/tui/src/core/tool_parser.rs index 08a73848..d0bdc2da 100644 --- a/crates/tui/src/core/tool_parser.rs +++ b/crates/tui/src/core/tool_parser.rs @@ -12,11 +12,11 @@ //! //! Or XML-style format: //! ```text -//! +//! //! //! value //! -//! +//! //! ``` //! //! This module parses these text patterns into structured tool calls. @@ -60,8 +60,8 @@ fn get_tool_call_regex() -> &'static Regex { fn get_xml_tool_call_regex() -> &'static Regex { XML_TOOL_CALL_REGEX.get_or_init(|| { - // Match ... or similar XML patterns - Regex::new(r"(?s)<(?:deepseek:)?tool_call[^>]*>\s*(.*?)\s*") + // Match ... or similar XML patterns + Regex::new(r"(?s)<(?:codewhale:)?tool_call[^>]*>\s*(.*?)\s*") .expect("XML tool_call regex pattern is valid") }) } @@ -108,7 +108,7 @@ pub fn parse_tool_calls(text: &str) -> ParseResult { clean_text = clean_text.replace(full_match, ""); } - // Parse XML-style or format + // Parse XML-style or format let xml_regex = get_xml_tool_call_regex(); for cap in xml_regex.captures_iter(text) { let (Some(full_match), Some(inner)) = (cap.get(0), cap.get(1)) else { @@ -443,7 +443,7 @@ fn extract_json_object(text: &str) -> Option { /// Check if text contains tool call markers (either format). pub fn has_tool_call_markers(text: &str) -> bool { text.contains("[TOOL_CALL]") - || text.contains(" &'static str { MessageId::CmdNoteDescription => "Add, list, edit, or remove workspace notes", MessageId::CmdThemeDescription => "Switch theme or open the theme picker", MessageId::CmdProviderDescription => { - "Switch or view the active LLM backend (deepseek | nvidia-nim | ollama)" + "Switch or view the active LLM backend (codewhale | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "View or edit queued messages", MessageId::CmdRecallDescription => "Search prior cycle archives (BM25 over message text)", @@ -1131,7 +1131,7 @@ fn english(id: MessageId) -> &'static str { MessageId::LinksTip => "Tip: API keys are available in the dashboard console.", MessageId::SubagentsFetching => "Fetching sub-agent status...", MessageId::HelpUnknownCommand => "Unknown command: {topic}", - MessageId::HomeDashboardTitle => "DeepSeek TUI Home Dashboard", + MessageId::HomeDashboardTitle => "codewhale Home Dashboard", MessageId::HomeModel => "Model:", MessageId::HomeMode => "Mode:", MessageId::HomeWorkspace => "Workspace:", @@ -1336,7 +1336,7 @@ fn japanese(id: MessageId) -> Option<&'static str> { "テーマを切り替え(ダーク/ライト/グレースケール/システム)" } MessageId::CmdProviderDescription => { - "現在の LLM バックエンドを切り替え・確認(deepseek | nvidia-nim | ollama)" + "現在の LLM バックエンドを切り替え・確認(codewhale | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "キューされたメッセージを確認・編集", MessageId::CmdRecallDescription => { @@ -1516,7 +1516,7 @@ fn japanese(id: MessageId) -> Option<&'static str> { MessageId::LinksTip => "ヒント: API キーはダッシュボードコンソールで取得できます。", MessageId::SubagentsFetching => "サブエージェントの状態を取得中...", MessageId::HelpUnknownCommand => "不明なコマンド: {topic}", - MessageId::HomeDashboardTitle => "DeepSeek TUI ホームダッシュボード", + MessageId::HomeDashboardTitle => "codewhale ホームダッシュボード", MessageId::HomeModel => "モデル:", MessageId::HomeMode => "モード:", MessageId::HomeWorkspace => "ワークスペース:", @@ -1679,7 +1679,7 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> { MessageId::CmdNoteDescription => "添加、列出、编辑或删除工作区笔记", MessageId::CmdThemeDescription => "切换主题:深色、浅色、灰度或系统", MessageId::CmdProviderDescription => { - "切换或查看当前 LLM 后端(deepseek | nvidia-nim | ollama)" + "切换或查看当前 LLM 后端(codewhale | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "查看或编辑已排队的消息", MessageId::CmdRecallDescription => "搜索此前的循环归档(基于消息文本的 BM25 检索)", @@ -1833,7 +1833,7 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> { MessageId::LinksTip => "提示:API 密钥可在控制台中获取。", MessageId::SubagentsFetching => "正在获取子代理状态...", MessageId::HelpUnknownCommand => "未知命令:{topic}", - MessageId::HomeDashboardTitle => "DeepSeek TUI 主面板", + MessageId::HomeDashboardTitle => "codewhale 主面板", MessageId::HomeModel => "模型:", MessageId::HomeMode => "模式:", MessageId::HomeWorkspace => "工作区:", @@ -2006,7 +2006,7 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> { MessageId::CmdNoteDescription => "Adicionar, listar, editar ou remover notas do workspace", MessageId::CmdThemeDescription => "Alternar tema: escuro, claro, tons de cinza ou sistema", MessageId::CmdProviderDescription => { - "Trocar ou exibir o backend LLM ativo (deepseek | nvidia-nim | ollama)" + "Trocar ou exibir o backend LLM ativo (codewhale | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "Ver ou editar mensagens enfileiradas", MessageId::CmdRecallDescription => { @@ -2198,7 +2198,7 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> { MessageId::LinksTip => "Dica: chaves de API estão disponíveis no console do painel.", MessageId::SubagentsFetching => "Buscando status dos sub-agentes...", MessageId::HelpUnknownCommand => "Comando desconhecido: {topic}", - MessageId::HomeDashboardTitle => "Painel Inicial do DeepSeek TUI", + MessageId::HomeDashboardTitle => "Painel Inicial do codewhale", MessageId::HomeModel => "Modelo:", MessageId::HomeMode => "Modo:", MessageId::HomeWorkspace => "Workspace:", @@ -2393,7 +2393,7 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> { MessageId::CmdNoteDescription => "Agregar nota al archivo persistente (.deepseek/notes.md)", MessageId::CmdThemeDescription => "Alternar entre tema claro y oscuro", MessageId::CmdProviderDescription => { - "Cambiar o mostrar el backend LLM activo (deepseek | nvidia-nim | ollama)" + "Cambiar o mostrar el backend LLM activo (codewhale | nvidia-nim | ollama)" } MessageId::CmdQueueDescription => "Ver o editar mensajes en cola", MessageId::CmdRecallDescription => { @@ -2591,7 +2591,7 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> { MessageId::LinksTip => "Tip: las claves de API están disponibles en la consola del panel.", MessageId::SubagentsFetching => "Obteniendo estado de los sub-agentes...", MessageId::HelpUnknownCommand => "Comando desconocido: {topic}", - MessageId::HomeDashboardTitle => "Panel Inicial de DeepSeek TUI", + MessageId::HomeDashboardTitle => "Panel Inicial de codewhale", MessageId::HomeModel => "Modelo:", MessageId::HomeMode => "Modo:", MessageId::HomeWorkspace => "Workspace:", diff --git a/crates/tui/src/logging.rs b/crates/tui/src/logging.rs index 15dd52c0..1dd8e330 100644 --- a/crates/tui/src/logging.rs +++ b/crates/tui/src/logging.rs @@ -67,7 +67,7 @@ mod tests { #[test] fn log_value_parser_accepts_common_rust_log_directives() { assert!(log_value_enables_verbose("debug")); - assert!(log_value_enables_verbose("deepseek_cli=debug")); + assert!(log_value_enables_verbose("codewhale_cli=debug")); assert!(log_value_enables_verbose( "warn,codewhale_tui::client=trace" )); diff --git a/crates/tui/src/main.rs b/crates/tui/src/main.rs index 75bfbda9..11beeb87 100644 --- a/crates/tui/src/main.rs +++ b/crates/tui/src/main.rs @@ -101,12 +101,12 @@ fn configure_windows_console_utf8() {} #[derive(Parser, Debug)] #[command( - name = "deepseek-tui", - bin_name = "deepseek-tui", + name = "codewhale-tui", + bin_name = "codewhale-tui", author, version = env!("DEEPSEEK_BUILD_VERSION"), - about = "DeepSeek TUI/CLI for DeepSeek models", - long_about = "Terminal-native TUI and CLI for DeepSeek models.\n\nRun 'deepseek' to start.\n\nNot affiliated with DeepSeek Inc." + about = "codewhale/CLI for DeepSeek models", + long_about = "Terminal-native TUI and CLI for DeepSeek models.\n\nRun 'codewhale' to start.\n\nNot affiliated with DeepSeek Inc." )] struct Cli { /// Subcommand to run @@ -372,7 +372,7 @@ fn resolve_exec_resume_session_id(args: &ExecArgs, workspace: &Path) -> Result ...`.", + "No saved sessions found for workspace {}. Use `codewhale sessions` to list sessions, or pass `codewhale exec --resume ...`.", workspace.display() ) }, @@ -590,15 +590,15 @@ enum McpCommand { Validate, /// Register this DeepSeek binary as a local MCP stdio server. /// - /// This adds a config entry that runs `deepseek serve --mcp` (stdio protocol). - /// For the HTTP/SSE runtime API, use `deepseek serve --http` directly instead. + /// This adds a config entry that runs `codewhale serve --mcp` (stdio protocol). + /// For the HTTP/SSE runtime API, use `codewhale serve --http` directly instead. #[command( name = "add-self", - long_about = "Register this DeepSeek binary as a local MCP stdio server.\n\nAdds a config entry to ~/.deepseek/mcp.json that launches `deepseek serve --mcp`\nvia the stdio transport. Other DeepSeek sessions (or any MCP client) can then\ndiscover and call tools exposed by this server.\n\nUse `deepseek serve --http` instead if you need the HTTP/SSE runtime API." + long_about = "Register this DeepSeek binary as a local MCP stdio server.\n\nAdds a config entry to ~/.deepseek/mcp.json that launches `codewhale serve --mcp`\nvia the stdio transport. Other DeepSeek sessions (or any MCP client) can then\ndiscover and call tools exposed by this server.\n\nUse `codewhale serve --http` instead if you need the HTTP/SSE runtime API." )] AddSelf { - /// Server name in mcp.json (default: "deepseek") - #[arg(long, default_value = "deepseek")] + /// Server name in mcp.json (default: "codewhale") + #[arg(long, default_value = "codewhale")] name: String, /// Workspace directory for the MCP server #[arg(long)] @@ -894,7 +894,7 @@ async fn main() -> Result<()> { return run_one_shot(&config, &model, &prompt).await; } - // Handle session resume. Plain `deepseek` starts fresh: interrupted + // Handle session resume. Plain `codewhale` starts fresh: interrupted // snapshots are preserved for explicit resume, but never auto-attached. let resume_session_id = if cli.continue_session { let workspace = resolve_workspace(&cli); @@ -1087,7 +1087,7 @@ fn init_skills_dir(skills_dir: &Path, force: bool) -> Result<(PathBuf, WriteStat fn tools_readme_template() -> &'static str { "# Local tools\n\n\ Drop self-describing scripts here so they can be discovered by\n\ - `deepseek-tui setup --status` and surfaced in `deepseek-tui doctor`.\n\n\ + `codewhale-tui setup --status` and surfaced in `codewhale-tui doctor`.\n\n\ Each script should start with a frontmatter-style header so the\n\ description is visible without executing the file:\n\n\ ```\n\ @@ -1105,7 +1105,7 @@ fn tools_example_script() -> &'static str { # name: example\n\ # description: Print a confirmation that local tool discovery works\n\ # usage: example [name]\n\ - printf 'deepseek-tui local tool ok: %s\\n' \"${1:-world}\"\n" + printf 'codewhale-tui local tool ok: %s\\n' \"${1:-world}\"\n" } fn init_tools_dir(tools_dir: &Path, force: bool) -> Result<(PathBuf, WriteStatus, WriteStatus)> { @@ -1166,7 +1166,7 @@ fn init_plugins_dir( Ok((readme_path, example_path, readme_status, example_status)) } -/// Resolve the user-supplied CORS origins for `deepseek serve --http`. +/// Resolve the user-supplied CORS origins for `codewhale serve --http`. /// /// Sources, in priority order (later sources extend earlier ones): /// 1. `--cors-origin URL` flags (repeatable) @@ -1291,7 +1291,9 @@ fn run_setup(config: &Config, workspace: &Path, args: SetupArgs) -> Result<()> { println!(" · MCP config already exists at {}", mcp_path.display()); } } - println!(" Next: edit the file, then run `deepseek mcp list` or `deepseek mcp tools`."); + println!( + " Next: edit the file, then run `codewhale mcp list` or `codewhale mcp tools`." + ); } if run_skills { @@ -1463,45 +1465,45 @@ fn run_setup_status(config: &Config, workspace: &Path) -> Result<()> { let (env_var, login_hint) = match config.api_provider() { crate::config::ApiProvider::NvidiaNim => ( "NVIDIA_API_KEY", - "deepseek auth set --provider nvidia-nim --api-key \"...\"", + "codewhale auth set --provider nvidia-nim --api-key \"...\"", ), crate::config::ApiProvider::Openai => ( "OPENAI_API_KEY", - "deepseek auth set --provider openai --api-key \"...\"", + "codewhale auth set --provider openai --api-key \"...\"", ), crate::config::ApiProvider::Atlascloud => ( "ATLASCLOUD_API_KEY", - "deepseek auth set --provider atlascloud --api-key \"...\"", + "codewhale auth set --provider atlascloud --api-key \"...\"", ), crate::config::ApiProvider::WanjieArk => ( "WANJIE_ARK_API_KEY", - "deepseek auth set --provider wanjie-ark --api-key \"...\"", + "codewhale auth set --provider wanjie-ark --api-key \"...\"", ), crate::config::ApiProvider::Openrouter => ( "OPENROUTER_API_KEY", - "deepseek auth set --provider openrouter --api-key \"...\"", + "codewhale auth set --provider openrouter --api-key \"...\"", ), crate::config::ApiProvider::Novita => ( "NOVITA_API_KEY", - "deepseek auth set --provider novita --api-key \"...\"", + "codewhale auth set --provider novita --api-key \"...\"", ), crate::config::ApiProvider::Fireworks => ( "FIREWORKS_API_KEY", - "deepseek auth set --provider fireworks --api-key \"...\"", + "codewhale auth set --provider fireworks --api-key \"...\"", ), crate::config::ApiProvider::Sglang => ( "SGLANG_API_KEY", - "deepseek auth set --provider sglang --api-key \"...\"", + "codewhale auth set --provider sglang --api-key \"...\"", ), crate::config::ApiProvider::Vllm => ( "VLLM_API_KEY", - "deepseek auth set --provider vllm --api-key \"...\"", + "codewhale auth set --provider vllm --api-key \"...\"", ), crate::config::ApiProvider::Ollama => { - ("OLLAMA_API_KEY", "deepseek auth set --provider ollama") + ("OLLAMA_API_KEY", "codewhale auth set --provider ollama") } crate::config::ApiProvider::Deepseek | crate::config::ApiProvider::DeepseekCN => { - ("DEEPSEEK_API_KEY", "deepseek auth set --provider deepseek") + ("DEEPSEEK_API_KEY", "codewhale auth set --provider deepseek") } }; println!( @@ -1596,7 +1598,7 @@ fn run_setup_status(config: &Config, workspace: &Path) -> Result<()> { println!(" {} {}", "·".dimmed(), dotenv_status_line(workspace)); println!(); - println!("Run `deepseek doctor --json` for a machine-readable check."); + println!("Run `codewhale doctor --json` for a machine-readable check."); Ok(()) } @@ -1664,16 +1666,14 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt println!( "{}", - "DeepSeek TUI Doctor" - .truecolor(blue_r, blue_g, blue_b) - .bold() + "codewhale Doctor".truecolor(blue_r, blue_g, blue_b).bold() ); println!("{}", "==================".truecolor(sky_r, sky_g, sky_b)); println!(); // Version info println!("{}", "Version Information:".bold()); - println!(" deepseek-tui: {}", env!("DEEPSEEK_BUILD_VERSION")); + println!(" codewhale-tui: {}", env!("DEEPSEEK_BUILD_VERSION")); println!(" rust: {}", rustc_version()); println!(); @@ -1836,7 +1836,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt "✗".truecolor(red_r, red_g, red_b) ); println!( - " Run 'deepseek auth set --provider ' to save a key to ~/.deepseek/config.toml." + " Run 'codewhale auth set --provider ' to save a key to ~/.deepseek/config.toml." ); false }; @@ -1888,21 +1888,21 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt ); if error_msg.contains("401") || error_msg.contains("Unauthorized") { println!( - " Invalid API key. Check `deepseek auth status`, DEEPSEEK_API_KEY, or config.toml" + " Invalid API key. Check `codewhale auth status`, DEEPSEEK_API_KEY, or config.toml" ); if matches!(api_key_source, ApiKeySource::Keyring) { println!( " The rejected key came from the OS keyring via the dispatcher." ); println!( - " Run `deepseek auth status` to inspect config/keyring/env sources." + " Run `codewhale auth status` to inspect config/keyring/env sources." ); } else if matches!(api_key_source, ApiKeySource::Env) { println!( " The rejected key came from DEEPSEEK_API_KEY; no saved config key is present." ); println!( - " Run `deepseek auth set --provider deepseek` to save a config key that overrides stale env." + " Run `codewhale auth set --provider deepseek` to save a config key that overrides stale env." ); } } else if error_msg.contains("403") || error_msg.contains("Forbidden") { @@ -2004,7 +2004,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt "·".dimmed(), crate::utils::display_path(&mcp_config_path) ); - println!(" Run `deepseek mcp init` or `deepseek setup --mcp`."); + println!(" Run `codewhale mcp init` or `codewhale setup --mcp`."); } // Skills configuration @@ -2134,7 +2134,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt .is_some_and(|dir| dir.exists()) && !global_skills_dir.exists() { - println!(" Run `deepseek setup --skills` (or add --local for ./skills)."); + println!(" Run `codewhale setup --skills` (or add --local for ./skills)."); } // Tools directory @@ -2155,7 +2155,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt "·".dimmed(), crate::utils::display_path(&tools_dir) ); - println!(" Run `deepseek setup --tools` to scaffold a starter dir."); + println!(" Run `codewhale setup --tools` to scaffold a starter dir."); } // Plugins directory @@ -2176,7 +2176,7 @@ async fn run_doctor(config: &Config, workspace: &Path, config_path_override: Opt "·".dimmed(), crate::utils::display_path(&plugins_dir) ); - println!(" Run `deepseek setup --plugins` to scaffold a starter dir."); + println!(" Run `codewhale setup --plugins` to scaffold a starter dir."); } // Storage surfaces (#422 / #440 / #500) @@ -2707,7 +2707,7 @@ fn run_doctor_json( }, "api_connectivity": { "checked": false, - "note": "Skipped in --json mode; run `deepseek doctor` for a live check.", + "note": "Skipped in --json mode; run `codewhale doctor` for a live check.", }, "capability": provider_capability_report(config), }); @@ -2844,7 +2844,7 @@ fn doctor_timeout_recovery_lines(config: &Config) -> Vec { && !target.base_url.contains("api.deepseeki.com") => { lines.push( - "If this is a custom DeepSeek-compatible endpoint, set its HTTPS base URL in ~/.deepseek/config.toml and rerun `deepseek doctor`." + "If this is a custom DeepSeek-compatible endpoint, set its HTTPS base URL in ~/.deepseek/config.toml and rerun `codewhale doctor`." .to_string(), ); } @@ -2863,7 +2863,7 @@ fn doctor_timeout_recovery_lines(config: &Config) -> Vec { } lines.push( - "Run `deepseek doctor --json` and include `base_url`, `default_text_model`, and `api_connectivity` when filing an issue." + "Run `codewhale doctor --json` and include `base_url`, `default_text_model`, and `api_connectivity` when filing an issue." .to_string(), ); lines @@ -2987,7 +2987,7 @@ fn list_sessions(limit: usize, search: Option) -> Result<()> { println!("{}", "No sessions found.".truecolor(sky_r, sky_g, sky_b)); println!( "Start a new session with: {}", - "deepseek".truecolor(blue_r, blue_g, blue_b) + "codewhale".truecolor(blue_r, blue_g, blue_b) ); return Ok(()); } @@ -3020,12 +3020,12 @@ fn list_sessions(limit: usize, search: Option) -> Result<()> { println!(); println!( "Resume with: {} {}", - "deepseek --resume".truecolor(blue_r, blue_g, blue_b), + "codewhale --resume".truecolor(blue_r, blue_g, blue_b), "".dimmed() ); println!( "Continue latest in this workspace: {}", - "deepseek --continue".truecolor(blue_r, blue_g, blue_b) + "codewhale --continue".truecolor(blue_r, blue_g, blue_b) ); Ok(()) @@ -3062,7 +3062,7 @@ fn init_project() -> Result<()> { ); println!(); println!("Edit this file to customize how the AI agent works with your project."); - println!("The instructions will be loaded automatically when you run deepseek."); + println!("The instructions will be loaded automatically when you run codewhale."); } Err(e) => { println!( @@ -3126,7 +3126,7 @@ fn resolve_session_id(session_id: Option, last: bool, workspace: &Path) if last { return latest_session_id_for_workspace(workspace)?.ok_or_else(|| { anyhow!( - "No saved sessions found for workspace {}. Use `deepseek sessions` to list all sessions, or `deepseek resume ` to resume one explicitly.", + "No saved sessions found for workspace {}. Use `codewhale sessions` to list all sessions, or `codewhale resume ` to resume one explicitly.", workspace.display() ) }); @@ -3289,7 +3289,7 @@ Provide findings ordered by severity with file references, then open questions, Ok(()) } -/// `deepseek pr ` (#451) — fetch a GitHub PR via `gh`, format +/// `codewhale pr ` (#451) — fetch a GitHub PR via `gh`, format /// title + body + diff as the composer's first message, and launch /// the interactive TUI. Falls back gracefully if `gh` is missing. async fn run_pr( @@ -3303,7 +3303,7 @@ async fn run_pr( bail!( "`gh` CLI not found on PATH. Install GitHub CLI \ (https://cli.github.com) and authenticate (`gh auth login`) \ - so `deepseek pr ` can fetch PR metadata and the diff." + so `codewhale pr ` can fetch PR metadata and the diff." ); } @@ -3583,7 +3583,7 @@ async fn run_mcp_command(config: &Config, command: McpCommand) -> Result<()> { ); } } - println!("Edit the file, then run `deepseek mcp list` or `deepseek mcp tools`."); + println!("Edit the file, then run `codewhale mcp list` or `codewhale mcp tools`."); Ok(()) } McpCommand::List => { @@ -3763,7 +3763,7 @@ async fn run_mcp_command(config: &Config, command: McpCommand) -> Result<()> { let mut cfg = load_mcp_config(&config_path)?; if cfg.servers.contains_key(&name) { bail!( - "MCP server '{name}' already exists in {}. Use `deepseek mcp remove {name}` first, or choose a different --name.", + "MCP server '{name}' already exists in {}. Use `codewhale mcp remove {name}` first, or choose a different --name.", config_path.display() ); } @@ -3796,8 +3796,8 @@ async fn run_mcp_command(config: &Config, command: McpCommand) -> Result<()> { workspace.map_or(String::new(), |ws| format!(" --workspace {ws}")) ); println!(); - println!("Tip: Use `deepseek mcp validate` to test the connection."); - println!(" Use `deepseek serve --http` for the HTTP/SSE runtime API instead."); + println!("Tip: Use `codewhale mcp validate` to test the connection."); + println!(" Use `codewhale serve --http` for the HTTP/SSE runtime API instead."); Ok(()) } } @@ -4119,7 +4119,7 @@ fn checkpoint_age_label(age: std::time::Duration) -> String { /// **The checkpoint's workspace must also match the resolved launch workspace /// after canonicalisation.** If the workspace doesn't match, the checkpoint is /// persisted as a regular session (so the user can find it via -/// `deepseek sessions` / `deepseek resume `) and cleared, but not loaded. +/// `codewhale sessions` / `codewhale resume `) and cleared, but not loaded. fn recover_interrupted_checkpoint_for_resume(launch_workspace: &Path) -> Option { let manager = session_manager::SessionManager::default_location().ok()?; let (session, age) = load_recent_checkpoint(&manager)?; @@ -4133,7 +4133,7 @@ fn recover_interrupted_checkpoint_for_resume(launch_workspace: &Path) -> Option< session_manager::workspace_scope_matches(&session_workspace, launch_workspace); if !workspace_matches { - // Persist the checkpoint so the user can find it via `deepseek + // Persist the checkpoint so the user can find it via `codewhale // sessions`, then clear it so the next launch in this folder doesn't // re-trip the nag. Print a one-line notice pointing at the explicit // resume command — but DO NOT auto-load the session here. @@ -4141,7 +4141,7 @@ fn recover_interrupted_checkpoint_for_resume(launch_workspace: &Path) -> Option< let _ = manager.clear_checkpoint(); eprintln!( "Note: an interrupted session from another workspace ({}) is \ - available. Run `deepseek sessions` to list saved sessions. Starting \ + available. Run `codewhale sessions` to list saved sessions. Starting \ fresh in {}.", session_workspace.display(), launch_workspace.display(), @@ -4166,7 +4166,7 @@ fn recover_interrupted_checkpoint_for_resume(launch_workspace: &Path) -> Option< } /// Preserve an interrupted checkpoint on a normal fresh launch without -/// attaching it to the new TUI instance. This keeps "open another deepseek in +/// attaching it to the new TUI instance. This keeps "open another codewhale in /// the same folder" from re-entering the previous in-flight session while still /// leaving an explicit resume path. fn preserve_interrupted_checkpoint_for_explicit_resume(launch_workspace: &Path) { @@ -4185,12 +4185,12 @@ fn preserve_interrupted_checkpoint_for_explicit_resume(launch_workspace: &Path) if session_manager::workspace_scope_matches(&session_workspace, launch_workspace) { eprintln!( "Found an in-flight session snapshot ({age_str}). Starting a new \ - session. Run `deepseek --continue` to resume it." + session. Run `codewhale --continue` to resume it." ); } else { eprintln!( "Note: an interrupted session from another workspace ({}) is \ - available. Run `deepseek sessions` to list saved sessions. Starting \ + available. Run `codewhale sessions` to list saved sessions. Starting \ fresh in {}.", session_workspace.display(), launch_workspace.display(), @@ -5205,7 +5205,7 @@ mod doctor_endpoint_tests { assert!(text.contains("api.deepseek.com")); assert!(text.contains("custom DeepSeek-compatible endpoint")); assert!(!text.contains("provider = \"deepseek-cn\"")); - assert!(text.contains("deepseek doctor --json")); + assert!(text.contains("codewhale doctor --json")); } #[test] @@ -5234,19 +5234,19 @@ mod terminal_mode_tests { #[test] fn prompt_flag_accepts_split_prompt_words_for_windows_cmd_shims() { - let cli = parse_cli(&["deepseek", "-p", "hello", "world"]); + let cli = parse_cli(&["codewhale", "-p", "hello", "world"]); assert_eq!(cli.prompt, vec!["hello", "world"]); } #[test] fn companion_binary_reports_its_own_name() { - assert_eq!(Cli::command().get_name(), "deepseek-tui"); + assert_eq!(Cli::command().get_name(), "codewhale-tui"); } #[test] fn exec_accepts_split_prompt_words_for_windows_cmd_shims() { - let cli = parse_cli(&["deepseek", "exec", "hello", "world"]); + let cli = parse_cli(&["codewhale", "exec", "hello", "world"]); let Some(Commands::Exec(args)) = cli.command else { panic!("expected exec command"); }; @@ -5256,7 +5256,7 @@ mod terminal_mode_tests { #[test] fn exec_keeps_flags_before_split_prompt_words() { - let cli = parse_cli(&["deepseek", "exec", "--json", "hello", "world"]); + let cli = parse_cli(&["codewhale", "exec", "--json", "hello", "world"]); let Some(Commands::Exec(args)) = cli.command else { panic!("expected exec command"); }; @@ -5268,7 +5268,7 @@ mod terminal_mode_tests { #[test] fn exec_accepts_resume_session_flags_for_harnesses() { let cli = parse_cli(&[ - "deepseek", + "codewhale", "exec", "--resume", "abc123", @@ -5287,7 +5287,7 @@ mod terminal_mode_tests { #[test] fn exec_accepts_session_id_alias() { - let cli = parse_cli(&["deepseek", "exec", "--session-id", "abc123", "follow up"]); + let cli = parse_cli(&["codewhale", "exec", "--session-id", "abc123", "follow up"]); let Some(Commands::Exec(args)) = cli.command else { panic!("expected exec command"); }; @@ -5298,7 +5298,7 @@ mod terminal_mode_tests { #[test] fn exec_accepts_continue_for_latest_workspace_session() { - let cli = parse_cli(&["deepseek", "exec", "--continue", "follow up"]); + let cli = parse_cli(&["codewhale", "exec", "--continue", "follow up"]); let Some(Commands::Exec(args)) = cli.command else { panic!("expected exec command"); }; @@ -5309,7 +5309,7 @@ mod terminal_mode_tests { #[test] fn exec_json_conflicts_with_stream_json_output() { let err = Cli::try_parse_from([ - "deepseek", + "codewhale", "exec", "--json", "--output-format", @@ -5337,7 +5337,7 @@ mod terminal_mode_tests { #[test] fn alternate_screen_defaults_on_in_auto_mode() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(should_use_alt_screen(&cli, &config)); @@ -5345,7 +5345,7 @@ mod terminal_mode_tests { #[test] fn no_alt_screen_flag_is_accepted_but_keeps_alternate_screen() { - let cli = parse_cli(&["deepseek", "--no-alt-screen"]); + let cli = parse_cli(&["codewhale", "--no-alt-screen"]); let config = Config::default(); assert!(should_use_alt_screen(&cli, &config)); @@ -5353,7 +5353,7 @@ mod terminal_mode_tests { #[test] fn config_never_is_accepted_but_keeps_alternate_screen() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config { tui: Some(crate::config::TuiConfig { alternate_screen: Some("never".to_string()), @@ -5373,7 +5373,7 @@ mod terminal_mode_tests { #[test] #[cfg(not(windows))] fn mouse_capture_defaults_on_when_alternate_screen_is_active() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(should_use_mouse_capture_with( @@ -5387,7 +5387,7 @@ mod terminal_mode_tests { // Legacy conhost (no `WT_SESSION` and no `ConEmuPID`) keeps the // v0.8.x default-off behavior: mouse-mode reporting on legacy console // can leak SGR escapes into the composer. - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(!should_use_mouse_capture_with( @@ -5403,7 +5403,7 @@ mod terminal_mode_tests { #[test] #[cfg(windows)] fn mouse_capture_defaults_on_in_windows_terminal() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(should_use_mouse_capture_with( @@ -5421,7 +5421,7 @@ mod terminal_mode_tests { #[test] #[cfg(windows)] fn mouse_capture_defaults_on_in_conemu() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(should_use_mouse_capture_with( @@ -5436,7 +5436,7 @@ mod terminal_mode_tests { #[test] fn no_mouse_capture_flag_disables_mouse_capture() { - let cli = parse_cli(&["deepseek", "--no-mouse-capture"]); + let cli = parse_cli(&["codewhale", "--no-mouse-capture"]); let config = Config::default(); assert!(!should_use_mouse_capture_with( @@ -5446,7 +5446,7 @@ mod terminal_mode_tests { #[test] fn config_can_disable_default_mouse_capture() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config { tui: Some(crate::config::TuiConfig { alternate_screen: None, @@ -5467,7 +5467,7 @@ mod terminal_mode_tests { #[test] fn mouse_capture_flag_enables_mouse_capture() { - let cli = parse_cli(&["deepseek", "--mouse-capture"]); + let cli = parse_cli(&["codewhale", "--mouse-capture"]); let config = Config::default(); assert!(should_use_mouse_capture_with( @@ -5477,7 +5477,7 @@ mod terminal_mode_tests { #[test] fn config_can_enable_mouse_capture() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config { tui: Some(crate::config::TuiConfig { alternate_screen: None, @@ -5498,7 +5498,7 @@ mod terminal_mode_tests { #[test] fn mouse_capture_is_off_without_alternate_screen() { - let cli = parse_cli(&["deepseek", "--mouse-capture"]); + let cli = parse_cli(&["codewhale", "--mouse-capture"]); let config = Config::default(); assert!(!should_use_mouse_capture_with( @@ -5515,7 +5515,7 @@ mod terminal_mode_tests { #[test] fn mouse_capture_defaults_off_in_jetbrains_jediterm() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); assert!(!should_use_mouse_capture_with( @@ -5530,7 +5530,7 @@ mod terminal_mode_tests { #[test] fn jetbrains_default_off_is_case_insensitive() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config::default(); // JetBrains has occasionally varied the casing across releases; @@ -5547,7 +5547,7 @@ mod terminal_mode_tests { #[test] fn mouse_capture_flag_overrides_jetbrains_default() { - let cli = parse_cli(&["deepseek", "--mouse-capture"]); + let cli = parse_cli(&["codewhale", "--mouse-capture"]); let config = Config::default(); assert!(should_use_mouse_capture_with( @@ -5562,7 +5562,7 @@ mod terminal_mode_tests { #[test] fn config_mouse_capture_true_overrides_jetbrains_default() { - let cli = parse_cli(&["deepseek"]); + let cli = parse_cli(&["codewhale"]); let config = Config { tui: Some(crate::config::TuiConfig { alternate_screen: None, @@ -5782,24 +5782,24 @@ max_subagents = -3 fn project_overlay_skips_missing_config_file() { let tmp = tempdir().expect("tempdir"); let mut config = Config { - provider: Some("deepseek".to_string()), + provider: Some("codewhale".to_string()), ..Config::default() }; merge_project_config(&mut config, tmp.path()); // Untouched. - assert_eq!(config.provider.as_deref(), Some("deepseek")); + assert_eq!(config.provider.as_deref(), Some("codewhale")); } #[test] fn project_overlay_skips_malformed_toml() { let tmp = workspace_with_project_config("this is not valid TOML !!"); let mut config = Config { - provider: Some("deepseek".to_string()), + provider: Some("codewhale".to_string()), ..Config::default() }; merge_project_config(&mut config, tmp.path()); // Untouched on parse error — better to fall back to global than crash. - assert_eq!(config.provider.as_deref(), Some("deepseek")); + assert_eq!(config.provider.as_deref(), Some("codewhale")); } #[test] @@ -5811,13 +5811,13 @@ model = "" "#, ); let mut config = Config { - provider: Some("deepseek".to_string()), + provider: Some("codewhale".to_string()), default_text_model: Some("deepseek-v4-pro".to_string()), ..Config::default() }; merge_project_config(&mut config, tmp.path()); // Empty strings are ignored — they're rarely a deliberate override. - assert_eq!(config.provider.as_deref(), Some("deepseek")); + assert_eq!(config.provider.as_deref(), Some("codewhale")); assert_eq!( config.default_text_model.as_deref(), Some("deepseek-v4-pro") @@ -5958,7 +5958,7 @@ mod doctor_mcp_tests { #[test] fn test_self_hosted_absolute_is_ok() { - let server = make_server(Some("/usr/local/bin/deepseek"), &["serve", "--mcp"], None); + let server = make_server(Some("/usr/local/bin/codewhale"), &["serve", "--mcp"], None); match doctor_check_mcp_server(&server) { McpServerDoctorStatus::Ok(detail) | McpServerDoctorStatus::Error(detail) => { // On systems where the path doesn't exist, this will be Error. @@ -5976,7 +5976,7 @@ mod doctor_mcp_tests { #[test] fn test_self_hosted_relative_is_warning() { - let server = make_server(Some("deepseek"), &["serve", "--mcp"], None); + let server = make_server(Some("codewhale"), &["serve", "--mcp"], None); match doctor_check_mcp_server(&server) { McpServerDoctorStatus::Warning(detail) => { assert!(detail.contains("relative")); @@ -6461,7 +6461,7 @@ mod pr_prompt_tests { // A deliberately-implausible name to confirm the negative // branch — `--version` on this would exec(3) → ENOENT. assert!( - !is_command_available("this-command-cannot-exist-deepseek-tui-test-ENOENT-marker"), + !is_command_available("this-command-cannot-exist-codewhale-tui-test-ENOENT-marker"), "missing command should return false, not panic" ); } diff --git a/crates/tui/src/mcp.rs b/crates/tui/src/mcp.rs index d25c0734..e9c60406 100644 --- a/crates/tui/src/mcp.rs +++ b/crates/tui/src/mcp.rs @@ -1328,7 +1328,7 @@ impl McpConnection { "params": { "protocolVersion": "2024-11-05", "clientInfo": { - "name": "deepseek-tui", + "name": "codewhale-tui", "version": env!("CARGO_PKG_VERSION") }, "capabilities": { @@ -3343,7 +3343,7 @@ mod tests { r#"{ "mcpServers": { "broken": { - "command": "deepseek-tui-test-this-binary-does-not-exist-9f8e7d6c5b4a", + "command": "codewhale-tui-test-this-binary-does-not-exist-9f8e7d6c5b4a", "args": [] } } diff --git a/crates/tui/src/prompts.rs b/crates/tui/src/prompts.rs index f801ed59..912ab283 100644 --- a/crates/tui/src/prompts.rs +++ b/crates/tui/src/prompts.rs @@ -277,7 +277,7 @@ pub(crate) fn locale_reinforcement_closer(locale_tag: &str) -> Option<&'static s } const LOCALE_PREAMBLE_ZH_HANS: &str = "## 语言要求\n\n\ -你正在 DeepSeek TUI 中运行。无论任务上下文(代码、错误日志、文件名)\ +你正在 codewhale 中运行。无论任务上下文(代码、错误日志、文件名)\ 是英文,无论系统提示的其余部分是英文,你都必须用简体中文进行 \ `reasoning_content`(内部思考)和最终回复。代码、文件路径、工具名称\ (例如 `read_file`、`exec_shell`)、环境变量、命令行参数和 URL \ @@ -286,7 +286,7 @@ const LOCALE_PREAMBLE_ZH_HANS: &str = "## 语言要求\n\n\ 如果用户明确要求(例如 \"think in English\"),则覆盖此规则。"; const LOCALE_PREAMBLE_JA: &str = "## 言語要件\n\n\ -DeepSeek TUI を実行しています。タスクコンテキスト(コード、エラーログ、\ +codewhale を実行しています。タスクコンテキスト(コード、エラーログ、\ ファイル名)が英語であっても、システムプロンプトの他の部分が英語で\ あっても、`reasoning_content`(内部思考)と最終的な返信は日本語で\ 行ってください。コード、ファイルパス、ツール名(例:`read_file`、\ @@ -297,7 +297,7 @@ DeepSeek TUI を実行しています。タスクコンテキスト(コード \"think in English\")はこのルールを上書きします。"; const LOCALE_PREAMBLE_PT_BR: &str = "## Requisito de Idioma\n\n\ -Você está rodando dentro do DeepSeek TUI. Escreva tanto \ +Você está rodando dentro do codewhale. Escreva tanto \ `reasoning_content` (seu pensamento interno) quanto a resposta final \ em português do Brasil, mesmo quando o contexto da tarefa (código, \ logs de erro, nomes de arquivos) estiver em inglês e mesmo quando o \ @@ -888,7 +888,7 @@ mod tests { SystemPrompt::Blocks(_) => panic!("expected text system prompt"), }; let preamble_marker = "## 语言要求"; - let base_marker = "You are DeepSeek TUI"; + let base_marker = "You are codewhale"; let preamble_pos = text .find(preamble_marker) .expect("zh-Hans preamble should be present"); @@ -1262,7 +1262,7 @@ mod tests { fn compose_prompt_includes_all_layers() { let prompt = compose_prompt(AppMode::Agent, Personality::Calm); // Base layer - assert!(prompt.contains("You are DeepSeek TUI")); + assert!(prompt.contains("You are codewhale")); // Personality layer assert!(prompt.contains("Personality: Calm")); // Mode layer @@ -1321,7 +1321,7 @@ mod tests { #[test] fn compose_prompt_deterministic_order() { let prompt = compose_prompt(AppMode::Yolo, Personality::Calm); - let base_pos = prompt.find("You are DeepSeek TUI").unwrap(); + let base_pos = prompt.find("You are codewhale").unwrap(); let personality_pos = prompt.find("Personality: Calm").unwrap(); let mode_pos = prompt.find("Mode: YOLO").unwrap(); let approval_pos = prompt.find("Approval Policy: Auto").unwrap(); @@ -1581,7 +1581,7 @@ mod tests { fn subagent_done_sentinel_section_present() { let prompt = compose_prompt(AppMode::Agent, Personality::Calm); assert!(prompt.contains("Internal Sub-agent Completion Events")); - assert!(prompt.contains("")); + assert!(prompt.contains("")); assert!(prompt.contains("not user input")); assert!(prompt.contains("Integration protocol")); assert!(prompt.contains("Do not tell the user they pasted sentinels")); diff --git a/crates/tui/src/prompts/agent.txt b/crates/tui/src/prompts/agent.txt index 42ee3301..42ab337f 100644 --- a/crates/tui/src/prompts/agent.txt +++ b/crates/tui/src/prompts/agent.txt @@ -11,6 +11,6 @@ flow. ## Sub-agent completion sentinel When you open a sub-agent via `agent_open`, the child runs independently. -You will receive a `` element in the transcript when it finishes. +You will receive a `` element in the transcript when it finishes. Read its `summary` field and integrate the work — do not re-do what the child already did. You can also call `agent_eval` with the agent name or id to pull the current structured projection or transcript handle. diff --git a/crates/tui/src/prompts/base.md b/crates/tui/src/prompts/base.md index 0180f5f8..4e342bdb 100644 --- a/crates/tui/src/prompts/base.md +++ b/crates/tui/src/prompts/base.md @@ -1,4 +1,4 @@ -You are DeepSeek TUI. You're already running inside it. Do not launch a nested interactive `deepseek` or `deepseek-tui` session unless the user explicitly asks. Using `deepseek` CLI subcommands such as `deepseek --version`, `deepseek -p`, `deepseek doctor`, or `deepseek auth status` is allowed when it directly helps the task. +You are codewhale. You're already running inside it. Do not launch a nested interactive `codewhale` or `codewhale-tui` session unless the user explicitly asks. Using `codewhale` CLI subcommands such as `codewhale --version`, `codewhale -p`, `codewhale doctor`, or `codewhale auth status` is allowed when it directly helps the task. ## Language @@ -14,7 +14,7 @@ Code, file paths, identifiers, tool names, environment variables, command-line f ## Runtime Identity -If the user asks what DeepSeek TUI version you are running, use the `deepseek_version` field in the `## Environment` section as the runtime version. Workspace files such as `Cargo.toml` describe the checkout you are inspecting; they may be stale, dirty, or intentionally different from the installed runtime. If those disagree, report both instead of replacing the runtime version with the workspace version. +If the user asks what codewhale version you are running, use the `deepseek_version` field in the `## Environment` section as the runtime version. Workspace files such as `Cargo.toml` describe the checkout you are inspecting; they may be stale, dirty, or intentionally different from the installed runtime. If those disagree, report both instead of replacing the runtime version with the workspace version. ## Preamble Rhythm @@ -203,7 +203,7 @@ Use persistent RLM sessions for long-context semantic work, bulk classification/ ## Internal Sub-agent Completion Events -When you open a sub-agent via `agent_open`, the child runs independently. The runtime may send you an internal `` completion event when it finishes. This event is not user input. It carries: +When you open a sub-agent via `agent_open`, the child runs independently. The runtime may send you an internal `` completion event when it finishes. This event is not user input. It carries: - `agent_id` — the child's identifier - `status` — `"completed"` or `"failed"` @@ -211,14 +211,14 @@ When you open a sub-agent via `agent_open`, the child runs independently. The ru - `details` — currently `agent_eval`, the tool to call when you need the full projection or transcript handle **Integration protocol:** -1. When you see ``, read the human summary line immediately before it first. +1. When you see ``, read the human summary line immediately before it first. 2. Integrate the child's findings into your work — do not re-do what the child already did. 3. If the summary is insufficient, call `agent_eval` with the agent name or id to pull the current structured projection or transcript handle. 4. If the child failed (`"failed"`), assess whether the failure blocks your plan or whether you can proceed with a fallback. 5. Update your `checklist_write` items to reflect the child's contribution. 6. Do not tell the user they pasted sentinels or explain this protocol unless they explicitly ask about sub-agent internals. -You may see multiple `` sentinels in a single turn when children were opened in parallel. Process each one, then synthesize. +You may see multiple `` sentinels in a single turn when children were opened in parallel. Process each one, then synthesize. ## Output formatting diff --git a/crates/tui/src/prompts/base.txt b/crates/tui/src/prompts/base.txt index a38f9e73..58f03268 100644 --- a/crates/tui/src/prompts/base.txt +++ b/crates/tui/src/prompts/base.txt @@ -1,4 +1,4 @@ -You are DeepSeek TUI. You're already running inside it. Do not launch a nested interactive `deepseek` or `deepseek-tui` session unless the user explicitly asks. Using `deepseek` CLI subcommands such as `deepseek --version`, `deepseek -p`, `deepseek doctor`, or `deepseek auth status` is allowed when it directly helps the task. +You are codewhale. You're already running inside it. Do not launch a nested interactive `codewhale` or `codewhale-tui` session unless the user explicitly asks. Using `codewhale` CLI subcommands such as `codewhale --version`, `codewhale -p`, `codewhale doctor`, or `codewhale auth status` is allowed when it directly helps the task. ## Decomposition Philosophy diff --git a/crates/tui/src/tools/subagent/mod.rs b/crates/tui/src/tools/subagent/mod.rs index 25d6a85c..0ac510cf 100644 --- a/crates/tui/src/tools/subagent/mod.rs +++ b/crates/tui/src/tools/subagent/mod.rs @@ -607,7 +607,7 @@ pub const DEFAULT_MAX_SPAWN_DEPTH: u32 = 3; /// Terminal-state notification emitted to the engine's parent turn loop /// when one of its direct children finishes (issue #756). Carries the -/// already-rendered `` sentinel that the model +/// already-rendered `` sentinel that the model /// expects in the transcript per `prompts/base.md`. #[derive(Debug, Clone)] pub struct SubAgentCompletion { @@ -3308,12 +3308,12 @@ fn build_initial_subagent_messages( .filter(|state| !state.is_empty()) { messages.push(system_text_message(format!( - "\n{state}\n" + "\n{state}\n" ))); } messages.push(system_text_message(format!( - "\n{}\n", + "\n{}\n", build_subagent_system_prompt(agent_type, assignment) ))); } @@ -3381,7 +3381,7 @@ async fn run_subagent_task(task: SubAgentTask) { // sidebar / cell) AND a structured sentinel the model can recognize // on its next turn. Format: human summary on the first line, // sentinel on the second. The sentinel uses an opaque tag - // (`deepseek:subagent.done`) to avoid collision with normal user + // (`codewhale:subagent.done`) to avoid collision with normal user // text. let (summary, sentinel) = match &result { Ok(res) => ( @@ -3448,7 +3448,7 @@ pub(crate) fn emit_parent_completion( true } -/// Build a `` JSON sentinel for a successful child. +/// Build a `` JSON sentinel for a successful child. /// Intended to surface in the parent's transcript so the model recognizes /// child completion and can decide whether to read the full result via /// `agent_eval`. @@ -3465,10 +3465,10 @@ fn subagent_done_sentinel(agent_id: &str, res: &SubAgentResult) -> String { "summary_location": "previous_line", "details": "agent_eval", }); - format!("{payload}") + format!("{payload}") } -/// Build a `` sentinel for a failed child. +/// Build a `` sentinel for a failed child. fn subagent_failed_sentinel(agent_id: &str, _err: &str) -> String { let payload = json!({ "agent_id": agent_id, @@ -3476,7 +3476,7 @@ fn subagent_failed_sentinel(agent_id: &str, _err: &str) -> String { "error_location": "previous_line", "details": "agent_eval", }); - format!("{payload}") + format!("{payload}") } #[allow(clippy::too_many_arguments)] @@ -4412,7 +4412,7 @@ async fn subagent_flash_router( } const SUBAGENT_ROUTER_SYSTEM_PROMPT: &str = "\ -You are the DeepSeek TUI sub-agent routing manager. Return only compact JSON: \ +You are the codewhale sub-agent routing manager. Return only compact JSON: \ {\"model\":\"deepseek-v4-flash|deepseek-v4-pro\",\"thinking\":\"off|high|max\"}. \ Treat each child assignment like a customer request entering a team queue: decide the least \ sufficient worker and thinking budget for that assignment. Do not treat being a sub-agent as \ diff --git a/crates/tui/src/tools/subagent/tests.rs b/crates/tui/src/tools/subagent/tests.rs index 30b3494d..58a42d9d 100644 --- a/crates/tui/src/tools/subagent/tests.rs +++ b/crates/tui/src/tools/subagent/tests.rs @@ -472,9 +472,9 @@ fn forked_subagent_messages_preserve_parent_prefix_then_append_task() { assert_eq!(messages.first(), Some(&parent_message)); assert_eq!(messages.len(), 4); assert_eq!(messages[1].role, "system"); - assert!(message_text(&messages[1]).contains("")); + assert!(message_text(&messages[1]).contains("")); assert_eq!(messages[2].role, "system"); - assert!(message_text(&messages[2]).contains("")); + assert!(message_text(&messages[2]).contains("")); assert_eq!(messages[3].role, "user"); assert!(message_text(&messages[3]).contains("inspect parser")); } @@ -1152,13 +1152,13 @@ fn build_subagent_system_prompt_skips_role_when_blank() { fn subagent_done_sentinel_format_is_well_formed() { let res = make_snapshot(SubAgentStatus::Completed); let sentinel = subagent_done_sentinel("agent_xyz", &res); - assert!(sentinel.starts_with("")); - assert!(sentinel.ends_with("")); + assert!(sentinel.starts_with("")); + assert!(sentinel.ends_with("")); // The inner JSON parses and carries the expected fields. let inner = sentinel - .trim_start_matches("") - .trim_end_matches(""); + .trim_start_matches("") + .trim_end_matches(""); let parsed: serde_json::Value = serde_json::from_str(inner).expect("inner JSON parses"); assert_eq!(parsed["agent_id"], "agent_xyz"); assert_eq!(parsed["status"], "completed"); @@ -1174,8 +1174,8 @@ fn subagent_done_sentinel_format_is_well_formed() { fn subagent_failed_sentinel_format_is_well_formed() { let sentinel = subagent_failed_sentinel("agent_zzz", "boom"); let inner = sentinel - .trim_start_matches("") - .trim_end_matches(""); + .trim_start_matches("") + .trim_end_matches(""); let parsed: serde_json::Value = serde_json::from_str(inner).expect("inner JSON parses"); assert_eq!(parsed["agent_id"], "agent_zzz"); assert_eq!(parsed["status"], "failed"); @@ -1651,7 +1651,7 @@ fn persisted_non_empty_allowed_tools_loads_as_narrow() { fn stub_runtime() -> SubAgentRuntime { use tokio_util::sync::CancellationToken; - let workspace = std::env::temp_dir().join("deepseek-test-stub"); + let workspace = std::env::temp_dir().join("codewhale-test-stub"); let context = ToolContext::new(workspace.clone()); SubAgentRuntime { client: stub_client(), @@ -2023,7 +2023,7 @@ fn child_runtime_preserves_step_api_timeout() { #[test] fn subagent_completion_payload_carries_existing_sentinel_format() { // The payload format is the same one already documented in - // prompts/base.md: human summary on line 1, `` + // prompts/base.md: human summary on line 1, `` // sentinel on line 2. This test pins the format so future refactors // don't silently break the model's parsing contract. let mut snap = make_snapshot(SubAgentStatus::Completed); @@ -2037,14 +2037,14 @@ fn subagent_completion_payload_carries_existing_sentinel_format() { let first = lines.next().expect("first line is summary"); let second = lines.next().expect("second line is sentinel"); assert!( - !first.starts_with(""), + !first.starts_with(""), "summary should not be the sentinel itself" ); assert!( - second.starts_with(""), + second.starts_with(""), "second line is the sentinel" ); - assert!(second.ends_with("")); + assert!(second.ends_with("")); assert!( second.contains("\"agent_id\":\"agent_test\""), "sentinel JSON includes agent_id" diff --git a/crates/tui/src/tui/notifications.rs b/crates/tui/src/tui/notifications.rs index fcfe4ba3..670f73f9 100644 --- a/crates/tui/src/tui/notifications.rs +++ b/crates/tui/src/tui/notifications.rs @@ -143,7 +143,7 @@ fn build_escape(method: Method, in_tmux: bool, msg: &str) -> Vec { } Method::Ghostty => { // Ghostty notification: OSC 777 ; notify ; title ; message BEL - let seq = format!("\x1b]777;notify;DeepSeek TUI;{msg}\x07"); + let seq = format!("\x1b]777;notify;codewhale;{msg}\x07"); wrap_for_multiplexer(&seq, in_tmux).into_bytes() } // Auto and Off should not reach build_escape. @@ -332,18 +332,18 @@ pub fn completed_turn_message( ) -> String { let mut msg = text_summary(current_streaming_text) .or_else(|| latest_assistant_text(&app.api_messages)) - .unwrap_or_else(|| "deepseek: turn complete".to_string()); + .unwrap_or_else(|| "codewhale: turn complete".to_string()); if include_summary { let human = humanize_duration(turn_elapsed); let summary = match turn_cost { Some(c) => { let cost = crate::pricing::format_cost_estimate(c, app.cost_currency); - format!("deepseek: turn complete ({human}, {cost})") + format!("codewhale: turn complete ({human}, {cost})") } - None => format!("deepseek: turn complete ({human})"), + None => format!("codewhale: turn complete ({human})"), }; - if msg == "deepseek: turn complete" { + if msg == "codewhale: turn complete" { msg = summary; } else { msg.push('\n'); @@ -366,16 +366,16 @@ pub fn subagent_completion_message( let result_line = result .lines() .map(str::trim) - .find(|line| !line.is_empty() && !line.starts_with("")); + .find(|line| !line.is_empty() && !line.starts_with("")); let mut msg = result_line .and_then(text_summary) .map(|summary| format!("sub-agent {id}: {summary}")) - .unwrap_or_else(|| format!("deepseek: sub-agent {id} complete")); + .unwrap_or_else(|| format!("codewhale: sub-agent {id} complete")); if include_summary { let human = humanize_duration(elapsed); msg.push('\n'); - msg.push_str(&format!("deepseek: sub-agent complete ({human})")); + msg.push_str(&format!("codewhale: sub-agent complete ({human})")); } msg @@ -471,8 +471,8 @@ mod tests { #[test] fn osc9_body_format() { - let out = capture(Method::Osc9, false, "deepseek: done", 0, 1); - assert_eq!(out, b"\x1b]9;deepseek: done\x07"); + let out = capture(Method::Osc9, false, "codewhale: done", 0, 1); + assert_eq!(out, b"\x1b]9;codewhale: done\x07"); } #[test] @@ -501,7 +501,7 @@ mod tests { let out = capture(Method::Ghostty, false, "done", 0, 1); let s = String::from_utf8(out).unwrap(); assert!( - s.contains("777;notify;DeepSeek TUI;done"), + s.contains("777;notify;codewhale;done"), "should have ghostty seq" ); } diff --git a/crates/tui/src/tui/onboarding/welcome.rs b/crates/tui/src/tui/onboarding/welcome.rs index 3726c6a6..46d710fe 100644 --- a/crates/tui/src/tui/onboarding/welcome.rs +++ b/crates/tui/src/tui/onboarding/welcome.rs @@ -8,7 +8,7 @@ use crate::palette; pub fn lines() -> Vec> { vec![ Line::from(Span::styled( - "DeepSeek TUI", + "codewhale", Style::default() .fg(palette::DEEPSEEK_BLUE) .add_modifier(Modifier::BOLD), diff --git a/crates/tui/src/tui/sidebar.rs b/crates/tui/src/tui/sidebar.rs index 4a102150..1744ac27 100644 --- a/crates/tui/src/tui/sidebar.rs +++ b/crates/tui/src/tui/sidebar.rs @@ -2051,7 +2051,7 @@ mod tests { .push(HistoryCell::Tool(ToolCell::Generic(GenericToolCell { name: "read_file".to_string(), status: ToolStatus::Success, - input_summary: Some("deepseek-tui/CHANGELOG.md".to_string()), + input_summary: Some("codewhale-tui/CHANGELOG.md".to_string()), output: Some("done".to_string()), prompts: None, spillover_path: None, @@ -2328,7 +2328,7 @@ mod tests { fn tasks_panel_failed_shell_rows_point_to_activity_details() { let mut app = create_test_app(); app.history.push(HistoryCell::Tool(ToolCell::Exec(ExecCell { - command: "cargo test -p deepseek-tui".to_string(), + command: "cargo test -p codewhale-tui".to_string(), status: ToolStatus::Failed, output: Some("test failed".to_string()), started_at: None, diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index 3cf028a4..552a4f4b 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -576,7 +576,7 @@ fn should_show_resume_hint(session_id: Option<&str>) -> bool { } fn resume_hint_text() -> &'static str { - "To continue this session, execute deepseek run --continue" + "To continue this session, execute codewhale run --continue" } fn terminal_probe_timeout(config: &Config) -> Duration { diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 5ec4f788..bc8b7d1d 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -116,7 +116,7 @@ impl Drop for SettingsHomeGuard { fn resume_hint_uses_canonical_resume_command() { assert_eq!( resume_hint_text(), - "To continue this session, execute deepseek run --continue" + "To continue this session, execute codewhale run --continue" ); assert!(should_show_resume_hint(Some( "019dd9d6-4f44-7c83-9863-59674a12b827" @@ -1952,7 +1952,7 @@ fn init_git_repo() -> TempDir { let commit = Command::new("git") .args([ "-c", - "user.name=DeepSeek TUI Tests", + "user.name=codewhale Tests", "-c", "user.email=tests@example.com", "commit", @@ -2836,7 +2836,7 @@ fn visible_slash_menu_entries_excludes_removed_commands() { assert!(entries.iter().any(|entry| entry.name == "/config")); assert!(entries.iter().any(|entry| entry.name == "/links")); assert!(!entries.iter().any(|entry| entry.name == "/set")); - assert!(!entries.iter().any(|entry| entry.name == "/deepseek")); + assert!(!entries.iter().any(|entry| entry.name == "/codewhale")); } #[test] @@ -5942,7 +5942,7 @@ fn completed_turn_notification_falls_back_to_default_when_empty() { Duration::from_secs(5), None, ); - assert_eq!(msg, "deepseek: turn complete"); + assert_eq!(msg, "codewhale: turn complete"); } #[test] @@ -5965,13 +5965,13 @@ fn completed_turn_notification_truncates_long_text() { fn subagent_completion_notification_uses_summary_line_not_sentinel() { let msg = crate::tui::notifications::subagent_completion_message( "agent_live", - "Finished the docs audit.\n{}", + "Finished the docs audit.\n{}", false, Duration::from_secs(42), ); assert_eq!(msg, "sub-agent agent_live: Finished the docs audit."); - assert!(!msg.contains("deepseek:subagent.done")); + assert!(!msg.contains("codewhale:subagent.done")); } #[test] @@ -5983,8 +5983,8 @@ fn subagent_completion_notification_can_include_elapsed_summary() { Duration::from_secs(65), ); - assert!(msg.contains("deepseek: sub-agent agent_live complete")); - assert!(msg.contains("deepseek: sub-agent complete (1m 5s)")); + assert!(msg.contains("codewhale: sub-agent agent_live complete")); + assert!(msg.contains("codewhale: sub-agent complete (1m 5s)")); } #[test] diff --git a/crates/tui/src/tui/widgets/header.rs b/crates/tui/src/tui/widgets/header.rs index afcacd50..3c680412 100644 --- a/crates/tui/src/tui/widgets/header.rs +++ b/crates/tui/src/tui/widgets/header.rs @@ -619,7 +619,7 @@ mod tests { HeaderData::new( AppMode::Agent, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ), @@ -627,7 +627,7 @@ mod tests { ); assert!(rendered.contains("Agent")); - assert!(rendered.contains("deepseek-tui")); + assert!(rendered.contains("codewhale-tui")); assert!(rendered.contains("deepseek-v4-pro")); assert!(!rendered.contains("Plan")); assert!(!rendered.contains("Yolo")); @@ -637,12 +637,12 @@ mod tests { fn header_renders_version_chip_when_width_allows() { // At a generous width the header must surface the runtime version // — users repeatedly ask for it in the live UI (vs only via - // `deepseek --version` / `/status`). + // `codewhale --version` / `/status`). let rendered = render_header( HeaderData::new( AppMode::Agent, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ), @@ -663,7 +663,7 @@ mod tests { HeaderData::new( AppMode::Yolo, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", true, palette::DEEPSEEK_INK, ) @@ -775,7 +775,7 @@ mod tests { HeaderData::new( AppMode::Agent, "deepseek-ai/deepseek-v4-flash", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ) @@ -794,7 +794,7 @@ mod tests { HeaderData::new( AppMode::Agent, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ), @@ -859,7 +859,7 @@ mod tests { HeaderData::new( AppMode::Agent, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ) @@ -890,7 +890,7 @@ mod tests { HeaderData::new( AppMode::Agent, "deepseek-v4-pro", - "deepseek-tui", + "codewhale-tui", false, palette::DEEPSEEK_INK, ) diff --git a/crates/tui/src/tui/widgets/mod.rs b/crates/tui/src/tui/widgets/mod.rs index 2eb2c63a..fdad7dc4 100644 --- a/crates/tui/src/tui/widgets/mod.rs +++ b/crates/tui/src/tui/widgets/mod.rs @@ -333,7 +333,7 @@ impl Renderable for ChatWidget { let area = _area; - // Repaint the full chat area with the deepseek-ink background each + // Repaint the full chat area with the codewhale-ink background each // frame. Ratatui's `Paragraph` only writes cells that contain text, // so cells the current frame's paragraph doesn't touch would // otherwise hold the *previous* frame's contents (the `:24Z` @@ -1926,7 +1926,7 @@ fn build_empty_state_lines(app: &App, area: Rect) -> Vec> { let body = vec![ Line::from(Span::styled( - format!("{inset}>_ DeepSeek TUI (v{})", env!("CARGO_PKG_VERSION")), + format!("{inset}>_ codewhale (v{})", env!("CARGO_PKG_VERSION")), Style::default().fg(palette::DEEPSEEK_BLUE).bold(), )), Line::from(""), @@ -2557,7 +2557,7 @@ mod tests { fn slash_completion_hints_exclude_set_and_deepseek_commands() { let hints = slash_completion_hints("/", 128, &[], Locale::En, None, ApiProvider::Deepseek); assert!(!hints.iter().any(|hint| hint.name == "/set")); - assert!(!hints.iter().any(|hint| hint.name == "/deepseek")); + assert!(!hints.iter().any(|hint| hint.name == "/codewhale")); } #[test] @@ -2809,7 +2809,7 @@ mod tests { let mut app = create_test_app(); app.composer_density = ComposerDensity::Comfortable; app.session_title = - Some("hello could you please take a look at deepseek-tui and all changes".to_string()); + Some("hello could you please take a look at codewhale-tui and all changes".to_string()); let slash_menu_entries = Vec::::new(); let mention_menu_entries = Vec::::new(); let widget = ComposerWidget::new(&app, 5, &slash_menu_entries, &mention_menu_entries); @@ -2825,7 +2825,7 @@ mod tests { let rendered = buffer_text(&buf, area); assert!(rendered.contains("Composer")); - assert!(!rendered.contains("deepseek-tui")); + assert!(!rendered.contains("codewhale-tui")); assert!(!rendered.contains("hello could you")); } @@ -2951,7 +2951,7 @@ mod tests { #[test] fn empty_state_shows_startup_context() { let mut app = create_test_app(); - app.workspace = PathBuf::from("/tmp/deepseek-test-workspace"); + app.workspace = PathBuf::from("/tmp/codewhale-test-workspace"); app.model = "deepseek-v4-pro".to_string(); let lines = build_empty_state_lines(&app, Rect::new(0, 0, 100, 20)); @@ -2966,9 +2966,9 @@ mod tests { .collect::>() .join("\n"); - assert!(rendered.contains(&format!(">_ DeepSeek TUI (v{})", env!("CARGO_PKG_VERSION")))); + assert!(rendered.contains(&format!(">_ codewhale (v{})", env!("CARGO_PKG_VERSION")))); assert!(rendered.contains("model: deepseek-v4-pro /model to switch")); - assert!(rendered.contains("directory: /tmp/deepseek-test-workspace")); + assert!(rendered.contains("directory: /tmp/codewhale-test-workspace")); } /// Probe: confirm `cell.lines_with_motion` returns no Line whose total @@ -3449,7 +3449,7 @@ mod tests { /// pays the wrap cost; subsequent calls at different offsets should hit /// the per-cell cache and be ~constant time regardless of offset. /// - /// Run with: `cargo test -p deepseek-tui --release bench_transcript_scroll + /// Run with: `cargo test -p codewhale-tui --release bench_transcript_scroll /// -- --ignored --nocapture` // Perf bench prints timing rows to stdout — runs in `cargo test`, // never inside the TUI alt-screen. diff --git a/crates/tui/tests/protocol_recovery.rs b/crates/tui/tests/protocol_recovery.rs index b42f174e..7f567a26 100644 --- a/crates/tui/tests/protocol_recovery.rs +++ b/crates/tui/tests/protocol_recovery.rs @@ -48,7 +48,7 @@ fn any_engine_source_contains(needle: &str) -> bool { const EXPECTED_START_MARKERS: &[&str] = &[ "[TOOL_CALL]", - "", @@ -56,7 +56,7 @@ const EXPECTED_START_MARKERS: &[&str] = &[ const EXPECTED_END_MARKERS: &[&str] = &[ "[/TOOL_CALL]", - "", + "", "", "", "", diff --git a/crates/tui/tests/support/qa_harness/harness.rs b/crates/tui/tests/support/qa_harness/harness.rs index 3ebebde4..3ebda0fa 100644 --- a/crates/tui/tests/support/qa_harness/harness.rs +++ b/crates/tui/tests/support/qa_harness/harness.rs @@ -227,7 +227,7 @@ impl Harness { return PathBuf::from(path); } // Legacy fallback for callers still referencing the old bin name. - if name == "deepseek-tui" + if name == "codewhale-tui" && let Some(path) = option_env!("CARGO_BIN_EXE_deepseek-tui") { return PathBuf::from(path);