CodeVetter · Repo Unpack · Behavior traces
farion1231/cc-switch
Three flows dominate daily use: process startup (DB open, crash recovery, proxy restore, then the React shell), an exclusive provider switch (backfill then atomic live write, or a proxy hot-switch), and proxy takeover (backup live config, point the CLI at localhost, route through ProviderRouter). Deep-link import and usage-script execution are the two untrusted-input paths that still end in the same database and live-file writers.
- Startup, backend: main sets Linux WebKit vars; run() installs the panic hook; setup refreshes the app-config-dir Store override, starts the log plugin at ~/.cc-switch/logs/cc-switch.log (20 MiB, KeepSome 4), installs the rustls ring provider, opens or migrates cc-switch.db from legacy config.json, and if user_version is newer than the binary records kind db_version_too_new instead of applying DDL.
- Startup, after the DB is up: a background task checks has_any_live_backup and detect_takeover_in_live_configs; if either is set it calls proxy_service.recover_from_crash. It then scrubs leaked Gemini common-config credentials, initialize_common_config_snippets, restore_proxy_state_on_startup, runs periodic_backup_if_needed, and arms a 24-hour backup timer plus the 60-second session sync loop. Silent startup hides the main window and, on Windows, sets skip_taskbar.
- Startup, renderer: main.tsx installs global error handlers, listens for configLoadError, then bootstrap() invokes get_init_error. kind db_version_too_new renders DatabaseUpgrade and returns. Any other path/error shows a dialog and calls plugin-process exit(1). Otherwise it mounts QueryClientProvider, ThemeProvider, UpdateProvider, and App, then fires syncModelsDevPricingOnStartup.
- Exclusive provider switch: UI calls providersApi.switch; switch_provider spawn_blocking calls ProviderService::switch; if not taken over, switch_normal backfills via read_live_settings and save_provider, writes the target with write_live helpers, syncs MCP when not in takeover, and returns SwitchResult.warnings (for example backfill_failed:<id>). The UI may then apply Claude plugin config when enableClaudePluginIntegration is on and refresh the tray.
- Proxy takeover switch: set_proxy_takeover_for_app enables takeover for one app. Later switch_provider sees the backup or live placeholder, refuses unsupported official targets, and calls hot_switch_provider_inner so the proxy's current provider map changes while live files stay pointed at the local listener. Stopping the process with stop_proxy_server errors if any takeover flag remains; stop_proxy_with_restore is the path that puts the original live files back.
- Normal live persistence for Codex is write_codex_live_atomic to ~/.codex/config.toml and auth.json, plus an optional model-catalog sidecar that is never inlined into those files. Claude writes settings JSON through the shared atomic writer. Gemini writes .env and patches security.auth.selectedType in ~/.gemini/settings.json without dropping other keys. Grok writes ~/.grok/config.toml.
- Deep-link flow: OS or second-instance argv hits handle_deeplink_url; parse_deeplink_url fills DeepLinkImportRequest; the webview receives deeplink-import; the user confirms in DeepLinkImportDialog; import commands (import_from_deeplink, import_from_deeplink_unified, merge_deeplink_config) write the provider, MCP, prompt, or skill through the same services as the UI. usageEnabled must be explicitly true before a carried usage script is treated as enabled.
- Usage query flow: the provider card calls queryProviderUsage or testUsageScript; execute_usage_script builds a sandboxed QuickJS runtime, evals user code to a request config, Rust issues the HTTP request, then the extractor function maps the response JSON. A 5-second interrupt handler aborts runaway scripts.
- Failover flow: an upstream failure is recorded on the per-provider CircuitBreaker inside ProviderRouter. When auto_failover_enabled is set, select_providers walks the failover queue and skips open circuits. FailoverSwitchManager dedupes concurrent promotions and emits UI plus tray updates. Codex official cards stay a single route even if failover was left on.
- Tray switch: update_tray_menu rebuilds the menu from AppState via tray::create_tray_menu and set_menu on tray id TRAY_ID. Menu text follows the same locale order as the renderer (zh-TW, zh, ja, en, default zh). Provider-switched events from the backend are subscribed in providersApi.onSwitched.