Commit Graph

169 Commits

  • feat(webdav): follow-up 补齐自动同步与大文件防护 (#1043)
    * feat(webdav): add robust auto sync with failure feedback
    
    (cherry picked from commit bb6760124a62a964b36902c004e173534910728f)
    
    * fix(webdav): enforce bounded download and extraction size
    
    (cherry picked from commit 7777d6ec2b9bba07c8bbba9b04fe3ea6b15e0e79)
    
    * fix(webdav): only show auto-sync callout for auto-source errors
    
    * refactor(webdav): remove services->commands auto-sync dependency
  • Fix/skill zip symlink resolution (#1040)
    * fix(skill): resolve symlinks in ZIP extraction for GitHub repos (#1001)
    
    - detect symlink entries via is_symlink() during ZIP extraction and collect target paths
    
    - add resolve_symlinks_in_dir() to copy symlink target content into link location
    
    - canonicalize base_dir to fix macOS /tmp → /private/tmp path comparison issue
    
    - add path traversal safety check to block symlinks pointing outside repo boundary
    
    - apply symlink resolution to both download_and_extract and extract_local_zip paths
    
    Closes https://github.com/farion1231/cc-switch/issues/1001
    
    * fix(skill): change search to match name and repo instead of description
    
    * feat(skill): support importing skills from ~/.agents/skills/ directory
    
    - Scan ~/.agents/skills/ in scan_unmanaged() for skill discovery
    - Parse ~/.agents/.skill-lock.json to extract repo owner/name metadata
    - Auto-add discovered repos to skill_repos management on import
    - Add path field to UnmanagedSkill to show discovered location in UI
    
    Closes #980
    
    * fix(skill): use metadata name or ZIP filename for root-level SKILL.md imports (#1000)
    
    When a ZIP contains SKILL.md at the root without a wrapper directory,
    the install name was derived from the temp directory name (e.g. .tmpDZKGpF).
    Now falls back to SKILL.md frontmatter name, then ZIP filename stem.
    
    * feat(skill): scan ~/.cc-switch/skills/ for unmanaged skill discovery and import
    
    * refactor(skill): unify scan/import logic with lock file skillPath and repo saving
    
    - Deduplicate scan_unmanaged and import_from_apps using shared source list
    - Replace hand-written AppType match with as_str() and AppType::all()
    - Extract read_skill_name_desc, build_repo_info_from_lock, save_repos_from_lock helpers
    - Add SkillApps::from_labels for building enable state from source labels
    - Parse skillPath from .skill-lock.json for correct readme URLs
    - Save skill repos to skill_repos table in both import and migration paths
    
    * fix(skill): resolve symlink and path traversal issues in ZIP skill import
    
    * fix(skill): separate source path validation and add canonicalization for symlink safety
  • fix(openclaw): address code review findings across P0-P3 issues
    - Add 25 missing i18n keys for OpenClawFormFields in all 3 locales (P0)
    - Replace key={index} with stable crypto.randomUUID() keys in EnvPanel,
      ToolsPanel, and OpenClawFormFields to prevent list state bugs (P1)
    - Exclude openclaw from ProxyToggle/FailoverToggle in App.tsx (P1)
    - Add merge_additive_config() for openclaw/opencode deep link imports (P1)
    - Normalize serde(flatten) field naming to `extra` + HashMap (P2)
    - Add directory existence check in remove_openclaw_provider_from_live (P2)
    - Remove dead code in import_default_config and openclaw API methods (P2)
    - Add duplicate key validation in EnvPanel before save (P2)
    - Add openclawConfigDir to Settings type (P2)
    - Add staleTime to OpenClaw query hooks (P3)
    - Fix type-unsafe delete via destructuring in mutations.ts (P3)
  • refactor(openclaw): migrate config panels to TanStack Query hooks
    Centralize query keys and extract reusable hooks (useOpenClaw.ts),
    replacing manual useState/useEffect load/save patterns in Env, Tools,
    and AgentsDefaults panels for consistency with MCP/Skills modules.
  • feat(openclaw): add Env/Tools/Agents config panels
    - Migrate OpenClaw commands from provider.rs to dedicated commands/openclaw.rs
    - Add backend types and read/write for env, tools, agents.defaults sections
    - Create EnvPanel (API key + custom vars KV editor)
    - Create ToolsPanel (profile selector + allow/deny lists)
    - Create AgentsDefaultsPanel (default model + runtime parameters)
    - Extend App.tsx menu bar with Env/Tools/Agents buttons
    - Remove Prompts button for OpenClaw (overlaps with Workspace AGENTS.md)
  • feat(openclaw): add Workspace Files panel for managing bootstrap md files
    Add a dedicated panel to read/write OpenClaw's 6 workspace bootstrap files
    (AGENTS.md, SOUL.md, USER.md, IDENTITY.md, TOOLS.md, MEMORY.md) directly
    from ~/.openclaw/workspace/, with a whitelist-secured backend and Markdown
    editor UI. Also fix prompt auto-import missing OpenCode/OpenClaw and the
    PromptFormPanel filenameMap type exclusion.
  • perf: remove unnecessary query cache for Tauri local IPC
    Tauri IPC calls are in-process (microsecond latency), so the 5-minute
    staleTime and disabled refetchOnWindowFocus from web app templates are
    counterproductive. Set staleTime to 0 and enable refetchOnWindowFocus
    so external config changes are reflected immediately.
  • feat(openclaw): add default model button and fix sessionsApi export
    - Add "Enable as Default" button to OpenClaw provider cards
    - Place enable button before add/remove button for better UX
    - Disable remove button when provider is set as default
    - Add sessionsApi re-export from api barrel file to fix white screen
    - Add i18n keys for default model feature (zh/en/ja)
  • feat(openclaw): register suggested models to allowlist on provider add
    When adding an OpenClaw provider with suggestedDefaults, automatically
    merge its model catalog into the allowlist and set the default model
    if not already configured.
  • fix(openclaw): update button state and toast message after switch
    Add cache invalidation for openclawLiveProviderIds in useSwitchProviderMutation
    to ensure button state updates correctly after adding/removing providers.
    
    Also fix toast message to show "已添加到配置" for OpenClaw (same as OpenCode).
  • feat(openclaw): add providerKey input field with validation
    - Add providerKey input field in ProviderForm for OpenClaw
    - Implement duplicate key detection by querying existing providers
    - Add format validation (lowercase letters, numbers, hyphens only)
    - Disable field in edit mode (key cannot be changed after creation)
    - Update mutations.ts to support OpenClaw providerKey
    - Add i18n translations for zh/en/ja
  • feat(openclaw): add additive mode frontend support
    - Add getOpenClawLiveProviderIds() API for querying live config
    - Update ProviderList to query OpenClaw live IDs
    - Rename isOpenCodeMode to isAdditiveMode (covers OpenCode + OpenClaw)
    - Update ProviderCard shouldAutoQuery and isActiveProvider logic
    - Update App.tsx onRemoveFromConfig and invalidateQueries for OpenClaw
  • feat(openclaw): add agents.defaults config support
    - Add types for default model config (primary + fallbacks)
    - Add types for model catalog/allowlist with aliases
    - Extend OpenClawModelEntry with cost and contextWindow fields
    - Add Tauri commands: get/set_openclaw_default_model, get/set_openclaw_model_catalog
    - Create frontend API (src/lib/api/openclaw.ts)
    - Add suggestedDefaults to provider presets with model metadata
    - Add i18n translations (zh/en/ja) for openclawConfig.*
  • feat(types): add OpenClaw TypeScript type definitions
    - Add OpenClawProviderConfig and OpenClawModel interfaces
    - Add openclaw to McpApps, VisibleApps, ProxyTakeoverStatus
    - Add "openclaw" to AppId union type
    - Add openclaw to SkillApps interface
  • Webdav (#923)
    * feat: WebDAV backup/restore
    
    - Add WebDAV test/backup/restore commands and settings\n- Fix ja i18n missing keys; decode PROPFIND href as UTF-8\n- Stabilize Windows prompt auto-import tests via CC_SWITCH_TEST_HOME
    
    * chore: format and minor cleanups
    
    * fix: update build config
    
    * feat(webdav): unify sync UX and hardening fixes
    
    * fix(webdav): harden sync flow and stabilize sync UX/tests
    
    * fix(webdav): add resource limits to skills.zip extraction
    
    Prevent zip bomb / resource exhaustion by enforcing:
    - MAX_EXTRACT_ENTRIES (10,000 files)
    - MAX_EXTRACT_BYTES (512 MB cumulative)
    
    * refactor(webdav): drop deviceId and display deviceName only
    
    ---------
    
    Co-authored-by: small-lovely-cat <77799160+small-lovely-cat@users.noreply.github.com>
    Co-authored-by: saladday <1203511142@qq.com>
  • feat(proxy): fix thinking rectifiers and resolve clippy warnings (#1005)
    * feat(proxy): align thinking rectifiers and resolve clippy warnings
    
    - add thinking budget rectifier flow with single retry on anthropic budget errors
    
    - align thinking signature rectification behavior with adaptive-safe handling
    
    - expose requestThinkingBudget in settings/ui/i18n and default rectifier config to disabled
    
    - fix clippy warnings in model_mapper format args and RectifierConfig default derive
    
    * fix(proxy): thinking rectifiers
  • feat(omo): integrate Oh My OpenCode profile management (#972)
    * feat(omo): integrate Oh My OpenCode profile management into Provider system
    
    Adds full-stack OMO support: backend config read/write/import, OMO-specific
    provider CRUD with exclusive switching, frontend profile editor with
    agent/category/model configuration, global config management, and i18n support.
    
    * feat(omo): add model/variant dropdowns from enabled providers
    
    Replace model text inputs with Select dropdowns sourced from enabled
    OpenCode providers, add thinking-level variant selection, and prevent
    auto-enabling newly added OMO providers.
    
    * fix(omo): use standard provider action styles for OMO switch button
    
    * fix(omo): replace hardcoded isZh strings with proper i18n t() calls
  • feat(usage): enhance dashboard with auto-refresh control and robust formatting (#942)
    * style: format code and apply clippy lint fixes
    
    * feat(usage): enhance dashboard with auto-refresh control and robust formatting
    
    - Add configurable auto-refresh interval toggle (off/5s/10s/30s/60s) to usage dashboard
    - Extract shared format utilities (fmtUsd, fmtInt, parseFiniteNumber, getLocaleFromLanguage)
    - Refactor request log time filtering to rolling vs fixed mode with validation
    - Use stable serializable query keys instead of filter objects
    - Handle NaN/Infinity safely in number formatting across all usage components
    - Use RFC 3339 date format in backend trend data
  • refactor(terminal): unify terminal selection using global settings
    - Remove terminal selector from Session Manager page
    - Backend now reads terminal preference from global settings
    - Add terminal name mapping (iterm2 → iterm) for compatibility
    - Add WezTerm support to macOS terminal options
    - Add WezTerm translations for zh/en/ja
  • refactor(ui): extract shared components and deduplicate MCP/Skills panels (#897)
    * refactor(ui): add tooltips and icons to MCP and Skills panels
    
    * refactor: deduplicate UnifiedSkillsPanel and UnifiedMcpPanel shared code
  • feat: session manger (#867)
    * feat: init session manger
    
    * feat: persist selected app to localStorage
    
    - Save app selection when switching providers
    - Restore last selected app on page load
    
    * feat: persist current view to localStorage
    
    - Save view selection when switching tabs
    - Restore last selected view on page load
    
    * styles: update ui
    
    * feat: Improve macOS Terminal activation and refactor Kitty launch to use  command with user's default shell.
    
    * fix: session view
    
    * feat: toc
    
    * feat: Implement FlexSearch for improved session search functionality.
    
    * feat: Redesign session manager search and filter UI for a more compact and dynamic experience.
    
    * refactor: modularize session manager by extracting components and utility functions into dedicated files.
    
    * feat: Enhance session terminal launching with support for iTerm2, Ghostty, WezTerm, and Alacritty, including UI and custom configuration options.
    
    * feat: Conditionally render terminal selection and resume session buttons only on macOS.
  • fix(mutations): use extractErrorMessage for complete error display
    Provider add/update/delete mutations were using error.message directly,
    which doesn't extract Tauri invoke errors properly. Now using the same
    extractErrorMessage pattern as the rest of the codebase.
  • feat(claude): show proxy hint when switching to OpenAI Chat format provider
    Display an info toast when switching to a provider that uses OpenAI Chat
    format (apiFormat === "openai_chat"), reminding users to enable the proxy
    service. Move toast logic from mutation to useProviderActions for better
    control over notification content based on provider properties.
  • feat(skills): add install from ZIP file feature
    - Add open_zip_file_dialog command for selecting ZIP files
    - Add install_from_zip service method with recursive skill scanning
    - Add install_skills_from_zip Tauri command
    - Add frontend API methods and useInstallSkillsFromZip hook
    - Add "Install from ZIP" button in Skills management page
    - Support local skill ID format: local:{directory}
    - Add i18n translations for new feature and error messages
  • Feat/pricing config enhancement (#781)
    * feat(db): add pricing config fields to proxy_config table
    
    - Add default_cost_multiplier field per app type
    - Add pricing_model_source field (request/response)
    - Add request_model field to proxy_request_logs table
    - Implement schema migration v5
    
    * feat(api): add pricing config commands and provider meta fields
    
    - Add get/set commands for default cost multiplier
    - Add get/set commands for pricing model source
    - Extend ProviderMeta with cost_multiplier and pricing_model_source
    - Register new commands in Tauri invoke handler
    
    * fix(proxy): apply cost multiplier to total cost only
    
    - Move multiplier calculation from per-item to total cost
    - Add resolve_pricing_config for provider-level override
    - Include request_model and cost_multiplier in usage logs
    - Return new fields in get_request_logs API
    
    * feat(ui): add pricing config UI and usage log enhancements
    
    - Add pricing config section to provider advanced settings
    - Refactor PricingConfigPanel to compact table layout
    - Display all three apps (Claude/Codex/Gemini) in one view
    - Add multiplier column and request model display to logs
    - Add frontend API wrappers for pricing config
    
    * feat(i18n): add pricing config translations
    
    - Add zh/en/ja translations for pricing defaults config
    - Add translations for multiplier, requestModel, responseModel
    - Add provider pricing config translations
    
    * fix(pricing): align backfill cost calculation with real-time logic
    
    - Fix backfill to deduct cache_read_tokens from input (avoid double billing)
    - Apply multiplier only to total cost, not to each item
    - Add multiplier display in request detail panel with i18n support
    - Use AppError::localized for backend error messages
    - Fix init_proxy_config_rows to use per-app default values
    - Fix silent failure in set_default_cost_multiplier/set_pricing_model_source
    - Add clippy allow annotation for test mutex across await
    
    * style: format code with cargo fmt and prettier
    
    * fix(tests): correct error type assertions in proxy DAO tests
    
    The tests expected AppError::InvalidInput but the DAO functions use
    AppError::localized() which returns AppError::Localized variant.
    Updated assertions to match the correct error type with key validation.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • fix(skills): prevent duplicate skill installation from different repos (#778)
    - Add directory conflict detection before installation
    - Fix installed status check to match repo owner and name
    - Add i18n translations for conflict error messages
  • feat(skills): add skill sync method setting (symlink/copy)
    - Add SyncMethod enum (Auto/Symlink/Copy) in Rust backend
    - Implement sync_to_app_dir with symlink support (cross-platform)
    - Add SkillSyncMethodSettings UI component (simplified 2-button selector)
    - Add i18n support for zh/en/ja
    - Replace copy_to_app with configurable sync_to_app_dir
    - Add skill_sync_method field to AppSettings
    
    User can now choose between symlink (disk space saving) or copy (best compatibility) in Settings > General.
  • fix(failover): switch to P1 immediately when enabling auto failover
    Previously, enabling auto failover kept using the current provider until
    the first failure, causing inconsistency when the current provider was
    not in the failover queue. When stopping proxy, the restored config
    would not match user expectations.
    
    New behavior:
    - Enable auto failover = immediately switch to queue P1
    - Subsequent routing follows queue order (P1→P2→...)
    - Auto-add current provider to queue if queue is empty
    
    Changes:
    - Add switch_proxy_target() for hot-switching during proxy mode
    - Update provider_router to use queue order when failover enabled
    - Sync tray menu Auto click with the same logic
    - Update UI tooltips to reflect new semantics
    - Add tests for queue-only routing scenario
  • Feat/provider individual config (#663)
    * 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 #636
    Fixes #583
    
    * fix(ui): sync toast theme with app setting
    
    * feat(settings): add log config management
    
    Fixes #612
    Fixes #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.
  • feat(opencode): add manual provider key input with duplicate check
    - Add Provider Key input field for OpenCode providers (between icon and name)
    - User must manually enter a unique key instead of auto-generating from name
    - Real-time validation: format check and duplicate detection
    - Key is immutable after creation (disabled in edit mode)
    - Remove slugify auto-generation logic from mutations
    - Add beforeNameSlot prop to BasicFormFields for extensibility
    - Add i18n translations for zh/en/ja
  • fix(opencode): fix add/remove provider flow and toast messages
    - Create separate removeFromLiveConfig API for additive mode apps
      (remove only removes from live config, not database)
    - Fix useSwitchProviderMutation to invalidate opencodeLiveProviderIds
      cache so button state updates correctly after add operation
    - Show appropriate toast messages:
      - Add: "已添加到配置" / "Added to config"
      - Remove: "已从配置移除" / "Removed from config"
    - Add i18n texts for addToConfigSuccess and removeFromConfigSuccess
  • fix(opencode): prevent config nesting and use slugified provider IDs
    - 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
  • feat(opencode): add OpenCode toggle switches to MCP and Skills panels
    - Add opencode to AppType and SkillApps interfaces in skills.ts
    - Add OpenCode Switch component to UnifiedMcpPanel list items
    - Add OpenCode Switch component to UnifiedSkillsPanel list items
    - Include OpenCode in enabled counts and header statistics for both panels
  • feat(opencode): implement isInConfig semantics for additive provider management
    OpenCode uses additive provider management where providers can exist in
    the database but not necessarily in the live opencode.json config. This
    commit implements proper isInConfig state:
    
    Backend:
    - Add get_opencode_live_provider_ids command to query live config
    
    Frontend:
    - Add getOpenCodeLiveProviderIds API method
    - ProviderList queries live provider IDs and computes isInConfig
    - ProviderCard receives and passes isInConfig to ProviderActions
    - ProviderActions already handles the add/remove button logic
  • feat(opencode): Phase 7 - Frontend TypeScript type definitions
    - Add "opencode" to AppId type in lib/api/types.ts
    - Extend McpApps interface with opencode field in types.ts
    - Add OpenCode-specific types: OpenCodeModel, OpenCodeProviderOptions,
      OpenCodeProviderConfig, OpenCodeMcpServerSpec
    - Add opencodeConfigDir to Settings interface
    - Add importOpenCodeFromLive() to providersApi
    - Fix type errors across components:
      - AppSwitcher: add opencode to icon/name mappings
      - McpFormModal: add opencode to enabledApps state
      - PromptFormModal/Panel: add opencode filename mapping
      - EndpointSpeedTest: add opencode timeout config
      - useBaseUrlState: add opencode to appType union
      - ProxyToggle: add opencode label
      - App.tsx: handle opencode fallback for SkillsPage
    - Update ProxyTakeoverStatus with opencode field (always false)
    - Fix test mocks in tests/msw/state.ts
  • feat(usage): improve custom template system with variable hints and validation fixes (#628)
    * feat(usage): improve custom template with variables display and explicit type detection
    
    Combine two feature improvements:
    1. Display supported variables ({{baseUrl}}, {{apiKey}}) with actual values in custom template mode
    2. Add explicit templateType field for accurate template mode detection
    
    ## Changes
    
    ### Frontend
    - Display template variables with actual values extracted from provider settings
    - Add templateType field to UsageScript for explicit mode detection
    - Support template mode persistence across sessions
    
    ### Backend
    - Add template_type field to UsageScript struct
    - Improve validation logic based on explicit template type
    - Maintain backward compatibility with type inference
    
    ### I18n
    - Add "Supported Variables" section translation (zh/en/ja)
    
    ### Benefits
    - More accurate template mode detection (no more guessing)
    - Better user experience with variable hints
    - Clearer validation rules per template type
    
    * fix(usage): resolve custom template cache and validation issues
    
    Combine three bug fixes to make custom template mode work correctly:
    
    1. **Update cache after test**: Testing usage script successfully now updates the main list cache immediately
    2. **Fix same-origin check**: Custom template mode can now access different domains (SSRF protection still active)
    3. **Fix field naming**: Unified to use autoQueryInterval consistently between frontend and backend
    
    ## Problems Solved
    
    - Main provider list showing "Query failed" after successful test
    - Custom templates blocked by overly strict same-origin validation
    - Auto-query intervals not saved correctly due to inconsistent naming
    
    ## Changes
    
    ### Frontend (UsageScriptModal)
    - Import useQueryClient and update cache after successful test
    - Invalidate usage cache when saving script configuration
    - Use standardized autoQueryInterval field name
    
    ### Backend (usage_script.rs)
    - Allow custom template mode to bypass same-origin checks
    - Maintain SSRF protection for all modes
    
    ### Hooks (useProviderActions)
    - Invalidate usage query cache when saving script
    
    ## Impact
    
    Users can now use custom templates freely while security validations remain intact for general templates.
    
    * fix(usage): correct provider credential field names
    
    - Claude: support both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN
    - Gemini: use GEMINI_API_KEY instead of GOOGLE_GEMINI_API_KEY
    - Codex: use OPENAI_API_KEY and parse base_url from TOML config string
    
    Addresses review feedback from PR #628
    
    * style: format code
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>
  • feat(proxy): add thinking signature rectifier for Claude API (#595)
    * feat(proxy): add thinking signature rectifier for Claude API
    
    Add automatic request rectification when Anthropic API returns signature
    validation errors. This improves compatibility when switching between
    different Claude providers or when historical messages contain incompatible
    thinking block signatures.
    
    - Add thinking_rectifier.rs module with trigger detection and rectification
    - Integrate rectifier into forwarder error handling flow
    - Remove thinking/redacted_thinking blocks and signature fields on retry
    - Delete top-level thinking field when assistant message lacks thinking prefix
    
    * fix(proxy): complete rectifier retry path with failover switch and chain continuation
    
    - Add failover switch trigger on rectifier retry success when provider differs from start
    - Replace direct error return with error categorization on rectifier retry failure
    - Continue failover chain for retryable errors instead of terminating early
    
    * feat(proxy): add rectifier config with master switch
    
    - Add RectifierConfig struct with enabled and requestThinkingSignature fields
    - Update should_rectify_thinking_signature to check master switch first
    - Add tests for master switch functionality
    
    * feat(db): add rectifier config storage in settings table
    
    Store rectifier config as JSON in single key for extensibility
    
    * feat(commands): add get/set rectifier config commands
    
    * feat(ui): add rectifier config panel in advanced settings
    
    - Add RectifierConfigPanel component with master switch and thinking signature toggle
    - Add API wrapper for rectifier config
    - Add i18n translations for zh/en/ja
    
    * feat(proxy): integrate rectifier config into request forwarding
    
    - Load rectifier config from database in RequestContext
    - Pass config to RequestForwarder for runtime checking
    - Use should_rectify_thinking_signature with config parameter
    
    * test(proxy): add nested JSON error detection test for thinking rectifier
    
    * fix(proxy): resolve HalfOpen permit leak and RectifierConfig default values
    
    - Fix RectifierConfig::default() to return enabled=true (was false due to derive)
    - Add release_permit_neutral() for releasing permits without affecting health stats
    - Fix 3 permit leak points in rectifier retry branches
    - Add unit tests for default values and permit release
    
    * style(ui): format ProviderCard style attribute
    
    * fix(rectifier): add detection for signature field required error
    
    Add support for detecting "signature: Field required" error pattern
    in the thinking signature rectifier. This enables automatic request
    rectification when upstream API returns this specific validation error.
  • feat(stream-check): enhance health check with configurable prompt and CLI-compatible requests (#623)
    - Add configurable test prompt field to StreamCheckConfig
    - Implement Claude CLI-compatible request format with proper headers:
      - Authorization + x-api-key dual auth
      - anthropic-beta, anthropic-version headers
      - x-stainless-* SDK headers with dynamic OS/arch detection
      - URL with ?beta=true parameter
    - Implement Codex CLI-compatible Responses API format:
      - /v1/responses endpoint
      - input array format with reasoning effort support
      - codex_cli_rs user-agent and originator headers
    - Add dynamic OS name and CPU architecture detection
    - Internationalize error messages (Chinese -> English)
    - Add test prompt Textarea UI component with i18n support
    - Remove obsolete testPromptDesc translation key
  • Feature/global proxy (#596)
    * 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
    
    * feat(proxy): add global proxy settings support
    
    Add ability to configure a global HTTP/HTTPS proxy for all outbound
    requests including provider API calls, speed tests, and stream checks.
    
    * 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
    
    * feat(proxy): add local proxy auto-scan and fix hot-reload
    
    - Add scan_local_proxies command to detect common proxy ports
    - Fix SkillService not using updated proxy after hot-reload
    - Move global proxy settings to advanced tab
    - Add error handling for scan failures
    
    * fix(proxy): allow localhost input in proxy address field
    
    * fix(proxy): restore request timeout and fix proxy hot-reload issues
    
    - Add URL scheme validation in build_client (http/https/socks5/socks5h)
    - Restore per-request timeout for speedtest, stream_check, usage_script, forwarder
    - Fix set_global_proxy_url to validate before persisting to DB
    - Mask proxy credentials in all log outputs
    - Fix forwarder hot-reload by fetching client on each request
    
    * style: format code with prettier
    
    * fix(proxy): improve global proxy stability and error handling
    
    - Fix RwLock silent failures with explicit error propagation
    - Handle init() duplicate calls gracefully with warning log
    - Align fallback client config with build_client settings
    - Make scan_local_proxies async to avoid UI blocking
    - Add mixed mode support for Clash 7890 port (http+socks5)
    - Use multiple test targets for better proxy connectivity test
    - Clear invalid proxy config on init failure
    - Restore timeout constraints in usage_script
    - Fix mask_url output for URLs without port
    - Add structured error codes [GP-001 to GP-009]
    
    * feat(proxy): add username/password authentication support
    
    - Add separate username and password input fields
    - Implement password visibility toggle with eye icon
    - Add clear button to reset all proxy fields
    - Auto-extract auth info from saved URL and merge on save
    - Update i18n translations (zh/en/ja)
    
    * fix(proxy): fix double encoding issue in proxy auth and add debug logs
    
    - Remove encodeURIComponent in mergeAuth() since URL object's
      username/password setters already do percent-encoding automatically
    - Add GP-010 debug log for database read operations
    - Add GP-011 debug log to track incoming URL info (length, has_auth)
    - Fix username.trim() in fallback branch for consistent behavior
  • 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
  • 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
  • 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
  • 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>
  • 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)
  • 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
  • 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
  • Merge upstream/main into main
    Resolved conflicts in src-tauri/src/lib.rs:
    - Kept both: open_provider_terminal (my feature) and universal provider commands (upstream)
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
  • feat: add Universal Provider feature (#348)
    * feat: add Universal Provider feature
    
    - Add Universal Provider data structures and type definitions
    - Implement backend CRUD operations and sync functionality
    - Add frontend UI components (UniversalProviderPanel, Card, FormModal)
    - Add NewAPI icon and preset configuration
    - Support cross-app (Claude/Codex/Gemini) configuration sync
    - Add website URL field for providers
    - Implement real-time refresh via event notifications
    - Add i18n support (Chinese/English/Japanese)
    
    * feat: integrate universal provider presets into add provider dialog
    
    - Add universal provider presets (NewAPI, Custom Gateway) to preset selector
    - Show universal presets with Layers icon badge in preset selector
    - Open UniversalProviderFormModal when universal preset is clicked
    - Pass initialPreset to auto-fill form when opened from add dialog
    - Add i18n keys for addSuccess/addFailed messages
    - Keep separate universal provider panel for management
    
    * refactor: move universal provider management to add dialog
    
    - Remove Layers button from main navigation header
    - Add 'Manage' button next to universal provider presets
    - Open UniversalProviderPanel from within add provider dialog
    - Add i18n keys for 'manage' in all locales
    
    * style: display universal provider presets on separate line
    
    - Move universal provider section to a new row with border separator
    - Add label '统一供应商:' to clarify the section
    
    * style: unify universal provider label style with preset label
    
    - Use FormLabel component for consistent styling
    - Add background to 'Manage' button matching preset buttons
    - Update icon size and button padding for consistency
    
    * feat: add sync functionality and JSON preview for Universal Provider
    
    * fix: add missing in_failover_queue field to Provider structs
    
    After rebasing to main, the Provider struct gained a new
    `in_failover_queue` field. This fix adds the missing field
    to the three to_*_provider() methods in UniversalProvider.
    
    * refactor: redesign AddProviderDialog with tab-based layout
    
    - Add tabs to separate app-specific providers and universal providers
    - Move "Add Universal Provider" button from panel header to footer
    - Remove unused handleAdd callback and clean up imports
    - Update emptyHint i18n text to reference the footer button
    
    * fix: append /v1 suffix to Codex base_url in Universal Provider
    
    Codex uses OpenAI-compatible API which requires the /v1 endpoint suffix.
    The Universal Provider now automatically appends /v1 to base_url when
    generating Codex provider config if not already present.
    
    - Handle trailing slashes to avoid double slashes
    - Apply fix to both backend (to_codex_provider) and frontend preview
    
    * feat: auto-sync universal provider to apps on creation
    
    Previously, users had to manually click sync after adding a universal
    provider. Now it automatically syncs to Claude/Codex/Gemini on creation,
    providing a smoother user experience.
    
    ---------
    
    Co-authored-by: Jason <farion1231@gmail.com>