refactor(provider): use local settings for current provider selection

Complete the device-level settings separation for cloud sync support.

Backend changes:
- Modify switch() to update both local settings and database is_current
- Modify current() to read from local settings first, fallback to database
- Rename sync_current_from_db() to sync_current_to_live()
- Update tray menu to read current provider from local settings

Frontend changes:
- Update Settings interface: remove legacy fields (customEndpoints*, security)
- Add currentProviderClaude/Codex/Gemini fields
- Update settings schema accordingly

Test fixes:
- Update Gemini security tests to check ~/.gemini/settings.json
  instead of ~/.cc-switch/settings.json (security field was never
  stored in CC Switch settings)

This ensures each device maintains its own current provider selection
independently when database is synced across devices.
This commit is contained in:
Jason
2025-11-27 11:42:19 +08:00
parent ea7169abc0
commit 2c90ae3509
7 changed files with 92 additions and 59 deletions

View File

@@ -843,21 +843,22 @@ fn sync_gemini_packycode_sets_security_selected_type() {
ConfigService::sync_current_providers_to_live(&mut config)
.expect("syncing gemini live should succeed");
let settings_path = home.join(".cc-switch").join("settings.json");
// security field is written to ~/.gemini/settings.json, not ~/.cc-switch/settings.json
let gemini_settings = home.join(".gemini").join("settings.json");
assert!(
settings_path.exists(),
"settings.json should exist at {}",
settings_path.display()
gemini_settings.exists(),
"Gemini settings.json should exist at {}",
gemini_settings.display()
);
let raw = std::fs::read_to_string(&settings_path).expect("read settings.json");
let value: serde_json::Value = serde_json::from_str(&raw).expect("parse settings.json");
let raw = std::fs::read_to_string(&gemini_settings).expect("read gemini settings.json");
let value: serde_json::Value = serde_json::from_str(&raw).expect("parse gemini settings.json");
assert_eq!(
value
.pointer("/security/auth/selectedType")
.and_then(|v| v.as_str()),
Some("gemini-api-key"),
"syncing PackyCode Gemini should enforce security.auth.selectedType"
"syncing PackyCode Gemini should enforce security.auth.selectedType in Gemini settings"
);
}
@@ -893,22 +894,7 @@ fn sync_gemini_google_official_sets_oauth_security() {
ConfigService::sync_current_providers_to_live(&mut config)
.expect("syncing google official gemini should succeed");
let cc_settings = home.join(".cc-switch").join("settings.json");
assert!(
cc_settings.exists(),
"app settings should exist at {}",
cc_settings.display()
);
let cc_raw = std::fs::read_to_string(&cc_settings).expect("read .cc-switch settings");
let cc_value: serde_json::Value = serde_json::from_str(&cc_raw).expect("parse app settings");
assert_eq!(
cc_value
.pointer("/security/auth/selectedType")
.and_then(|v| v.as_str()),
Some("oauth-personal"),
"syncing Google official should set oauth-personal in app settings"
);
// security field is written to ~/.gemini/settings.json, not ~/.cc-switch/settings.json
let gemini_settings = home.join(".gemini").join("settings.json");
assert!(
gemini_settings.exists(),
@@ -923,7 +909,7 @@ fn sync_gemini_google_official_sets_oauth_security() {
.pointer("/security/auth/selectedType")
.and_then(|v| v.as_str()),
Some("oauth-personal"),
"Gemini settings should also record oauth-personal"
"Gemini settings should record oauth-personal for Google Official"
);
}