Fixed two critical data loss bugs where user-added custom endpoints were discarded:
1. **AddProviderDialog**: Form submission ignored values.meta from ProviderForm and
re-inferred URLs only from presets/config, causing loss of endpoints added via
speed test modal. Now prioritizes form-collected meta and uses fallback inference
only when custom_endpoints is missing.
2. **ProviderForm**: Edit mode always returned initialData.meta, discarding any
changes made in the speed test modal. Now uses mergeProviderMeta to properly
merge customEndpointsMap with existing meta fields.
Changes:
- Extract mergeProviderMeta utility to handle meta field merging logic
- Preserve other meta fields (e.g., usage_script) during endpoint updates
- Unify new/edit code paths to use consistent meta handling
- Add comprehensive unit tests for meta merging scenarios
- Add integration tests for AddProviderDialog submission flow
Impact:
- Third-party and custom providers can now reliably manage multiple endpoints
- Edit operations correctly reflect user modifications
- No data loss for existing meta fields like usage_script
- Separate MCP server metadata from connection spec for cleaner architecture
- Add comprehensive server entry fields: name, description, tags, homepage, docs
- Remove legacy format compatibility logic from extract_server_spec
- Implement data validation and filtering in get_servers_snapshot_for
- Add strict id consistency check in upsert_in_config_for
- Enhance import logic with defensive programming for corrupted data
- Simplify frontend by removing normalization logic (moved to backend)
- Improve error messages with contextual information
- Add comprehensive i18n support for new metadata fields
- chore(deps): switch TOML dependency from @iarna/toml to smol-toml and update lockfile
- feat(mcp): add TOML editing/validation for Codex while keeping JSON for Claude; support auto ID extraction from TOML and JSON->TOML conversion for wizard output; add pre-submit required checks (stdio.command / http.url)
- refactor(mcp): unify JSON/TOML validation errors via i18n; add formatTomlError for consistent, localized messages; consolidate state into formConfig/configError
- feat(i18n): add TOML labels/placeholders and error keys (tomlConfig, tomlPlaceholder, tomlInvalid)
- feat(utils): introduce tomlUtils with parse/stringify/validate/convert helpers using smol-toml; provide tomlToMcpServer, mcpServerToToml, extractIdFromToml, validateToml
- build: confirm Vite no longer externalizes Node builtins during build; renderer builds without 'Module 'stream' has been externalized' warning
* feat: add unified endpoint speed test for API providers
Add a comprehensive endpoint latency testing system that allows users to:
- Test multiple API endpoints concurrently
- Auto-select the fastest endpoint based on latency
- Add/remove custom endpoints dynamically
- View latency results with color-coded indicators
Backend (Rust):
- Implement parallel HTTP HEAD requests with configurable timeout
- Handle various error scenarios (timeout, connection failure, invalid URL)
- Return structured latency data with status codes
Frontend (React):
- Create interactive speed test UI component with auto-sort by latency
- Support endpoint management (add/remove custom endpoints)
- Extract and update Codex base_url from TOML configuration
- Integrate with provider presets for default endpoint candidates
This feature improves user experience when selecting optimal API endpoints,
especially useful for users with multiple provider options or proxy setups.
* refactor: convert endpoint speed test to modal dialog
- Transform EndpointSpeedTest component into a modal dialog
- Add "Advanced" button next to base URL input to open modal
- Support ESC key and backdrop click to close modal
- Apply Linear design principles: minimal styling, clean layout
- Remove unused showBaseUrlInput variable
- Implement same modal pattern for both Claude and Codex
* fix: prevent modal cascade closing when ESC is pressed
- Add state checks to prevent parent modal from closing when child modals (endpoint speed test or template wizard) are open
- Update ESC key handler dependencies to track all modal states
- Ensures only the topmost modal responds to ESC key
* refactor: unify speed test panel UI with project design system
UI improvements:
- Update modal border radius from rounded-lg to rounded-xl
- Unify header padding from px-6 py-4 to p-6
- Change speed test button color to blue theme (bg-blue-500) for consistency
- Update footer background from bg-gray-50 to bg-gray-100
- Style "Done" button as primary action button with blue theme
- Adjust footer button spacing and hover states
Simplify endpoint display:
- Remove endpoint labels (e.g., "Current Address", "Custom 1")
- Display only URL for cleaner interface
- Clean up all label-related logic:
* Remove label field from EndpointCandidate interface
* Remove label generation in buildInitialEntries function
* Remove label handling in useEffect merge logic
* Remove label generation in handleAddEndpoint
* Remove label parameters from claudeSpeedTestEndpoints
* Remove label parameters from codexSpeedTestEndpoints
* refactor: improve endpoint list UI consistency
- Show delete button for all endpoints on hover for uniform UI
- Change selected state to use blue theme matching main interface:
* Blue border (border-blue-500) for selected items
* Light blue background (bg-blue-50/dark:bg-blue-900/20)
* Blue indicator dot (bg-blue-500/dark:bg-blue-400)
- Switch from compact list (space-y-px) to card-based layout (space-y-2)
- Add rounded corners to each endpoint item for better visual separation
* feat: persist custom endpoints to settings.json
- Extend AppSettings to store custom endpoints for Claude and Codex
- Add Tauri commands: get/add/remove/update custom endpoints
- Update frontend API with endpoint persistence methods
- Modify EndpointSpeedTest to load/save custom endpoints via API
- Track endpoint last used time for future sorting/cleanup
- Store endpoints per app type in settings.json instead of localStorage
* - feat(types): add Provider.meta and ProviderMeta (snake_case) with custom_endpoints map
- feat(provider-form): persist custom endpoints on provider create by merging EndpointSpeedTest’s custom URLs into meta.custom_endpoints on submit
- feat(endpoint-speed-test): add onCustomEndpointsChange callback emitting normalized custom URLs; wire it for both Claude/Codex modals
- fix(api): send alias param names (app/appType/app_type and provider_id/providerId) in Tauri invokes to avoid “missing providerId” with older backends
- storage: custom endpoints are stored in ~/.cc-switch/config.json under providers[<id>].meta.custom_endpoints (not in settings.json)
- behavior: edit flow remains immediate writes; create flow now writes once via addProvider, removing the providerId dependency during creation
* feat: add endpoint candidates support and code formatting improvements
- Add endpointCandidates field to ProviderPreset and CodexProviderPreset interfaces
- Integrate preset endpoint candidates into speed test endpoint selection
- Add multiple endpoint options for PackyCode providers (Claude & Codex)
- Apply consistent code formatting (trailing commas, line breaks)
- Improve template value type safety and readability
* refactor: improve endpoint management button UX
Replace ambiguous "Advanced" text with intuitive "Manage & Test" label accompanied by Zap icon, making the endpoint management panel entry point more discoverable and self-explanatory for both Claude and Codex configurations.
* - merge: merge origin/main, resolve conflicts and preserve both feature sets
- feat(tauri): register import/export and file dialogs; keep endpoint speed test and custom endpoints
- feat(api): add updateTrayMenu and onProviderSwitched; wire import/export APIs
- feat(types): extend global API declarations (import/export)
- chore(presets): GLM preset supports both new and legacy model keys
- chore(rust): add chrono dependency; refresh lockfile
---------
Co-authored-by: Jason <farion1231@gmail.com>
Merged duplicate try-catch blocks that handle invalid chatgpt.config values.
Now handles all edge cases (scalar values, arrays, empty objects) in a single
unified check, reducing code duplication and improving performance by parsing
JSON only once.
- refactor(ProviderList): use shared base_url helpers
- refactor(App): reuse shared base_url helpers for VS Code sync
- fix(auto-sync): global shared VS Code auto-apply state (localStorage + event broadcast)
- feat(tray): auto-apply to VS Code on Codex provider-switched when enabled
- behavior: manual Apply enables auto-sync; manual Remove disables; official providers clear managed keys only
- chore(typecheck): pass pnpm typecheck
- feat(tauri): Add commands to read/write VS Code settings.json with cross-variant detection (Code/Insiders/VSCodium/OSS)
- fix(vscode): Use top-level keys “chatgpt.apiBase” and “chatgpt.config.preferred_auth_method”
- fix(vscode): Handle empty settings.json (skip deletes, direct write) to avoid “Can not delete in empty document”
- fix(windows): Make atomic writes robust by removing target before rename
- ui(provider-list): Improve error surfacing when applying/removing
- chore(types): Extend window.api typings and tauri-api wrappers for VS Code commands
- deps: Add jsonc-parser
- Add automatic VS Code config sync when base_url changes in TOML
- Improve error handling for VS Code configuration writes
- Enhance state management with ref tracking to prevent duplicate API calls
- Fix code formatting issues and improve readability across components
- Optimize common configuration handling for both Claude and Codex providers
- Extract common validateJsonConfig function for reuse
- Apply unified validation to both main config and common config snippets
- Add real-time JSON validation to JsonEditor component using CodeMirror linter
- Simplify error handling without over-engineering error position extraction
- Move extractErrorMessage function from App.tsx to utils/errorUtils.ts
- Improve code organization and reusability
- Enhance error notification with dynamic message extraction and timeout
- Added separate common config state and storage for Codex
- Implemented TOML-based common config merging with markers
- Created UI components for Codex common config editor
- Added toggle and edit functionality similar to Claude config
- Store Codex common config in localStorage separately
- Support appending/removing common TOML snippets to config.toml
- Replace single "disable co-authored" checkbox with universal "common config snippet" functionality
- Add localStorage persistence for common config snippets
- Implement deep merge/remove operations for complex JSON structures
- Add modal editor for managing common config snippets
- Optimize performance with custom deepClone function instead of JSON.parse/stringify
- Fix deep remove logic to only delete matching values
- Improve error handling and validation for JSON snippets
* feat: refactor ProviderForm component with new subcomponents
- Introduced PresetSelector, ApiKeyInput, ClaudeConfigEditor, and CodexConfigEditor for improved modularity and readability.
- Simplified preset selection logic for both Claude and Codex configurations.
- Enhanced API Key input handling with dedicated components for better user experience.
- Removed redundant code and improved state management in the ProviderForm component.
* feat: add Kimi model selection to ProviderForm component
- Introduced KimiModelSelector for enhanced model configuration options.
- Implemented state management for Kimi model selection, including initialization and updates based on preset selection.
- Improved user experience by conditionally displaying the Kimi model selector based on the selected preset.
- Refactored related logic to ensure proper handling of Kimi-specific settings in the ProviderForm.
* feat: enhance API Key input and model selection in ProviderForm
- Added toggle functionality to show/hide API Key in ApiKeyInput component for improved user experience.
- Updated placeholder text in ProviderForm to provide clearer instructions based on the selected preset.
- Enhanced KimiModelSelector to display a more informative message when API Key is not provided.
- Refactored provider presets to remove hardcoded API Key values for better security practices.
* fix(kimi): optimize debounce implementation in model selector
- Fix initial state: use empty string instead of apiKey.trim()
- Refactor fetchModels to fetchModelsWithKey with explicit key parameter
- Ensure consistent behavior between auto-fetch and manual refresh
- Eliminate mental overhead from optional parameter fallback logic
* fix(api-key): remove custom masking logic, use native password input
- Remove getDisplayValue function with custom star masking
- Use native browser password input behavior for better UX consistency
- Simplify component logic while maintaining show/hide toggle functionality
* chore: format code with prettier
- Apply consistent code formatting across all TypeScript files
- Fix indentation and spacing according to project style guide
---------
Co-authored-by: Jason <farion1231@gmail.com>
* feat(editor): add JsonEditor component for JSON configuration editing
* fix(provider): update API Key visibility logic in ProviderForm component
* fix(editor): stabilize JsonEditor height and restore API Key logic
- Revert API Key visibility to preset-based rule and injection to non-custom preset only.
- Reduce JsonEditor min-height from rows*22px to rows*18px to lessen layout jitter when switching presets.
- Keep fonts/size consistent with the previous textarea for visual parity.
* - fix(form): remove websiteUrl auto-extraction from JSON to prevent incorrect overrides
---------
Co-authored-by: Jason <farion1231@gmail.com>
- Format all TypeScript/React code with Prettier
- Format all Rust code with cargo fmt
- Fix bundle identifier from .app to .desktop to avoid macOS conflicts
- Prepare codebase for v3.0.0 Tauri release