Files
cc-switch/src-tauri/src/app_config.rs

192 lines
7.0 KiB
Rust
Raw Normal View History

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
refactor(api): unify AppType parsing with FromStr trait BREAKING CHANGE: Remove support for legacy app_type/appType parameters. All Tauri commands now accept only the 'app' parameter (values: "claude" or "codex"). Invalid app values will return localized error messages with allowed values. This commit addresses code duplication and improves error handling: - Consolidate AppType parsing into FromStr trait implementation * Eliminates duplicate parse_app() functions across 3 command modules * Provides single source of truth for app type validation * Enables idiomatic Rust .parse::<AppType>() syntax - Enhance error messages with localization * Return bilingual error messages (Chinese + English) * Include list of allowed values in error responses * Use structured AppError::localized for better categorization - Add input normalization * Case-insensitive matching ("CLAUDE" → AppType::Claude) * Automatic whitespace trimming (" codex \n" → AppType::Codex) * Improves API robustness against user input variations - Introduce comprehensive unit tests * Test valid inputs with case variations * Test whitespace handling * Verify error message content and localization * 100% coverage of from_str logic - Update documentation * Add CHANGELOG entry marking breaking change * Update README with accurate architecture description * Revise REFACTORING_MASTER_PLAN with migration examples * Remove all legacy app_type/appType references Code Quality Metrics: - Lines removed: 27 (duplicate code) - Lines added: 52 (including tests and docs) - Code duplication: 3 → 0 instances - Test coverage: 0% → 100% for AppType parsing
2025-10-30 12:33:35 +08:00
use std::str::FromStr;
/// MCP 配置单客户端维度claude 或 codex 下的一组服务器)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct McpConfig {
/// 以 id 为键的服务器定义(宽松 JSON 对象,包含 enabled/source 等 UI 辅助字段)
#[serde(default)]
pub servers: HashMap<String, serde_json::Value>,
}
/// MCP 根:按客户端分开维护(无历史兼容压力,直接以 v2 结构落地)
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct McpRoot {
#[serde(default)]
pub claude: McpConfig,
#[serde(default)]
pub codex: McpConfig,
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
#[serde(default)]
pub gemini: McpConfig, // Gemini MCP 配置(预留)
}
use crate::config::{copy_file, get_app_config_dir, get_app_config_path, write_json_file};
refactor(backend): phase 1 - unified error handling with thiserror Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
2025-10-27 16:29:11 +08:00
use crate::error::AppError;
use crate::provider::ProviderManager;
/// 应用类型
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AppType {
Claude,
Codex,
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
Gemini, // 新增
}
impl AppType {
pub fn as_str(&self) -> &str {
match self {
AppType::Claude => "claude",
AppType::Codex => "codex",
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
AppType::Gemini => "gemini", // 新增
}
}
}
refactor(api): unify AppType parsing with FromStr trait BREAKING CHANGE: Remove support for legacy app_type/appType parameters. All Tauri commands now accept only the 'app' parameter (values: "claude" or "codex"). Invalid app values will return localized error messages with allowed values. This commit addresses code duplication and improves error handling: - Consolidate AppType parsing into FromStr trait implementation * Eliminates duplicate parse_app() functions across 3 command modules * Provides single source of truth for app type validation * Enables idiomatic Rust .parse::<AppType>() syntax - Enhance error messages with localization * Return bilingual error messages (Chinese + English) * Include list of allowed values in error responses * Use structured AppError::localized for better categorization - Add input normalization * Case-insensitive matching ("CLAUDE" → AppType::Claude) * Automatic whitespace trimming (" codex \n" → AppType::Codex) * Improves API robustness against user input variations - Introduce comprehensive unit tests * Test valid inputs with case variations * Test whitespace handling * Verify error message content and localization * 100% coverage of from_str logic - Update documentation * Add CHANGELOG entry marking breaking change * Update README with accurate architecture description * Revise REFACTORING_MASTER_PLAN with migration examples * Remove all legacy app_type/appType references Code Quality Metrics: - Lines removed: 27 (duplicate code) - Lines added: 52 (including tests and docs) - Code duplication: 3 → 0 instances - Test coverage: 0% → 100% for AppType parsing
2025-10-30 12:33:35 +08:00
impl FromStr for AppType {
type Err = AppError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let normalized = s.trim().to_lowercase();
match normalized.as_str() {
"claude" => Ok(AppType::Claude),
"codex" => Ok(AppType::Codex),
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
"gemini" => Ok(AppType::Gemini), // 新增
refactor(api): unify AppType parsing with FromStr trait BREAKING CHANGE: Remove support for legacy app_type/appType parameters. All Tauri commands now accept only the 'app' parameter (values: "claude" or "codex"). Invalid app values will return localized error messages with allowed values. This commit addresses code duplication and improves error handling: - Consolidate AppType parsing into FromStr trait implementation * Eliminates duplicate parse_app() functions across 3 command modules * Provides single source of truth for app type validation * Enables idiomatic Rust .parse::<AppType>() syntax - Enhance error messages with localization * Return bilingual error messages (Chinese + English) * Include list of allowed values in error responses * Use structured AppError::localized for better categorization - Add input normalization * Case-insensitive matching ("CLAUDE" → AppType::Claude) * Automatic whitespace trimming (" codex \n" → AppType::Codex) * Improves API robustness against user input variations - Introduce comprehensive unit tests * Test valid inputs with case variations * Test whitespace handling * Verify error message content and localization * 100% coverage of from_str logic - Update documentation * Add CHANGELOG entry marking breaking change * Update README with accurate architecture description * Revise REFACTORING_MASTER_PLAN with migration examples * Remove all legacy app_type/appType references Code Quality Metrics: - Lines removed: 27 (duplicate code) - Lines added: 52 (including tests and docs) - Code duplication: 3 → 0 instances - Test coverage: 0% → 100% for AppType parsing
2025-10-30 12:33:35 +08:00
other => Err(AppError::localized(
"unsupported_app",
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
format!("不支持的应用标识: '{other}'。可选值: claude, codex, gemini。"),
format!("Unsupported app id: '{other}'. Allowed: claude, codex, gemini."),
refactor(api): unify AppType parsing with FromStr trait BREAKING CHANGE: Remove support for legacy app_type/appType parameters. All Tauri commands now accept only the 'app' parameter (values: "claude" or "codex"). Invalid app values will return localized error messages with allowed values. This commit addresses code duplication and improves error handling: - Consolidate AppType parsing into FromStr trait implementation * Eliminates duplicate parse_app() functions across 3 command modules * Provides single source of truth for app type validation * Enables idiomatic Rust .parse::<AppType>() syntax - Enhance error messages with localization * Return bilingual error messages (Chinese + English) * Include list of allowed values in error responses * Use structured AppError::localized for better categorization - Add input normalization * Case-insensitive matching ("CLAUDE" → AppType::Claude) * Automatic whitespace trimming (" codex \n" → AppType::Codex) * Improves API robustness against user input variations - Introduce comprehensive unit tests * Test valid inputs with case variations * Test whitespace handling * Verify error message content and localization * 100% coverage of from_str logic - Update documentation * Add CHANGELOG entry marking breaking change * Update README with accurate architecture description * Revise REFACTORING_MASTER_PLAN with migration examples * Remove all legacy app_type/appType references Code Quality Metrics: - Lines removed: 27 (duplicate code) - Lines added: 52 (including tests and docs) - Code duplication: 3 → 0 instances - Test coverage: 0% → 100% for AppType parsing
2025-10-30 12:33:35 +08:00
)),
}
}
}
/// 多应用配置结构(向后兼容)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MultiAppConfig {
#[serde(default = "default_version")]
pub version: u32,
/// 应用管理器claude/codex
#[serde(flatten)]
pub apps: HashMap<String, ProviderManager>,
/// MCP 配置(按客户端分治)
#[serde(default)]
pub mcp: McpRoot,
}
fn default_version() -> u32 {
2
}
impl Default for MultiAppConfig {
fn default() -> Self {
let mut apps = HashMap::new();
apps.insert("claude".to_string(), ProviderManager::default());
apps.insert("codex".to_string(), ProviderManager::default());
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
apps.insert("gemini".to_string(), ProviderManager::default()); // 新增
Self {
version: 2,
apps,
mcp: McpRoot::default(),
}
}
}
impl MultiAppConfig {
/// 从文件加载配置(仅支持 v2 结构)
refactor(backend): phase 1 - unified error handling with thiserror Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
2025-10-27 16:29:11 +08:00
pub fn load() -> Result<Self, AppError> {
let config_path = get_app_config_path();
if !config_path.exists() {
log::info!("配置文件不存在,创建新的多应用配置");
return Ok(Self::default());
}
// 尝试读取文件
let content =
std::fs::read_to_string(&config_path).map_err(|e| AppError::io(&config_path, e))?;
// 先解析为 Value以便严格判定是否为 v1 结构;
// 满足:顶层同时包含 providers(object) + current(string),且不包含 version/apps/mcp 关键键,即视为 v1
let value: serde_json::Value =
serde_json::from_str(&content).map_err(|e| AppError::json(&config_path, e))?;
let is_v1 = value.as_object().is_some_and(|map| {
let has_providers = map.get("providers").map(|v| v.is_object()).unwrap_or(false);
let has_current = map.get("current").map(|v| v.is_string()).unwrap_or(false);
// v1 的充分必要条件:有 providers 和 current且 apps 不存在version/mcp 可能存在但不作为 v2 判据)
let has_apps = map.contains_key("apps");
has_providers && has_current && !has_apps
});
if is_v1 {
return Err(AppError::localized(
"config.unsupported_v1",
"检测到旧版 v1 配置格式。当前版本已不再支持运行时自动迁移。\n\n解决方案:\n1. 安装 v3.2.x 版本进行一次性自动迁移\n2. 或手动编辑 ~/.cc-switch/config.json将顶层结构调整为\n {\"version\": 2, \"claude\": {...}, \"codex\": {...}, \"mcp\": {...}}\n\n",
"Detected legacy v1 config. Runtime auto-migration is no longer supported.\n\nSolutions:\n1. Install v3.2.x for one-time auto-migration\n2. Or manually edit ~/.cc-switch/config.json to adjust the top-level structure:\n {\"version\": 2, \"claude\": {...}, \"codex\": {...}, \"mcp\": {...}}\n\n",
));
}
// 解析 v2 结构
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
let mut config: Self = serde_json::from_value(value).map_err(|e| AppError::json(&config_path, e))?;
// 确保 gemini 应用存在(兼容旧配置文件)
if !config.apps.contains_key("gemini") {
config.apps.insert("gemini".to_string(), ProviderManager::default());
}
Ok(config)
}
/// 保存配置到文件
refactor(backend): phase 1 - unified error handling with thiserror Introduce AppError enum to replace Result<T, String> pattern across the codebase, improving error context preservation and type safety. ## Changes ### Core Infrastructure - Add src/error.rs with AppError enum using thiserror - Add thiserror dependency to Cargo.toml - Implement helper functions: io(), json(), toml() for ergonomic error creation - Implement From<PoisonError> for automatic lock error conversion - Implement From<AppError> for String to maintain Tauri command compatibility ### Module Migrations (60% complete) - config.rs: Full migration to AppError - read_json_file, write_json_file, atomic_write - archive_file, copy_file, delete_file - claude_mcp.rs: Full migration to AppError - get_mcp_status, read_mcp_json, upsert_mcp_server - delete_mcp_server, validate_command_in_path - set_mcp_servers_map - codex_config.rs: Full migration to AppError - write_codex_live_atomic with rollback support - read_and_validate_codex_config_text - validate_config_toml - app_config.rs: Partial migration - MultiAppConfig::load, MultiAppConfig::save - store.rs: Partial migration - AppState::save now returns Result<(), AppError> - commands.rs: Minimal changes - Use .map_err(Into::into) for compatibility - mcp.rs: Minimal changes - sync_enabled_to_claude uses Into::into conversion ### Documentation - Add docs/BACKEND_REFACTOR_PLAN.md with detailed refactoring roadmap ## Benefits - Type-safe error handling with preserved error chains - Better error messages with file paths and context - Reduced boilerplate code (118 Result<T, String> instances to migrate) - Automatic error conversion for seamless integration ## Testing - All existing tests pass (4/4) - Compilation successful with no warnings - Build time: 0.61s (no performance regression) ## Remaining Work - claude_plugin.rs (7 functions) - migration.rs, import_export.rs - Add unit tests for error.rs - Complete commands.rs migration after dependent modules Co-authored-by: Claude <claude@anthropic.com>
2025-10-27 16:29:11 +08:00
pub fn save(&self) -> Result<(), AppError> {
let config_path = get_app_config_path();
// 先备份旧版(若存在)到 ~/.cc-switch/config.json.bak再写入新内容
if config_path.exists() {
let backup_path = get_app_config_dir().join("config.json.bak");
if let Err(e) = copy_file(&config_path, &backup_path) {
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
log::warn!("备份 config.json 到 .bak 失败: {e}");
}
}
write_json_file(&config_path, self)?;
Ok(())
}
/// 获取指定应用的管理器
pub fn get_manager(&self, app: &AppType) -> Option<&ProviderManager> {
self.apps.get(app.as_str())
}
/// 获取指定应用的管理器(可变引用)
pub fn get_manager_mut(&mut self, app: &AppType) -> Option<&mut ProviderManager> {
self.apps.get_mut(app.as_str())
}
/// 确保应用存在
pub fn ensure_app(&mut self, app: &AppType) {
if !self.apps.contains_key(app.as_str()) {
self.apps
.insert(app.as_str().to_string(), ProviderManager::default());
}
}
/// 获取指定客户端的 MCP 配置(不可变引用)
pub fn mcp_for(&self, app: &AppType) -> &McpConfig {
match app {
AppType::Claude => &self.mcp.claude,
AppType::Codex => &self.mcp.codex,
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
AppType::Gemini => &self.mcp.gemini,
}
}
/// 获取指定客户端的 MCP 配置(可变引用)
pub fn mcp_for_mut(&mut self, app: &AppType) -> &mut McpConfig {
match app {
AppType::Claude => &mut self.mcp.claude,
AppType::Codex => &mut self.mcp.codex,
feat(gemini): add Gemini provider integration (#202) * feat(gemini): add Gemini provider integration - Add gemini_config.rs module for .env file parsing - Extend AppType enum to support Gemini - Implement GeminiConfigEditor and GeminiFormFields components - Add GeminiIcon with standardized 1024x1024 viewBox - Add Gemini provider presets configuration - Update i18n translations for Gemini support - Extend ProviderService and McpService for Gemini * fix(gemini): resolve TypeScript errors, add i18n support, and fix MCP logic **Critical Fixes:** - Fix TS2741 errors in tests/msw/state.ts by adding missing Gemini type definitions - Fix ProviderCard.extractApiUrl to support GOOGLE_GEMINI_BASE_URL display - Add missing apps.gemini i18n keys (zh/en) for proper app name display - Fix MCP service Gemini cross-app duplication logic to prevent self-copy **Technical Details:** - tests/msw/state.ts: Add gemini default providers, current ID, and MCP config - ProviderCard.tsx: Check both ANTHROPIC_BASE_URL and GOOGLE_GEMINI_BASE_URL - services/mcp.rs: Skip Gemini in sync_other_side logic with unreachable!() guards - Run pnpm format to auto-fix code style issues **Verification:** - ✅ pnpm typecheck passes - ✅ pnpm format completed * feat(gemini): enhance authentication and config parsing - Add strict and lenient .env parsing modes - Implement PackyCode partner authentication detection - Support Google OAuth official authentication - Auto-configure security.auth.selectedType for PackyCode - Add comprehensive test coverage for all auth types - Update i18n for OAuth hints and Gemini config --------- Co-authored-by: Jason <farion1231@gmail.com>
2025-11-12 10:47:34 +08:00
AppType::Gemini => &mut self.mcp.gemini,
}
}
}