From 5d50f3b311a855cf82d8001ef16003c79910c45e Mon Sep 17 00:00:00 2001 From: quangdang46 Date: Sun, 24 May 2026 23:16:58 +0700 Subject: [PATCH] feat(provider): disable_providers config + provider_key_disabled (#163) Gap close: upstream PR 1jehuang/jcode#219 (open) added a disabled_providers config + provider_key_disabled helper. Master had neither. This PR ports the primitive layer: # ~/.jcode/config.toml [provider] disabled_providers = ["copilot", "openrouter"] // From any auth/login codepath: if crate::auth::provider_key_disabled("copilot") { // skip Copilot in status / login UI / catalog } Recognized aliases: 'copilot' <-> 'github copilot' case-insensitive, whitespace-trimmed entries. Out of scope (#163 follow-up): - Wiring provider_key_disabled into AuthStatus::assessment_for_provider - Hiding disabled providers from login picker UI - Filtering disabled providers from auto-import paths Refs upstream PR 1jehuang/jcode#219, fork #163. --- crates/jcode-config-types/src/lib.rs | 6 ++++++ src/auth/mod.rs | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/crates/jcode-config-types/src/lib.rs b/crates/jcode-config-types/src/lib.rs index c14262c64..81d103c48 100644 --- a/crates/jcode-config-types/src/lib.rs +++ b/crates/jcode-config-types/src/lib.rs @@ -689,6 +689,11 @@ pub struct ProviderConfig { pub default_model: Option, /// Default provider to use (claude|openai|copilot|openrouter) pub default_provider: Option, + /// Issue #163: list of provider keys to treat as disabled. + /// Each entry matches case-insensitively against provider keys + /// (e.g. `["copilot", "openrouter"]`). Disabled providers are + /// hidden from auth status, login UI, and provider catalog. + pub disabled_providers: Vec, /// Reasoning effort for OpenAI Responses API (none|low|medium|high|xhigh) pub openai_reasoning_effort: Option, /// Reasoning effort for Anthropic Messages API output_config (none|low|medium|high|xhigh; max aliases to strongest supported) @@ -728,6 +733,7 @@ impl Default for ProviderConfig { Self { default_model: None, default_provider: None, + disabled_providers: Vec::new(), openai_reasoning_effort: Some("low".to_string()), anthropic_reasoning_effort: None, openai_transport: None, diff --git a/src/auth/mod.rs b/src/auth/mod.rs index b81c59faa..77d2f7de8 100644 --- a/src/auth/mod.rs +++ b/src/auth/mod.rs @@ -172,6 +172,29 @@ fn copilot_auth_state_from_credentials() -> (AuthState, bool) { } } +/// Issue #163: check whether `key` is listed in +/// `provider.disabled_providers` config. Case-insensitive, +/// whitespace-trimmed. Recognized aliases: +/// "copilot" matches "github copilot" and vice versa. +/// +/// Used by auth status, login picker, and provider catalog to hide +/// providers an operator has explicitly turned off (e.g. enterprise +/// policy, billing constraints). +pub fn provider_key_disabled(key: &str) -> bool { + crate::config::config() + .provider + .disabled_providers + .iter() + .any(|raw| { + let value = raw.trim(); + value.eq_ignore_ascii_case(key) + || (key.eq_ignore_ascii_case("copilot") + && value.eq_ignore_ascii_case("github copilot")) + || (key.eq_ignore_ascii_case("github copilot") + && value.eq_ignore_ascii_case("copilot")) + }) +} + impl AuthStatus { /// Check all authentication sources and return their status. /// Results are cached for 30 seconds to avoid expensive PATH scanning on every frame.