Commit Graph

831 Commits

  • feat(ui): add exit animation to FullScreenPanel dialogs
    - Wrap FullScreenPanel content with AnimatePresence for exit animation
    - Add exit={{ opacity: 0 }} to enable fade-out on close
    - Use useRef + useEffect to preserve provider data during exit animation
    - Follow React best practices by updating refs in useEffect instead of render
    
    Affected components:
    - EditProviderDialog
    - UsageScriptModal
    - AddProviderDialog
    - McpFormModal
    - ProxySettingsDialog
  • fix(ui): reduce header spacing and fix layout shift on view switch
    - Change right-side button container from min-h-[40px] to h-[32px]
      for more compact header layout
    - Remove conditional padding (pt-6/pt-4) from main content area
      to eliminate layout jump during view transitions
  • Feat/auto failover switch (#440)
    * feat(failover): add auto-failover master switch with proxy integration
    
    - Add persistent auto_failover_enabled setting in database
    - Add get/set_auto_failover_enabled commands
    - Provider router respects master switch state
    - Proxy shutdown automatically disables failover
    - Enabling failover auto-starts proxy server
    - Optimistic updates for failover queue toggle
    
    * feat(proxy): persist proxy takeover state across app restarts
    
    - Add proxy_takeover_{app_type} settings for per-app state tracking
    - Restore proxy takeover state automatically on app startup
    - Preserve state on normal exit, clear on manual stop
    - Add stop_with_restore_keep_state method for graceful shutdown
    
    * fix(proxy): set takeover state for all apps in start_with_takeover
    
    * fix(windows): hide console window when checking CLI versions
    
    Add CREATE_NO_WINDOW flag to prevent command prompt from flashing
    when detecting claude/codex/gemini CLI versions on Windows.
    
    * refactor(failover): make auto-failover toggle per-app independent
    
    - Change setting key from 'auto_failover_enabled' to 'auto_failover_enabled_{app_type}'
    - Update provider_router to check per-app failover setting
    - When failover disabled, use current provider only; when enabled, use queue order
    - Add unit tests for failover enabled/disabled behavior
    
    * feat(failover): auto-switch to higher priority provider on recovery
    
    - After circuit breaker reset, check if recovered provider has higher priority
    - Automatically switch back if queue_order is lower (higher priority)
    - Stream health check now resets circuit breaker on success/degraded
    
    * chore: remove unused start_proxy_with_takeover command
    
    - Remove command registration from lib.rs
    - Add comment clarifying failover queue is preserved on proxy stop
    
    * feat(ui): integrate failover controls into provider cards
    
    - Add failover toggle button to provider card actions
    - Show priority badge (P1, P2, ...) for queued providers
    - Highlight active provider with green border in failover mode
    - Sync drag-drop order with failover queue
    - Move per-app failover toggle to FailoverQueueManager
    - Simplify SettingsPage failover section
    
    * test(providers): add mocks for failover hooks in ProviderList tests
    
    * refactor(failover): merge failover_queue table into providers
    
    - Add in_failover_queue field to providers table
    - Remove standalone failover_queue table and related indexes
    - Simplify queue ordering by reusing sort_index field
    - Remove reorder_failover_queue and set_failover_item_enabled commands
    - Update frontend to use simplified FailoverQueueItem type
    
    * fix(database): ensure in_failover_queue column exists for v2 databases
    
    Add column check in create_tables to handle existing v2 databases
    that were created before the failover queue refactor.
    
    * fix(ui): differentiate active provider border color by proxy mode
    
    - Use green border/gradient when proxy takeover is active
    - Use blue border/gradient in normal mode (no proxy)
    - Improves visual distinction between proxy and non-proxy states
    
    * fix(database): clear provider health record when removing from failover queue
    
    When a provider is removed from the failover queue, its health monitoring
    is no longer needed. This change ensures the health record is also deleted
    from the database to prevent stale data.
    
    * fix(failover): improve cache cleanup for provider health and circuit breaker
    
    - Use removeQueries instead of invalidateQueries when stopping proxy to
      completely clear health and circuit breaker caches
    - Clear provider health and circuit breaker caches when removing from
      failover queue
    - Refresh failover queue after drag-sort since queue order depends on
      sort_index
    - Only show health badge when provider is in failover queue
    
    * style: apply prettier formatting to App.tsx and ProviderList.tsx
    
    * fix(proxy): handle missing health records and clear health on proxy stop
    
    - Return default healthy state when provider health record not found
    - Add clear_provider_health_for_app to clear health for specific app
    - Clear app health records when stopping proxy takeover
    
    * fix(proxy): track actual provider used in forwarding for accurate logging
    
    Introduce ForwardResult and ForwardError structs to return the actual
    provider that handled the request. This ensures usage statistics and
    error logs reflect the correct provider after failover.
  • fix(ui): prevent header layout shift when switching views
    Add min-height to right-side button container and ml-auto to add buttons
    in MCP/Prompts views to maintain consistent header height and button
    position across all views.
  • feat(ui): add fade transition for view and panel switching
    Add smooth fade animations when navigating between views (Settings,
    MCP, Skills, Prompts) and opening full-screen panels (Add/Edit Provider).
  • feat: add provider search filter (#435)
    * feat: add provider search filter
    
    * feat: add provider search overlay
  • feat(failover): add auto-failover master switch with proxy integration (#427)
    * feat(failover): add auto-failover master switch with proxy integration
    
    - Add persistent auto_failover_enabled setting in database
    - Add get/set_auto_failover_enabled commands
    - Provider router respects master switch state
    - Proxy shutdown automatically disables failover
    - Enabling failover auto-starts proxy server
    - Optimistic updates for failover queue toggle
    
    * feat(proxy): persist proxy takeover state across app restarts
    
    - Add proxy_takeover_{app_type} settings for per-app state tracking
    - Restore proxy takeover state automatically on app startup
    - Preserve state on normal exit, clear on manual stop
    - Add stop_with_restore_keep_state method for graceful shutdown
    
    * fix(proxy): set takeover state for all apps in start_with_takeover
  • feat(ui): add fade transition for app switching
    - Add AnimatePresence + motion.div wrapper for provider list
    - Use key={activeApp} to trigger enter/exit animations on app switch
    - Remove redundant animate-slide-up from ProviderList to prevent
      animation conflicts and visual jitter
  • style(settings): unify tab transition animations
    Add framer-motion fade-in and slide-up animations to General and
    Advanced tabs, matching the existing Usage and About tab animations.
  • feat(settings): add option to skip Claude Code first-run confirmation
    Add a new setting to automatically skip Claude Code's onboarding screen
    by writing hasCompletedOnboarding=true to ~/.claude.json. The setting
    defaults to enabled for better user experience.
    
    - Add set/clear_has_completed_onboarding functions in claude_mcp.rs
    - Add Tauri commands and frontend API integration
    - Add toggle in WindowSettings with i18n support (en/zh/ja)
    - Fix hardcoded Chinese text in tests to use i18n keys
  • i18n: complete usage panel and settings internationalization
    - Add missing i18n keys for usage statistics panel (trends, cost, perMillion, etc.)
    - Add i18n keys for settings advanced section (configDir, proxy, modelTest, etc.)
    - Add streamCheck i18n keys for health check configuration
    - Remove hardcoded Chinese fallback values from t() calls
    - Add common keys (all, search, reset, actions, deleting)
  • i18n: complete internationalization for v3.8+ features
    - Add health status translations (operational, degraded, failed, circuitOpen)
    - Add proxy panel translations (serviceAddress, stats, stopped state)
    - Add usage filter translations (appType, statusCode, searchPlaceholder)
    - Add providerIcon click hints (clickToChange, clickToSelect)
    - Add config load error translations for main.tsx
    - Complete Japanese proxy section (failoverQueue, autoFailover)
    - Fix date/time locale in usage charts and tables
    - Use t() function in all hardcoded UI strings
  • style(switch): improve dark mode appearance
    - Track (unchecked): lighten in light mode (gray-300 → gray-200),
      darken in dark mode (gray-700 → gray-900) to blend with background
    - Thumb: soften in dark mode (white → gray-400) to reduce glare
  • fix(ui): improve text visibility in dark mode
    Replace hardcoded gray color classes with semantic color classes
    to fix poor text contrast in dark mode:
    
    - MCP panel: server names, descriptions, tags, app labels
    - Prompt panel: prompt names, descriptions, empty states
    - Usage footer: timestamps, refresh buttons
    - Update badge: close button icon
    - API key input: disabled state text
    - Env warning banner: source info text
    
    Changes:
    - `text-gray-400 dark:text-gray-500` → `text-muted-foreground`
      (fixes reversed dark mode logic)
    - `text-gray-500 dark:text-gray-400` → `text-muted-foreground`
    - `bg-gray-100 dark:bg-gray-800` → `bg-muted`
  • chore: bump version to 3.9.0-2 for second test release
    - Update version in package.json, Cargo.toml, tauri.conf.json
    - Fix clippy too_many_arguments warning in forwarder.rs
  • style(header): unify height and styling of header toolbar sections
    - Use consistent h-8 fixed height for all inner elements
    - Standardize border-radius to rounded-xl across all sections
    - Remove background from ProxyToggle for cleaner appearance
    - Simplify ProxyToggle structure with nested container
  • feat(providers): add DMXAPI as official partner
    Mark DMXAPI as partner in both Claude and Codex presets with promotion
    message for their Claude Code exclusive model 66% OFF offer.
  • feat(icons): add provider icons for OpenRouter, LongCat, ModelScope, AiHubMix
    - Add SVG icons for OpenRouter, LongCat, ModelScope, and AiHubMix
    - Register icons in index.ts and metadata.ts with search keywords
    - Link icons to corresponding provider presets in claudeProviderPresets.ts
  • refactor(proxy): switch OpenRouter to passthrough mode for native Claude API
    OpenRouter now supports Claude Code compatible endpoint (/v1/messages),
    eliminating the need for Anthropic ↔ OpenAI format conversion.
    
    - Disable format transformation for OpenRouter (keep old logic as fallback)
    - Pass through original endpoint instead of redirecting to /v1/chat/completions
    - Add anthropic-version header for ClaudeAuth and Bearer strategies
    - Update tests to reflect new passthrough behavior
  • fix(window): add minWidth/minHeight to Windows platform config
    Tauri 2.0 platform config merging is shallow, not deep. The Windows
    config only specified titleBarStyle, causing minWidth/minHeight to
    be missing on Windows. This allowed users to resize the window below
    900px, causing header elements to misalign.
  • fix(proxy): respect existing token field when syncing Claude config
    - Add support for ANTHROPIC_API_KEY in Claude auth extraction
    - Only update existing token fields during sync, avoid adding fields
      that weren't originally configured by the user
    - Add tests for both scenarios
  • fix(proxy): add fallback recovery for orphaned takeover state
    - Detect takeover residue in Live configs even when proxy is not running
    - Implement 3-tier fallback: backup → SSOT → cleanup placeholders
    - Only delete backup after successful restore to prevent data loss
    - Fix EditProviderDialog to check current app's takeover status only
  • refactor(proxy): remove global auto-start flag
    - Remove global proxy auto-start flag from config and UI.
    - Simplify per-app takeover start/stop and stop server when the last takeover is disabled.
    - Restore live takeover detection used for crash recovery.
    - Keep proxy_config.enabled column but always write 0 for compatibility.
    - Tests: not run (not requested).
  • fix(import): refresh all providers immediately after SQL import
    - Remove setTimeout delay that could be cancelled on component unmount
    - Invalidate all providers cache (not just current app) since import affects all apps
    - Call onImportSuccess before sync to ensure UI refresh even if sync fails
    - Update i18n: "Data refreshed" (past tense, reflecting immediate action)
  • fix(backup): restrict SQL import to CC Switch exported backups only
    - Add validation to reject SQL files without CC Switch export header
    - Remove redundant sanitize_import_sql (sqlite_* objects already excluded at export time)
    - Fix backup filename collision by appending counter suffix
    - Update i18n hints to clarify import restriction
  • Fix/about section UI (#419)
    * fix(ui): improve AboutSection styling and version detection
    
    - Add framer-motion animations for smooth page transitions
    - Unify button sizes and add icons for consistency
    - Add gradient backgrounds and hover effects to cards
    - Add notInstalled i18n translations (zh/en/ja)
    - Fix version detection when stdout/stderr is empty
    
    * fix(proxy): persist per-app takeover state across app restarts
    
    - Fix proxy toggle color to reflect current app's takeover state only
    - Restore proxy service on startup if Live config is still in takeover state
    - Preserve per-app backup records instead of clearing all on restart
    - Only recover Live config when proxy service fails to start
  • chore: rename version to 3.9.0-1 for MSI compatibility
    MSI installer requires numeric-only pre-release identifiers.
    Changed from 3.9.0-beta.1 to 3.9.0-1.
  • fix: import RunEvent for all platforms
    The #[cfg(target_os = "macos")] restriction was a historical artifact
    from when RunEvent was only used for macOS-specific events (Reopen, Opened).
    After c9ea13a added ExitRequested handling for all platforms, the import
    should have been updated but was overlooked.
  • chore: bump version to 3.9.0-beta.1
    - Update version in package.json, Cargo.toml, tauri.conf.json
    - Add CHANGELOG entry for v3.9.0-beta.1 with:
      - Local Proxy Server feature
      - Auto Failover with circuit breaker
      - Skills multi-app support
      - Provider icon colors
      - 25+ bug fixes
    - Add proxy feature guide documentation (Chinese)
  • fix(ui): restore fade transition for Skills button
    The Skills button transition was accidentally removed in commit 1fb2d5e
    when adding multi-app support. This restores the smooth fade-in/out
    animation when switching between apps that support Skills (Claude/Codex)
    and those that don't (Gemini).
  • fix(mcp): skip sync when target CLI app is not installed
    Add guard functions to check if Claude/Codex/Gemini CLI has been
    initialized before attempting to sync MCP configurations. This prevents
    creating unwanted config files in directories that don't exist.
    
    - Claude: check ~/.claude dir OR ~/.claude.json file exists
    - Codex: check ~/.codex dir exists
    - Gemini: check ~/.gemini dir exists
    
    When the target app is not installed, sync operations now silently
    succeed without writing any files, allowing users to manage MCP servers
    for apps they actually use without side effects on others.
  • fix(mcp): improve upsert and import robustness
    - Remove server from live config when app is disabled during upsert
    - Merge enabled flags instead of overwriting when importing from multiple apps
    - Normalize Gemini MCP type field (url-only → sse, command → stdio)
    - Use atomic write for Codex config updates
    - Add tests for disable-removal, multi-app merge, and Gemini SSE import
  • feat(proxy): implement per-app takeover mode
    Replace global live takeover with granular per-app control:
    - Add start_proxy_server command (start without takeover)
    - Add get_proxy_takeover_status to query each app's state
    - Add set_proxy_takeover_for_app for individual app control
    - Use live backup existence as SSOT for takeover state
    - Refactor sync_live_to_provider to eliminate code duplication
    - Update ProxyToggle to show status per active app
  • fix(proxy): takeover Codex base_url via model_provider
    - Update Codex `model_providers.<model_provider>.base_url` to the proxy origin with `/v1`
    - Add route fallbacks for `/responses` and `/chat/completions` (plus double-`/v1` safeguard)
    - Add unit tests for the TOML base_url takeover logic
  • fix(proxy): harden crash recovery with fallback detection
    - Set takeover flag before writing proxy config to fix race condition
      where crash during takeover left Live configs corrupted but flag unset
    - Add fallback detection by checking for placeholder tokens in Live
      configs when backups exist but flag is false (handles legacy/edge cases)
    - Improve error handling with proper rollback at each stage of startup
    - Clean up stale backups when Live configs are not in takeover state
      to avoid long-term storage of sensitive tokens
  • fix(proxy): sync UI when active provider differs from current setting
    Previously, UI sync was triggered only when failover happened (retry count > 1).
    This missed cases where the first provider in the failover queue succeeded but
    was different from the user's selected provider in settings.
    
    Now we capture the current provider ID at request start and compare it with
    the actually used provider. This ensures UI/tray always reflects the real
    provider handling requests.
  • fix(proxy): resolve circuit breaker race condition and error classification
    This commit addresses two critical issues in the proxy failover logic:
    
    1. Circuit Breaker HalfOpen Concurrency Bug:
       - Introduced `AllowResult` struct to track half-open permit usage
       - Added state guard in `transition_to_half_open()` to prevent duplicate resets
       - Replaced `fetch_sub` with CAS loop in `release_half_open_permit()` to prevent underflow
       - Separated `is_available()` (routing) from `allow_request()` (permit acquisition)
    
    2. Error Classification Conflation:
       - Split retry logic into `should_retry_same_provider()` and `categorize_proxy_error()`
       - Same-provider retry: only for transient errors (timeout, 429, 5xx)
       - Cross-provider failover: now includes ConfigError, TransformError, AuthError
       - 4xx errors (401/403) no longer waste retries on the same provider
  • fix(proxy): stabilize live takeover and provider editing
    - Skip live writes when takeover is active and proxy is running
    - Refresh live backups from provider edits during takeover
    - Sync live tokens to DB without clobbering real keys with placeholders
    - Avoid injecting extra placeholder keys into Claude live env
    - Reapply takeover after proxy listen address/port changes
    - In takeover mode, edit dialog uses DB config and keeps API key state in sync
  • Feature/error request logging (#401)
    * feat(proxy): add error mapper for HTTP status code mapping
    
    - Add error_mapper.rs module to map ProxyError to HTTP status codes
    - Implement map_proxy_error_to_status() for error classification
    - Implement get_error_message() for user-friendly error messages
    - Support all error types: upstream, timeout, connection, provider failures
    - Include comprehensive unit tests for all mappings
    
    * feat(proxy): enhance error logging with context support
    
    - Add log_error_with_context() method for detailed error recording
    - Support streaming flag, session_id, and provider_type fields
    - Remove dead_code warning from log_error() method
    - Enable comprehensive error request tracking in database
    
    * feat(proxy): implement error capture and logging in all handlers
    
    - Capture and log all failed requests in handle_messages (Claude)
    - Capture and log all failed requests in handle_gemini (Gemini)
    - Capture and log all failed requests in handle_responses (Codex)
    - Capture and log all failed requests in handle_chat_completions (Codex)
    - Record error status codes, messages, and latency for all failures
    - Generate unique session_id for each request
    - Support both streaming and non-streaming error scenarios
    
    * style: fix clippy warnings and typescript errors
    
    - Add allow(dead_code) for CircuitBreaker::get_state (reserved for future)
    - Fix all uninlined format string warnings (27 instances)
    - Use inline format syntax for better readability
    - Fix unused import and parameter warnings in ProviderActions.tsx
    - Achieve zero warnings in both Rust and TypeScript
    
    * style: apply code formatting
    
    - Remove trailing whitespace in misc.rs
    - Add trailing comma in App.tsx
    - Format multi-line className in ProviderCard.tsx
    
    * feat(proxy): add settings button to proxy panel
    
    Add configuration buttons in both running and stopped states to
    provide easy access to proxy settings dialog.
    
    * fix(speedtest): skip client build for invalid inputs
    
    * chore(clippy): fix uninlined format args
    
    * Merge branch 'main' into feature/error-request-logging
  • refactor(proxy): remove is_proxy_target in favor of failover_queue
    - Remove `is_proxy_target` field from Provider struct (Rust & TypeScript)
    - Remove related DAO methods: get_proxy_target_provider, set_proxy_target
    - Remove deprecated Tauri commands: get_proxy_targets, set_proxy_target
    - Add `is_available()` method to CircuitBreaker for availability checks
      without consuming HalfOpen probe permits (used in select_providers)
    - Keep `allow_request()` for actual request gating with permit tracking
    - Update stream_check to use failover_queue instead of is_proxy_target
    - Clean up commented-out reset circuit breaker button in ProviderActions
    - Remove unused useProxyTargets and useSetProxyTarget hooks
  • chore(i18n): remove restart prompt from provider switch notification
    Claude Code now supports hot reload, so users no longer need to restart
    the terminal after switching providers. Also removes unused `restartClaude`
    i18n string.
  • fix(proxy): invalidate health cache when proxy stops
    The previous fix (e081c75) only cleared the database records but
    didn't invalidate the React Query cache. This caused stale health
    badges to appear when restarting the proxy.
    
    Now invalidates all providerHealth queries on stop, ensuring the
    frontend fetches fresh data from the database.
  • fix(ui): prevent card jitter when health badge appears
    Increase min-height of the name row from 20px to 28px (min-h-7)
    to accommodate the health badge height, preventing layout shift
    when the badge dynamically appears.