Commit Graph

900 Commits

  • 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(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): 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): 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(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
  • fix(skills): skip hidden directories when scanning for skills
    Filter out directories starting with '.' (e.g., .system) during skill
    scanning to avoid exposing internal system directories from Codex.
  • fix(prompts): change toggle color from blue to emerald
    Align with the app-wide Switch component color scheme for
    visual consistency across all toggle elements.
  • fix(prompts): unify add button style with other panels
    Replace circular orange icon button with ghost text button
    to match Skills and MCP panel styling.
  • fix(mcp): unify header buttons style with skills panel
    Changed MCP panel buttons to match Skills panel styling:
    - Replace circular orange icon button with ghost text button
    - Update button labels: "Import" → "Import Existing", add "Add MCP"
  • feat(mcp): add import button to import MCP servers from apps
    - Add import_mcp_from_apps command that reuses existing import logic
    - Add Import button in MCP panel header (consistent with Skills)
    - Fix import count to only return truly new servers (not already in DB)
    - Update translations for import success/no-import messages (zh/en/ja)
  • fix(skills): move import button to header for better discoverability
    - Add import button next to discover button in skills page header
    - Expose openImport method via UnifiedSkillsPanel ref
    - Show toast instead of dialog when no unmanaged skills found
    - Remove redundant buttons from empty state view
  • fix(ui): remove hover scale effect from skill cards
    The hover:scale-[1.01] effect caused cards to overflow their container
    boundaries. Keeping only hover:shadow-lg provides sufficient visual
    feedback without the overflow issue.
  • fix(skills): show loading indicator when refreshing discovery list
    Use isFetching instead of just isLoading to show the loading spinner.
    isLoading is only true on initial load, while isFetching is true
    during any fetch operation including refetch.
  • fix(skills): remove refresh button from installed skills panel
    The refresh button is only needed in the discovery panel (to fetch
    latest skills from GitHub). The installed skills panel uses local
    database which auto-updates on install/uninstall operations.
  • fix(i18n): rename Skills title to be app-agnostic
    - Remove "Claude" prefix from Skills management title
    - Update descriptions to include Gemini alongside Claude Code/Codex
    - Applied to all three locales: zh, en, ja
  • perf(skills): use infinite cache for discoverable skills
    Change staleTime from 5 minutes to Infinity. Cache is still properly
    invalidated when repos are added/removed or skills are installed/uninstalled.
  • fix(ui): align FullScreenPanel header with App.tsx layout
    - Use same DRAG_BAR_HEIGHT (28px) and HEADER_HEIGHT (64px) as App.tsx
    - Remove border-b divider line from header
    - Add rounded-lg class to back button for consistency
  • fix(skills): remove redundant navigation buttons in skills pages
    - Remove duplicate "Repo Manager" button from installed skills view
      (should only appear in discovery view)
    - Remove redundant back button from SkillsPage component
      (header already provides unified navigation)
    - Clean up unused openRepoManagerOnDiscovery state and related useEffect
    - Remove unused onClose prop and ArrowLeft import from SkillsPage
  • feat(skills): unified management architecture with SSOT and React Query
    - Introduce SSOT (Single Source of Truth) at ~/.cc-switch/skills/
    - Add three-app toggle support (Claude/Codex/Gemini) for each skill
    - Refactor frontend to use TanStack Query hooks instead of manual state
    - Add UnifiedSkillsPanel for managing installed skills with app toggles
    - Add useSkills.ts with declarative data fetching hooks
    - Extend skills.ts API with unified install/uninstall/toggle methods
    - Support importing unmanaged skills from app directories
    - Add v2→v3 database migration for new skills table structure
  • fix: prevent env check card border overflow on hover
    Add horizontal padding to the grid container to accommodate the scale
    transform effect when hovering over environment check cards.
  • Feat/usage improvements (#508)
    * i18n: update cache terminology across all languages
    
    - Change 'Cache Read' to 'Cache Hit' in all languages
    - Change 'Cache Write' to 'Cache Creation' in all languages
    - Update zh: 缓存读取 → 缓存命中, 缓存写入 → 缓存创建
    - Update en: Cache Read → Cache Hit, Cache Write → Cache Creation
    - Update ja: キャッシュ読取 → キャッシュヒット, キャッシュ書込 → キャッシュ作成
    
    Affected keys: cacheReadTokens, cacheCreationTokens, cacheReadCost,
    cacheWriteCost, cacheRead, cacheWrite
    
    * feat(usage): add cache metrics to trend chart
    
    - Add cache creation tokens visualization (orange line)
    - Add cache hit tokens visualization (purple line)
    - Add gradient definitions for new cache metrics
    - Include cache data in hourly aggregation
    - Display cache metrics alongside input/output tokens
    
    This provides better visibility into cache usage patterns over time.
    
    * fix(usage): fix timezone handling in datetime picker
    
    - Add timestampToLocalDatetime() to convert Unix timestamp to local datetime
    - Add localDatetimeToTimestamp() with validation for incomplete input
    - Fix issue where typing hours/minutes would jump to previous day
    - Validate datetime format completeness before conversion
    - Use local timezone instead of UTC for datetime-local input
    
    This resolves the issue where users couldn't fine-tune time selection
    and the input would jump unexpectedly when editing hours or minutes.
    
    * feat(usage): add auto-refresh for usage statistics
    
    - Add 30-second auto-refresh interval for all usage queries
    - Disable background refresh to save resources
    - Apply to: summary, trends, provider stats, model stats, request logs
    - Queries automatically update when tab is active
    - Pause refresh when user switches to another tab
    
    This keeps usage data fresh without manual refresh.
    
    * fix(proxy): improve usage logging and cache token parsing
    
    - Log requests even when usage parsing fails (with default values)
    - Add detailed debug logging for usage metrics
    - Support cache_read_input_tokens field in Codex responses
    - Fallback to input_tokens_details.cached_tokens if needed
    - Add test case for cached_tokens in input_tokens_details
    - Ensure all requests are tracked in database for analytics
    
    This fixes missing request logs when API responses lack usage data
    and improves cache token detection across different response formats.
    
    * style(rust): use inline format args in format! macros
    
    - Replace format!("...", var) with format!("...{var}")
    - Update universal provider ID formatting
    - Update error message formatting
    - Update config.toml generation in Codex provider
    
    Fixes clippy::uninlined_format_args warnings.
    
    * feat(proxy): enhance provider router logging
    
    - Add debug logs for failover queue provider count
    - Log circuit breaker state for each provider check
    - Add logs for missing current provider scenarios
    - Log when no current provider is configured
    - Use inline format args for better readability
    
    This improves debugging of provider selection and failover behavior.
    
    * feat(database): update model pricing data
    
    - Update Claude models to full version format (e.g. claude-opus-4-5-20251101)
    - Add GPT-5.2 series model pricing (10 models)
    - Add GPT-5.1 series model pricing (10 models)
    - Add GPT-5 series model pricing (12 models)
    - Add Gemini 3 series model pricing (2 models)
    - Update Gemini 2.5 series model ID format (use dot separator)
    - Unify display names by removing thinking level suffixes
    
    * fix(usage): correct Gemini output token calculation
    
    Fix Gemini API output token parsing to use totalTokenCount - promptTokenCount
    instead of candidatesTokenCount alone. This ensures thoughtsTokenCount is
    included in output statistics.
    
    - Update from_gemini_response to calculate output from total - input
    - Update from_gemini_stream_chunks with same logic for consistency
    - Fix from_codex_stream_events to use adjusted token calculation
    - Add test case for responses with thoughtsTokenCount
    - Update existing tests to match new calculation logic
    
    * fix(usage): correct cache token billing and add Codex format auto-detection
    
    - Avoid double-billing cache tokens by subtracting from input before calculation
    - Add smart Codex parser that auto-detects OpenAI vs Codex API format
    - Extract model name from Codex responses for accurate tracking
    
    * fix(proxy): improve takeover detection with live config check
    
    - Add live config takeover detection for hot-switch decision
    - Rebuild takeover when backup is missing or placeholder remains
    - Make detect_takeover_in_live_config_for_app public
    - Fix is_takeover_active to use actual takeover status
    
    * refactor(usage): simplify model pricing lookup by removing suffix fallback
    
    Replace complex suffix-stripping fallback with direct prefix/suffix cleanup.
    Model IDs are now cleaned by removing vendor prefix (before /) and colon
    suffix (after :), then matched exactly against pricing table.
    
    * feat(database): add Chinese AI model pricing data
    
    Add pricing for domestic AI models (CNY/1M tokens):
    - Doubao-Seed-Code (ByteDance)
    - DeepSeek V3/V3.1/V3.2
    - Kimi K2/K2-Thinking/K2-Turbo (Moonshot)
    - MiniMax M2/M2.1/M2.1-Lightning
    - GLM-4.6/4.7 (Zhipu)
    - Mimo V2 Flash (Xiaomi)
    
    Also fix test case to use correct model ID and remove invalid currency column.
    
    * refactor(proxy): improve header forwarding with blacklist approach
    
    Change from whitelist to blacklist mode for request header forwarding.
    Only skip headers that will be overridden (auth, host, content-length).
    This preserves client's original headers and improves compatibility.
    
    * fix(proxy): bypass timeout and retry configs when failover is disabled
    
    When auto_failover_enabled is false, timeout and retry configurations
    should not affect normal request flow. This change ensures:
    
    - create_forwarder: passes 0 for all timeout/retry params when failover
      is disabled, effectively bypassing these checks
    - streaming_timeout_config: returns 0 for both first_byte_timeout and
      idle_timeout when failover is disabled
    
    This prevents unnecessary timeout errors and retry attempts when users
    have explicitly disabled the failover feature.
    
    * fix(proxy): handle zero value input in failover config fields
    
    * refactor(proxy): remove retry logic and add enabled check for failover
    
    * refactor(proxy): distinguish circuit-open from no-provider errors
    
    * Align usage stats to sliding windows
    
    * feat(proxy): add body and header filtering for upstream requests
    
    * feat(proxy): enable transparent passthrough for headers
    
    - Passthrough anthropic-beta header as-is from client
    - Passthrough anthropic-version header from client
    - Passthrough client IP headers (x-forwarded-for, x-real-ip) by default
    - Filter private params (underscore-prefixed fields) from request body
    - No database changes required
    
    * feat(proxy): extract session ID from client requests for logging
    
    - Add SessionIdExtractor to parse session ID from Claude/Codex requests
    - Support extraction from metadata.user_id, headers, previous_response_id
    - Pass session_id through RequestContext to usage logger
    - Enable request correlation by session in proxy_request_logs