From fa4f268d0432f9c72f0b0b5b3fff088fd72f0f63 Mon Sep 17 00:00:00 2001 From: Paul Anduschus <157472224+DreamyTalesPAN@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:45:16 +0200 Subject: [PATCH] config: list removed providers only while they are enabled `config providers` printed one row per ProviderId::all(), including the two soft-removed providers as "Kimi K2 (removed)" and "CrossModel (removed)". The VibeTV Windows app builds its provider list from that output, so a customer was offered both rows (DreamyTalesPAN/CodexBar-Display#547). The command now follows the rule the settings UI already uses for ProviderId::is_deprecated(): a deprecated provider is listed only while it is enabled in settings. Resolving the names (`--provider kimik2`, `config enable kimik2`) is unchanged. Co-Authored-By: Claude Opus 5.5 --- rust/src/cli/config.rs | 50 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/rust/src/cli/config.rs b/rust/src/cli/config.rs index b49be7ae2cd..e59a136efe8 100755 --- a/rust/src/cli/config.rs +++ b/rust/src/cli/config.rs @@ -322,16 +322,28 @@ fn redact_secrets_value(value: serde_json::Value) -> serde_json::Value { } } +/// Providers shown by `config providers`. +/// +/// Same rule as the settings UI: a deprecated provider is listed only while +/// it is still enabled in settings. +fn listed_providers(settings: &Settings) -> Vec { + ProviderId::all() + .iter() + .copied() + .filter(|id| !id.is_deprecated() || settings.is_provider_enabled(*id)) + .collect() +} + /// List provider enabled state. async fn list_providers() -> anyhow::Result<()> { let settings = Settings::load(); - for id in ProviderId::all() { - let state = if settings.is_provider_enabled(*id) { + for id in listed_providers(&settings) { + let state = if settings.is_provider_enabled(id) { "enabled" } else { "disabled" }; - let default_marker = if instantiate_provider(*id).metadata().default_enabled { + let default_marker = if instantiate_provider(id).metadata().default_enabled { " default" } else { "" @@ -478,10 +490,11 @@ async fn show_paths() -> anyhow::Result<()> { #[cfg(test)] mod tests { - use super::{ConfigFileError, read_json_config, sanitize_settings_for_dump}; + use super::{ConfigFileError, listed_providers, read_json_config, sanitize_settings_for_dump}; + use crate::core::ProviderId; #[cfg(windows)] use crate::secure_file; - use crate::settings::ManualCookies; + use crate::settings::{ManualCookies, Settings}; use serde_json::json; #[cfg(windows)] @@ -593,4 +606,31 @@ mod tests { assert_eq!(out["api_key"], "keep-me"); assert_eq!(out["nested"]["token"], "also-keep"); } + + #[test] + fn listed_providers_hides_deprecated_providers_by_default() { + let listed = listed_providers(&Settings::default()); + + assert!(!listed.contains(&ProviderId::KimiK2)); + assert!(!listed.contains(&ProviderId::CrossModel)); + for id in ProviderId::all() { + assert_eq!( + listed.contains(id), + !id.is_deprecated(), + "unexpected listing for {}", + id.cli_name() + ); + } + } + + #[test] + fn listed_providers_keeps_deprecated_provider_enabled_in_settings() { + let mut settings = Settings::default(); + settings.enable_provider(ProviderId::KimiK2); + + let listed = listed_providers(&settings); + + assert!(listed.contains(&ProviderId::KimiK2)); + assert!(!listed.contains(&ProviderId::CrossModel)); + } }