* feat(skills): add Claude Skills management feature
Implement complete Skills management system with repository discovery,
installation, and lifecycle management capabilities.
Backend:
- Add SkillService with GitHub integration and installation logic
- Implement skill commands (list, install, uninstall, check updates)
- Support multiple skill repositories with caching
Frontend:
- Add Skills management page with repository browser
- Create SkillCard and RepoManager components
- Add badge, card, table UI components
- Integrate Skills API with Tauri commands
Files: 10 files changed, 1488 insertions(+)
* feat(skills): integrate Skills feature into application
Integrate Skills management feature with complete dependency updates,
configuration structure extensions, and internationalization support.
Dependencies:
- Add @radix-ui/react-visually-hidden for accessibility
- Add anyhow, zip, serde_yaml, tempfile for Skills backend
- Enable chrono serde feature for timestamp serialization
Backend Integration:
- Extend MultiAppConfig with SkillStore field
- Implement skills.json migration from legacy location
- Register SkillService and skill commands in main app
- Export skill module in commands and services
Frontend Integration:
- Add Skills page route and dialog in App
- Integrate Skills UI with main navigation
Internationalization:
- Add complete Chinese translations for Skills UI
- Add complete English translations for Skills UI
Code Quality:
- Remove redundant blank lines in gemini_mcp.rs
- Format log statements in mcp.rs
Tests:
- Update import_export_sync tests for SkillStore
- Update mcp_commands tests for new structure
Files: 16 files changed, 540 insertions(+), 39 deletions(-)
* style(skills): improve SkillsPage typography and spacing
Optimize visual hierarchy and readability of Skills page:
- Reduce title size from 2xl to lg with tighter tracking
- Improve description spacing and color contrast
- Enhance empty state with better text hierarchy
- Use explicit gray colors for better dark mode support
* feat(skills): support custom subdirectory path for skill scanning
Add optional skillsPath field to SkillRepo to enable scanning skills
from subdirectories (e.g., "skills/") instead of repository root.
Changes:
- Backend: Add skillsPath field with subdirectory scanning logic
- Frontend: Add skillsPath input field and display in repo list
- Presets: Add cexll/myclaude repo with skills/ subdirectory
- Code quality: Fix clippy warnings (dedup logic, string formatting)
Backward compatible: skillsPath is optional, defaults to root scanning.
* refactor(skills): improve repo manager dialog layout
Optimize dialog structure with fixed header and scrollable content:
- Add flexbox layout with fixed header and scrollable body
- Remove outer border wrapper for cleaner appearance
- Match SkillsPage design pattern for consistency
- Improve UX with better content hierarchy
BREAKING CHANGE: The [mcp.servers] format was completely incorrect and not
any official Codex format. The only correct format is [mcp_servers] at the
top level of config.toml.
Changes:
- Remove incorrect [mcp.servers] nested table support
- Always use [mcp_servers] top-level table (official Codex format)
- Auto-migrate and cleanup erroneous [mcp.servers] entries on write
- Preserve error-tolerant import for migrating old incorrect configs
- Simplify sync logic by removing format selection branches (~60 lines)
- Update all documentation and tests to reflect correct format
- Add warning logs when detecting and cleaning incorrect format
Backend (Rust):
- mcp.rs: Simplify sync_enabled_to_codex by removing Target enum
- mcp.rs: sync_single_server_to_codex now always uses [mcp_servers]
- mcp.rs: remove_server_from_codex cleans both locations
- mcp.rs: Update import_from_codex comments to clarify format status
- tests: Rename test to sync_enabled_to_codex_migrates_erroneous_*
- tests: Update assertions to verify migration behavior
Frontend (TypeScript):
- tomlUtils.ts: Prioritize [mcp_servers] format in parsing
- tomlUtils.ts: Update error messages to guide correct format
Documentation:
- README.md: Correct MCP format reference to [mcp_servers]
- CLAUDE.md: Add comprehensive format specification with examples
All 79 tests pass. This ensures backward compatibility while enforcing
the correct Codex official standard going forward.
Refs: https://github.com/openai/codex/issues/3441
- Add unified `common_config_snippets` structure to MultiAppConfig
- Implement `get_common_config_snippet` and `set_common_config_snippet` commands
- Replace localStorage with config.json persistence for Codex and Gemini
- Auto-migrate legacy `claude_common_config_snippet` to new unified structure
- Deprecate individual API methods in favor of unified interface
- Add automatic migration from localStorage on first load
BREAKING CHANGE: Common config snippets now stored in unified `common_config_snippets` object instead of separate fields
- Change auto_import_prompt_if_exists return type to Result<bool>
- Remove redundant save() calls by introducing updated flag
- Eliminate unnecessary clone() in app type iterations
- Remove semantic contradiction in let _ = ...? pattern
- Improve code semantics and maintainability
Performance: Reduce disk I/O by 50%+ through unified save logic
Problem:
- On first launch, McpRoot::default() created `servers: None`
- McpService::get_all_servers() would incorrectly return error "old structure detected"
- This confused new users who had no legacy MCP data
Root Cause:
- Derived Default trait sets Option<T> fields to None
- New installations should start with v3.7.0 structure immediately
Solution:
- Explicitly implement Default for McpRoot
- Initialize `servers: Some(HashMap::new())` for v3.7.0+ structure
- Legacy fields (claude/codex/gemini) remain empty, only used for deserializing old configs
Impact:
- First-time users get correct v3.7.0 structure immediately
- migrate_mcp_to_unified() correctly detects already-migrated state
- No false "old structure" errors on fresh installs
Migrate the Claude common config snippet storage from browser localStorage
to the persistent config.json file for better cross-device sync and backup support.
**Backend Changes:**
- Add `claude_common_config_snippet` field to `MultiAppConfig` struct
- Add `get_claude_common_config_snippet` and `set_claude_common_config_snippet` Tauri commands
- Include JSON validation in the setter command
**Frontend Changes:**
- Create new `lib/api/config.ts` API module
- Refactor `useCommonConfigSnippet` hook to use config.json instead of localStorage
- Add automatic one-time migration from localStorage to config.json
- Add loading state during initialization
**Benefits:**
- Cross-device synchronization via backup/restore
- More reliable persistence than browser storage
- Centralized configuration management
- Seamless migration for existing users
Address code review feedback for PR #214:
- Replace hardcoded Chinese strings with English in auto-imported prompts
- Prompt name: "Auto-imported Prompt" instead of "初始提示词"
- Description: "Automatically imported on first launch"
- Remove panic risk by replacing expect() with proper error propagation
- Use AppError::localized for bilingual error messages
- Extract get_base_dir_with_fallback() helper to eliminate code duplication
- Update test assertions to match new English strings
- Suppress false-positive dead_code warning on TempHome.dir field
All 5 tests passing with zero compiler warnings.
- Extract prompt file path logic to dedicated prompt_files module
- Refactor PromptService to use centralized path resolution
- Implement auto-import for existing prompt files on first startup
- Add comprehensive unit tests for auto-import functionality
Refactor tray menu system to support three applications (Claude/Codex/Gemini):
- Introduce generic TrayAppSection structure and TRAY_SECTIONS array
- Implement append_provider_section and handle_provider_tray_event helper functions
- Enhance Gemini provider service with .env config read/write support
- Implement Gemini LiveSnapshot for atomic operations and rollback
- Update README documentation to reflect Gemini tray quick switching feature
* feat(prompts): add prompt management across Tauri service and React UI
- backend: add commands/prompt.rs, services/prompt.rs, register in commands/mod.rs and lib.rs, refine app_config.rs
- frontend: add PromptPanel, PromptFormModal, PromptListItem, MarkdownEditor, usePromptActions, integrate in App.tsx
- api: add src/lib/api/prompts.ts
- i18n: update src/i18n/locales/{en,zh}.json
- build: update package.json and pnpm-lock.yaml
* feat(i18n): improve i18n for prompts and Markdown editor
- update src/i18n/locales/{en,zh}.json keys and strings
- apply i18n in PromptFormModal, PromptPanel, and MarkdownEditor
- align prompt text with src-tauri/src/services/prompt.rs
* feat(prompts): add enable/disable toggle and simplify panel UI
- Add PromptToggle component and integrate in prompt list items
- Implement toggleEnabled with optimistic update; enable via API, disable via upsert with enabled=false;
reload after success
- Simplify PromptPanel: remove file import and current-file preview to keep CRUD flow focused
- Tweak header controls style (use mcp variant) and minor copy: rename “Prompt Management” to “Prompts”
- i18n: add disableSuccess/disableFailed messages
- Backend (Tauri): prevent duplicate backups when importing original prompt content
* style: unify code formatting with trailing commas
* feat(prompts): add Gemini filename support to PromptFormModal
Update filename mapping to use Record<AppId, string> pattern, supporting
GEMINI.md alongside CLAUDE.md and AGENTS.md.
* fix(prompts): sync enabled prompt to file when updating
When updating a prompt that is currently enabled, automatically sync
the updated content to the corresponding live file (CLAUDE.md/AGENTS.md/GEMINI.md).
This ensures the active prompt file always reflects the latest content
when editing enabled prompts.
- Format code in app_config.rs to comply with rustfmt rules
- Remove extra blank line in config.rs
- Format test code in app_config_load.rs for consistency
- Remove 5 unused functions that were left over from migration refactoring:
- get_archive_root, ensure_unique_path, archive_file (config.rs)
- read_config_text_from_path, read_and_validate_config_from_path (codex_config.rs)
- Simplify is_v1 check using is_some_and instead of map_or for better readability
- Remove outdated comments about removed functions
This eliminates all dead_code warnings and improves code maintainability.
BREAKING CHANGE: Runtime auto-migration from v1 to v2 config format has been removed.
Changes:
- Remove automatic v1→v2 migration logic from MultiAppConfig::load()
- Improve v1 detection using structural analysis (checks for 'apps' key absence)
- Return clear error with migration instructions when v1 config is detected
- Add comprehensive tests for config loading edge cases
- Fix false positive detection when v1 config contains 'version' or 'mcp' fields
Migration path for users:
1. Install v3.2.x to perform one-time auto-migration, OR
2. Manually edit ~/.cc-switch/config.json to v2 format
Rationale:
- Separates concerns: load() should be read-only, not perform side effects
- Fail-fast principle: unsupported formats should error immediately
- Simplifies code maintenance by removing migration logic from hot path
Tests added:
- load_v1_config_returns_error_and_does_not_write
- load_v1_with_extra_version_still_treated_as_v1
- load_invalid_json_returns_parse_error_and_does_not_write
- load_valid_v2_config_succeeds
- Extract internal functions in commands/mcp.rs and commands/provider.rs
to enable unit testing without Tauri context
- Add test hooks: set_mcp_enabled_test_hook, import_mcp_from_claude_test_hook,
import_mcp_from_codex_test_hook, import_default_config_test_hook
- Migrate error types from String to AppError for precise error matching in tests
- Extend ProviderService with delete() method to unify Codex/Claude cleanup logic
- Add comprehensive test coverage:
- tests/mcp_commands.rs: command-level tests for MCP operations
- tests/provider_service.rs: service-level tests for switch/delete operations
- Run cargo fmt to fix formatting issues (EOF newlines)
- Update BACKEND_REFACTOR_PLAN.md to mark phase 3 complete
- Derive Default trait instead of manual implementation for McpRoot and ProviderManager
- Remove redundant closures in codex_config.rs and config.rs
- Simplify match statements to if let patterns in migration.rs and lib.rs
- Remove unnecessary type conversions and borrows in lib.rs
- Fix i18n key inconsistency: sequentialThinking → sequential-thinking
- Format TypeScript files to match Prettier style
All clippy warnings resolved, code passes all quality checks.
- Backend: reject "sse" in validators; accept missing type as stdio; require url only for http (mcp.rs, claude_mcp.rs)
- Frontend: McpServer.type narrowed to "stdio" | "http" (optional) (src/types.ts)
- UI: avoid undefined in list item details (McpListItem)
- Claude-only sync after delete to update ~/.claude.json (commands.rs)
Notes:
- Ran typecheck and cargo check: both pass
- Clippy shows advisory warnings unrelated to this change
- Prettier check warns on a few files; limited scope changes kept minimal
- Add McpConfig to MultiAppConfig and persist MCP servers in ~/.cc-switch/config.json
- Add Tauri commands: get_mcp_config, upsert_mcp_server_in_config, delete_mcp_server_in_config, set_mcp_enabled, sync_enabled_mcp_to_claude, import_mcp_from_claude
- Only write enabled MCPs to ~/.claude.json (mcpServers) and strip UI-only fields (enabled/source)
- Frontend: update API wrappers and MCP panel to read/write via config.json; seed presets on first open; import from ~/.claude.json
- Fix warnings (remove unused mut, dead code)
- Verified with cargo check and pnpm typecheck
- Remove file archiving when switching providers or updating current provider
- Keep archive functionality only for initial migration (one-time operation)
- Retain simple .bak backup for config.json on each save
- Simplify code by removing unnecessary archive operations from daily workflows
This change prevents unlimited archive growth while maintaining data safety through:
1. Initial migration archives for historical data preservation
2. Single .bak file for basic rollback capability
3. All provider configs stored in SSOT (config.json)
- Add timestamped backup at `~/.cc-switch/config.v1.backup.<ts>.json`
- Keep provider files untouched; only cc-switch metadata is backed up
- Remove UI notification plan; backup only as requested
- Update CHANGELOG with migration backup notes