Commit Graph

1046 Commits

  • fix(config): improve Gemini merge and remove duplicate logging
    Address multiple audit findings:
    
    1. config_merge.rs:701 - Gemini merge now initializes env from common
       config when custom config has no env field, ensuring common API keys
       and base URLs are applied correctly.
    
    2. Remove duplicate logging - merge functions now only return warnings,
       callers (live.rs, proxy.rs) handle logging in one place.
    
    3. live.rs:169 - Unify error message style to plain English descriptions
       instead of error codes embedded in messages.
    
    Changes:
    - Add fallback to initialize env from common_env when missing
    - Remove log::warn! calls from merge functions
    - Use descriptive error messages consistently
  • fix(dialog): support wrapped format for Gemini common config
    Address audit finding: EditProviderDialog.tsx:121 only parsed flat JSON
    format, not the wrapped {"env": {...}} format.
    
    Changes:
    - Detect if common config is wrapped or flat format
    - Extract env object from either format
    - Properly compute difference for live settings extraction
    
    This ensures backward compatibility with existing wrapped-format data.
  • fix(form): use JSON parsing for Gemini common config snippet
    Address audit finding: ProviderForm.tsx:944 was using envStringToObj()
    (KEY=VALUE format) to parse Gemini common config, but it's stored as JSON.
    
    Changes:
    - Add parseGeminiCommonConfig() helper function
    - Support both flat {"KEY": "VALUE"} and wrapped {"env": {...}} formats
    - Properly extract difference between custom and common env
    
    This prevents common config values from being incorrectly saved as
    custom config when the formats don't match.
  • fix(form): add type guard for Gemini env values
    Address code audit finding #10:
    
    Replace unsafe type assertion with proper type guard when extracting
    custom env config. Convert all values to strings explicitly using
    String() to prevent runtime type errors when env contains non-string
    values (numbers, booleans, etc).
    
    Before: envObj = customConfig as Record<string, string>
    After: Iterate and convert each value with String(value)
  • refactor(hooks): improve error handling and user feedback
    Address code audit findings #3, #5, #9:
    
    Save queue improvements:
    - Add error logging in enqueueSave() catch handlers
    - Use console.error with [SaveQueue] prefix for debugging
    - Prevent silent failures in async save operations
    
    Extract operation improvements:
    - Add toast.success() notification after extract completes
    - Notify user that custom config was automatically updated
    - Add error logging for failed settingsConfig updates
    
    I18n improvements:
    - Replace MCP i18n keys with dedicated Codex keys:
      - codexConfig.tomlFormatError
      - codexConfig.tomlSyntaxError
      - codexConfig.extractedTomlInvalid
    - Avoid namespace pollution between modules
  • fix(dialog): unify Gemini common config format parsing
    Address code audit finding #4:
    
    The frontend was incorrectly parsing Gemini common config as KEY=VALUE
    format while the backend expects JSON format. Unify to use JSON parsing
    {"KEY": "VALUE"} which matches the format stored by useGeminiCommonConfig.
    
    Also add type guard when converting to string record to prevent type
    assertion issues with non-string values.
  • refactor(config): extract common config merge to shared function
    Address code audit findings #1, #2, #6, #7, #11:
    
    - Extract merge logic to merge_config_for_live() in config_merge.rs
    - Add is_common_config_enabled() helper function
    - Add MergeResult struct with config and optional warning
    - Update live.rs and proxy.rs to use the shared function
    - Add logging for JSON parse failures instead of silent fallback
    - Convert Chinese error messages to error codes (CODEX_CONFIG_*)
    - Support both flat and wrapped formats for Gemini common config
    
    This eliminates code duplication between live.rs and proxy.rs,
    making future maintenance easier and preventing behavioral drift.
  • feat(dialog): extract custom config from live settings on edit
    Update EditProviderDialog to extract custom configuration from live
    settings when common config is enabled, ensuring the edit form shows
    only the provider-specific values.
    
    When loading live settings for editing:
    - Check if common config is enabled for the provider and app type
    - Fetch the common config snippet from database
    - Extract the difference (custom config) from live settings
    - Handle all three formats: Claude (JSON), Codex (TOML), Gemini (env)
    
    This prevents the merged common config values from appearing in the
    edit form, which would cause them to be saved as custom config and
    result in duplicate values after the next merge.
  • feat(form): extract custom config difference on provider save
    Update ProviderForm to extract only the custom (provider-specific)
    configuration when saving, removing common config values that would
    be merged at runtime.
    
    Changes:
    - Import configMerge utilities (extractDifference, extractTomlDifference)
    - Pass finalConfig from hooks to config editor components
    - On save, extract difference between current config and common snippet
    - Apply extraction for all three app types (Claude JSON, Codex TOML, Gemini env)
    
    This ensures the database stores only the provider's unique configuration,
    while the common config is stored separately and merged at runtime when
    writing to live files.
  • feat(ui): add merge preview to common config editor components
    Add real-time merge preview functionality to all config editor components
    (Claude, Codex, Gemini) that shows the final merged configuration when
    common config is enabled.
    
    UI changes:
    - Add finalConfig/finalEnv prop to display merged result
    - Add toggle button to show/hide merge preview (Eye/EyeOff icons)
    - Auto-show preview when common config is enabled
    - Display custom config editor with label when preview is visible
    - Show read-only merged preview below custom config
    - Add visual indicators: "只读" badge, green hint text
    
    The preview helps users understand how their custom configuration
    combines with the shared common config template before saving.
  • refactor(hooks): redesign common config hooks for runtime merge architecture
    Refactor all three common config hooks (Claude, Codex, Gemini) to support
    the new runtime merge architecture where:
    - settingsConfig stores only custom (provider-specific) configuration
    - commonConfigSnippet stores shared template configuration in database
    - finalConfig is computed at runtime: merge(commonConfig, customConfig)
    - Toggling common config only changes enabled state, not settingsConfig
    
    Key changes across all hooks:
    - Add finalConfig/finalEnv return value for merge preview
    - Use configMerge utilities (computeFinalConfig, extractDifference)
    - Remove direct config manipulation on toggle (no more inject/remove)
    - Add proper TypeScript return type interfaces
    - Simplify state management by removing unnecessary refs
    - Improve code organization with clear section comments
    
    This refactor enables:
    - Clean separation between custom and common configuration
    - Real-time merge preview in the UI
    - Consistent behavior across Claude (JSON), Codex (TOML), and Gemini (env)
  • feat(editor): add readOnly mode to JsonEditor component
    Add a readOnly prop to the JsonEditor component that:
    - Enables CodeMirror's EditorState.readOnly extension
    - Applies visual styling (reduced opacity, default cursor)
    - Prevents user modifications to the editor content
    
    This feature is needed for displaying merged config previews where
    users should see the final result but not edit it directly.
  • fix(deeplink): disable common config for deeplink imported providers
    Set common_config_enabled to false by default for providers imported
    via deeplink URLs. This prevents unexpected configuration merging when
    users import providers from external sources.
    
    Deeplink imported providers should use their settings_config directly
    without merging with the global common config snippet, as the imported
    configuration is expected to be complete and self-contained.
    
    Changes:
    - Always return ProviderMeta with common_config_enabled = false
    - Refactor build_provider_meta to handle usage_script conditionally
    - Add documentation explaining the design decision
  • feat(proxy): add common config merge to proxy live config restore
    Extend the proxy service's restore_live_config function to support
    common config runtime merge when restoring live configuration after
    proxy takeover ends.
    
    This ensures that when the proxy releases control and restores the
    original provider configuration, the common config merge is applied
    consistently with the main provider switching logic.
    
    The merge follows the same pattern as live.rs:
    - Check common_config_enabled flag per app type
    - Merge common snippet with provider's custom config
    - customConfig overrides commonConfig
  • feat(provider): add common config runtime merge to live config sync
    Implement runtime merge of common config snippet with provider's custom
    config when writing to live configuration files. This enables shared
    configuration templates across providers while preserving provider-specific
    overrides.
    
    Key changes:
    - Add write_live_snapshot_with_merge() function that performs runtime merge
    - Support JSON merge for Claude, TOML merge for Codex, and env merge for Gemini
    - Update sync_current_to_live() to use the new merge function
    - Update provider switch and update operations to use merge function
    - Merge rule: customConfig (provider-specific) overrides commonConfig (shared)
    
    The merge is only performed when common_config_enabled is true for the
    provider and the corresponding app type.
  • feat(config): add core utilities for config merge and difference extraction
    Add comprehensive config merge utilities for both Rust backend and TypeScript frontend
    to support the new common config architecture where customConfig overrides commonConfig.
    
    Backend (Rust):
    - Add config_merge.rs module with JSON and TOML merge functions
    - Support deep merge where source overrides target for nested objects
    - Add extract_difference functions to identify custom-only keys
    - Include compute_final_*_config functions for runtime merge calculation
    - Register module in lib.rs
    
    Frontend (TypeScript):
    - Add configMerge.ts with isPlainObject, deepClone, deepEqual, deepMerge utilities
    - Implement computeFinalConfig for merging common + custom configs
    - Add extractDifference to identify keys unique to live config
    - Add tomlConfigMerge.ts with TOML-specific merge/extract functions
    - Use smol-toml for parsing and serialization
    
    These utilities form the foundation for the refactored common config system
    where providers store only custom config and merge with shared templates at runtime.
  • 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
  • refactor(config): improve TOML common config merge without markers
    - Remove cc-switch:common-config:start/end marker injection
    - Allow table definitions in common config snippets
    - Add intelligent TOML structure parsing and merging
    - Keep legacy marker cleanup for backward compatibility
  • feat(backend): add CommonConfigEnabledByApp to ProviderMeta
    - Add CommonConfigEnabledByApp struct for per-app tracking
    - Add common_config_enabled and common_config_enabled_by_app to ProviderMeta
    - Add is_empty() method to CommonConfigSnippets
    - Skip serializing empty common_config_snippets in config.json
  • fix(form): add common config loading check and meta persistence
    - Check common config loading state before submit
    - Add validation for common config errors on submit
    - Add TOML validation for Codex before submit
    - Persist commonConfigEnabledByApp to provider meta
    - Pass currentProviderId to common config hooks for sync skip
  • refactor(hooks): improve config state hooks for codex and gemini
    - Improve type safety in config state management
    - Better error handling for config parsing
  • feat(types): add CommonConfigEnabledByApp type for per-app tracking
    - Add CommonConfigEnabledByApp type for claude/codex/gemini
    - Add commonConfigEnabled field to ProviderMeta
    - Add commonConfigEnabledByApp field with higher priority
  • feat(i18n): add common config sync related translations
    - Add providerForm.commonConfigLoading key
    - Add providerForm.commonConfigSyncFailed key
    - Support zh/en/ja languages
  • fix(gemini): add clearing sync and save queue for common config
    - Trigger sync when clearing common config to remove from all providers
    - Add saveSequenceRef and enqueueSave for ordered async saves
    - Add toast notification for sync failures
    - Prevent stale sync operations with sequence ID check
  • fix(codex): add TOML validation and clearing sync for common config
    - Add TomlValidationErrorCode type for structured error handling
    - Add TOML syntax validation in getSnippetApplyError
    - Trigger sync when clearing common config
    - Add saveSequenceRef and enqueueSave for ordered async saves
    - Add toast notification for sync failures
  • fix(claude): add clearing sync and save queue for common config
    - Trigger sync when clearing common config to remove from all providers
    - Add saveSequenceRef and enqueueSave for ordered async saves
    - Add toast notification for sync failures
    - Prevent stale sync operations with sequence ID check
  • fix(utils): add type validation and error codes for config utilities
    - Add isPlainObject validation in replaceGeminiCommonConfigSnippet
    - Return error codes instead of hardcoded Chinese strings
    - Add CONFIG_NOT_OBJECT, ENV_NOT_OBJECT, COMMON_CONFIG_JSON_INVALID codes
    - Use TOML marker constants to avoid hardcoded strings
  • fix(sync): add in-flight lock and callback support for common config sync
    - Add SyncResult interface for structured sync results
    - Add SyncResultCallback type for async notification
    - Add syncInFlight lock per appType to prevent concurrent syncs
    - Add executeSyncWithLock function for concurrency control
    - Add meta fallback detection with automatic backfill
    - Improve error handling with detailed error messages
  • feat(ui): replace update badge dot with ArrowUpCircle icon
    - Replace blue dot indicator with lucide ArrowUpCircle icon
    - Change color scheme from blue to green for better visibility
    - Enlarge button (h-8 w-8) and icon (h-5 w-5) for better UX
    - Move UpdateBadge from title area to after settings icon
  • 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.
  • feat(partner): add RightCode as official partner
    Update RightCode referral link to use CCSWITCH affiliate code and mark
    as official partner with promotional messages in all supported languages.
  • fix(prompt): clear prompt file when all prompts are disabled
    When disabling a prompt, check if any other prompts remain enabled.
    If all prompts are disabled, clear the prompt file to ensure UI state
    matches the actual configuration that Claude Code reads.
  • fix(opencode): preserve extra model fields during serialization
    Add `extra` field with serde flatten to OpenCodeModel struct to capture
    custom fields like cost, modalities, thinking, and variants that were
    previously lost during save operations.
  • fix(form): backfill model fields when editing Claude provider
    Use lazy initialization in useState to parse model values from config
    on first render, matching the pattern used in useApiKeyState. This
    fixes an issue where model fields were not populated in edit mode.
  • chore: release v3.10.1
    - Bump version to 3.10.1 across all config files
    - Update CHANGELOG with all fixes since v3.10.0
    - Fix Rust Clippy warning by using derive(Default)
    - Apply code formatting
  • fix(proxy): change rectifier default state to disabled
    Change the default state of the rectifier from enabled to disabled.
    This allows users to opt-in to the rectifier feature rather than having it enabled by default.
    
    Changes:
    - Set RectifierConfig::default() enabled and request_thinking_signature to false
    - Update serde default attributes from default_true to default
    - Update unit tests to reflect new default behavior
  • feat(icons): update RightCode provider icon
    - Import new detailed RC icon from rc.svg (128x128 viewBox)
    - Add icon configuration to Claude provider preset
    - Remove duplicate old RC icon definition to fix TS1117 error
  • fix(ui): increase app icon collapse threshold from 3 to 4
    Improve readability by keeping app names visible when 3 apps are shown.
    Icons now only collapse to compact mode when 4 or more apps are visible.
  • fix(ui): improve ProviderIcon color validation to prevent black icons
    Enhance the effectiveColor logic in ProviderIcon to properly validate
    the color prop before using it. Now only uses color when it's a valid
    non-empty string, otherwise falls back to icon metadata defaultColor.
    
    This fixes the issue where Gemini icons would turn black when selected
    in ProviderCard due to null/undefined/empty string color values being
    passed through.
  • fix(ui): unify layout padding across all panels
    Remove max-width constraints and standardize padding to px-6 for consistent full-width layout across header and all content panels.
  • fix(settings): reorder window settings and change default values
    Move "minimize to tray on close" to the bottom of window settings.
    Change skipClaudeOnboarding default to false.
  • fix(terminal): keep Windows terminal window open after execution
    Use /K instead of /C flag to prevent cmd window from closing
    immediately after batch file execution. Also remove the buggy
    errorlevel check that was checking del command's return value
    instead of claude's.
    
    Fixes #726
  • fix(config): correct OpenCode config path on Windows
    OpenCode uses ~/.config/opencode on all platforms, not %APPDATA%\opencode
    on Windows. Remove the platform-specific path handling to use unified
    ~/.config/opencode path across all operating systems.
  • fix(ui): align panel content with header constraints
    Add max-w-[56rem] and mx-auto to Skills, MCP, and Prompts panels
    to match the header layout constraints, ensuring the back button
    and action buttons align with the content area.