Commit Graph

924 Commits

  • Feat/deeplink multi endpoints (#597)
    * 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
  • Merge tianrking/main: feat: add provider-specific terminal button
    Merged PR #452 which adds:
    - Terminal button for Claude providers to launch with provider-specific config
    - Cross-platform support (macOS/Linux/Windows)
    - Auto-cleanup of temporary config files
  • fix(deeplink): prioritize GOOGLE_GEMINI_BASE_URL over GEMINI_BASE_URL
    When merging Gemini config from local env file during deeplink import,
    check GOOGLE_GEMINI_BASE_URL first (official variable name) before
    falling back to GEMINI_BASE_URL.
  • fix(mcp): skip cmd /c wrapper for WSL target paths (#592)
    * fix(mcp): skip cmd /c wrapper for WSL target paths
    
    When the Claude config directory is set to a WSL network path
    (e.g., \wsl$\Ubuntu\home\user\.claude), the MCP export should
    not wrap npx/npm commands with cmd /c since WSL runs Linux.
    
    - Add is_wsl_path() to detect \wsl$\ and \wsl.localhost\ paths
    - Skip wrap_command_for_windows() when target is WSL path
    - Add comprehensive tests for various WSL distributions
    
    * chore(mcp): add debug log for WSL path detection
    
    * refactor(mcp): optimize is_wsl_path with next() and rename variable
  • Refactor/simplify proxy logs (#585)
    * refactor(proxy): simplify logging for better readability
    
    - Delete 17 verbose debug logs from handlers, streaming, and response_processor
    - Convert excessive INFO logs to DEBUG level for internal processing details
    - Add 2 critical INFO logs in forwarder.rs for failover scenarios:
      - Log when switching to next provider after failure
      - Log when all providers have been exhausted
    - Fix clippy uninlined_format_args warning
    
    This reduces log noise while maintaining visibility into key user-facing decisions.
    
    * fix: replace unsafe unwrap() calls with proper error handling
    
    - database/dao/mcp.rs: Use map_err for serde_json serialization
    - database/dao/providers.rs: Use map_err for settings_config and meta serialization
    - commands/misc.rs: Use expect() for compile-time regex pattern
    - services/prompt.rs: Use unwrap_or_default() for SystemTime
    - deeplink/provider.rs: Replace unwrap() with is_none_or pattern for Option checks
    
    Reduces potential panic points from 26 to 1 (static regex init, safe).
    
    * refactor(proxy): simplify verbose logging output
    
    - Remove response JSON full output logging in response_processor
    - Remove per-request INFO logs in provider_router (failover status, provider selection)
    - Change model mapping log from INFO to DEBUG
    - Change usage logging failure from INFO to WARN
    - Remove redundant debug logs for circuit breaker operations
    
    Reduces log noise significantly while preserving important warnings and errors.
    
    * feat(proxy): add structured log codes for i18n support
    
    Add error code system to proxy module logs for multi-language support:
    
    - CB-001~006: Circuit breaker state transitions and triggers
    - SRV-001~004: Proxy server lifecycle events
    - FWD-001~002: Request forwarding and failover
    - FO-001~005: Failover switch operations
    - USG-001~002: Usage logging errors
    
    Log format: [CODE] Chinese message
    Frontend/log tools can map codes to any language.
    
    New file: src/proxy/log_codes.rs - centralized code definitions
    
    * chore: bump version to 3.9.1
    
    * style: format code with prettier and rustfmt
    
    * fix(ui): allow number inputs to be fully cleared before saving
    
    - Convert numeric state to string type for controlled inputs
    - Use isNaN() check instead of || fallback to allow 0 values
    - Apply fix to ProxyPanel, CircuitBreakerConfigPanel,
      AutoFailoverConfigPanel, and ModelTestConfigPanel
    
    * feat(pricing): support @ separator in model name matching
    
    - Refactor model name cleaning into chained method calls
    - Add @ to - replacement (e.g., gpt-5.2-codex@low → gpt-5.2-codex-low)
    - Add test case for @ separator matching
    
    * fix(proxy): improve validation and error handling in proxy config panels
    
    - Add StopTimeout/StopFailed error types for proper stop() error reporting
    - Replace silent clamp with validation-and-block in config panels
    - Add listenAddress format validation in ProxyPanel
    - Use log_codes constants instead of hardcoded strings
    - Use once_cell::Lazy for regex precompilation
    
    * fix(proxy): harden error handling and input validation
    
    - Handle RwLock poisoning in settings.rs with unwrap_or_else
    - Add fallback for dirs::home_dir() in config modules
    - Normalize localhost to 127.0.0.1 in ProxyPanel
    - Format IPv6 addresses with brackets for valid URLs
    - Strict port validation with pure digit regex
    - Treat NaN as validation failure in config panels
    - Log warning on cost_multiplier parse failure
    - Align timeoutSeconds range to [0, 300] across all panels
  • fix(live): sync skills to app directories on config path change
    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.
  • fix(provider-form): reset baseUrl and apiKey states when switching presets
    Fix state synchronization in useBaseUrlState and useApiKeyState hooks
    to properly clear values when config is reset. Previously, when switching
    from a preset to "custom", the baseUrl and apiKey states would retain
    their old values because the sync logic only updated when new values
    existed, not when they were cleared.
    
    Changes:
    - useBaseUrlState: Always sync baseUrl to config value (empty if undefined)
    - useApiKeyState: Remove hasApiKeyField check that prevented clearing
  • fix(usage): prevent usage script config from leaking between providers
    Add key prop to UsageScriptModal to ensure component remounts when
    switching between different providers. This fixes issue #569 where
    configuring usage query for one provider would incorrectly apply
    the same configuration to all providers.
    
    The root cause was that useState initialization only runs on first
    mount, and due to useLastValidValue hook keeping the modal rendered
    during close animation, the component might not fully unmount when
    switching providers rapidly.
    
    Closes #569
  • refactor(proxy): disable OpenRouter compat mode by default and hide UI toggle
    OpenRouter now natively supports Claude Code compatible API (/v1/messages),
    so format transformation (Anthropic ↔ OpenAI) is no longer needed by default.
    
    - Change default value from `true` to `false` in both frontend and backend
    - Hide the "OpenRouter Compatibility Mode" toggle in provider form
    - Users can still enable it manually by adding `"openrouter_compat_mode": true` in config JSON
    - Update unit tests to reflect new default behavior
  • fix(gemini): convert timeout params to Gemini CLI format (#580)
    Claude Code/Codex uses startup_timeout_sec and tool_timeout_sec,
    but Gemini CLI only supports a single timeout param in milliseconds.
    
    - Collect startup and tool timeout separately with defaults
      - startup_timeout_sec default: 10s
      - tool_timeout_sec default: 60s
    - Take max of both values as final timeout
    - Support both sec and ms variants
    - Remove original fields and insert Gemini-compatible timeout
  • fix(ci): temporarily remove Flatpak build
    Flatpak build has persistent issues with libdbusmenu dependencies.
    Removing it for now to allow release. Can be re-added later with
    proper libayatana dependency configuration.
  • fix(flatpak): remove --enable-tests=no to fix HAVE_VALGRIND error
    libdbusmenu's configure.ac has a bug where AM_CONDITIONAL([HAVE_VALGRIND])
    is only defined when tests are enabled. Removing --enable-tests=no allows
    the conditional to be properly defined.
    
    Ref: https://bugs.launchpad.net/ubuntu/+source/libdbusmenu/+bug/1708938
  • fix(flatpak): bundle intltool for libdbusmenu build
    intltool was removed from org.gnome.Sdk in 2019. libdbusmenu's configure
    script requires it even with --disable-nls. Using cleanup: ["*"] ensures
    intltool is only used at build time.
  • fix(flatpak): disable NLS for libdbusmenu-gtk3
    The Flatpak SDK lacks intltool, causing libdbusmenu-gtk3 configure to
    fail. Disabling NLS avoids this dependency.
  • fix(ci): add elfutils for Flatpak build
    The libayatana modules added in 2923627b require eu-strip to strip
    debug symbols during flatpak-builder execution.
  • chore: bump version to v3.9.1
    - Update version in package.json, tauri.conf.json, Cargo.toml
    - Update version badges and current version in README files
    - Add v3.9.1 changelog entry with bug fixes and improvements
  • fix(presets): rename AiGoCode to AIGoCode
    Update the display name casing for AIGoCode across all provider presets
    and i18n files to match their official branding.
  • fix(windows): correct window title and remove extra titlebar spacing
    - Add missing "title" field to tauri.windows.conf.json to display
      "CC Switch" instead of default "Tauri app"
    - Make DRAG_BAR_HEIGHT platform-aware: 0px on Windows/Linux (native
      titlebar), 28px on macOS (Overlay mode needs traffic light space)
    - Apply same fix to FullScreenPanel component for consistency
    
    Fixes the issue where Windows showed wrong title and had ~28px extra
    blank space below the native titlebar introduced in v3.9.0.
  • feat(presets): add AiGoCode icon and partner promotion
    - Add AiGoCode colored icon (blue body #5B7FFF, purple star #7C6AEF)
    - Add original SVG source file for reference
    - Add icon metadata with keywords and default color
    - Add iconColor to AiGoCode presets for Claude, Codex, and Gemini
    - Add partner promotion messages in zh/en/ja locales
  • feat(logging): add crash logging and improve log management (#562)
    * feat(logging): add crash logging and improve log management
    
    - Add panic hook to capture crash info to ~/.cc-switch/crash.log
      - Records timestamp, app version, OS/arch, thread info
      - Full stack trace with force_capture for release builds
      - Safe error handling (no nested panics)
    
    - Enable logging for both Debug and Release builds
      - Info level for all builds
      - Output to console and ~/.cc-switch/logs/
      - 5MB max file size with rotation
    
    - Add log cleanup on startup
      - Keep only 2 most recent log files
      - Works on all platforms
    
    - Change panic strategy from "abort" to "unwind"
      - Required for backtrace capture in release builds
    
    * fix(logging): use OnceLock for config dir and add URL redaction
    
    - Use OnceLock to support custom config directory override for crash.log
    - Add redact_url_for_log() to protect sensitive URL parameters in logs
    - Change verbose deep link logs from info to debug level
    - Move Store refresh before panic_hook init to ensure correct path
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • Fix/Resolve panic issues in proxy-related code (#560)
    * fix(proxy): change default port from 5000 to 15721
    
    Port 5000 conflicts with AirPlay Receiver on macOS 12+.
    Also adds error handling for proxy toggle and i18n placeholder updates.
    
    * fix(proxy): replace unwrap/expect with graceful error handling
    
    - Handle HTTP client initialization failure with no_proxy fallback
    - Fix potential panic on Unicode slicing in API key preview
    - Add proper error handling for response body builder
    - Handle edge case where SystemTime is before UNIX_EPOCH
    
    * fix(proxy): handle UTF-8 char boundary when truncating request body log
    
    Rust strings are UTF-8 encoded, slicing at a fixed byte index may cut
    in the middle of a multi-byte character (e.g., Chinese, emoji), causing
    a panic. Use is_char_boundary() to find the nearest safe cut point.
    
    * fix(proxy): improve robustness and prevent panics
    
    - Add reqwest socks feature to support SOCKS proxy environments
    - Fix UTF-8 safety in masked_key/masked_access_token (use chars() instead of byte slicing)
    - Fix UTF-8 boundary check in usage_script HTTP response truncation
    - Add defensive checks for JSON operations in proxy service
    - Remove verbose debug logs that could trigger panic-prone code paths
  • fix(flatpak): bundle libayatana-appindicator for tray icon support (#556)
    The Flatpak was failing to load because libayatana-appindicator3 is not
    included in org.gnome.Platform runtime. This adds the required modules:
    - libayatana-ido
    - libdbusmenu-gtk3
    - libayatana-indicator
    - libayatana-appindicator
    
    Fixes panic: 'Failed to load ayatana-appindicator3 or appindicator3 dynamic library'
    
    Co-authored-by: Said John <said.john@gmail.com>
  • docs: update v3.9.0 release notes with acknowledgments and improved macOS instructions
    - Add special thanks section for contributors @xunyu @deijing @su-fen
    - Update macOS tip: replace xattr command with System Settings GUI guidance
    - Reformat markdown tables with aligned columns
    - Move Linux section after Homebrew section
  • docs: enhance download section with detailed installation guide for v3.9.0
    - Convert system requirements to table format with architecture info
    - Add Windows/macOS file descriptions with recommended options
    - Replace Linux section with comprehensive distro-based table
    - Include complete installation commands for deb/rpm/AppImage/flatpak
    - Add helpful tips for macOS Gatekeeper and AppImage usage
  • docs: add download options for each system version in 3.9.0 release note (#547)
    * docs: add download options for each system version in 3.9.0 release note.
    
    * docs: add download options for each system version in 3.9.0 release note.
  • chore(release): prepare v3.9.0 stable release
    - Bump version from 3.9.0-3 to 3.9.0 across all config files
    - Add comprehensive release notes in English, Chinese, and Japanese
    - Update CHANGELOG with v3.9.0 stable and v3.9.0-2 entries
    - Update README badges and release note links to v3.9.0
  • feat(presets): add Cubence as partner provider
    - Add Cubence provider presets for Claude, Codex, and Gemini
    - Add Cubence icon to icon system
    - Add partner promotion text in zh/en/ja
  • docs: add Cubence as sponsor partner
    Add Cubence sponsor information to README in all three languages
    (English, Chinese, Japanese).
  • Feat/proxy header improvements (#538)
    * fix(proxy): improve header handling for Claude API compatibility
    
    - Streamline header blacklist by removing overly aggressive filtering
      (browser-specific headers like sec-fetch-*, accept-language)
    - Ensure anthropic-beta header always includes 'claude-code-20250219'
      marker required by upstream services for request validation
    - Centralize anthropic-version header handling in forwarder to prevent
      duplicate headers across different auth strategies
    - Add ?beta=true query parameter to /v1/messages endpoint for
      compatibility with certain upstream services (e.g., DuckCoding)
    - Remove redundant anthropic-version from ClaudeAdapter auth headers
      as it's now managed exclusively by the forwarder
    
    This improves proxy reliability with various Claude API endpoints
    and third-party services that have specific header requirements.
    
    * style(services): use inline format arguments in format strings
    
    Apply Rust 1.58+ format string syntax across provider and skill
    services. This replaces format!("msg {}", var) with format!("msg {var}")
    for improved readability and consistency with modern Rust idioms.
    
    Changed files:
    - services/provider/mod.rs: 1 format string
    - services/skill.rs: 10 format strings (error messages, log statements)
    
    No functional changes, purely stylistic improvement.
    
    * fix(proxy): restrict Anthropic headers to Claude adapter only
    
    - Move anthropic-beta and anthropic-version header handling inside
      Claude-specific condition to avoid sending unnecessary headers
      to Codex and Gemini APIs
    - Update test cases to reflect ?beta=true query parameter behavior
    - Add edge case tests for non-messages endpoints and existing queries
  • chore(presets): update model versions for provider presets
    Claude presets:
    - Zhipu GLM: glm-4.6 → glm-4.7
    - Z.ai GLM: glm-4.6 → glm-4.7
    - ModelScope: GLM-4.6 → GLM-4.7
    - MiniMax: MiniMax-M2 → MiniMax-M2.1
    
    Codex presets:
    - Azure, AiHubMix, DMXAPI, PackyCode: gpt-5.1-codex → gpt-5.2
    - Custom template: gpt-5-codex → gpt-5.2
  • fix(settings): navigate to About tab when clicking update badge
    - Add defaultTab prop to SettingsPage for external tab control
    - UpdateBadge click now opens settings directly to About tab
    - Settings button still opens to General tab (default behavior)
    - Change update badge text from version number to "Update available"
  • fix(prompts): allow saving prompts with empty content
    Remove content validation requirement to allow users to save prompts
    with empty content for placeholder or draft purposes.
  • fix(database): show error dialog on initialization failure with retry option
    - Add user-friendly dialog when database init or schema migration fails
    - Support retry mechanism instead of crashing the app
    - Include bilingual (Chinese/English) error messages with troubleshooting tips
    - Add comprehensive test for v3.8 → current schema migration path
  • feat(release): add RPM and Flatpak packaging support for Linux
    - Add RPM bundle to Linux build targets in CI workflow
    - Add Flatpak manifest, desktop entry, and AppStream metainfo
    - Update release workflow to build and publish .rpm and .flatpak artifacts
    - Update README docs with new Linux package formats and installation instructions
    - Add .gitignore rules for Flatpak build artifacts
  • refactor(settings): reorder advanced tab items for better UX
    Move Auto Failover section directly after Proxy section since they are
    functionally related (failover depends on proxy service).
  • fix(common): improve window dragging area in FullScreenPanel (#525)
    Add data-tauri-drag-region and WebkitAppRegion styles to header area to match	App.tsx behavior, ensuring proper window dragging on macOS.
  • chore(proxy): remove unused body filter helper
    Remove unused `filter_recursive` function from body_filter.rs to fix
    `dead-code` warning from `cargo clippy -- -D warnings`.
  • fix(proxy): clean up model override env vars when switching providers in takeover mode
    When proxy takeover is enabled, switching providers no longer writes to
    the Live config. However, if model override fields (ANTHROPIC_MODEL,
    ANTHROPIC_REASONING_MODEL, etc.) remain in the Live config, Claude Code
    continues sending requests with the old model name, causing failures
    when the new provider doesn't support that model.
    
    This fix:
    - Removes model override env keys from Claude Live config during takeover
    - Adds cleanup when switching providers in takeover mode
    - Fixes has_mapping() to include reasoning_model in the check
    - Adds test coverage for reasoning-only model mapping scenarios
  • fix(common-config): reset initialization flag when preset changes
    The common config checkbox was only auto-enabled for the first preset
    (custom) because hasInitializedNewMode ref was permanently locked to
    true after first initialization.
    
    Add selectedPresetId parameter to all three common config hooks and
    reset the initialization flag when preset changes, allowing the
    initialization logic to re-run for each preset switch.
  • fix(codex): remove entire model_providers table from common config extraction
    Previously only removed base_url from model_providers.* tables. Now removes
    the entire model_providers section since all its fields (name, base_url,
    wire_api, requires_openai_auth) are provider-specific configuration.
    
    MCP servers configuration remains preserved as it's provider-agnostic.
  • refactor(common-config): extract snippet from editor content instead of active provider
    - Change extraction source from current active provider to editor's live content
    - Add i18n support for JSON parse error messages via invalid_json_format_error()
    - Simplify API by removing unused providerId parameter
    - Update button labels and error messages in zh/en/ja locales
  • fix(codex): prevent extract_common_config from removing MCP servers' base_url
    - Replace regex patterns with toml_edit for precise field removal
    - Only remove top-level model/model_provider/base_url fields
    - Only remove base_url from [model_providers.*] tables
    - Add regression test to ensure [mcp_servers.*] base_url is preserved
  • feat(common-config): add extract from current provider functionality
    - Add backend command to extract common config snippet from current provider
    - Automatically extract common config on first run after importing default provider
    - Auto-enable common config checkbox in new provider mode when snippet exists
    - Refactor Gemini common config to operate on .env instead of config.json
    - Add "Extract from Current" button to all three common config modals
    - Update i18n translations for new extraction feature
  • feat(proxy): update failover timeout and circuit breaker defaults (#521)
    - Double all timeout values (streaming/non-streaming)
    - Codex/Gemini: circuit_failure_threshold 5→4, error_rate 0.5→0.6
    - Claude: circuit_error_rate_threshold 0.6→0.7
  • Merge origin/main into main
    Resolved conflict in src-tauri/src/commands/misc.rs by combining imports from both sides.
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude <noreply@anthropic.com>