* refactor(ui): simplify UpdateBadge to minimal dot indicator
* feat(provider): add individual test and proxy config for providers
Add support for provider-specific model test and proxy configurations:
- Add ProviderTestConfig and ProviderProxyConfig types in Rust and TypeScript
- Create ProviderAdvancedConfig component with collapsible panels
- Update stream_check service to merge provider config with global config
- Proxy config UI follows global proxy style (single URL input)
Provider-level configs stored in meta field, no database schema changes needed.
* feat(ui): add failover toggle and improve proxy controls
- Add FailoverToggle component with slide animation
- Simplify ProxyToggle style to match FailoverToggle
- Add usage statistics button when proxy is active
- Fix i18n parameter passing for failover messages
- Add missing failover translation keys (inQueue, addQueue, priority)
- Replace AboutSection icon with app logo
* fix(proxy): support system proxy fallback and provider-level proxy config
- Remove no_proxy() calls in http_client.rs to allow system proxy fallback
- Add get_for_provider() to build HTTP client with provider-specific proxy
- Update forwarder.rs and stream_check.rs to use provider proxy config
- Fix EditProviderDialog.tsx to include provider.meta in useMemo deps
- Add useEffect in ProviderAdvancedConfig.tsx to sync expand state
Fixes#636Fixes#583
* fix(ui): sync toast theme with app setting
* feat(settings): add log config management
Fixes#612Fixes#514
* fix(proxy): increase request body size limit to 200MB
Fixes#666
* docs(proxy): update timeout config descriptions and defaults
Fixes#612
* fix(proxy): filter x-goog-api-key header to prevent duplication
* fix(proxy): prevent proxy recursion when system proxy points to localhost
Detect if HTTP_PROXY, HTTPS_PROXY, or ALL_PROXY environment variables
point to loopback addresses (localhost, 127.0.0.1), and bypass system
proxy in such cases to avoid infinite request loops.
* fix(i18n): add providerAdvanced i18n keys and fix failover toast parameter
- Add providerAdvanced.* i18n keys to en.json, zh.json, and ja.json
- Fix failover toggleFailed toast to pass detail parameter
- Remove Chinese fallback text from UI for English/Japanese users
* fix(tray): restore tray-provider events and enable Auto failover properly
- Emit provider-switched event on tray provider click (backward compatibility)
- Auto button now: starts proxy, takes over live config, enables failover
* fix(log): enable dynamic log level and single file mode
- Initialize log at Trace level for dynamic adjustment
- Change rotation strategy to KeepSome(1) for single file
- Set max file size to 1GB
- Delete old log file on startup for clean start
* fix(tray): fix clippy uninlined format args warning
Use inline format arguments: {app_type_str} instead of {}
* fix(provider): allow typing :// in endpoint URL inputs
Change input type from "url" to "text" to prevent browser
URL validation from blocking :// input.
Closes#681
* fix(stream-check): use Gemini native streaming API format
- Change endpoint from OpenAI-compatible to native streamGenerateContent
- Add alt=sse parameter for SSE format response
- Use x-goog-api-key header instead of Bearer token
- Convert request body to Gemini contents/parts format
* feat(proxy): add request logging for debugging
Add debug logs for outgoing requests including URL and body content
with byte size, matching the existing response logging format.
* fix(log): prevent usize underflow in KeepSome rotation strategy
KeepSome(n) internally computes n-2, so n=1 causes underflow.
Use KeepSome(2) as the minimum safe value.
- Skip backfill logic for OpenCode (additive mode doesn't need it)
- Add defensive check in write_live_snapshot to extract provider fragment
- Use slugified name as provider ID for readable config keys
- Fix MCP server not removed from opencode.json when unchecked in edit modal
- Fix Windows atomic write failure when opencode.json already exists
- Fix i18n keys mismatch in OpenCodeFormFields (use opencode.* namespace)
- Fix unit test missing apps.opencode field assertion
Implement OpenCode-specific provider service logic with additive mode:
- add(): Always write to live config (no is_current check needed)
- update(): Always sync changes to live config
- delete(): Remove from both DB and live config (no is_current check)
New helper functions in live.rs:
- write_live_snapshot(): Write provider to opencode.json provider section
- remove_opencode_provider_from_live(): Remove provider from live config
- import_opencode_providers_from_live(): Import existing providers from
~/.config/opencode/opencode.json into CC Switch database
Key design: OpenCode uses additive mode where all providers coexist
in the config file, unlike Claude/Codex/Gemini which use replacement
mode with a single active provider.
Add OpenCode as the 4th supported application with additive provider management:
- Add OpenCode variant to AppType enum with all related match statements
- Add enabled_opencode field to McpApps and SkillApps structures
- Add opencode field to McpRoot and PromptRoot
- Add database schema migration v3→v4 with enabled_opencode columns
- Add settings.rs support for opencode_config_dir and current_provider_opencode
- Create opencode_config.rs module for config file I/O operations
- Update all services (proxy, mcp, skill, provider, stream_check) for OpenCode
- Add OpenCode support to deeplink provider and MCP parsing
- Update commands/config.rs for OpenCode config status and paths
Key design decisions:
- OpenCode uses additive mode (no is_current needed, no proxy support)
- Config path: ~/.config/opencode/opencode.json
- MCP format: stdio→local, sse/http→remote conversion planned
- Stream check returns error (not yet implemented for OpenCode)
* feat(deeplink): support comma-separated multiple endpoints in URL
Allow importing multiple API endpoints via single endpoint parameter.
First URL becomes primary endpoint, rest are added as custom endpoints.
* feat(deeplink): add usage query fields to deeplink generator
Add form fields for usage query configuration in deeplink HTML generator:
- usageEnabled, usageBaseUrl, usageApiKey
- usageScript, usageAutoInterval
- usageAccessToken, usageUserId
* fix(deeplink): auto-infer homepage and improve multi-endpoint display
- Auto-infer homepage from primary endpoint when not provided
- Display multiple endpoints as list in import dialog (primary marked)
- Update deeplink parser in deplink.html to show multi-endpoint info
- Add test for homepage inference from endpoint
- Minor log format fix in live.rs
* fix(deeplink): use primary endpoint for usage script base_url
- Fix usage_script.base_url getting comma-separated string when multiple endpoints
- Add i18n support for primary endpoint label in DeepLinkImportDialog
When users change app config directories (claudeConfigDir, codexConfigDir,
geminiConfigDir), MCP servers were being synced to the new paths but Skills
were not. This adds Skill synchronization to sync_current_to_live() to ensure
installed Skills are also copied to the new app directories.
- Replace global `is_empty_for_first_import()` with independent checks:
- `is_mcp_table_empty()` for MCP server imports
- `is_prompts_table_empty()` for prompt imports
- Skills and providers already have built-in idempotency checks
- Fix misleading logs in provider import:
- Change `import_default_config` return type from `Result<()>` to `Result<bool>`
- Return `true` when actually imported, `false` when skipped
- Only log success message when import actually occurred
- Add idempotency protection to `import_from_file_on_first_launch`
This allows each data type to be independently recovered if deleted,
rather than requiring all tables to be empty for any import to trigger.
Add recursive directory scanning to discover SKILL.md files in nested
directories. When a SKILL.md is found, treat sibling directories as
functional folders rather than separate skills.
Add get_effective_current_provider() to validate local settings ID
against database, with automatic cleanup and fallback to DB is_current.
This fixes edge cases in multi-device cloud sync scenarios where local
settings may contain stale provider IDs:
- current(): now returns validated effective provider ID
- update(): correctly syncs live config when local ID differs from DB
- delete(): checks both local settings and DB to prevent deletion
- switch(): backfill logic now targets valid provider
- sync_current_to_live(): uses validated ID with auto-fallback
- tray menu: displays correct checkmark on startup
Also fixes test issues:
- Add missing test setup calls (mutex, reset_test_fs, ensure_test_home)
- Correct Gemini security settings path to ~/.gemini/settings.json
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.
write_live_snapshot was incorrectly passing the already-extracted env
sub-field to json_to_env, which expects the full settings_config object.
This caused json_to_env to look for env.env (nested), returning an empty
HashMap and writing an empty .env file.
Fix by delegating to write_gemini_live which correctly handles env file
writing and security flag configuration in one place.
- Remove redundant security.auth.selectedType from CC Switch settings
- Fix Generic provider type not writing security flag on switch
- All non-Google Official providers now correctly write "gemini-api-key"
- Delete unused ensure_packycode_security_flag function
- Clean up SecuritySettings and SecurityAuthSettings types from AppSettings
Split the 1446-line services/provider.rs into 5 focused modules:
- gemini_auth.rs (250 lines): Gemini authentication type detection
- PackyCode, Google OAuth, and generic provider detection
- Security flag management for different auth types
- live.rs (300 lines): Live configuration operations
- LiveSnapshot backup/restore
- Reading and writing live config files
- Sync current provider to live config
- usage.rs (150 lines): Usage script execution
- Query and test usage scripts
- Format usage results
- Validate usage script configuration
- endpoints.rs (80 lines): Custom endpoints management
- CRUD operations for provider custom endpoints
- Last-used timestamp tracking
- mod.rs (650 lines): Core provider CRUD and service facade
- ProviderService struct with all public methods
- Provider add/update/delete/switch operations
- Claude model key normalization
- Credential extraction and validation
All 107 tests pass. This improves maintainability by:
- Separating concerns into cohesive modules
- Making Gemini-specific logic easier to find and modify
- Reducing cognitive load when working on specific features