mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-05-11 14:21:22 +08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 543d0df5c1 | |||
| 6d7ec14644 | |||
| 8f1ad6e057 | |||
| 2b3c80703c | |||
| eef328d2a4 | |||
| 4eb983c58f | |||
| cef3812745 | |||
| 6c9a7ef949 | |||
| 48c434a20a | |||
| 4f6dfff179 | |||
| 4b9cca12d3 | |||
| 8db44a78b2 | |||
| efad0c0f91 | |||
| b536bd0366 | |||
| 783bc60329 | |||
| 924e5386f9 | |||
| 74f67bc1ee | |||
| ae5d05b08c | |||
| 4edb08cd53 | |||
| a8ea99c3fe | |||
| 22c0e7bb5c | |||
| 8af31c3e61 |
@@ -9,55 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
---
|
||||
|
||||
## [3.10.2] - 2026-01-24
|
||||
|
||||
### Patch Release
|
||||
|
||||
This maintenance release adds skill sync options and includes important bug fixes.
|
||||
|
||||
### Added
|
||||
|
||||
- **Skills**: Add skill sync method setting with symlink/copy options
|
||||
- **Partners**: Add RightCode as official partner
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Prompts**: Clear prompt file when all prompts are disabled
|
||||
- **OpenCode**: Preserve extra model fields during serialization
|
||||
- **Provider Form**: Backfill model fields when editing Claude provider
|
||||
|
||||
---
|
||||
|
||||
## [3.10.1] - 2026-01-23
|
||||
|
||||
### Patch Release
|
||||
|
||||
This maintenance release includes important bug fixes for Windows platform, UI improvements, and code quality enhancements.
|
||||
|
||||
### Added
|
||||
|
||||
- **Provider Icons**: Updated RightCode provider icon with improved visual design
|
||||
|
||||
### Changed
|
||||
|
||||
- **Proxy Rectifier**: Changed rectifier default state to disabled for better stability
|
||||
- **Window Settings**: Reordered window settings and updated default values for improved UX
|
||||
- **UI Layout**: Increased app icon collapse threshold from 3 to 4 icons
|
||||
- **Code Quality**: Simplified `RectifierConfig` implementation using `#[derive(Default)]`
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Windows Platform**:
|
||||
- Fixed terminal window closing immediately after execution on Windows
|
||||
- Corrected OpenCode config path resolution on Windows
|
||||
- **UI Improvements**:
|
||||
- Fixed ProviderIcon color validation to prevent black icons from appearing
|
||||
- Unified layout padding across all panels for consistent spacing
|
||||
- Fixed panel content alignment with header constraints
|
||||
- **Code Quality**: Resolved Rust Clippy warnings and applied consistent formatting
|
||||
|
||||
---
|
||||
|
||||
## [3.10.0] - 2026-01-21
|
||||
|
||||
### Feature Release
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# All-in-One Assistant for Claude Code, Codex & Gemini CLI
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://tauri.app/)
|
||||
[](https://github.com/farion1231/cc-switch/releases/latest)
|
||||
@@ -52,7 +52,7 @@ This project is sponsored by Z.ai, supporting us with their GLM CODING PLAN.GLM
|
||||
|
||||
## Features
|
||||
|
||||
### Current Version: v3.10.2 | [Full Changelog](CHANGELOG.md) | [Release Notes](docs/release-note-v3.9.0-en.md)
|
||||
### Current Version: v3.10.0 | [Full Changelog](CHANGELOG.md) | [Release Notes](docs/release-note-v3.9.0-en.md)
|
||||
|
||||
**v3.8.0 Major Update (2025-11-28)**
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
# Claude Code / Codex / Gemini CLI オールインワン・アシスタント
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://tauri.app/)
|
||||
[](https://github.com/farion1231/cc-switch/releases/latest)
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
## 特長
|
||||
|
||||
### 現在のバージョン:v3.10.2 | [完全な更新履歴](CHANGELOG.md) | [リリースノート](docs/release-note-v3.9.0-ja.md)
|
||||
### 現在のバージョン:v3.10.0 | [完全な更新履歴](CHANGELOG.md) | [リリースノート](docs/release-note-v3.9.0-ja.md)
|
||||
|
||||
**v3.8.0 メジャーアップデート (2025-11-28)**
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
# Claude Code / Codex / Gemini CLI 全方位辅助工具
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://tauri.app/)
|
||||
[](https://github.com/farion1231/cc-switch/releases/latest)
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 当前版本:v3.10.2 | [完整更新日志](CHANGELOG.md) | [发布说明](docs/release-note-v3.9.0-zh.md)
|
||||
### 当前版本:v3.10.0 | [完整更新日志](CHANGELOG.md) | [发布说明](docs/release-note-v3.9.0-zh.md)
|
||||
|
||||
**v3.8.0 重大更新(2025-11-28)**
|
||||
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
# CC Switch v3.10.0
|
||||
|
||||
> OpenCode Support, Global Proxy, Claude Rectifier & Multi-App Experience Enhancements
|
||||
|
||||
**[中文版 →](release-note-v3.10.0-zh.md) | [日本語版 →](release-note-v3.10.0-ja.md)**
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
CC Switch v3.10.0 introduces OpenCode support, becoming the fourth managed CLI application.
|
||||
This release also brings global proxy settings, Claude Rectifier (thinking signature fixer), enhanced health checks, per-provider configuration, and many other important features, along with comprehensive improvements to multi-app workflows and terminal experience.
|
||||
|
||||
**Release Date**: 2026-01-21
|
||||
|
||||
---
|
||||
|
||||
## Highlights
|
||||
|
||||
- OpenCode Support: Full management of providers, MCP servers, and Skills with auto-import on first launch
|
||||
- Global Proxy: Configure a unified proxy for all outbound network requests
|
||||
- Claude Rectifier: Thinking signature fixer for better compatibility with third-party APIs
|
||||
- Enhanced Health Checks: Configurable prompts and CLI-compatible request format
|
||||
- Per-Provider Config: Persistent provider-specific configuration support
|
||||
- App Visibility Control: Freely show/hide apps with synchronized tray menu updates
|
||||
- Terminal Improvements: Provider-specific terminal buttons, fnm path support, cross-platform safe launch
|
||||
- WSL Tool Detection: Detect tool versions in WSL environment with security hardening
|
||||
|
||||
---
|
||||
|
||||
## Main Features
|
||||
|
||||
### OpenCode Support (New Fourth App)
|
||||
|
||||
- Complete OpenCode provider management: add, edit, switch, delete
|
||||
- MCP server management: unified architecture with Claude/Codex/Gemini
|
||||
- Skills support: OpenCode can also use Skills functionality
|
||||
- Auto-import on first launch: automatically imports existing OpenCode configuration when detected
|
||||
- Full internationalization: Chinese/English/Japanese support (#695)
|
||||
|
||||
### Global Proxy
|
||||
|
||||
- Configure a unified proxy for all outbound network requests (#596, thanks @yovinchen)
|
||||
- Supports HTTP/HTTPS proxy protocols
|
||||
- Suitable for network environments requiring proxy access to external APIs
|
||||
|
||||
### Claude Rectifier (Thinking Signature Fixer)
|
||||
|
||||
- Automatically fixes Claude API thinking signatures (#595, thanks @yovinchen)
|
||||
- Resolves incompatible thinking block formats returned by some third-party API gateways
|
||||
- Can be enabled/disabled in Advanced Settings
|
||||
|
||||
### Enhanced Health Checks
|
||||
|
||||
- Configurable custom prompts for streaming health checks (#623, thanks @yovinchen)
|
||||
- Supports CLI-compatible request format for better simulation of real usage scenarios
|
||||
- Improves fault detection accuracy
|
||||
|
||||
### Per-Provider Config
|
||||
|
||||
- Support for saving configuration separately for each provider (#663, thanks @yovinchen)
|
||||
- Persistent configuration: provider-specific settings retained after restart
|
||||
- Suitable for scenarios where different providers require different configurations
|
||||
|
||||
### App Visibility Control
|
||||
|
||||
- Freely show/hide any app (Gemini hidden by default)
|
||||
- Tray menu automatically syncs visibility settings
|
||||
- Hidden apps won't appear in the main interface or tray menu
|
||||
|
||||
### Takeover Compact Mode
|
||||
|
||||
- Automatically uses compact layout when 3 or more visible apps are displayed
|
||||
- Optimizes space utilization in multi-app scenarios
|
||||
|
||||
### Terminal Improvements
|
||||
|
||||
- Provider-specific terminal button: one-click to use current provider in terminal (#564, thanks @kkkman22)
|
||||
- `fnm` path support: automatically recognizes Node.js paths managed by fnm
|
||||
- Cross-platform safe launch: improved terminal launch logic for Windows/macOS/Linux
|
||||
|
||||
### WSL Tool Detection
|
||||
|
||||
- Detect tool versions in WSL environment (#627, thanks @yovinchen)
|
||||
- Added security hardening to prevent command injection risks
|
||||
|
||||
### Skills Preset Enhancements
|
||||
|
||||
- Added `baoyu-skills` preset repository
|
||||
- Automatically supplements missing default repositories for out-of-the-box experience
|
||||
|
||||
---
|
||||
|
||||
## Experience Improvements
|
||||
|
||||
- Keyboard shortcuts: Press `ESC` to quickly return/close panels (#670, thanks @xxk8)
|
||||
- Simplified proxy logs: cleaner and more readable output (#585, thanks @yovinchen)
|
||||
- Pricing editor UX: unified `FullScreenPanel` style
|
||||
- Advanced settings layout: Rectifier section moved below Failover for better logical flow
|
||||
- OpenRouter compatibility mode: disabled by default, UI toggle hidden (reduces clutter)
|
||||
|
||||
---
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
### Proxy & Failover
|
||||
|
||||
- Immediately switch to P1 when auto-failover is enabled (instead of waiting for next request)
|
||||
|
||||
### Provider Management
|
||||
|
||||
- Fixed stale data when reopening provider edit dialog after save (#654, thanks @YangYongAn)
|
||||
- Fixed baseUrl and apiKey state not resetting when switching presets
|
||||
- Fixed endpoint auto-selection state not persisting (#611, thanks @yovinchen)
|
||||
- Automatically apply default color when icon color is not set
|
||||
|
||||
### Deep Links
|
||||
|
||||
- Support multi-endpoint import (#597, thanks @yovinchen)
|
||||
- Prefer `GOOGLE_GEMINI_BASE_URL` over `GEMINI_BASE_URL`
|
||||
|
||||
### MCP
|
||||
|
||||
- Skip `cmd /c` wrapper for WSL target paths (#592, thanks @cxyfer)
|
||||
|
||||
### Usage Templates
|
||||
|
||||
- Added variable hints, fixed validation issues (#628, thanks @YangYongAn)
|
||||
- Prevent configuration leakage between providers
|
||||
- Usage block offset automatically adapts to action button width (#613, thanks @yovinchen)
|
||||
|
||||
### Gemini
|
||||
|
||||
- Convert timeout parameters to Gemini CLI format (#580, thanks @cxyfer)
|
||||
|
||||
### UI
|
||||
|
||||
- Fixed Select dropdown rendering issues in `FullScreenPanel`
|
||||
|
||||
---
|
||||
|
||||
## Notes & Considerations
|
||||
|
||||
- **OpenCode is a newly supported app**: OpenCode CLI must be installed first to use related features.
|
||||
- **Global proxy affects all outbound requests**: including usage queries, health checks, and other network operations.
|
||||
- **Rectifier is experimental**: can be disabled in Advanced Settings if issues occur.
|
||||
|
||||
---
|
||||
|
||||
## Special Thanks
|
||||
|
||||
Thanks to @yovinchen @YangYongAn @cxyfer @xxk8 @kkkman22 @Shuimo03 for their contributions to this release!
|
||||
Thanks to @libukai for designing the elegant failover-related UI!
|
||||
|
||||
---
|
||||
|
||||
## Download & Installation
|
||||
|
||||
Visit [Releases](https://github.com/farion1231/cc-switch/releases/latest) to download the appropriate version.
|
||||
|
||||
### System Requirements
|
||||
|
||||
| System | Minimum Version | Architecture |
|
||||
| ------- | ------------------------------ | ----------------------------------- |
|
||||
| Windows | Windows 10 or later | x64 |
|
||||
| macOS | macOS 10.15 (Catalina) or later | Intel (x64) / Apple Silicon (arm64) |
|
||||
| Linux | See table below | x64 |
|
||||
|
||||
### Windows
|
||||
|
||||
| File | Description |
|
||||
| ---------------------------------------- | ---------------------------------------------------- |
|
||||
| `CC-Switch-v3.10.0-Windows.msi` | **Recommended** - MSI installer with auto-update |
|
||||
| `CC-Switch-v3.10.0-Windows-Portable.zip` | Portable version, extract and run, no registry write |
|
||||
|
||||
### macOS
|
||||
|
||||
| File | Description |
|
||||
| -------------------------------- | ------------------------------------------------------------------ |
|
||||
| `CC-Switch-v3.10.0-macOS.zip` | **Recommended** - Extract and drag to Applications, Universal Binary |
|
||||
| `CC-Switch-v3.10.0-macOS.tar.gz` | For Homebrew installation and auto-update |
|
||||
|
||||
> **Note**: Since the author doesn't have an Apple Developer account, you may see an "unidentified developer" warning on first launch. Please close it, then go to "System Settings" → "Privacy & Security" → click "Open Anyway", and it will open normally afterwards.
|
||||
|
||||
### Homebrew (macOS)
|
||||
|
||||
```bash
|
||||
brew tap farion1231/ccswitch
|
||||
brew install --cask cc-switch
|
||||
```
|
||||
|
||||
Update:
|
||||
|
||||
```bash
|
||||
brew upgrade --cask cc-switch
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
| Distribution | Recommended Format | Installation Method |
|
||||
| --------------------------------------- | ------------------ | ---------------------------------------------------------------------- |
|
||||
| Ubuntu / Debian / Linux Mint / Pop!\_OS | `.deb` | `sudo dpkg -i CC-Switch-*.deb` or `sudo apt install ./CC-Switch-*.deb` |
|
||||
| Fedora / RHEL / CentOS / Rocky Linux | `.rpm` | `sudo rpm -i CC-Switch-*.rpm` or `sudo dnf install ./CC-Switch-*.rpm` |
|
||||
| openSUSE | `.rpm` | `sudo zypper install ./CC-Switch-*.rpm` |
|
||||
| Arch Linux / Manjaro | `.AppImage` | Add execute permission and run directly, or use AUR |
|
||||
| Other distributions / Unsure | `.AppImage` | `chmod +x CC-Switch-*.AppImage && ./CC-Switch-*.AppImage` |
|
||||
@@ -1,206 +0,0 @@
|
||||
# CC Switch v3.10.0
|
||||
|
||||
> OpenCode サポート、グローバルプロキシ、Claude Rectifier とマルチアプリ体験の強化
|
||||
|
||||
**[中文版 →](release-note-v3.10.0-zh.md) | [English →](release-note-v3.10.0-en.md)**
|
||||
|
||||
---
|
||||
|
||||
## 概要
|
||||
|
||||
CC Switch v3.10.0 では OpenCode サポートが追加され、4番目の管理対象 CLI アプリケーションとなりました。
|
||||
また、グローバルプロキシ設定、Claude Rectifier(thinking 署名修正機能)、ヘルスチェックの強化、プロバイダー別設定など、多くの重要な機能が追加され、マルチアプリワークフローとターミナル体験が全面的に改善されました。
|
||||
|
||||
**リリース日**: 2026-01-21
|
||||
|
||||
---
|
||||
|
||||
## ハイライト
|
||||
|
||||
- OpenCode サポート:プロバイダー、MCP サーバー、Skills の完全管理、初回起動時の自動インポート
|
||||
- グローバルプロキシ:すべての送信ネットワークリクエストに統一プロキシを設定
|
||||
- Claude Rectifier:thinking 署名修正機能、サードパーティ API との互換性向上
|
||||
- ヘルスチェック強化:カスタムプロンプト設定、CLI 互換リクエスト形式
|
||||
- プロバイダー別設定:プロバイダー固有の設定の永続化をサポート
|
||||
- アプリ表示制御:アプリの表示/非表示を自由に設定、トレイメニューと同期
|
||||
- ターミナル改善:プロバイダー専用ターミナルボタン、fnm パスサポート、クロスプラットフォーム安全起動
|
||||
- WSL ツール検出:WSL 環境でのツールバージョン検出とセキュリティ強化
|
||||
|
||||
---
|
||||
|
||||
## 主な機能
|
||||
|
||||
### OpenCode サポート(新しい4番目のアプリ)
|
||||
|
||||
- 完全な OpenCode プロバイダー管理:追加、編集、切り替え、削除
|
||||
- MCP サーバー管理:Claude/Codex/Gemini と統一されたアーキテクチャ
|
||||
- Skills サポート:OpenCode でも Skills 機能を使用可能
|
||||
- 初回起動時の自動インポート:既存の OpenCode 設定を検出すると自動的にインポート
|
||||
- 完全な国際化:中国語/英語/日本語サポート (#695)
|
||||
|
||||
### グローバルプロキシ
|
||||
|
||||
- すべての送信ネットワークリクエストに統一プロキシを設定 (#596、@yovinchen に感謝)
|
||||
- HTTP/HTTPS プロキシプロトコルをサポート
|
||||
- 外部 API へのプロキシアクセスが必要なネットワーク環境に適用
|
||||
|
||||
### Claude Rectifier(Thinking 署名修正機能)
|
||||
|
||||
- Claude API の thinking 署名を自動修正 (#595、@yovinchen に感謝)
|
||||
- 一部のサードパーティ API ゲートウェイが返す互換性のない thinking ブロック形式を解決
|
||||
- 詳細設定で有効/無効を切り替え可能
|
||||
|
||||
### ヘルスチェック強化
|
||||
|
||||
- ストリーミングヘルスチェック用のカスタムプロンプトを設定可能 (#623、@yovinchen に感謝)
|
||||
- CLI 互換リクエスト形式をサポートし、実際の使用シナリオをより良くシミュレート
|
||||
- 障害検出の精度を向上
|
||||
|
||||
### プロバイダー別設定
|
||||
|
||||
- 各プロバイダーごとに設定を個別に保存可能 (#663、@yovinchen に感謝)
|
||||
- 設定の永続化:再起動後もプロバイダー固有の設定を保持
|
||||
- 異なるプロバイダーに異なる設定が必要なシナリオに適用
|
||||
|
||||
### アプリ表示制御
|
||||
|
||||
- 任意のアプリを自由に表示/非表示(Gemini はデフォルトで非表示)
|
||||
- トレイメニューは表示設定と自動的に同期
|
||||
- 非表示のアプリはメインインターフェースとトレイメニューに表示されない
|
||||
|
||||
### Takeover コンパクトモード
|
||||
|
||||
- 3つ以上の表示アプリがある場合、自動的にコンパクトレイアウトを使用
|
||||
- マルチアプリシナリオでのスペース利用を最適化
|
||||
|
||||
### ターミナル改善
|
||||
|
||||
- プロバイダー専用ターミナルボタン:ワンクリックでターミナルで現在のプロバイダーを使用 (#564、@kkkman22 に感謝)
|
||||
- `fnm` パスサポート:fnm で管理された Node.js パスを自動認識
|
||||
- クロスプラットフォーム安全起動:Windows/macOS/Linux のターミナル起動ロジックを改善
|
||||
|
||||
### WSL ツール検出
|
||||
|
||||
- WSL 環境でツールバージョンを検出 (#627、@yovinchen に感謝)
|
||||
- コマンドインジェクションリスクを防ぐためのセキュリティ強化を追加
|
||||
|
||||
### Skills プリセット強化
|
||||
|
||||
- `baoyu-skills` プリセットリポジトリを追加
|
||||
- 不足しているデフォルトリポジトリを自動補完し、すぐに使える状態を確保
|
||||
|
||||
---
|
||||
|
||||
## 体験の改善
|
||||
|
||||
- キーボードショートカット:`ESC` を押してパネルをすばやく戻る/閉じる (#670、@xxk8 に感謝)
|
||||
- プロキシログの簡素化:より明確で読みやすい出力 (#585、@yovinchen に感謝)
|
||||
- 価格エディター UX:統一された `FullScreenPanel` スタイル
|
||||
- 詳細設定レイアウト:Rectifier セクションを Failover の下に移動し、論理的な流れを改善
|
||||
- OpenRouter 互換モード:デフォルトで無効、UI トグルを非表示(煩雑さを軽減)
|
||||
|
||||
---
|
||||
|
||||
## バグ修正
|
||||
|
||||
### プロキシとフェイルオーバー
|
||||
|
||||
- 自動フェイルオーバーが有効な場合、すぐに P1 に切り替え(次のリクエストを待たずに)
|
||||
|
||||
### プロバイダー管理
|
||||
|
||||
- 保存後にプロバイダー編集ダイアログを再度開いたときにデータが古い問題を修正 (#654、@YangYongAn に感謝)
|
||||
- プリセット切り替え時に baseUrl と apiKey の状態がリセットされない問題を修正
|
||||
- エンドポイント自動選択状態が永続化されない問題を修正 (#611、@yovinchen に感謝)
|
||||
- アイコンカラーが設定されていない場合、デフォルトカラーを自動適用
|
||||
|
||||
### ディープリンク
|
||||
|
||||
- マルチエンドポイントインポートをサポート (#597、@yovinchen に感謝)
|
||||
- `GEMINI_BASE_URL` より `GOOGLE_GEMINI_BASE_URL` を優先
|
||||
|
||||
### MCP
|
||||
|
||||
- WSL ターゲットパスの `cmd /c` ラッパーをスキップ (#592、@cxyfer に感謝)
|
||||
|
||||
### 使用量テンプレート
|
||||
|
||||
- 変数ヒントを追加、検証の問題を修正 (#628、@YangYongAn に感謝)
|
||||
- プロバイダー間での設定漏洩を防止
|
||||
- 使用量ブロックのオフセットがアクションボタンの幅に自動適応 (#613、@yovinchen に感謝)
|
||||
|
||||
### Gemini
|
||||
|
||||
- タイムアウトパラメータを Gemini CLI 形式に変換 (#580、@cxyfer に感謝)
|
||||
|
||||
### UI
|
||||
|
||||
- `FullScreenPanel` での Select ドロップダウンのレンダリング問題を修正
|
||||
|
||||
---
|
||||
|
||||
## 注意事項
|
||||
|
||||
- **OpenCode は新しくサポートされたアプリです**:関連機能を使用するには、まず OpenCode CLI をインストールする必要があります。
|
||||
- **グローバルプロキシはすべての送信リクエストに影響します**:使用量クエリ、ヘルスチェックなどのネットワーク操作を含みます。
|
||||
- **Rectifier は実験的機能です**:問題が発生した場合は、詳細設定で無効にできます。
|
||||
|
||||
---
|
||||
|
||||
## 特別な感謝
|
||||
|
||||
@yovinchen @YangYongAn @cxyfer @xxk8 @kkkman22 @Shuimo03 の皆様、このリリースへの貢献に感謝します!
|
||||
@libukai 様、エレガントなフェイルオーバー関連 UI のデザインに感謝します!
|
||||
|
||||
---
|
||||
|
||||
## ダウンロードとインストール
|
||||
|
||||
[Releases](https://github.com/farion1231/cc-switch/releases/latest) から適切なバージョンをダウンロードしてください。
|
||||
|
||||
### システム要件
|
||||
|
||||
| システム | 最小バージョン | アーキテクチャ |
|
||||
| -------- | -------------------------------- | ----------------------------------- |
|
||||
| Windows | Windows 10 以降 | x64 |
|
||||
| macOS | macOS 10.15 (Catalina) 以降 | Intel (x64) / Apple Silicon (arm64) |
|
||||
| Linux | 下表参照 | x64 |
|
||||
|
||||
### Windows
|
||||
|
||||
| ファイル | 説明 |
|
||||
| ---------------------------------------- | ---------------------------------------------------- |
|
||||
| `CC-Switch-v3.10.0-Windows.msi` | **推奨** - MSI インストーラー、自動更新対応 |
|
||||
| `CC-Switch-v3.10.0-Windows-Portable.zip` | ポータブル版、解凍して実行、レジストリ書き込みなし |
|
||||
|
||||
### macOS
|
||||
|
||||
| ファイル | 説明 |
|
||||
| -------------------------------- | ----------------------------------------------------------------- |
|
||||
| `CC-Switch-v3.10.0-macOS.zip` | **推奨** - 解凍して Applications にドラッグ、Universal Binary |
|
||||
| `CC-Switch-v3.10.0-macOS.tar.gz` | Homebrew インストールと自動更新用 |
|
||||
|
||||
> **注意**:作者が Apple Developer アカウントを持っていないため、初回起動時に「開発元を確認できません」という警告が表示される場合があります。一度閉じてから、「システム設定」→「プライバシーとセキュリティ」→「このまま開く」をクリックすると、その後は正常に開けます。
|
||||
|
||||
### Homebrew (macOS)
|
||||
|
||||
```bash
|
||||
brew tap farion1231/ccswitch
|
||||
brew install --cask cc-switch
|
||||
```
|
||||
|
||||
更新:
|
||||
|
||||
```bash
|
||||
brew upgrade --cask cc-switch
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
| ディストリビューション | 推奨形式 | インストール方法 |
|
||||
| --------------------------------------- | ----------- | ---------------------------------------------------------------------- |
|
||||
| Ubuntu / Debian / Linux Mint / Pop!\_OS | `.deb` | `sudo dpkg -i CC-Switch-*.deb` または `sudo apt install ./CC-Switch-*.deb` |
|
||||
| Fedora / RHEL / CentOS / Rocky Linux | `.rpm` | `sudo rpm -i CC-Switch-*.rpm` または `sudo dnf install ./CC-Switch-*.rpm` |
|
||||
| openSUSE | `.rpm` | `sudo zypper install ./CC-Switch-*.rpm` |
|
||||
| Arch Linux / Manjaro | `.AppImage` | 実行権限を追加して直接実行、または AUR を使用 |
|
||||
| その他のディストリビューション / 不明 | `.AppImage` | `chmod +x CC-Switch-*.AppImage && ./CC-Switch-*.AppImage` |
|
||||
@@ -1,206 +0,0 @@
|
||||
# CC Switch v3.10.0
|
||||
|
||||
> OpenCode 支持、全局代理、Claude Rectifier 与多应用体验增强
|
||||
|
||||
**[English →](release-note-v3.10.0-en.md) | [日本語版 →](release-note-v3.10.0-ja.md)**
|
||||
|
||||
---
|
||||
|
||||
## 概览
|
||||
|
||||
CC Switch v3.10.0 新增 OpenCode 支持,成为第四个受管理的 CLI 应用。
|
||||
同时带来全局代理设置、Claude Rectifier(thinking 签名修正器)、健康检查增强、按供应商配置等多项重要功能,并对多应用工作流与终端体验做了全面改进。
|
||||
|
||||
**发布日期**:2026-01-21
|
||||
|
||||
---
|
||||
|
||||
## 重点内容
|
||||
|
||||
- OpenCode 支持:供应商、MCP 服务器、Skills 全面管理,首次启动自动导入
|
||||
- 全局代理:为出站网络请求统一配置代理
|
||||
- Claude Rectifier:thinking 签名修正器,兼容更多第三方 API
|
||||
- 健康检查增强:可配置提示词、CLI 兼容请求
|
||||
- 按供应商配置:支持供应商特定配置的持久化
|
||||
- 应用可见性控制:自由显示/隐藏应用,托盘菜单同步更新
|
||||
- 终端改进:供应商专属终端按钮、fnm 路径支持、跨平台安全启动
|
||||
- WSL 工具检测:在 WSL 环境检测工具版本,并增加安全加固
|
||||
|
||||
---
|
||||
|
||||
## 主要功能
|
||||
|
||||
### OpenCode 支持(新增第四应用)
|
||||
|
||||
- 完整的 OpenCode 供应商管理:新增、编辑、切换、删除
|
||||
- MCP 服务器管理:与 Claude/Codex/Gemini 统一架构
|
||||
- Skills 支持:OpenCode 也可使用 Skills 功能
|
||||
- 首次启动自动导入:检测到已有 OpenCode 配置时自动导入
|
||||
- 完整国际化:中/英/日三语支持(#695)
|
||||
|
||||
### 全局代理(Global Proxy)
|
||||
|
||||
- 为所有出站网络请求配置统一代理(#596,感谢 @yovinchen)
|
||||
- 支持 HTTP/HTTPS 代理协议
|
||||
- 适用于需要代理访问外部 API 的网络环境
|
||||
|
||||
### Claude Rectifier(Thinking 签名修正器)
|
||||
|
||||
- 自动修正 Claude API 的 thinking 签名(#595,感谢 @yovinchen)
|
||||
- 解决部分第三方 API 网关返回的 thinking 块格式不兼容问题
|
||||
- 在高级设置中可开启/关闭
|
||||
|
||||
### 健康检查增强
|
||||
|
||||
- 可配置自定义提示词(prompt)用于流式健康检查(#623,感谢 @yovinchen)
|
||||
- 支持 CLI 兼容请求格式,更好地模拟真实使用场景
|
||||
- 提升故障检测的准确性
|
||||
|
||||
### 按供应商配置(Per-Provider Config)
|
||||
|
||||
- 支持为每个供应商单独保存配置(#663,感谢 @yovinchen)
|
||||
- 配置持久化:重启后保留供应商专属设置
|
||||
- 适用于不同供应商需要不同配置的场景
|
||||
|
||||
### 应用可见性控制
|
||||
|
||||
- 自由显示/隐藏任意应用(Gemini 默认隐藏)
|
||||
- 托盘菜单自动同步可见性设置
|
||||
- 隐藏的应用不会出现在主界面和托盘菜单中
|
||||
|
||||
### Takeover Compact Mode
|
||||
|
||||
- 当显示 3 个及以上可见应用时,自动使用紧凑布局
|
||||
- 优化多应用场景下的空间利用
|
||||
|
||||
### 终端改进
|
||||
|
||||
- 供应商专属终端按钮:一键在终端中使用当前供应商(#564,感谢 @kkkman22)
|
||||
- `fnm` 路径支持:自动识别 fnm 管理的 Node.js 路径
|
||||
- 跨平台安全启动:改进 Windows/macOS/Linux 的终端启动逻辑
|
||||
|
||||
### WSL 工具检测
|
||||
|
||||
- 在 WSL 环境中检测工具版本(#627,感谢 @yovinchen)
|
||||
- 增加安全加固,防止命令注入风险
|
||||
|
||||
### Skills 预设增强
|
||||
|
||||
- 新增 `baoyu-skills` 预设仓库
|
||||
- 自动补充缺失的默认仓库,确保开箱即用
|
||||
|
||||
---
|
||||
|
||||
## 体验优化
|
||||
|
||||
- 键盘快捷键:按 `ESC` 快速返回/关闭面板(#670,感谢 @xxk8)
|
||||
- 代理日志简化:输出更清晰易读(#585,感谢 @yovinchen)
|
||||
- 定价编辑器 UX:统一使用 `FullScreenPanel` 风格
|
||||
- 高级设置布局:Rectifier 区块移至 Failover 下方,逻辑更顺畅
|
||||
- OpenRouter 兼容模式:默认禁用,UI 开关隐藏(减少干扰)
|
||||
|
||||
---
|
||||
|
||||
## Bug 修复
|
||||
|
||||
### 代理与故障切换
|
||||
|
||||
- 启用自动故障切换时立即切换到 P1(而非等待下次请求)
|
||||
|
||||
### 供应商管理
|
||||
|
||||
- 修复供应商编辑对话框保存后重新打开时数据过时的问题(#654,感谢 @YangYongAn)
|
||||
- 修复切换预设时 baseUrl 和 apiKey 状态未重置的问题
|
||||
- 修复端点自动选择状态未持久化的问题(#611,感谢 @yovinchen)
|
||||
- 未设置图标颜色时自动应用默认颜色
|
||||
|
||||
### 深链接
|
||||
|
||||
- 支持多端点导入(#597,感谢 @yovinchen)
|
||||
- 优先使用 `GOOGLE_GEMINI_BASE_URL` 而非 `GEMINI_BASE_URL`
|
||||
|
||||
### MCP
|
||||
|
||||
- WSL 目标路径跳过 `cmd /c` 包裹(#592,感谢 @cxyfer)
|
||||
|
||||
### 用量模板
|
||||
|
||||
- 新增变量提示,修复验证问题(#628,感谢 @YangYongAn)
|
||||
- 防止配置在供应商之间泄漏
|
||||
- 用量区块偏移量根据操作按钮宽度自动适应(#613,感谢 @yovinchen)
|
||||
|
||||
### Gemini
|
||||
|
||||
- 超时参数转换为 Gemini CLI 格式(#580,感谢 @cxyfer)
|
||||
|
||||
### UI
|
||||
|
||||
- 修复 `FullScreenPanel` 中 Select 下拉框渲染问题
|
||||
|
||||
---
|
||||
|
||||
## 说明与注意事项
|
||||
|
||||
- **OpenCode 为新支持的应用**:需要先安装 OpenCode CLI 才能使用相关功能。
|
||||
- **全局代理会影响所有出站请求**:包括用量查询、健康检查等网络操作。
|
||||
- **Rectifier 功能为实验性**:如遇问题可在高级设置中关闭。
|
||||
|
||||
---
|
||||
|
||||
## 特别感谢
|
||||
|
||||
感谢 @yovinchen @YangYongAn @cxyfer @xxk8 @kkkman22 @Shuimo03 为本版本做出的贡献!
|
||||
感谢 @libukai 设计的故障转移相关 UI,非常优雅!
|
||||
|
||||
---
|
||||
|
||||
## 下载与安装
|
||||
|
||||
访问 [Releases](https://github.com/farion1231/cc-switch/releases/latest) 下载对应版本。
|
||||
|
||||
### 系统要求
|
||||
|
||||
| 系统 | 最低版本 | 架构 |
|
||||
| ------- | ----------------------------- | ----------------------------------- |
|
||||
| Windows | Windows 10 及以上 | x64 |
|
||||
| macOS | macOS 10.15 (Catalina) 及以上 | Intel (x64) / Apple Silicon (arm64) |
|
||||
| Linux | 见下表 | x64 |
|
||||
|
||||
### Windows
|
||||
|
||||
| 文件 | 说明 |
|
||||
| ---------------------------------------- | ----------------------------------- |
|
||||
| `CC-Switch-v3.10.0-Windows.msi` | **推荐** - MSI 安装包,支持自动更新 |
|
||||
| `CC-Switch-v3.10.0-Windows-Portable.zip` | 便携版,解压即用,不写入注册表 |
|
||||
|
||||
### macOS
|
||||
|
||||
| 文件 | 说明 |
|
||||
| -------------------------------- | --------------------------------------------------------- |
|
||||
| `CC-Switch-v3.10.0-macOS.zip` | **推荐** - 解压后拖入 Applications 即可,Universal Binary |
|
||||
| `CC-Switch-v3.10.0-macOS.tar.gz` | 用于 Homebrew 安装和自动更新 |
|
||||
|
||||
> **注意**:由于作者没有苹果开发者账号,首次打开可能出现"未知开发者"警告,请先关闭,然后前往"系统设置" → "隐私与安全性" → 点击"仍要打开",之后便可以正常打开
|
||||
|
||||
### Homebrew(macOS)
|
||||
|
||||
```bash
|
||||
brew tap farion1231/ccswitch
|
||||
brew install --cask cc-switch
|
||||
```
|
||||
|
||||
更新:
|
||||
|
||||
```bash
|
||||
brew upgrade --cask cc-switch
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
| 发行版 | 推荐格式 | 安装方式 |
|
||||
| --------------------------------------- | ----------- | ---------------------------------------------------------------------- |
|
||||
| Ubuntu / Debian / Linux Mint / Pop!\_OS | `.deb` | `sudo dpkg -i CC-Switch-*.deb` 或 `sudo apt install ./CC-Switch-*.deb` |
|
||||
| Fedora / RHEL / CentOS / Rocky Linux | `.rpm` | `sudo rpm -i CC-Switch-*.rpm` 或 `sudo dnf install ./CC-Switch-*.rpm` |
|
||||
| openSUSE | `.rpm` | `sudo zypper install ./CC-Switch-*.rpm` |
|
||||
| Arch Linux / Manjaro | `.AppImage` | 添加执行权限后直接运行,或使用 AUR |
|
||||
| 其他发行版 / 不确定 | `.AppImage` | `chmod +x CC-Switch-*.AppImage && ./CC-Switch-*.AppImage` |
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cc-switch",
|
||||
"version": "3.10.2",
|
||||
"version": "3.10.0",
|
||||
"description": "All-in-One Assistant for Claude Code, Codex & Gemini CLI",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
Generated
+1
-1
@@ -701,7 +701,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc-switch"
|
||||
version = "3.10.2"
|
||||
version = "3.10.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cc-switch"
|
||||
version = "3.10.2"
|
||||
version = "3.10.0"
|
||||
description = "All-in-One Assistant for Claude Code, Codex & Gemini CLI"
|
||||
authors = ["Jason Young"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -729,16 +729,19 @@ echo {}
|
||||
claude --settings \"{}\"
|
||||
del \"{}\" >nul 2>&1
|
||||
del \"%~f0\" >nul 2>&1
|
||||
",
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo Press any key to close...
|
||||
pause >nul
|
||||
)",
|
||||
config_path_for_batch, config_path_for_batch, config_path_for_batch
|
||||
);
|
||||
|
||||
std::fs::write(&bat_file, content).map_err(|e| format!("写入批处理文件失败: {e}"))?;
|
||||
|
||||
// Use output() to capture errors from the start command
|
||||
// Use /K instead of /C to keep the window open after execution
|
||||
let output = Command::new("cmd")
|
||||
.args(["/C", "start", "cmd", "/K", &bat_file.to_string_lossy()])
|
||||
.args(["/C", "start", "cmd", "/C", &bat_file.to_string_lossy()])
|
||||
.creation_flags(CREATE_NO_WINDOW)
|
||||
.output()
|
||||
.map_err(|e| format!("执行 cmd 失败: {e}"))?;
|
||||
|
||||
@@ -42,10 +42,21 @@ pub fn get_opencode_dir() -> PathBuf {
|
||||
return override_dir;
|
||||
}
|
||||
|
||||
// 所有平台统一使用 ~/.config/opencode
|
||||
dirs::home_dir()
|
||||
.map(|h| h.join(".config").join("opencode"))
|
||||
.unwrap_or_else(|| PathBuf::from(".config").join("opencode"))
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// Windows: %APPDATA%\opencode
|
||||
dirs::data_dir()
|
||||
.map(|d| d.join("opencode"))
|
||||
.unwrap_or_else(|| PathBuf::from(".config").join("opencode"))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
// Unix: ~/.config/opencode
|
||||
dirs::home_dir()
|
||||
.map(|h| h.join(".config").join("opencode"))
|
||||
.unwrap_or_else(|| PathBuf::from(".config").join("opencode"))
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取 OpenCode 配置文件路径
|
||||
|
||||
@@ -596,11 +596,6 @@ pub struct OpenCodeModel {
|
||||
/// 模型额外选项(provider 路由等)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub options: Option<HashMap<String, Value>>,
|
||||
|
||||
/// 额外字段(cost、modalities、thinking、variants 等)
|
||||
/// 使用 flatten 捕获所有未明确定义的字段
|
||||
#[serde(flatten, default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub extra: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
/// OpenCode 模型限制
|
||||
|
||||
@@ -561,12 +561,19 @@ impl RequestForwarder {
|
||||
// 检查是否需要格式转换
|
||||
let needs_transform = adapter.needs_transform(provider);
|
||||
|
||||
let effective_endpoint =
|
||||
if needs_transform && adapter.name() == "Claude" && endpoint == "/v1/messages" {
|
||||
// 确定有效端点:
|
||||
// - 如果需要转换且是 Claude 的 /v1/messages 端点,改写为 /v1/chat/completions
|
||||
// - 但如果 base_url 已包含 chat/completions,则不再自动添加
|
||||
let effective_endpoint = if needs_transform && adapter.name() == "Claude" {
|
||||
let base_has_chat_completions = base_url.contains("chat/completions");
|
||||
if endpoint == "/v1/messages" && !base_has_chat_completions {
|
||||
"/v1/chat/completions"
|
||||
} else {
|
||||
endpoint
|
||||
};
|
||||
}
|
||||
} else {
|
||||
endpoint
|
||||
};
|
||||
|
||||
// 使用适配器构建 URL
|
||||
let url = adapter.build_url(&base_url, effective_endpoint);
|
||||
|
||||
@@ -23,10 +23,16 @@ impl ClaudeAdapter {
|
||||
/// 获取供应商类型
|
||||
///
|
||||
/// 根据 base_url 和 auth_mode 检测具体的供应商类型:
|
||||
/// - ChatCompletions: chat_completions_mode 为 true(优先级最高)
|
||||
/// - OpenRouter: base_url 包含 openrouter.ai
|
||||
/// - ClaudeAuth: auth_mode 为 bearer_only
|
||||
/// - Claude: 默认 Anthropic 官方
|
||||
pub fn provider_type(&self, provider: &Provider) -> ProviderType {
|
||||
// 检测 ChatCompletions 模式(优先级最高)
|
||||
if self.is_chat_completions_mode(provider) {
|
||||
return ProviderType::ChatCompletions;
|
||||
}
|
||||
|
||||
// 检测 OpenRouter
|
||||
if self.is_openrouter(provider) {
|
||||
return ProviderType::OpenRouter;
|
||||
@@ -48,6 +54,20 @@ impl ClaudeAdapter {
|
||||
false
|
||||
}
|
||||
|
||||
/// 检测是否启用 ChatCompletions 兼容模式
|
||||
fn is_chat_completions_mode(&self, provider: &Provider) -> bool {
|
||||
let raw = provider.settings_config.get("chat_completions_mode");
|
||||
match raw {
|
||||
Some(serde_json::Value::Bool(enabled)) => *enabled,
|
||||
Some(serde_json::Value::Number(num)) => num.as_i64().unwrap_or(0) != 0,
|
||||
Some(serde_json::Value::String(value)) => {
|
||||
let normalized = value.trim().to_lowercase();
|
||||
normalized == "true" || normalized == "1"
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 检测 OpenRouter 是否启用兼容模式
|
||||
fn is_openrouter_compat_enabled(&self, provider: &Provider) -> bool {
|
||||
if !self.is_openrouter(provider) {
|
||||
@@ -253,13 +273,9 @@ impl ProviderAdapter for ClaudeAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
fn needs_transform(&self, _provider: &Provider) -> bool {
|
||||
// NOTE:
|
||||
// OpenRouter 已推出 Claude Code 兼容接口(可直接处理 `/v1/messages`),默认不再启用
|
||||
// Anthropic ↔ OpenAI 的格式转换。
|
||||
//
|
||||
// 如果未来需要回退到旧的 OpenAI Chat Completions 方案,可恢复下面这行:
|
||||
self.is_openrouter_compat_enabled(_provider)
|
||||
fn needs_transform(&self, provider: &Provider) -> bool {
|
||||
// ChatCompletions 模式或 OpenRouter 兼容模式都需要转换
|
||||
self.is_chat_completions_mode(provider) || self.is_openrouter_compat_enabled(provider)
|
||||
}
|
||||
|
||||
fn transform_request(
|
||||
|
||||
@@ -50,6 +50,8 @@ pub enum ProviderType {
|
||||
GeminiCli,
|
||||
/// OpenRouter(已支持 Claude Code 兼容接口,默认透传;保留旧转换逻辑备用)
|
||||
OpenRouter,
|
||||
/// ChatCompletions 兼容模式(Anthropic ↔ OpenAI 格式转换,不限制上游地址)
|
||||
ChatCompletions,
|
||||
}
|
||||
|
||||
impl ProviderType {
|
||||
@@ -75,6 +77,7 @@ impl ProviderType {
|
||||
"https://generativelanguage.googleapis.com"
|
||||
}
|
||||
ProviderType::OpenRouter => "https://openrouter.ai/api",
|
||||
ProviderType::ChatCompletions => "https://api.openai.com",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +151,7 @@ impl ProviderType {
|
||||
ProviderType::Gemini => "gemini",
|
||||
ProviderType::GeminiCli => "gemini_cli",
|
||||
ProviderType::OpenRouter => "openrouter",
|
||||
ProviderType::ChatCompletions => "chat_completions",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,6 +173,9 @@ impl std::str::FromStr for ProviderType {
|
||||
"gemini" => Ok(ProviderType::Gemini),
|
||||
"gemini_cli" | "gemini-cli" => Ok(ProviderType::GeminiCli),
|
||||
"openrouter" => Ok(ProviderType::OpenRouter),
|
||||
"chat_completions" | "chat-completions" | "chatcompletions" => {
|
||||
Ok(ProviderType::ChatCompletions)
|
||||
}
|
||||
_ => Err(format!("Invalid provider type: {s}")),
|
||||
}
|
||||
}
|
||||
@@ -191,9 +198,10 @@ pub fn get_adapter(app_type: &AppType) -> Box<dyn ProviderAdapter> {
|
||||
#[allow(dead_code)]
|
||||
pub fn get_adapter_for_provider_type(provider_type: &ProviderType) -> Box<dyn ProviderAdapter> {
|
||||
match provider_type {
|
||||
ProviderType::Claude | ProviderType::ClaudeAuth | ProviderType::OpenRouter => {
|
||||
Box::new(ClaudeAdapter::new())
|
||||
}
|
||||
ProviderType::Claude
|
||||
| ProviderType::ClaudeAuth
|
||||
| ProviderType::OpenRouter
|
||||
| ProviderType::ChatCompletions => Box::new(ClaudeAdapter::new()),
|
||||
ProviderType::Codex => Box::new(CodexAdapter::new()),
|
||||
ProviderType::Gemini | ProviderType::GeminiCli => Box::new(GeminiAdapter::new()),
|
||||
}
|
||||
|
||||
@@ -115,16 +115,22 @@ pub fn create_anthropic_sse_stream(
|
||||
|
||||
if let Some(choice) = chunk.choices.first() {
|
||||
if !has_sent_message_start {
|
||||
// 构建完整的 message_start 事件,与原生 Anthropic 格式一致
|
||||
let event = json!({
|
||||
"type": "message_start",
|
||||
"message": {
|
||||
"id": message_id.clone().unwrap_or_default(),
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"content": [],
|
||||
"model": current_model.clone().unwrap_or_default(),
|
||||
"stop_reason": null,
|
||||
"stop_sequence": null,
|
||||
"usage": {
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0
|
||||
"input_tokens": chunk.usage.as_ref().map(|u| u.prompt_tokens).unwrap_or(1),
|
||||
"output_tokens": 0,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -272,18 +278,17 @@ pub fn create_anthropic_sse_stream(
|
||||
}
|
||||
|
||||
let stop_reason = map_stop_reason(Some(finish_reason));
|
||||
// 构建 usage 信息,包含 input_tokens 和 output_tokens
|
||||
let usage_json = chunk.usage.as_ref().map(|u| json!({
|
||||
"input_tokens": u.prompt_tokens,
|
||||
"output_tokens": u.completion_tokens
|
||||
}));
|
||||
// 构建 usage 信息,Anthropic 格式只需要 output_tokens
|
||||
let output_tokens = chunk.usage.as_ref().map(|u| u.completion_tokens).unwrap_or(0);
|
||||
let event = json!({
|
||||
"type": "message_delta",
|
||||
"delta": {
|
||||
"stop_reason": stop_reason,
|
||||
"stop_sequence": null
|
||||
},
|
||||
"usage": usage_json
|
||||
"usage": {
|
||||
"output_tokens": output_tokens
|
||||
}
|
||||
});
|
||||
let sse_data = format!("event: message_delta\ndata: {}\n\n",
|
||||
serde_json::to_string(&event).unwrap_or_default());
|
||||
|
||||
@@ -195,19 +195,28 @@ pub struct AppProxyConfig {
|
||||
/// 整流器配置
|
||||
///
|
||||
/// 存储在 settings 表中
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RectifierConfig {
|
||||
/// 总开关:是否启用整流器
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
/// 请求整流:启用 thinking 签名整流器
|
||||
///
|
||||
/// 处理错误:Invalid 'signature' in 'thinking' block
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_true")]
|
||||
pub request_thinking_signature: bool,
|
||||
}
|
||||
|
||||
impl Default for RectifierConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
request_thinking_signature: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
@@ -261,34 +270,35 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_rectifier_config_default_disabled() {
|
||||
// 验证 RectifierConfig::default() 返回全禁用状态
|
||||
fn test_rectifier_config_default_enabled() {
|
||||
// 验证 RectifierConfig::default() 返回全启用状态
|
||||
// 防止回归:#[derive(Default)] 会使 bool 默认为 false
|
||||
let config = RectifierConfig::default();
|
||||
assert!(!config.enabled, "整流器总开关默认应为 false");
|
||||
assert!(config.enabled, "整流器总开关默认应为 true");
|
||||
assert!(
|
||||
!config.request_thinking_signature,
|
||||
"thinking 签名整流器默认应为 false"
|
||||
config.request_thinking_signature,
|
||||
"thinking 签名整流器默认应为 true"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rectifier_config_serde_default() {
|
||||
// 验证反序列化缺字段时使用默认值 false
|
||||
// 验证反序列化缺字段时使用 default_true
|
||||
let json = "{}";
|
||||
let config: RectifierConfig = serde_json::from_str(json).unwrap();
|
||||
assert!(!config.enabled);
|
||||
assert!(!config.request_thinking_signature);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rectifier_config_serde_explicit_true() {
|
||||
// 验证显式设置 true 时正确反序列化
|
||||
let json = r#"{"enabled": true, "requestThinkingSignature": true}"#;
|
||||
let config: RectifierConfig = serde_json::from_str(json).unwrap();
|
||||
assert!(config.enabled);
|
||||
assert!(config.request_thinking_signature);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rectifier_config_serde_explicit_false() {
|
||||
// 验证显式设置 false 时正确反序列化
|
||||
let json = r#"{"enabled": false, "requestThinkingSignature": false}"#;
|
||||
let config: RectifierConfig = serde_json::from_str(json).unwrap();
|
||||
assert!(!config.enabled);
|
||||
assert!(!config.request_thinking_signature);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log_config_default() {
|
||||
let config = LogConfig::default();
|
||||
|
||||
@@ -36,22 +36,10 @@ impl PromptService {
|
||||
|
||||
state.db.save_prompt(app.as_str(), &prompt)?;
|
||||
|
||||
// 如果是已启用的提示词,同步更新到对应的文件
|
||||
if is_enabled {
|
||||
// 启用提示词:写入内容到文件
|
||||
let target_path = prompt_file_path(&app)?;
|
||||
write_text_file(&target_path, &prompt.content)?;
|
||||
} else {
|
||||
// 禁用提示词:检查是否还有其他已启用的提示词
|
||||
let prompts = state.db.get_prompts(app.as_str())?;
|
||||
let any_enabled = prompts.values().any(|p| p.enabled);
|
||||
|
||||
if !any_enabled {
|
||||
// 所有提示词都已禁用,清空文件
|
||||
let target_path = prompt_file_path(&app)?;
|
||||
if target_path.exists() {
|
||||
write_text_file(&target_path, "")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
+14
-158
@@ -21,19 +21,6 @@ use crate::error::format_skill_error;
|
||||
|
||||
// ========== 数据结构 ==========
|
||||
|
||||
/// Skill 同步方式
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SyncMethod {
|
||||
/// 自动选择:优先 symlink,失败时回退到 copy
|
||||
#[default]
|
||||
Auto,
|
||||
/// 符号链接(推荐,节省磁盘空间)
|
||||
Symlink,
|
||||
/// 文件复制(兼容模式)
|
||||
Copy,
|
||||
}
|
||||
|
||||
/// 可发现的技能(来自仓库)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DiscoverableSkill {
|
||||
@@ -252,50 +239,6 @@ impl SkillService {
|
||||
.map(|s| s.to_string_lossy().to_string())
|
||||
.unwrap_or_else(|| skill.directory.clone());
|
||||
|
||||
// 检查数据库中是否已有同名 directory 的 skill(来自其他仓库)
|
||||
let existing_skills = db.get_all_installed_skills()?;
|
||||
for existing in existing_skills.values() {
|
||||
if existing.directory.eq_ignore_ascii_case(&install_name) {
|
||||
// 检查是否来自同一仓库
|
||||
let same_repo = existing.repo_owner.as_deref() == Some(&skill.repo_owner)
|
||||
&& existing.repo_name.as_deref() == Some(&skill.repo_name);
|
||||
if same_repo {
|
||||
// 同一仓库的同名 skill,返回现有记录(可能需要更新启用状态)
|
||||
let mut updated = existing.clone();
|
||||
updated.apps.set_enabled_for(current_app, true);
|
||||
db.save_skill(&updated)?;
|
||||
Self::sync_to_app_dir(&updated.directory, current_app)?;
|
||||
log::info!(
|
||||
"Skill {} 已存在,更新 {:?} 启用状态",
|
||||
updated.name,
|
||||
current_app
|
||||
);
|
||||
return Ok(updated);
|
||||
} else {
|
||||
// 不同仓库的同名 skill,报错
|
||||
return Err(anyhow!(format_skill_error(
|
||||
"SKILL_DIRECTORY_CONFLICT",
|
||||
&[
|
||||
("directory", &install_name),
|
||||
(
|
||||
"existing_repo",
|
||||
&format!(
|
||||
"{}/{}",
|
||||
existing.repo_owner.as_deref().unwrap_or("unknown"),
|
||||
existing.repo_name.as_deref().unwrap_or("unknown")
|
||||
)
|
||||
),
|
||||
(
|
||||
"new_repo",
|
||||
&format!("{}/{}", skill.repo_owner, skill.repo_name)
|
||||
),
|
||||
],
|
||||
Some("uninstallFirst"),
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let dest = ssot_dir.join(&install_name);
|
||||
|
||||
// 如果已存在则跳过下载
|
||||
@@ -362,7 +305,7 @@ impl SkillService {
|
||||
db.save_skill(&installed_skill)?;
|
||||
|
||||
// 同步到当前应用目录
|
||||
Self::sync_to_app_dir(&install_name, current_app)?;
|
||||
Self::copy_to_app(&install_name, current_app)?;
|
||||
|
||||
log::info!(
|
||||
"Skill {} 安装成功,已启用 {:?}",
|
||||
@@ -425,7 +368,7 @@ impl SkillService {
|
||||
|
||||
// 同步文件
|
||||
if enabled {
|
||||
Self::sync_to_app_dir(&skill.directory, app)?;
|
||||
Self::copy_to_app(&skill.directory, app)?;
|
||||
} else {
|
||||
Self::remove_from_app(&skill.directory, app)?;
|
||||
}
|
||||
@@ -623,41 +566,8 @@ impl SkillService {
|
||||
|
||||
// ========== 文件同步方法 ==========
|
||||
|
||||
/// 创建符号链接(跨平台)
|
||||
///
|
||||
/// - Unix: 使用 std::os::unix::fs::symlink
|
||||
/// - Windows: 使用 std::os::windows::fs::symlink_dir
|
||||
#[cfg(unix)]
|
||||
fn create_symlink(src: &Path, dest: &Path) -> Result<()> {
|
||||
std::os::unix::fs::symlink(src, dest)
|
||||
.with_context(|| format!("创建符号链接失败: {} -> {}", src.display(), dest.display()))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn create_symlink(src: &Path, dest: &Path) -> Result<()> {
|
||||
std::os::windows::fs::symlink_dir(src, dest)
|
||||
.with_context(|| format!("创建符号链接失败: {} -> {}", src.display(), dest.display()))
|
||||
}
|
||||
|
||||
/// 检查路径是否为符号链接
|
||||
fn is_symlink(path: &Path) -> bool {
|
||||
path.symlink_metadata()
|
||||
.map(|m| m.file_type().is_symlink())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// 获取当前同步方式配置
|
||||
fn get_sync_method() -> SyncMethod {
|
||||
crate::settings::get_skill_sync_method()
|
||||
}
|
||||
|
||||
/// 同步 Skill 到应用目录(使用 symlink 或 copy)
|
||||
///
|
||||
/// 根据配置和平台选择最佳同步方式:
|
||||
/// - Auto: 优先尝试 symlink,失败时回退到 copy
|
||||
/// - Symlink: 仅使用 symlink
|
||||
/// - Copy: 仅使用文件复制
|
||||
pub fn sync_to_app_dir(directory: &str, app: &AppType) -> Result<()> {
|
||||
/// 复制 Skill 到应用目录
|
||||
pub fn copy_to_app(directory: &str, app: &AppType) -> Result<()> {
|
||||
let ssot_dir = Self::get_ssot_dir()?;
|
||||
let source = ssot_dir.join(directory);
|
||||
|
||||
@@ -670,77 +580,25 @@ impl SkillService {
|
||||
|
||||
let dest = app_dir.join(directory);
|
||||
|
||||
// 如果已存在则先删除(无论是 symlink 还是真实目录)
|
||||
if dest.exists() || Self::is_symlink(&dest) {
|
||||
Self::remove_path(&dest)?;
|
||||
// 如果已存在则先删除
|
||||
if dest.exists() {
|
||||
fs::remove_dir_all(&dest)?;
|
||||
}
|
||||
|
||||
let sync_method = Self::get_sync_method();
|
||||
Self::copy_dir_recursive(&source, &dest)?;
|
||||
|
||||
match sync_method {
|
||||
SyncMethod::Auto => {
|
||||
// 优先尝试 symlink
|
||||
match Self::create_symlink(&source, &dest) {
|
||||
Ok(()) => {
|
||||
log::debug!("Skill {directory} 已通过 symlink 同步到 {app:?}");
|
||||
return Ok(());
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!(
|
||||
"Symlink 创建失败,将回退到文件复制: {} -> {}. 错误: {err:#}",
|
||||
source.display(),
|
||||
dest.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
// Fallback 到 copy
|
||||
Self::copy_dir_recursive(&source, &dest)?;
|
||||
log::debug!("Skill {directory} 已通过复制同步到 {app:?}");
|
||||
}
|
||||
SyncMethod::Symlink => {
|
||||
Self::create_symlink(&source, &dest)?;
|
||||
log::debug!("Skill {directory} 已通过 symlink 同步到 {app:?}");
|
||||
}
|
||||
SyncMethod::Copy => {
|
||||
Self::copy_dir_recursive(&source, &dest)?;
|
||||
log::debug!("Skill {directory} 已通过复制同步到 {app:?}");
|
||||
}
|
||||
}
|
||||
log::debug!("Skill {directory} 已复制到 {app:?}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 复制 Skill 到应用目录(保留用于向后兼容)
|
||||
#[deprecated(note = "请使用 sync_to_app_dir() 代替")]
|
||||
pub fn copy_to_app(directory: &str, app: &AppType) -> Result<()> {
|
||||
Self::sync_to_app_dir(directory, app)
|
||||
}
|
||||
|
||||
/// 删除路径(支持 symlink 和真实目录)
|
||||
fn remove_path(path: &Path) -> Result<()> {
|
||||
if Self::is_symlink(path) {
|
||||
// 符号链接:仅删除链接本身,不影响源文件
|
||||
#[cfg(unix)]
|
||||
fs::remove_file(path)?;
|
||||
#[cfg(windows)]
|
||||
fs::remove_dir(path)?; // Windows 的目录 symlink 需要用 remove_dir
|
||||
} else if path.is_dir() {
|
||||
// 真实目录:递归删除
|
||||
fs::remove_dir_all(path)?;
|
||||
} else if path.exists() {
|
||||
// 普通文件
|
||||
fs::remove_file(path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从应用目录删除 Skill(支持 symlink 和真实目录)
|
||||
/// 从应用目录删除 Skill
|
||||
pub fn remove_from_app(directory: &str, app: &AppType) -> Result<()> {
|
||||
let app_dir = Self::get_app_skills_dir(app)?;
|
||||
let skill_path = app_dir.join(directory);
|
||||
|
||||
if skill_path.exists() || Self::is_symlink(&skill_path) {
|
||||
Self::remove_path(&skill_path)?;
|
||||
if skill_path.exists() {
|
||||
fs::remove_dir_all(&skill_path)?;
|
||||
log::debug!("Skill {directory} 已从 {app:?} 删除");
|
||||
}
|
||||
|
||||
@@ -753,7 +611,7 @@ impl SkillService {
|
||||
|
||||
for skill in skills.values() {
|
||||
if skill.apps.is_enabled_for(app) {
|
||||
Self::sync_to_app_dir(&skill.directory, app)?;
|
||||
Self::copy_to_app(&skill.directory, app)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -977,12 +835,10 @@ impl SkillService {
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
/// 去重技能列表(基于完整 key,不同仓库的同名 skill 分开显示)
|
||||
/// 去重技能列表
|
||||
fn deduplicate_discoverable_skills(skills: &mut Vec<DiscoverableSkill>) {
|
||||
let mut seen = HashMap::new();
|
||||
skills.retain(|skill| {
|
||||
// 使用完整 key(owner/repo:directory)作为唯一标识
|
||||
// 这样不同仓库的同名 skill 会分开显示
|
||||
let unique_key = skill.key.to_lowercase();
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = seen.entry(unique_key) {
|
||||
e.insert(true);
|
||||
|
||||
@@ -5,7 +5,6 @@ use std::sync::{OnceLock, RwLock};
|
||||
|
||||
use crate::app_config::AppType;
|
||||
use crate::error::AppError;
|
||||
use crate::services::skill::SyncMethod;
|
||||
|
||||
/// 自定义端点配置(历史兼容,实际存储在 provider.meta.custom_endpoints)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -74,7 +73,7 @@ pub struct AppSettings {
|
||||
#[serde(default)]
|
||||
pub enable_claude_plugin_integration: bool,
|
||||
/// 是否跳过 Claude Code 初次安装确认
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_true")]
|
||||
pub skip_claude_onboarding: bool,
|
||||
/// 是否开机自启
|
||||
#[serde(default)]
|
||||
@@ -109,11 +108,6 @@ pub struct AppSettings {
|
||||
/// 当前 OpenCode 供应商 ID(本地存储,对 OpenCode 可能无意义,但保持结构一致)
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub current_provider_opencode: Option<String>,
|
||||
|
||||
// ===== Skill 同步设置 =====
|
||||
/// Skill 同步方式:auto(默认,优先 symlink)、symlink、copy
|
||||
#[serde(default)]
|
||||
pub skill_sync_method: SyncMethod,
|
||||
}
|
||||
|
||||
fn default_show_in_tray() -> bool {
|
||||
@@ -130,7 +124,7 @@ impl Default for AppSettings {
|
||||
show_in_tray: true,
|
||||
minimize_to_tray_on_close: true,
|
||||
enable_claude_plugin_integration: false,
|
||||
skip_claude_onboarding: false,
|
||||
skip_claude_onboarding: true,
|
||||
launch_on_startup: false,
|
||||
language: None,
|
||||
visible_apps: None,
|
||||
@@ -142,7 +136,6 @@ impl Default for AppSettings {
|
||||
current_provider_codex: None,
|
||||
current_provider_gemini: None,
|
||||
current_provider_opencode: None,
|
||||
skill_sync_method: SyncMethod::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -389,16 +382,3 @@ pub fn get_effective_current_provider(
|
||||
// Fallback 到数据库的 is_current
|
||||
db.get_current_provider(app_type.as_str())
|
||||
}
|
||||
|
||||
// ===== Skill 同步方式管理函数 =====
|
||||
|
||||
/// 获取 Skill 同步方式配置
|
||||
pub fn get_skill_sync_method() -> SyncMethod {
|
||||
settings_store()
|
||||
.read()
|
||||
.unwrap_or_else(|e| {
|
||||
log::warn!("设置锁已毒化,使用恢复值: {e}");
|
||||
e.into_inner()
|
||||
})
|
||||
.skill_sync_method
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "CC Switch",
|
||||
"version": "3.10.2",
|
||||
"version": "3.10.0",
|
||||
"identifier": "com.ccswitch.desktop",
|
||||
"build": {
|
||||
"frontendDist": "../dist",
|
||||
|
||||
+9
-8
@@ -696,7 +696,7 @@ function App() {
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="flex h-full items-center justify-between gap-2 px-6"
|
||||
className="mx-auto flex h-full max-w-[56rem] items-center justify-between gap-2 px-4"
|
||||
data-tauri-drag-region
|
||||
style={{ WebkitAppRegion: "drag" } as any}
|
||||
>
|
||||
@@ -750,6 +750,13 @@ function App() {
|
||||
>
|
||||
CC Switch
|
||||
</a>
|
||||
<UpdateBadge
|
||||
onClick={() => {
|
||||
setSettingsDefaultTab("about");
|
||||
setCurrentView("settings");
|
||||
}}
|
||||
className="absolute -top-4 -right-4"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -763,12 +770,6 @@ function App() {
|
||||
>
|
||||
<Settings className="w-4 h-4" />
|
||||
</Button>
|
||||
<UpdateBadge
|
||||
onClick={() => {
|
||||
setSettingsDefaultTab("about");
|
||||
setCurrentView("settings");
|
||||
}}
|
||||
/>
|
||||
{isCurrentAppTakeoverActive && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -894,7 +895,7 @@ function App() {
|
||||
visibleApps={visibleApps}
|
||||
compact={
|
||||
isCurrentAppTakeoverActive &&
|
||||
Object.values(visibleApps).filter(Boolean).length >= 4
|
||||
Object.values(visibleApps).filter(Boolean).length >= 3
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -39,13 +39,9 @@ export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||||
};
|
||||
}, [size]);
|
||||
|
||||
// 获取有效颜色:优先使用传入的有效 color,否则从元数据获取 defaultColor
|
||||
// 获取有效颜色:优先使用传入的 color,否则从元数据获取 defaultColor
|
||||
const effectiveColor = useMemo(() => {
|
||||
// 只有当 color 是有效的非空字符串时才使用
|
||||
if (color && typeof color === "string" && color.trim() !== "") {
|
||||
return color;
|
||||
}
|
||||
// 否则从元数据获取 defaultColor
|
||||
if (color) return color;
|
||||
if (icon) {
|
||||
const metadata = getIconMetadata(icon);
|
||||
// 只有当 defaultColor 不是 currentColor 时才使用
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useUpdate } from "@/contexts/UpdateContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ArrowUpCircle } from "lucide-react";
|
||||
|
||||
interface UpdateBadgeProps {
|
||||
className?: string;
|
||||
@@ -31,12 +30,17 @@ export function UpdateBadge({ className = "", onClick }: UpdateBadgeProps) {
|
||||
aria-label={title}
|
||||
onClick={onClick}
|
||||
className={`
|
||||
relative h-8 w-8 rounded-full
|
||||
${isActive ? "text-green-600 dark:text-green-400 hover:bg-green-50 dark:hover:bg-green-500/10" : "text-muted-foreground hover:bg-muted/60"}
|
||||
relative h-6 w-6 rounded-full
|
||||
${isActive ? "text-blue-600 dark:text-blue-300 hover:bg-blue-50 dark:hover:bg-blue-500/10" : "text-muted-foreground hover:bg-muted/60"}
|
||||
${className}
|
||||
`}
|
||||
>
|
||||
<ArrowUpCircle className="h-5 w-5" />
|
||||
<span
|
||||
className={`
|
||||
absolute inset-0 m-auto h-2 w-2 rounded-full ring-1 ring-background
|
||||
${isActive ? "bg-blue-500 dark:bg-blue-400" : "bg-blue-300/70 dark:bg-blue-300/60"}
|
||||
`}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ interface AgentsPanelProps {
|
||||
|
||||
export function AgentsPanel({}: AgentsPanelProps) {
|
||||
return (
|
||||
<div className="px-6 flex flex-col h-[calc(100vh-8rem)]">
|
||||
<div className="mx-auto max-w-5xl flex flex-col h-[calc(100vh-8rem)]">
|
||||
<div className="flex-1 glass-card rounded-xl p-8 flex flex-col items-center justify-center text-center space-y-4">
|
||||
<div className="w-20 h-20 rounded-full bg-white/5 flex items-center justify-center mb-4 animate-pulse-slow">
|
||||
<Bot className="w-10 h-10 text-muted-foreground" />
|
||||
|
||||
@@ -5,42 +5,6 @@ interface UseModelStateProps {
|
||||
onConfigChange: (config: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse model values from settings config JSON
|
||||
*/
|
||||
function parseModelsFromConfig(settingsConfig: string) {
|
||||
try {
|
||||
const cfg = settingsConfig ? JSON.parse(settingsConfig) : {};
|
||||
const env = cfg?.env || {};
|
||||
const model =
|
||||
typeof env.ANTHROPIC_MODEL === "string" ? env.ANTHROPIC_MODEL : "";
|
||||
const reasoning =
|
||||
typeof env.ANTHROPIC_REASONING_MODEL === "string"
|
||||
? env.ANTHROPIC_REASONING_MODEL
|
||||
: "";
|
||||
const small =
|
||||
typeof env.ANTHROPIC_SMALL_FAST_MODEL === "string"
|
||||
? env.ANTHROPIC_SMALL_FAST_MODEL
|
||||
: "";
|
||||
const haiku =
|
||||
typeof env.ANTHROPIC_DEFAULT_HAIKU_MODEL === "string"
|
||||
? env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
: small || model;
|
||||
const sonnet =
|
||||
typeof env.ANTHROPIC_DEFAULT_SONNET_MODEL === "string"
|
||||
? env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
: model || small;
|
||||
const opus =
|
||||
typeof env.ANTHROPIC_DEFAULT_OPUS_MODEL === "string"
|
||||
? env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
: model || small;
|
||||
|
||||
return { model, reasoning, haiku, sonnet, opus };
|
||||
} catch {
|
||||
return { model: "", reasoning: "", haiku: "", sonnet: "", opus: "" };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理模型选择状态
|
||||
* 支持 ANTHROPIC_MODEL, ANTHROPIC_REASONING_MODEL 和各类型默认模型
|
||||
@@ -49,22 +13,11 @@ export function useModelState({
|
||||
settingsConfig,
|
||||
onConfigChange,
|
||||
}: UseModelStateProps) {
|
||||
// Initialize state by parsing config directly (fixes edit mode backfill)
|
||||
const [claudeModel, setClaudeModel] = useState(
|
||||
() => parseModelsFromConfig(settingsConfig).model,
|
||||
);
|
||||
const [reasoningModel, setReasoningModel] = useState(
|
||||
() => parseModelsFromConfig(settingsConfig).reasoning,
|
||||
);
|
||||
const [defaultHaikuModel, setDefaultHaikuModel] = useState(
|
||||
() => parseModelsFromConfig(settingsConfig).haiku,
|
||||
);
|
||||
const [defaultSonnetModel, setDefaultSonnetModel] = useState(
|
||||
() => parseModelsFromConfig(settingsConfig).sonnet,
|
||||
);
|
||||
const [defaultOpusModel, setDefaultOpusModel] = useState(
|
||||
() => parseModelsFromConfig(settingsConfig).opus,
|
||||
);
|
||||
const [claudeModel, setClaudeModel] = useState("");
|
||||
const [reasoningModel, setReasoningModel] = useState("");
|
||||
const [defaultHaikuModel, setDefaultHaikuModel] = useState("");
|
||||
const [defaultSonnetModel, setDefaultSonnetModel] = useState("");
|
||||
const [defaultOpusModel, setDefaultOpusModel] = useState("");
|
||||
|
||||
const isUserEditingRef = useRef(false);
|
||||
const lastConfigRef = useRef(settingsConfig);
|
||||
|
||||
@@ -35,7 +35,6 @@ import { LanguageSettings } from "@/components/settings/LanguageSettings";
|
||||
import { ThemeSettings } from "@/components/settings/ThemeSettings";
|
||||
import { WindowSettings } from "@/components/settings/WindowSettings";
|
||||
import { AppVisibilitySettings } from "@/components/settings/AppVisibilitySettings";
|
||||
import { SkillSyncMethodSettings } from "@/components/settings/SkillSyncMethodSettings";
|
||||
import { DirectorySettings } from "@/components/settings/DirectorySettings";
|
||||
import { ImportExportSection } from "@/components/settings/ImportExportSection";
|
||||
import { AboutSection } from "@/components/settings/AboutSection";
|
||||
@@ -250,12 +249,6 @@ export function SettingsPage({
|
||||
settings={settings}
|
||||
onChange={handleAutoSave}
|
||||
/>
|
||||
<SkillSyncMethodSettings
|
||||
value={settings.skillSyncMethod ?? "auto"}
|
||||
onChange={(method) =>
|
||||
handleAutoSave({ skillSyncMethod: method })
|
||||
}
|
||||
/>
|
||||
</motion.div>
|
||||
) : null}
|
||||
</TabsContent>
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { SkillSyncMethod } from "@/types";
|
||||
|
||||
export interface SkillSyncMethodSettingsProps {
|
||||
value: SkillSyncMethod;
|
||||
onChange: (value: SkillSyncMethod) => void;
|
||||
}
|
||||
|
||||
export function SkillSyncMethodSettings({
|
||||
value,
|
||||
onChange,
|
||||
}: SkillSyncMethodSettingsProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Handle default values: undefined or "auto" defaults to symlink display
|
||||
const displayValue = value === "copy" ? "copy" : "symlink";
|
||||
|
||||
return (
|
||||
<section className="space-y-2">
|
||||
<header className="space-y-1">
|
||||
<h3 className="text-sm font-medium">{t("settings.skillSync.title")}</h3>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("settings.skillSync.description")}
|
||||
</p>
|
||||
</header>
|
||||
<div className="inline-flex gap-1 rounded-md border border-border-default bg-background p-1">
|
||||
<SyncMethodButton
|
||||
active={displayValue === "symlink"}
|
||||
onClick={() => onChange("symlink")}
|
||||
>
|
||||
{t("settings.skillSync.symlink")}
|
||||
</SyncMethodButton>
|
||||
<SyncMethodButton
|
||||
active={displayValue === "copy"}
|
||||
onClick={() => onChange("copy")}
|
||||
>
|
||||
{t("settings.skillSync.copy")}
|
||||
</SyncMethodButton>
|
||||
</div>
|
||||
{displayValue === "symlink" && (
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("settings.skillSync.symlinkHint")}
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
interface SyncMethodButtonProps {
|
||||
active: boolean;
|
||||
onClick: () => void;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function SyncMethodButton({
|
||||
active,
|
||||
onClick,
|
||||
children,
|
||||
}: SyncMethodButtonProps) {
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
size="sm"
|
||||
variant={active ? "default" : "ghost"}
|
||||
className={cn(
|
||||
"min-w-[96px]",
|
||||
active
|
||||
? "shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-muted",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -27,6 +27,16 @@ export function WindowSettings({ settings, onChange }: WindowSettingsProps) {
|
||||
onCheckedChange={(value) => onChange({ launchOnStartup: value })}
|
||||
/>
|
||||
|
||||
<ToggleRow
|
||||
icon={<AppWindow className="h-4 w-4 text-blue-500" />}
|
||||
title={t("settings.minimizeToTray")}
|
||||
description={t("settings.minimizeToTrayDescription")}
|
||||
checked={settings.minimizeToTrayOnClose}
|
||||
onCheckedChange={(value) =>
|
||||
onChange({ minimizeToTrayOnClose: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<ToggleRow
|
||||
icon={<MonitorUp className="h-4 w-4 text-purple-500" />}
|
||||
title={t("settings.enableClaudePluginIntegration")}
|
||||
@@ -44,16 +54,6 @@ export function WindowSettings({ settings, onChange }: WindowSettingsProps) {
|
||||
checked={!!settings.skipClaudeOnboarding}
|
||||
onCheckedChange={(value) => onChange({ skipClaudeOnboarding: value })}
|
||||
/>
|
||||
|
||||
<ToggleRow
|
||||
icon={<AppWindow className="h-4 w-4 text-blue-500" />}
|
||||
title={t("settings.minimizeToTray")}
|
||||
description={t("settings.minimizeToTrayDescription")}
|
||||
checked={settings.minimizeToTrayOnClose}
|
||||
onCheckedChange={(value) =>
|
||||
onChange({ minimizeToTrayOnClose: value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -65,17 +65,10 @@ export const SkillsPage = forwardRef<SkillsPageHandle, SkillsPageProps>(
|
||||
const addRepoMutation = useAddSkillRepo();
|
||||
const removeRepoMutation = useRemoveSkillRepo();
|
||||
|
||||
// 已安装的 skill key 集合(使用 directory + repoOwner + repoName 组合判断)
|
||||
const installedKeys = useMemo(() => {
|
||||
// 已安装的 directory 集合
|
||||
const installedDirs = useMemo(() => {
|
||||
if (!installedSkills) return new Set<string>();
|
||||
return new Set(
|
||||
installedSkills.map((s) => {
|
||||
// 构建唯一 key:directory + repoOwner + repoName
|
||||
const owner = s.repoOwner?.toLowerCase() || "";
|
||||
const name = s.repoName?.toLowerCase() || "";
|
||||
return `${s.directory.toLowerCase()}:${owner}:${name}`;
|
||||
}),
|
||||
);
|
||||
return new Set(installedSkills.map((s) => s.directory.toLowerCase()));
|
||||
}, [installedSkills]);
|
||||
|
||||
type DiscoverableSkillItem = DiscoverableSkill & { installed: boolean };
|
||||
@@ -87,14 +80,12 @@ export const SkillsPage = forwardRef<SkillsPageHandle, SkillsPageProps>(
|
||||
const installName =
|
||||
d.directory.split("/").pop()?.toLowerCase() ||
|
||||
d.directory.toLowerCase();
|
||||
// 使用 directory + repoOwner + repoName 组合判断是否已安装
|
||||
const key = `${installName}:${d.repoOwner.toLowerCase()}:${d.repoName.toLowerCase()}`;
|
||||
return {
|
||||
...d,
|
||||
installed: installedKeys.has(key),
|
||||
installed: installedDirs.has(installName),
|
||||
};
|
||||
});
|
||||
}, [discoverableSkills, installedKeys]);
|
||||
}, [discoverableSkills, installedDirs]);
|
||||
|
||||
const loading = loadingDiscoverable || fetchingDiscoverable;
|
||||
|
||||
|
||||
@@ -452,18 +452,14 @@ export const providerPresets: ProviderPreset[] = [
|
||||
{
|
||||
name: "RightCode",
|
||||
websiteUrl: "https://www.right.codes",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=CCSWITCH",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=0bdf9bfa",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://www.right.codes/claude",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "rightcode",
|
||||
icon: "rc",
|
||||
iconColor: "#E96B2C",
|
||||
category: "third_party"
|
||||
},
|
||||
{
|
||||
name: "OpenRouter",
|
||||
@@ -483,6 +479,20 @@ export const providerPresets: ProviderPreset[] = [
|
||||
icon: "openrouter",
|
||||
iconColor: "#6566F1",
|
||||
},
|
||||
{
|
||||
name: "ChatCompletions",
|
||||
websiteUrl: "",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
},
|
||||
chat_completions_mode: true,
|
||||
},
|
||||
category: "third_party",
|
||||
icon: "openai",
|
||||
iconColor: "#10A37F",
|
||||
},
|
||||
{
|
||||
name: "Xiaomi MiMo",
|
||||
websiteUrl: "https://platform.xiaomimimo.com",
|
||||
|
||||
@@ -195,7 +195,7 @@ requires_openai_auth = true`,
|
||||
{
|
||||
name: "RightCode",
|
||||
websiteUrl: "https://www.right.codes",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=CCSWITCH",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=0bdf9bfa",
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"rightcode",
|
||||
@@ -203,8 +203,6 @@ requires_openai_auth = true`,
|
||||
"gpt-5.2",
|
||||
),
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "rightcode",
|
||||
icon: "rc",
|
||||
iconColor: "#E96B2C",
|
||||
},
|
||||
|
||||
@@ -649,7 +649,7 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
{
|
||||
name: "RightCode",
|
||||
websiteUrl: "https://www.right.codes",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=CCSWITCH",
|
||||
apiKeyUrl: "https://www.right.codes/register?aff=0bdf9bfa",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/openai",
|
||||
name: "RightCode",
|
||||
@@ -663,8 +663,6 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "rightcode",
|
||||
icon: "rc",
|
||||
iconColor: "#E96B2C",
|
||||
templateValues: {
|
||||
|
||||
@@ -83,7 +83,7 @@ export function useSettingsForm(): UseSettingsFormResult {
|
||||
minimizeToTrayOnClose: data.minimizeToTrayOnClose ?? true,
|
||||
enableClaudePluginIntegration:
|
||||
data.enableClaudePluginIntegration ?? false,
|
||||
skipClaudeOnboarding: data.skipClaudeOnboarding ?? false,
|
||||
skipClaudeOnboarding: data.skipClaudeOnboarding ?? true,
|
||||
claudeConfigDir: sanitizeDir(data.claudeConfigDir),
|
||||
codexConfigDir: sanitizeDir(data.codexConfigDir),
|
||||
language: normalizedLanguage,
|
||||
@@ -103,7 +103,7 @@ export function useSettingsForm(): UseSettingsFormResult {
|
||||
showInTray: true,
|
||||
minimizeToTrayOnClose: true,
|
||||
enableClaudePluginIntegration: false,
|
||||
skipClaudeOnboarding: false,
|
||||
skipClaudeOnboarding: true,
|
||||
language: readPersistedLanguage(),
|
||||
} as SettingsFormState);
|
||||
|
||||
@@ -138,7 +138,7 @@ export function useSettingsForm(): UseSettingsFormResult {
|
||||
minimizeToTrayOnClose: serverData.minimizeToTrayOnClose ?? true,
|
||||
enableClaudePluginIntegration:
|
||||
serverData.enableClaudePluginIntegration ?? false,
|
||||
skipClaudeOnboarding: serverData.skipClaudeOnboarding ?? false,
|
||||
skipClaudeOnboarding: serverData.skipClaudeOnboarding ?? true,
|
||||
claudeConfigDir: sanitizeDir(serverData.claudeConfigDir),
|
||||
codexConfigDir: sanitizeDir(serverData.codexConfigDir),
|
||||
language: normalizedLanguage,
|
||||
|
||||
@@ -280,13 +280,6 @@
|
||||
"geminiDesc": "Google Gemini CLI",
|
||||
"opencodeDesc": "OpenCode CLI"
|
||||
},
|
||||
"skillSync": {
|
||||
"title": "Skill Sync Method",
|
||||
"description": "Choose how to sync Skills files",
|
||||
"symlink": "Symlink",
|
||||
"copy": "Copy Files",
|
||||
"symlinkHint": "Symlinks save disk space and enable real-time sync. Note: May require admin privileges or Developer Mode on Windows"
|
||||
},
|
||||
"configDirectoryOverride": "Configuration Directory Override (Advanced)",
|
||||
"configDirectoryDescription": "When using Claude Code or Codex in environments like WSL, you can manually specify the configuration directory to the one in WSL to keep provider data consistent with the main environment.",
|
||||
"appConfigDir": "CC Switch Configuration Directory",
|
||||
@@ -400,8 +393,7 @@
|
||||
"minimax_en": "MiniMax Coding Plan Black Friday, Starter is now $2/mo (80% OFF!)",
|
||||
"dmxapi": "Claude Code exclusive model 66% OFF now!",
|
||||
"cubence": "Cubence is an official partner of CC Switch. Register using this link and enter \"CCSWITCH\" promo code during recharge to get 10% off every top-up",
|
||||
"aigocode": "AIGoCode is an official partner of CC Switch. Register using this link and get 10% bonus credit on your first top-up!",
|
||||
"rightcode": "RightCode is an official partner of CC Switch. Register using this link and get 5% bonus credit on every top-up!"
|
||||
"aigocode": "AIGoCode is an official partner of CC Switch. Register using this link and get 10% bonus credit on your first top-up!"
|
||||
},
|
||||
"parameterConfig": "Parameter Config - {{name}} *",
|
||||
"mainModel": "Main Model (optional)",
|
||||
@@ -972,7 +964,6 @@
|
||||
"downloadTimeoutHint": "Please check network connection or retry later",
|
||||
"skillPathNotFound": "Skill path '{{path}}' not found in repository {{owner}}/{{name}}",
|
||||
"skillDirNotFound": "Skill directory not found: {{path}}",
|
||||
"directoryConflict": "Skill directory '{{directory}}' is already occupied by {{existing_repo}}, cannot install from {{new_repo}}",
|
||||
"emptyArchive": "Downloaded archive is empty",
|
||||
"downloadFailed": "Download failed: HTTP {{status}}",
|
||||
"allBranchesFailed": "All branches failed, tried: {{branches}}",
|
||||
@@ -991,8 +982,7 @@
|
||||
"retryLater": "Please retry later",
|
||||
"checkRepoUrl": "Please check repository URL and branch name",
|
||||
"checkDiskSpace": "Please check disk space",
|
||||
"checkPermission": "Please check directory permissions",
|
||||
"uninstallFirst": "Please uninstall the existing skill with the same name first"
|
||||
"checkPermission": "Please check directory permissions"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -280,13 +280,6 @@
|
||||
"geminiDesc": "Google Gemini CLI",
|
||||
"opencodeDesc": "OpenCode CLI"
|
||||
},
|
||||
"skillSync": {
|
||||
"title": "スキル同期方式",
|
||||
"description": "スキルファイルの同期方法を選択",
|
||||
"symlink": "シンボリックリンク",
|
||||
"copy": "ファイルコピー",
|
||||
"symlinkHint": "シンボリックリンクはディスク容量を節約し、リアルタイム同期を有効にします。注意:Windowsでは管理者権限または開発者モードが必要な場合があります"
|
||||
},
|
||||
"configDirectoryOverride": "設定ディレクトリの上書き(詳細)",
|
||||
"configDirectoryDescription": "WSL などで Claude Code や Codex を使う場合、ここで設定ディレクトリを WSL 側に合わせるとデータを揃えられます。",
|
||||
"appConfigDir": "CC Switch 設定ディレクトリ",
|
||||
@@ -400,8 +393,7 @@
|
||||
"minimax_en": "MiniMax Coding Plan Black Friday、Starter が月額 $2(80% OFF)",
|
||||
"dmxapi": "Claude Code 専用モデル 66% OFF 実施中!",
|
||||
"cubence": "Cubence は CC Switch の公式パートナーです。登録後チャージ時に \"CCSWITCH\" を入力すると、毎回 10% オフ",
|
||||
"aigocode": "AIGoCode は CC Switch の公式パートナーです。このリンクから登録すると、初回チャージ時に 10% のボーナスクレジットがもらえます!",
|
||||
"rightcode": "RightCode は CC Switch の公式パートナーです。このリンクから登録すると、毎回のチャージに 5% のボーナスクレジットがもらえます!"
|
||||
"aigocode": "AIGoCode は CC Switch の公式パートナーです。このリンクから登録すると、初回チャージ時に 10% のボーナスクレジットがもらえます!"
|
||||
},
|
||||
"parameterConfig": "パラメーター設定 - {{name}} *",
|
||||
"mainModel": "メインモデル(任意)",
|
||||
@@ -972,7 +964,6 @@
|
||||
"downloadTimeoutHint": "ネットワークを確認するか、時間をおいて再試行してください",
|
||||
"skillPathNotFound": "リポジトリ {{owner}}/{{name}} にスキルパス '{{path}}' がありません",
|
||||
"skillDirNotFound": "スキルディレクトリが見つかりません: {{path}}",
|
||||
"directoryConflict": "スキルディレクトリ '{{directory}}' は既に {{existing_repo}} で使用されています。{{new_repo}} からインストールできません",
|
||||
"emptyArchive": "ダウンロードしたアーカイブが空です",
|
||||
"downloadFailed": "ダウンロードに失敗しました: HTTP {{status}}",
|
||||
"allBranchesFailed": "すべてのブランチで失敗しました。試行: {{branches}}",
|
||||
@@ -991,8 +982,7 @@
|
||||
"retryLater": "時間をおいて再試行してください",
|
||||
"checkRepoUrl": "リポジトリ URL とブランチ名を確認してください",
|
||||
"checkDiskSpace": "ディスク容量を確認してください",
|
||||
"checkPermission": "ディレクトリの権限を確認してください",
|
||||
"uninstallFirst": "同名のスキルを先にアンインストールしてください"
|
||||
"checkPermission": "ディレクトリの権限を確認してください"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -280,13 +280,6 @@
|
||||
"geminiDesc": "Google Gemini CLI",
|
||||
"opencodeDesc": "OpenCode CLI"
|
||||
},
|
||||
"skillSync": {
|
||||
"title": "Skill 同步方式",
|
||||
"description": "选择 Skills 的文件同步策略",
|
||||
"symlink": "软连接",
|
||||
"copy": "文件复制",
|
||||
"symlinkHint": "软连接节省磁盘空间并支持实时同步。注意:Windows 可能需要管理员权限或开启开发者模式"
|
||||
},
|
||||
"configDirectoryOverride": "配置目录覆盖(高级)",
|
||||
"configDirectoryDescription": "在 WSL 等环境使用 Claude Code 或 Codex 的时候,可手动指定为 WSL 里的配置目录,供应商数据与主环境保持一致。",
|
||||
"appConfigDir": "CC Switch 配置目录",
|
||||
@@ -400,8 +393,7 @@
|
||||
"minimax_en": "MiniMax Coding Plan 黑五特惠,Starter 套餐现仅 $2/月(2折优惠!)",
|
||||
"dmxapi": "Claude Code 专属模型 3.4 折优惠进行中!",
|
||||
"cubence": "Cubence 是 CC Switch 的官方合作伙伴,使用此链接注册并在充值时填写 \"CCSWITCH\" 优惠码,每次充值均可享受9折优惠",
|
||||
"aigocode": "AIGoCode 是 CC Switch 的官方合作伙伴,使用此链接注册首次充值时可以获得10%额度奖励!",
|
||||
"rightcode": "RightCode 是 CC Switch 的官方合作伙伴,使用此链接注册每次充值均可赠送5%额外额度!"
|
||||
"aigocode": "AIGoCode 是 CC Switch 的官方合作伙伴,使用此链接注册首次充值时可以获得10%额度奖励!"
|
||||
},
|
||||
"parameterConfig": "参数配置 - {{name}} *",
|
||||
"mainModel": "主模型 (可选)",
|
||||
@@ -972,7 +964,6 @@
|
||||
"downloadTimeoutHint": "请检查网络连接或稍后重试",
|
||||
"skillPathNotFound": "仓库 {{owner}}/{{name}} 中未找到技能路径 '{{path}}'",
|
||||
"skillDirNotFound": "技能目录不存在:{{path}}",
|
||||
"directoryConflict": "技能目录 '{{directory}}' 已被 {{existing_repo}} 占用,无法从 {{new_repo}} 安装",
|
||||
"emptyArchive": "下载的压缩包为空",
|
||||
"downloadFailed": "下载失败:HTTP {{status}}",
|
||||
"allBranchesFailed": "所有分支下载失败,尝试了:{{branches}}",
|
||||
@@ -991,8 +982,7 @@
|
||||
"retryLater": "请稍后重试",
|
||||
"checkRepoUrl": "请检查仓库地址和分支名称",
|
||||
"checkDiskSpace": "请检查磁盘空间",
|
||||
"checkPermission": "请检查目录权限",
|
||||
"uninstallFirst": "请先卸载已安装的同名技能"
|
||||
"checkPermission": "请检查目录权限"
|
||||
}
|
||||
},
|
||||
"repo": {
|
||||
|
||||
@@ -50,7 +50,7 @@ export const icons: Record<string, string> = {
|
||||
zeroone: `<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>01.AI</title><path d="M5.246 12c0 .837-.086 1.554-.257 2.151-.172.598-.45 1.055-.837 1.373-.386.317-.898.476-1.534.476-.901 0-1.563-.353-1.985-1.059C.211 14.235 0 13.255 0 12c0-.837.086-1.554.257-2.151.172-.598.45-1.055.832-1.373C1.472 8.16 1.981 8 2.618 8c.894 0 1.555.351 1.985 1.053.429.702.643 1.685.643 2.947zm-3.883 0c0 .956.09 1.668.273 2.134.183.467.51.7.982.7.465 0 .792-.23.981-.694.19-.463.285-1.176.285-2.14 0-.956-.095-1.668-.285-2.134-.19-.467-.516-.7-.981-.7-.472 0-.8.233-.982.7-.182.466-.273 1.178-.273 2.134zm8.52 3.771H8.517l.011-6.295-1.823.324V8.571l2.04-.457h1.136v7.657zm2.497-1.6h.543c.3 0 .543.256.543.572v.571a.558.558 0 01-.543.572h-.543a.558.558 0 01-.543-.572v-.571c0-.316.243-.572.543-.572zm10.317-6.057H24v7.772h-1.303V8.114zm-3.692 0l2.606 7.772h-1.303l-.69-2.058h-3.073l-.69 2.058h-1.303l2.606-7.772h1.847zm.191 4.457l-1.115-3.323-1.114 3.323h2.23z"></path></svg>`,
|
||||
zhipu: `<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Zhipu</title><path d="M11.991 23.503a.24.24 0 00-.244.248.24.24 0 00.244.249.24.24 0 00.245-.249.24.24 0 00-.22-.247l-.025-.001zM9.671 5.365a1.697 1.697 0 011.099 2.132l-.071.172-.016.04-.018.054c-.07.16-.104.32-.104.498-.035.71.47 1.279 1.186 1.314h.366c1.309.053 2.338 1.173 2.286 2.523-.052 1.332-1.152 2.38-2.478 2.327h-.174c-.715.018-1.274.64-1.239 1.368 0 .124.018.23.053.337.209.373.54.658.96.8.75.23 1.517-.125 1.9-.782l.018-.035c.402-.64 1.17-.96 1.92-.711.854.284 1.378 1.226 1.099 2.167a1.661 1.661 0 01-2.077 1.102 1.711 1.711 0 01-.907-.711l-.017-.035c-.2-.323-.463-.58-.851-.711l-.056-.018a1.646 1.646 0 00-1.954.746 1.66 1.66 0 01-1.065.764 1.677 1.677 0 01-1.989-1.279c-.209-.906.332-1.83 1.257-2.043a1.51 1.51 0 01.296-.035h.018c.68-.071 1.151-.622 1.116-1.333a1.307 1.307 0 00-.227-.693 2.515 2.515 0 01-.366-1.403 2.39 2.39 0 01.366-1.208c.14-.195.21-.444.227-.693.018-.71-.506-1.261-1.186-1.332l-.07-.018a1.43 1.43 0 01-.299-.07l-.05-.019a1.7 1.7 0 01-1.047-2.114 1.68 1.68 0 012.094-1.101zm-5.575 10.11c.26-.264.639-.367.994-.27.355.096.633.379.728.74.095.362-.007.748-.267 1.013-.402.41-1.053.41-1.455 0a1.062 1.062 0 010-1.482zm14.845-.294c.359-.09.738.024.992.297.254.274.344.665.237 1.025-.107.36-.396.634-.756.718-.551.128-1.1-.22-1.23-.781a1.05 1.05 0 01.757-1.26zm-.064-4.39c.314.32.49.753.49 1.206 0 .452-.176.886-.49 1.206-.315.32-.74.5-1.185.5-.444 0-.87-.18-1.184-.5a1.727 1.727 0 010-2.412 1.654 1.654 0 012.369 0zm-11.243.163c.364.484.447 1.128.218 1.691a1.665 1.665 0 01-2.188.923c-.855-.36-1.26-1.358-.907-2.228a1.68 1.68 0 011.33-1.038c.593-.08 1.183.169 1.547.652zm11.545-4.221c.368 0 .708.2.892.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.892.524c-.568 0-1.03-.47-1.03-1.048 0-.579.462-1.048 1.03-1.048zm-14.358 0c.368 0 .707.2.891.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.891.524c-.569 0-1.03-.47-1.03-1.048 0-.579.461-1.048 1.03-1.048zm10.031-1.475c.925 0 1.675.764 1.675 1.706s-.75 1.705-1.675 1.705-1.674-.763-1.674-1.705c0-.942.75-1.706 1.674-1.706zm-2.626-.684c.362-.082.653-.356.761-.718a1.062 1.062 0 00-.238-1.028 1.017 1.017 0 00-.996-.294c-.547.14-.881.7-.752 1.257.13.558.675.907 1.225.783zm0 16.876c.359-.087.644-.36.75-.72a1.062 1.062 0 00-.237-1.019 1.018 1.018 0 00-.985-.301 1.037 1.037 0 00-.762.717c-.108.361-.017.754.239 1.028.245.263.606.377.953.305l.043-.01zM17.19 3.5a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64a.631.631 0 00-.628.64c0 .355.28.64.628.64zm-10.38 0a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64a.631.631 0 00-.628.64c0 .355.279.64.628.64zm-5.182 7.852a.631.631 0 00-.628.64c0 .354.28.639.628.639a.63.63 0 00.627-.606l.001-.034a.62.62 0 00-.628-.64zm5.182 9.13a.631.631 0 00-.628.64c0 .355.279.64.628.64a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm10.38.018a.631.631 0 00-.628.64c0 .355.28.64.628.64a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64zm5.182-9.148a.631.631 0 00-.628.64c0 .354.279.639.628.639a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm-.384-4.992a.24.24 0 00.244-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249c0 .142.122.249.244.249zM11.991.497a.24.24 0 00.245-.248A.24.24 0 0011.99 0a.24.24 0 00-.244.249c0 .133.108.236.223.247l.021.001zM2.011 6.36a.24.24 0 00.245-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249.24.24 0 00.244.249zm0 11.263a.24.24 0 00-.243.248.24.24 0 00.244.249.24.24 0 00.244-.249.252.252 0 00-.244-.248zm19.995-.018a.24.24 0 00-.245.248.24.24 0 00.245.25.24.24 0 00.244-.25.252.252 0 00-.244-.248z" fill="#3859FF" fill-rule="nonzero"></path></svg>`,
|
||||
openrouter: `<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>OpenRouter</title><path d="M16.804 1.957l7.22 4.105v.087L16.73 10.21l.017-2.117-.821-.03c-1.059-.028-1.611.002-2.268.11-1.064.175-2.038.577-3.147 1.352L8.345 11.03c-.284.195-.495.336-.68.455l-.515.322-.397.234.385.23.53.338c.476.314 1.17.796 2.701 1.866 1.11.775 2.083 1.177 3.147 1.352l.3.045c.694.091 1.375.094 2.825.033l.022-2.159 7.22 4.105v.087L16.589 22l.014-1.862-.635.022c-1.386.042-2.137.002-3.138-.162-1.694-.28-3.26-.926-4.881-2.059l-2.158-1.5a21.997 21.997 0 00-.755-.498l-.467-.28a55.927 55.927 0 00-.76-.43C2.908 14.73.563 14.116 0 14.116V9.888l.14.004c.564-.007 2.91-.622 3.809-1.124l1.016-.58.438-.274c.428-.28 1.072-.726 2.686-1.853 1.621-1.133 3.186-1.78 4.881-2.059 1.152-.19 1.974-.213 3.814-.138l.02-1.907z"></path></svg>`,
|
||||
rc: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" style="flex:none;line-height:1" viewBox="0 0 128 128"><title>RightCode</title><path fill="#EA6C2C" fill-rule="evenodd" d="M 67.00 124.35 L 65.00 124.65 L 63.00 124.31 L 60.87 122.00 L 60.51 120.00 L 60.62 119.00 L 61.63 117.00 L 63.64 115.00 L 63.65 23.00 L 63.40 22.00 L 60.71 20.00 L 59.73 18.00 L 59.66 16.00 L 61.18 13.00 L 63.00 11.70 L 65.00 11.36 L 67.00 11.68 L 69.00 13.07 L 70.24 15.00 L 70.43 17.00 L 69.35 20.00 L 66.75 22.00 L 66.53 23.00 L 66.56 115.00 L 69.38 118.00 L 69.69 120.00 L 69.38 122.00 L 67.00 124.35 Z M 65.38 19.00 L 66.99 18.00 L 67.30 16.00 L 66.00 14.66 L 64.00 14.69 L 62.79 16.00 L 62.66 17.00 L 64.00 18.73 L 65.38 19.00 Z M 72.00 53.03 L 71.70 52.00 L 71.56 35.00 L 70.00 33.71 L 68.79 32.00 L 68.52 30.00 L 69.00 28.15 L 70.00 26.71 L 72.00 25.59 L 74.00 25.45 L 75.00 25.70 L 76.75 27.00 L 77.50 28.00 L 78.15 30.00 L 77.18 33.00 L 74.81 35.00 L 74.60 50.00 L 72.00 53.03 Z M 74.12 32.00 L 75.11 31.00 L 75.31 30.00 L 74.77 29.00 L 74.00 28.40 L 72.00 28.65 L 71.35 30.00 L 71.45 31.00 L 73.00 32.26 L 74.12 32.00 Z M 58.00 52.97 L 55.68 50.00 L 55.65 40.00 L 52.89 37.00 L 52.36 35.00 L 52.62 33.00 L 54.00 31.03 L 57.00 29.77 L 60.00 30.84 L 61.03 32.00 L 61.64 34.00 L 61.21 37.00 L 58.49 40.00 L 58.47 52.00 L 58.00 52.97 Z M 58.43 36.00 L 59.06 35.00 L 58.91 34.00 L 58.00 32.96 L 57.00 32.66 L 56.00 33.10 L 55.29 34.00 L 55.19 35.00 L 55.64 36.00 L 57.00 36.59 L 58.43 36.00 Z M 57.00 89.45 L 46.00 89.35 L 37.24 77.00 L 36.00 75.99 L 35.00 75.93 L 28.00 75.93 L 27.12 77.00 L 27.14 88.00 L 26.80 89.00 L 26.00 89.36 L 18.00 89.36 L 16.89 89.00 L 16.66 48.00 L 17.00 46.90 L 44.00 46.73 L 48.00 47.67 L 50.00 48.57 L 53.23 51.00 L 55.44 54.00 L 56.34 56.00 L 57.07 59.00 L 56.95 64.00 L 56.15 67.00 L 54.34 70.00 L 52.00 72.26 L 48.83 74.00 L 48.06 75.00 L 57.06 88.00 L 57.53 89.00 L 57.00 89.45 Z M 110.00 89.13 L 109.00 89.65 L 90.00 89.61 L 85.00 89.18 L 80.00 87.40 L 77.00 85.39 L 74.64 83.00 L 72.64 80.00 L 70.76 75.00 L 70.20 70.00 L 70.36 65.00 L 70.81 62.00 L 72.61 57.00 L 74.49 54.00 L 77.36 51.00 L 81.00 48.62 L 84.00 47.54 L 88.00 46.77 L 109.00 46.64 L 109.79 47.00 L 110.13 48.00 L 110.00 55.15 L 109.00 55.68 L 91.00 55.74 L 87.00 56.77 L 84.11 59.00 L 82.59 61.00 L 81.36 64.00 L 80.64 69.00 L 81.62 74.00 L 82.58 76.00 L 85.00 78.66 L 88.00 80.22 L 92.00 80.64 L 109.00 80.64 L 109.80 81.00 L 110.13 82.00 L 110.00 89.13 Z M 43.29 67.00 L 44.89 66.00 L 46.00 64.70 L 46.86 62.00 L 46.50 59.00 L 45.00 56.77 L 43.00 55.56 L 40.00 55.18 L 28.00 55.17 L 27.12 56.00 L 27.16 67.00 L 28.00 67.65 L 40.00 67.63 L 43.29 67.00 Z M 74.00 105.20 L 72.00 105.09 L 70.13 104.00 L 68.71 102.00 L 68.54 101.00 L 68.69 99.00 L 70.00 97.06 L 71.42 96.00 L 71.71 95.00 L 71.70 86.00 L 72.00 84.36 L 74.56 87.00 L 74.64 95.00 L 75.00 95.97 L 77.39 98.00 L 78.12 100.00 L 77.32 103.00 L 76.00 104.37 L 74.00 105.20 Z M 59.00 111.05 L 57.00 111.40 L 55.00 111.01 L 52.89 109.00 L 52.36 107.00 L 53.00 104.45 L 55.51 102.00 L 55.65 93.00 L 55.88 92.00 L 57.00 91.64 L 58.28 92.00 L 58.49 93.00 L 58.63 102.00 L 61.00 104.14 L 61.65 106.00 L 61.26 109.00 L 59.00 111.05 Z M 74.39 102.00 L 75.23 101.00 L 75.00 99.65 L 74.00 98.65 L 73.00 98.54 L 72.06 99.00 L 71.39 100.00 L 71.39 101.00 L 72.00 101.96 L 73.00 102.38 L 74.39 102.00 Z M 58.51 108.00 L 59.09 107.00 L 58.83 106.00 L 58.00 105.18 L 57.00 104.85 L 55.33 106.00 L 55.18 107.00 L 56.00 108.39 L 57.00 108.65 L 58.51 108.00 Z M 65.09 122.00 L 66.75 121.00 L 67.14 120.00 L 66.00 118.36 L 65.00 118.16 L 63.54 119.00 L 63.28 120.00 L 63.47 121.00 L 65.09 122.00 Z"/></svg>`,
|
||||
rc: `<svg viewBox="0 0 24 24" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg"><title>RightCode</title><path d="M3 4h6c2.2 0 4 1.8 4 4 0 1.5-.8 2.8-2 3.5L14 17h-3l-2.5-5H5v5H3V4zm2 2v4h4c1.1 0 2-.9 2-2s-.9-2-2-2H5z" fill="#E96B2C"/><path d="M21 8.5c0-2.5-2-4.5-4.5-4.5-1.5 0-2.8.7-3.6 1.8l1.5 1.2c.5-.7 1.2-1 2.1-1 1.4 0 2.5 1.1 2.5 2.5v.5h-1c-2.5 0-4.5 1.3-4.5 3.5 0 1.9 1.6 3.5 3.5 3.5 1.2 0 2.3-.6 3-1.5V16h2V8.5zM17 14c-1.1 0-2-.7-2-1.5s.9-1.5 2-1.5h2v1c0 1.1-.9 2-2 2z" fill="#E96B2C"/><rect x="3" y="18" width="18" height="2" rx="1" fill="#E96B2C"/></svg>`,
|
||||
longcat: `<svg fill="currentColor" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>LongCat</title><path clip-rule="evenodd" d="M.507 19.883a.507.507 0 01-.489-.642L4.29 3.745a1.013 1.013 0 011.533-.578l5.622 3.687a1.013 1.013 0 001.11 0L18.2 3.165a1.013 1.013 0 011.532.58l4.25 15.497a.506.506 0 01-.49.64H18.07a6.297 6.297 0 001.53-4.115v-.177a6.09 6.09 0 00-1.513-4.017l-.697-3.495a.438.438 0 00-.694-.266L14.07 9.781a.748.748 0 01-.654.121 5.156 5.156 0 00-2.833 0 .746.746 0 01-.653-.121L7.302 7.81a.435.435 0 00-.688.269l-.675 3.652a5.36 5.36 0 00-1.539 3.76v.333c0 1.474.527 2.9 1.488 4.02l.032.038H.507z" fill="#29E154" fill-rule="evenodd"></path><path d="M9.213 16.843h1.52v-3.546h-1.29l-.23 3.546zm5.573 0h-1.52v-3.546h1.29l.23 3.546z"></path></svg>`,
|
||||
modelscope: `<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>ModelScope</title><path d="M0 7.967h2.667v2.667H0zM8 10.633h2.667V13.3H8z" fill="#36CED0"></path><path d="M0 10.633h2.667V13.3H0zM2.667 13.3h2.666v2.667H8v2.666H2.667V13.3zM2.667 5.3H8v2.667H5.333v2.666H2.667V5.3zM10.667 13.3h2.667v2.667h-2.667z" fill="#624AFF"></path><path d="M24 7.967h-2.667v2.667H24zM16 10.633h-2.667V13.3H16z" fill="#36CED0"></path><path d="M24 10.633h-2.667V13.3H24zM21.333 13.3h-2.666v2.667H16v2.666h5.333V13.3zM21.333 5.3H16v2.667h2.667v2.666h2.666V5.3z" fill="#624AFF"></path></svg>`,
|
||||
aihubmix: `<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>AiHubMix</title><path d="M12 24c6.627 0 12-5.373 12-12S18.627 0 12 0 0 5.373 0 12s5.373 12 12 12z" fill="#006FFB"></path><path clip-rule="evenodd" d="M11.24 8.393c.095-.644.302-1.47.624-2.48L12 5.496l.136.417c.322 1.01.53 1.836.624 2.48.071.472.071 1.072 0 1.8-.072.731-.072 1.336 0 1.814.106.7.426 1.281.96 1.744a2.795 2.795 0 001.89.708 2.78 2.78 0 002.034-.84c.56-.559.842-1.234.848-2.024.003-.7.075-1.472.216-2.316.069-.422.14-.775.21-1.06l.095-.384.168.356a7.862 7.862 0 01.76 3.244v.16a7.84 7.84 0 01-.624 3.089 7.952 7.952 0 01-4.228 4.228 7.841 7.841 0 01-3.089.623 7.84 7.84 0 01-3.089-.623 7.952 7.952 0 01-4.228-4.228 7.84 7.84 0 01-.623-3.09v-.159a7.862 7.862 0 01.759-3.244l.169-.356.093.385c.072.284.143.637.211 1.059.141.844.213 1.616.216 2.316.006.79.29 1.465.848 2.024.563.56 1.241.84 2.035.84.715 0 1.345-.236 1.889-.708a2.79 2.79 0 00.96-1.744c.073-.478.073-1.083 0-1.814-.071-.728-.071-1.328 0-1.8zm.76 9.694c1.097 0 2.125-.26 3.085-.778a6.379 6.379 0 001.77-1.399c.063-.07-.01-.178-.101-.153-.37.1-.75.15-1.144.15a4.236 4.236 0 01-2.18-.59 4.253 4.253 0 01-1.35-1.233.099.099 0 00-.16 0 4.253 4.253 0 01-1.35 1.232 4.236 4.236 0 01-2.18.591c-.393 0-.774-.05-1.143-.15-.091-.025-.165.083-.102.153a6.38 6.38 0 001.77 1.399c.96.518 1.988.778 3.085.778z" fill="#fff" fill-rule="evenodd"></path></svg>`,
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128"><path fill="#EA6C2C" fill-rule="evenodd" d="M 67.00 124.35 L 65.00 124.65 L 63.00 124.31 L 60.87 122.00 L 60.51 120.00 L 60.62 119.00 L 61.63 117.00 L 63.64 115.00 L 63.65 23.00 L 63.40 22.00 L 60.71 20.00 L 59.73 18.00 L 59.66 16.00 L 61.18 13.00 L 63.00 11.70 L 65.00 11.36 L 67.00 11.68 L 69.00 13.07 L 70.24 15.00 L 70.43 17.00 L 69.35 20.00 L 66.75 22.00 L 66.53 23.00 L 66.56 115.00 L 69.38 118.00 L 69.69 120.00 L 69.38 122.00 L 67.00 124.35 Z M 65.38 19.00 L 66.99 18.00 L 67.30 16.00 L 66.00 14.66 L 64.00 14.69 L 62.79 16.00 L 62.66 17.00 L 64.00 18.73 L 65.38 19.00 Z M 72.00 53.03 L 71.70 52.00 L 71.56 35.00 L 70.00 33.71 L 68.79 32.00 L 68.52 30.00 L 69.00 28.15 L 70.00 26.71 L 72.00 25.59 L 74.00 25.45 L 75.00 25.70 L 76.75 27.00 L 77.50 28.00 L 78.15 30.00 L 77.18 33.00 L 74.81 35.00 L 74.60 50.00 L 72.00 53.03 Z M 74.12 32.00 L 75.11 31.00 L 75.31 30.00 L 74.77 29.00 L 74.00 28.40 L 72.00 28.65 L 71.35 30.00 L 71.45 31.00 L 73.00 32.26 L 74.12 32.00 Z M 58.00 52.97 L 55.68 50.00 L 55.65 40.00 L 52.89 37.00 L 52.36 35.00 L 52.62 33.00 L 54.00 31.03 L 57.00 29.77 L 60.00 30.84 L 61.03 32.00 L 61.64 34.00 L 61.21 37.00 L 58.49 40.00 L 58.47 52.00 L 58.00 52.97 Z M 58.43 36.00 L 59.06 35.00 L 58.91 34.00 L 58.00 32.96 L 57.00 32.66 L 56.00 33.10 L 55.29 34.00 L 55.19 35.00 L 55.64 36.00 L 57.00 36.59 L 58.43 36.00 Z M 57.00 89.45 L 46.00 89.35 L 37.24 77.00 L 36.00 75.99 L 35.00 75.93 L 28.00 75.93 L 27.12 77.00 L 27.14 88.00 L 26.80 89.00 L 26.00 89.36 L 18.00 89.36 L 16.89 89.00 L 16.66 48.00 L 17.00 46.90 L 44.00 46.73 L 48.00 47.67 L 50.00 48.57 L 53.23 51.00 L 55.44 54.00 L 56.34 56.00 L 57.07 59.00 L 56.95 64.00 L 56.15 67.00 L 54.34 70.00 L 52.00 72.26 L 48.83 74.00 L 48.06 75.00 L 57.06 88.00 L 57.53 89.00 L 57.00 89.45 Z M 110.00 89.13 L 109.00 89.65 L 90.00 89.61 L 85.00 89.18 L 80.00 87.40 L 77.00 85.39 L 74.64 83.00 L 72.64 80.00 L 70.76 75.00 L 70.20 70.00 L 70.36 65.00 L 70.81 62.00 L 72.61 57.00 L 74.49 54.00 L 77.36 51.00 L 81.00 48.62 L 84.00 47.54 L 88.00 46.77 L 109.00 46.64 L 109.79 47.00 L 110.13 48.00 L 110.00 55.15 L 109.00 55.68 L 91.00 55.74 L 87.00 56.77 L 84.11 59.00 L 82.59 61.00 L 81.36 64.00 L 80.64 69.00 L 81.62 74.00 L 82.58 76.00 L 85.00 78.66 L 88.00 80.22 L 92.00 80.64 L 109.00 80.64 L 109.80 81.00 L 110.13 82.00 L 110.00 89.13 Z M 43.29 67.00 L 44.89 66.00 L 46.00 64.70 L 46.86 62.00 L 46.50 59.00 L 45.00 56.77 L 43.00 55.56 L 40.00 55.18 L 28.00 55.17 L 27.12 56.00 L 27.16 67.00 L 28.00 67.65 L 40.00 67.63 L 43.29 67.00 Z M 74.00 105.20 L 72.00 105.09 L 70.13 104.00 L 68.71 102.00 L 68.54 101.00 L 68.69 99.00 L 70.00 97.06 L 71.42 96.00 L 71.71 95.00 L 71.70 86.00 L 72.00 84.36 L 74.56 87.00 L 74.64 95.00 L 75.00 95.97 L 77.39 98.00 L 78.12 100.00 L 77.32 103.00 L 76.00 104.37 L 74.00 105.20 Z M 59.00 111.05 L 57.00 111.40 L 55.00 111.01 L 52.89 109.00 L 52.36 107.00 L 53.00 104.45 L 55.51 102.00 L 55.65 93.00 L 55.88 92.00 L 57.00 91.64 L 58.28 92.00 L 58.49 93.00 L 58.63 102.00 L 61.00 104.14 L 61.65 106.00 L 61.26 109.00 L 59.00 111.05 Z M 74.39 102.00 L 75.23 101.00 L 75.00 99.65 L 74.00 98.65 L 73.00 98.54 L 72.06 99.00 L 71.39 100.00 L 71.39 101.00 L 72.00 101.96 L 73.00 102.38 L 74.39 102.00 Z M 58.51 108.00 L 59.09 107.00 L 58.83 106.00 L 58.00 105.18 L 57.00 104.85 L 55.33 106.00 L 55.18 107.00 L 56.00 108.39 L 57.00 108.65 L 58.51 108.00 Z M 65.09 122.00 L 66.75 121.00 L 67.14 120.00 L 66.00 118.36 L 65.00 118.16 L 63.54 119.00 L 63.28 120.00 L 63.47 121.00 L 65.09 122.00 Z"/></svg>
|
||||
<svg viewBox="0 0 24 24" width="1em" height="1em" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>RightCode</title>
|
||||
<path d="M3 4h6c2.2 0 4 1.8 4 4 0 1.5-.8 2.8-2 3.5L14 17h-3l-2.5-5H5v5H3V4zm2 2v4h4c1.1 0 2-.9 2-2s-.9-2-2-2H5z" fill="#E96B2C"/>
|
||||
<path d="M21 8.5c0-2.5-2-4.5-4.5-4.5-1.5 0-2.8.7-3.6 1.8l1.5 1.2c.5-.7 1.2-1 2.1-1 1.4 0 2.5 1.1 2.5 2.5v.5h-1c-2.5 0-4.5 1.3-4.5 3.5 0 1.9 1.6 3.5 3.5 3.5 1.2 0 2.3-.6 3-1.5V16h2V8.5zM17 14c-1.1 0-2-.7-2-1.5s.9-1.5 2-1.5h2v1c0 1.1-.9 2-2 2z" fill="#E96B2C"/>
|
||||
<rect x="3" y="18" width="18" height="2" rx="1" fill="#E96B2C"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 581 B |
@@ -35,7 +35,6 @@ function getErrorI18nKey(code: string): string {
|
||||
DOWNLOAD_TIMEOUT: "skills.error.downloadTimeout",
|
||||
DOWNLOAD_FAILED: "skills.error.downloadFailed",
|
||||
SKILL_DIR_NOT_FOUND: "skills.error.skillDirNotFound",
|
||||
SKILL_DIRECTORY_CONFLICT: "skills.error.directoryConflict",
|
||||
EMPTY_ARCHIVE: "skills.error.emptyArchive",
|
||||
GET_HOME_DIR_FAILED: "skills.error.getHomeDirFailed",
|
||||
};
|
||||
@@ -53,7 +52,6 @@ function getSuggestionI18nKey(suggestion: string): string {
|
||||
retryLater: "skills.error.suggestion.retryLater",
|
||||
checkRepoUrl: "skills.error.suggestion.checkRepoUrl",
|
||||
checkPermission: "skills.error.suggestion.checkPermission",
|
||||
uninstallFirst: "skills.error.suggestion.uninstallFirst",
|
||||
http403: "skills.error.http403",
|
||||
http404: "skills.error.http404",
|
||||
http429: "skills.error.http429",
|
||||
|
||||
@@ -25,9 +25,6 @@ export const settingsSchema = z.object({
|
||||
currentProviderClaude: z.string().optional(),
|
||||
currentProviderCodex: z.string().optional(),
|
||||
currentProviderGemini: z.string().optional(),
|
||||
|
||||
// Skill 同步设置
|
||||
skillSyncMethod: z.enum(["auto", "symlink", "copy"]).optional(),
|
||||
});
|
||||
|
||||
export type SettingsFormData = z.infer<typeof settingsSchema>;
|
||||
|
||||
@@ -137,9 +137,6 @@ export interface ProviderMeta {
|
||||
proxyConfig?: ProviderProxyConfig;
|
||||
}
|
||||
|
||||
// Skill 同步方式
|
||||
export type SkillSyncMethod = "auto" | "symlink" | "copy";
|
||||
|
||||
// 主页面显示的应用配置
|
||||
export interface VisibleApps {
|
||||
claude: boolean;
|
||||
@@ -185,10 +182,6 @@ export interface Settings {
|
||||
currentProviderCodex?: string;
|
||||
// 当前 Gemini 供应商 ID(优先于数据库 is_current)
|
||||
currentProviderGemini?: string;
|
||||
|
||||
// ===== Skill 同步设置 =====
|
||||
// Skill 同步方式:auto(默认,优先 symlink)、symlink、copy
|
||||
skillSyncMethod?: SkillSyncMethod;
|
||||
}
|
||||
|
||||
// MCP 服务器连接参数(宽松:允许扩展字段)
|
||||
@@ -317,8 +310,6 @@ export interface OpenCodeModel {
|
||||
output?: number;
|
||||
};
|
||||
options?: Record<string, unknown>; // 模型级别额外选项(provider 路由等)
|
||||
// 支持任意额外字段(cost、modalities、thinking、variants 等)
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
// OpenCode 供应商选项
|
||||
|
||||
Reference in New Issue
Block a user