mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-26 06:24:32 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55eec1e294 | |||
| e891f5c876 | |||
| 73073454cd | |||
| 7811383b59 | |||
| c1dff06625 | |||
| 43ae1e5f2c | |||
| b4f262c7bd | |||
| 693c3872f0 |
@@ -2,7 +2,7 @@
|
||||
|
||||
# CC Switch
|
||||
|
||||
### The All-in-One Manager for Claude Code, Codex, Gemini CLI, OpenCode, OpenClaw & Hermes Agent
|
||||
### The All-in-One Manager for Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw & Hermes Agent
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
@@ -152,13 +152,13 @@ Register now via <a href="https://pateway.ai/?ch=etzpm8&aff=WB6M6F67#/">this lin
|
||||
|
||||
## Why CC Switch?
|
||||
|
||||
Modern AI-powered coding relies on CLI tools like Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw — but each has its own configuration format. Switching API providers means manually editing JSON, TOML, or `.env` files, and there is no unified way to manage MCP and Skills across multiple tools.
|
||||
Modern AI-powered coding relies on tools like Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw, and Hermes — but each has its own configuration format. Switching API providers means manually editing JSON, TOML, or `.env` files, and there is no unified way to manage MCP and Skills across multiple tools.
|
||||
|
||||
**CC Switch** gives you a single desktop app to manage all five CLI tools. Instead of editing config files by hand, you get a visual interface to import providers with one click, switch between them instantly, with 50+ built-in provider presets, unified MCP and Skills management, and system tray quick switching — all backed by a reliable SQLite database with atomic writes that protect your configs from corruption.
|
||||
**CC Switch** gives you a single desktop app to manage all supported AI tools. Instead of editing config files by hand, you get a visual interface to import providers with one click, switch between them instantly, with 50+ built-in provider presets, unified MCP and Skills management, and system tray quick switching — all backed by a reliable SQLite database with atomic writes that protect your configs from corruption.
|
||||
|
||||
- **One App, Five CLI Tools** — Manage Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw from a single interface
|
||||
- **One App, Seven Tools** — Manage Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw, and Hermes from a single interface
|
||||
- **No More Manual Editing** — 50+ provider presets including AWS Bedrock, NVIDIA NIM, and community relays; just pick and switch
|
||||
- **Unified MCP & Skills Management** — One panel to manage MCP servers and Skills across four apps with bidirectional sync
|
||||
- **Unified MCP & Skills Management** — One panel to manage MCP servers and Skills across Claude, Codex, Gemini, OpenCode, and Hermes with bidirectional sync
|
||||
- **System Tray Quick Switch** — Switch providers instantly from the tray menu, no need to open the full app
|
||||
- **Cloud Sync** — Sync provider data across devices via Dropbox, OneDrive, iCloud, or WebDAV servers
|
||||
- **Cross-Platform** — Native desktop app for Windows, macOS, and Linux, built with Tauri 2
|
||||
@@ -172,12 +172,12 @@ Modern AI-powered coding relies on CLI tools like Claude Code, Codex, Gemini CLI
|
||||
|
||||
## Features
|
||||
|
||||
[Full Changelog](CHANGELOG.md) | [Release Notes](docs/release-notes/v3.15.0-en.md)
|
||||
[Full Changelog](CHANGELOG.md) | [Release Notes](docs/release-notes/v3.16.0-en.md)
|
||||
|
||||
### Provider Management
|
||||
|
||||
- **5 CLI tools, 50+ presets** — Claude Code, Codex, Gemini CLI, OpenCode, OpenClaw; copy your key and import with one click
|
||||
- **Universal providers** — One config syncs to multiple apps (OpenCode, OpenClaw)
|
||||
- **7 supported tools, 50+ presets** — Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw, Hermes; copy your key and import with one click
|
||||
- **Universal providers** — One config syncs to Claude Code, Codex, and Gemini CLI
|
||||
- One-click switching, system tray quick access, drag-and-drop sorting, import/export
|
||||
|
||||
### Proxy & Failover
|
||||
@@ -187,7 +187,7 @@ Modern AI-powered coding relies on CLI tools like Claude Code, Codex, Gemini CLI
|
||||
|
||||
### MCP, Prompts & Skills
|
||||
|
||||
- **Unified MCP panel** — Manage MCP servers across 4 apps with bidirectional sync and Deep Link import
|
||||
- **Unified MCP panel** — Manage MCP servers across Claude, Codex, Gemini, OpenCode, and Hermes with bidirectional sync and Deep Link import
|
||||
- **Prompts** — Markdown editor with cross-app sync (CLAUDE.md / AGENTS.md / GEMINI.md) and backfill protection
|
||||
- **Skills** — One-click install from GitHub repos or ZIP files, custom repository management, with symlink and file copy support
|
||||
|
||||
@@ -197,21 +197,21 @@ Modern AI-powered coding relies on CLI tools like Claude Code, Codex, Gemini CLI
|
||||
|
||||
### Session Manager & Workspace
|
||||
|
||||
- Browse, search, and restore conversation history across all apps
|
||||
- Browse, search, and restore conversation history across supported session sources
|
||||
- **Workspace editor** (OpenClaw) — Edit agent files (AGENTS.md, SOUL.md, etc.) with Markdown preview
|
||||
|
||||
### System & Platform
|
||||
|
||||
- **Cloud sync** — Custom config directory (Dropbox, OneDrive, iCloud, NAS) and WebDAV server sync
|
||||
- **Deep Link** (`ccswitch://`) — Import providers, MCP servers, prompts, and skills via URL
|
||||
- Dark / Light / System theme, auto-launch, auto-updater, atomic writes, auto-backups, i18n (zh/en/ja)
|
||||
- Dark / Light / System theme, auto-launch, auto-updater, atomic writes, auto-backups, i18n (zh/zh-TW/en/ja)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
<summary><strong>Which AI CLI tools does CC Switch support?</strong></summary>
|
||||
<summary><strong>Which AI tools does CC Switch support?</strong></summary>
|
||||
|
||||
CC Switch supports five tools: **Claude Code**, **Codex**, **Gemini CLI**, **OpenCode**, and **OpenClaw**. Each tool has dedicated provider presets and configuration management.
|
||||
CC Switch supports seven tools: **Claude Code**, **Claude Desktop**, **Codex**, **Gemini CLI**, **OpenCode**, **OpenClaw**, and **Hermes**. Each tool has dedicated provider presets and configuration management.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -280,8 +280,8 @@ For detailed guides on every feature, check out the **[User Manual](docs/user-ma
|
||||
|
||||
- **MCP**: Click the "MCP" button → Add servers via templates or custom config → Toggle per-app sync
|
||||
- **Prompts**: Click "Prompts" → Create presets with Markdown editor → Activate to sync to live files
|
||||
- **Skills**: Click "Skills" → Browse GitHub repos → One-click install to all apps
|
||||
- **Sessions**: Click "Sessions" → Browse, search, and restore conversation history across all apps
|
||||
- **Skills**: Click "Skills" → Browse GitHub repos → One-click install to supported apps
|
||||
- **Sessions**: Click "Sessions" → Browse, search, and restore conversation history across supported session sources
|
||||
|
||||
> **Note**: On first launch, you can manually import existing CLI tool configs as the default provider.
|
||||
|
||||
@@ -372,7 +372,7 @@ Download the latest Linux build from the [Releases](../../releases) page:
|
||||
- **ProviderService**: Provider CRUD, switching, backfill, sorting
|
||||
- **McpService**: MCP server management, import/export, live file sync
|
||||
- **ProxyService**: Local proxy mode with hot-switching and format conversion
|
||||
- **SessionManager**: Conversation history browsing across all supported apps
|
||||
- **SessionManager**: Conversation history browsing across supported session sources
|
||||
- **ConfigService**: Config import/export, backup rotation
|
||||
- **SpeedtestService**: API endpoint latency measurement
|
||||
|
||||
@@ -494,7 +494,7 @@ pnpm test:unit --coverage
|
||||
│ ├── lib/
|
||||
│ │ ├── api/ # Tauri API wrapper (type-safe)
|
||||
│ │ └── query/ # TanStack Query config
|
||||
│ ├── locales/ # Translations (zh/en/ja)
|
||||
│ ├── locales/ # Translations (zh/zh-TW/en/ja)
|
||||
│ ├── config/ # Presets (providers/mcp)
|
||||
│ └── types/ # TypeScript definitions
|
||||
├── src-tauri/ # Backend (Rust)
|
||||
|
||||
+16
-16
@@ -2,7 +2,7 @@
|
||||
|
||||
# CC Switch
|
||||
|
||||
### Der All-in-One-Manager für Claude Code, Codex, Gemini CLI, OpenCode, OpenClaw & Hermes Agent
|
||||
### Der All-in-One-Manager für Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw & Hermes Agent
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
@@ -152,13 +152,13 @@ Registrieren Sie sich jetzt über <a href="https://pateway.ai/?ch=etzpm8&aff=WB6
|
||||
|
||||
## Warum CC Switch?
|
||||
|
||||
Modernes KI-gestütztes Programmieren stützt sich auf CLI-Werkzeuge wie Claude Code, Codex, Gemini CLI, OpenCode und OpenClaw — doch jedes hat sein eigenes Konfigurationsformat. Der Wechsel des API-Anbieters bedeutet, JSON-, TOML- oder `.env`-Dateien von Hand zu bearbeiten, und es gibt keine einheitliche Möglichkeit, MCP und Skills über mehrere Werkzeuge hinweg zu verwalten.
|
||||
Modernes KI-gestütztes Programmieren stützt sich auf Werkzeuge wie Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw und Hermes — doch jedes hat sein eigenes Konfigurationsformat. Der Wechsel des API-Anbieters bedeutet, JSON-, TOML- oder `.env`-Dateien von Hand zu bearbeiten, und es gibt keine einheitliche Möglichkeit, MCP und Skills über mehrere Werkzeuge hinweg zu verwalten.
|
||||
|
||||
**CC Switch** gibt Ihnen eine einzige Desktop-App, um alle fünf CLI-Werkzeuge zu verwalten. Statt Konfigurationsdateien von Hand zu bearbeiten, erhalten Sie eine visuelle Oberfläche, um Anbieter mit einem Klick zu importieren und sofort zwischen ihnen zu wechseln — mit 50+ integrierten Anbieter-Presets, einheitlicher MCP- und Skills-Verwaltung und schnellem Umschalten über das System-Tray. Das Ganze gestützt auf eine zuverlässige SQLite-Datenbank mit atomaren Schreibvorgängen, die Ihre Konfigurationen vor Beschädigung schützen.
|
||||
**CC Switch** gibt Ihnen eine einzige Desktop-App, um alle unterstützten KI-Werkzeuge zu verwalten. Statt Konfigurationsdateien von Hand zu bearbeiten, erhalten Sie eine visuelle Oberfläche, um Anbieter mit einem Klick zu importieren und sofort zwischen ihnen zu wechseln — mit 50+ integrierten Anbieter-Presets, einheitlicher MCP- und Skills-Verwaltung und schnellem Umschalten über das System-Tray. Das Ganze gestützt auf eine zuverlässige SQLite-Datenbank mit atomaren Schreibvorgängen, die Ihre Konfigurationen vor Beschädigung schützen.
|
||||
|
||||
- **Eine App, fünf CLI-Werkzeuge** — Verwalten Sie Claude Code, Codex, Gemini CLI, OpenCode und OpenClaw über eine einzige Oberfläche
|
||||
- **Eine App, sieben Werkzeuge** — Verwalten Sie Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw und Hermes über eine einzige Oberfläche
|
||||
- **Kein manuelles Bearbeiten mehr** — 50+ Anbieter-Presets einschließlich AWS Bedrock, NVIDIA NIM und Community-Relays; einfach auswählen und umschalten
|
||||
- **Einheitliche MCP- & Skills-Verwaltung** — Ein Panel zur Verwaltung von MCP-Servern und Skills über vier Apps hinweg mit bidirektionaler Synchronisierung
|
||||
- **Einheitliche MCP- & Skills-Verwaltung** — Ein Panel zur Verwaltung von MCP-Servern und Skills für Claude, Codex, Gemini, OpenCode und Hermes mit bidirektionaler Synchronisierung
|
||||
- **Schnellumschaltung über System-Tray** — Wechseln Sie Anbieter sofort über das Tray-Menü, ohne die vollständige App öffnen zu müssen
|
||||
- **Cloud-Synchronisierung** — Synchronisieren Sie Anbieterdaten geräteübergreifend über Dropbox, OneDrive, iCloud oder WebDAV-Server
|
||||
- **Plattformübergreifend** — Native Desktop-App für Windows, macOS und Linux, gebaut mit Tauri 2
|
||||
@@ -172,12 +172,12 @@ Modernes KI-gestütztes Programmieren stützt sich auf CLI-Werkzeuge wie Claude
|
||||
|
||||
## Funktionen
|
||||
|
||||
[Vollständiges Changelog](CHANGELOG.md) | [Release Notes](docs/release-notes/v3.15.0-en.md)
|
||||
[Vollständiges Changelog](CHANGELOG.md) | [Release Notes](docs/release-notes/v3.16.0-en.md)
|
||||
|
||||
### Anbieterverwaltung
|
||||
|
||||
- **5 CLI-Werkzeuge, 50+ Presets** — Claude Code, Codex, Gemini CLI, OpenCode, OpenClaw; Schlüssel kopieren und mit einem Klick importieren
|
||||
- **Universelle Anbieter** — Eine Konfiguration synchronisiert sich mit mehreren Apps (OpenCode, OpenClaw)
|
||||
- **7 unterstützte Werkzeuge, 50+ Presets** — Claude Code, Claude Desktop, Codex, Gemini CLI, OpenCode, OpenClaw, Hermes; Schlüssel kopieren und mit einem Klick importieren
|
||||
- **Universelle Anbieter** — Eine Konfiguration synchronisiert sich mit Claude Code, Codex und Gemini CLI
|
||||
- Umschaltung mit einem Klick, Schnellzugriff über System-Tray, Sortierung per Drag-and-drop, Import/Export
|
||||
|
||||
### Proxy & Failover
|
||||
@@ -187,7 +187,7 @@ Modernes KI-gestütztes Programmieren stützt sich auf CLI-Werkzeuge wie Claude
|
||||
|
||||
### MCP, Prompts & Skills
|
||||
|
||||
- **Einheitliches MCP-Panel** — Verwalten Sie MCP-Server über 4 Apps hinweg mit bidirektionaler Synchronisierung und Deep-Link-Import
|
||||
- **Einheitliches MCP-Panel** — Verwalten Sie MCP-Server für Claude, Codex, Gemini, OpenCode und Hermes mit bidirektionaler Synchronisierung und Deep-Link-Import
|
||||
- **Prompts** — Markdown-Editor mit App-übergreifender Synchronisierung (CLAUDE.md / AGENTS.md / GEMINI.md) und Backfill-Schutz
|
||||
- **Skills** — Installation mit einem Klick aus GitHub-Repositorys oder ZIP-Dateien, Verwaltung eigener Repositorys, mit Unterstützung für Symlinks und Dateikopien
|
||||
|
||||
@@ -197,21 +197,21 @@ Modernes KI-gestütztes Programmieren stützt sich auf CLI-Werkzeuge wie Claude
|
||||
|
||||
### Session Manager & Workspace
|
||||
|
||||
- Durchsuchen, suchen und stellen Sie den Gesprächsverlauf über alle Apps hinweg wieder her
|
||||
- Gesprächsverlauf aus unterstützten Sitzungsquellen durchsuchen, suchen und wiederherstellen
|
||||
- **Workspace-Editor** (OpenClaw) — Bearbeiten Sie Agent-Dateien (AGENTS.md, SOUL.md usw.) mit Markdown-Vorschau
|
||||
|
||||
### System & Plattform
|
||||
|
||||
- **Cloud-Synchronisierung** — Eigenes Konfigurationsverzeichnis (Dropbox, OneDrive, iCloud, NAS) und WebDAV-Server-Synchronisierung
|
||||
- **Deep Link** (`ccswitch://`) — Importieren Sie Anbieter, MCP-Server, Prompts und Skills per URL
|
||||
- Dunkles / Helles / System-Theme, automatischer Start, automatischer Updater, atomare Schreibvorgänge, automatische Backups, i18n (zh/en/ja)
|
||||
- Dunkles / Helles / System-Theme, automatischer Start, automatischer Updater, atomare Schreibvorgänge, automatische Backups, i18n (zh/zh-TW/en/ja)
|
||||
|
||||
## FAQ
|
||||
|
||||
<details>
|
||||
<summary><strong>Welche KI-CLI-Werkzeuge unterstützt CC Switch?</strong></summary>
|
||||
<summary><strong>Welche KI-Werkzeuge unterstützt CC Switch?</strong></summary>
|
||||
|
||||
CC Switch unterstützt fünf Werkzeuge: **Claude Code**, **Codex**, **Gemini CLI**, **OpenCode** und **OpenClaw**. Jedes Werkzeug verfügt über dedizierte Anbieter-Presets und Konfigurationsverwaltung.
|
||||
CC Switch unterstützt sieben Werkzeuge: **Claude Code**, **Claude Desktop**, **Codex**, **Gemini CLI**, **OpenCode**, **OpenClaw** und **Hermes**. Jedes Werkzeug verfügt über dedizierte Anbieter-Presets und Konfigurationsverwaltung.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -280,8 +280,8 @@ Ausführliche Anleitungen zu jeder Funktion finden Sie im **[Benutzerhandbuch](d
|
||||
|
||||
- **MCP**: Klicken Sie auf die Schaltfläche „MCP" → Server über Vorlagen oder eigene Konfiguration hinzufügen → Synchronisierung pro App umschalten
|
||||
- **Prompts**: Klicken Sie auf „Prompts" → Presets mit dem Markdown-Editor erstellen → Aktivieren, um mit den Live-Dateien zu synchronisieren
|
||||
- **Skills**: Klicken Sie auf „Skills" → GitHub-Repositorys durchsuchen → mit einem Klick in allen Apps installieren
|
||||
- **Sessions**: Klicken Sie auf „Sessions" → Gesprächsverlauf über alle Apps hinweg durchsuchen, suchen und wiederherstellen
|
||||
- **Skills**: Klicken Sie auf „Skills" → GitHub-Repositorys durchsuchen → mit einem Klick in unterstützte Apps installieren
|
||||
- **Sessions**: Klicken Sie auf „Sessions" → Gesprächsverlauf aus unterstützten Sitzungsquellen durchsuchen, suchen und wiederherstellen
|
||||
|
||||
> **Hinweis**: Beim Erststart können Sie bestehende CLI-Werkzeug-Konfigurationen manuell als Standardanbieter importieren.
|
||||
|
||||
@@ -494,7 +494,7 @@ pnpm test:unit --coverage
|
||||
│ ├── lib/
|
||||
│ │ ├── api/ # Tauri-API-Wrapper (typsicher)
|
||||
│ │ └── query/ # TanStack-Query-Konfiguration
|
||||
│ ├── locales/ # Übersetzungen (zh/en/ja)
|
||||
│ ├── locales/ # Übersetzungen (zh/zh-TW/en/ja)
|
||||
│ ├── config/ # Presets (providers/mcp)
|
||||
│ └── types/ # TypeScript-Definitionen
|
||||
├── src-tauri/ # Backend (Rust)
|
||||
|
||||
+16
-16
@@ -2,7 +2,7 @@
|
||||
|
||||
# CC Switch
|
||||
|
||||
### Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes Agent のオールインワン管理ツール
|
||||
### Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes Agent のオールインワン管理ツール
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
@@ -151,13 +151,13 @@ Claude Code / Codex / Gemini 公式チャンネルが最安で元価格の 38% /
|
||||
|
||||
## CC Switch を選ぶ理由
|
||||
|
||||
最新の AI コーディングは Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw などの CLI ツールに依存していますが、各ツールの設定形式はバラバラです。API プロバイダを切り替えるたびに JSON、TOML、`.env` ファイルを手動で編集する必要があり、複数ツール間で MCP や Skills を統一的に管理する手段もありません。
|
||||
最新の AI コーディングは Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes などのツールに依存していますが、各ツールの設定形式はバラバラです。API プロバイダを切り替えるたびに JSON、TOML、`.env` ファイルを手動で編集する必要があり、複数ツール間で MCP や Skills を統一的に管理する手段もありません。
|
||||
|
||||
**CC Switch** は、5 つの CLI ツールを 1 つのデスクトップアプリで一元管理できます。設定ファイルを手作業で編集する代わりに、ワンクリックでプロバイダをインポートし、瞬時に切り替えられるビジュアルインターフェースを提供します。50 以上の組み込みプリセット、統一 MCP・Skills 管理、システムトレイからの即時切り替え機能を搭載。すべてはアトミック書き込みによる信頼性の高い SQLite データベースに支えられており、設定の破損を防ぎます。
|
||||
**CC Switch** は、対応する AI ツールを 1 つのデスクトップアプリで一元管理できます。設定ファイルを手作業で編集する代わりに、ワンクリックでプロバイダをインポートし、瞬時に切り替えられるビジュアルインターフェースを提供します。50 以上の組み込みプリセット、統一 MCP・Skills 管理、システムトレイからの即時切り替え機能を搭載。すべてはアトミック書き込みによる信頼性の高い SQLite データベースに支えられており、設定の破損を防ぎます。
|
||||
|
||||
- **1 つのアプリで 5 つの CLI ツール** -- Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw を単一インターフェースで管理
|
||||
- **1 つのアプリで 7 つのツール** -- Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes を単一インターフェースで管理
|
||||
- **手動編集は不要** -- AWS Bedrock、NVIDIA NIM、コミュニティリレーなど 50 以上のプロバイダプリセットを内蔵。選んで切り替えるだけ
|
||||
- **統一 MCP・Skills 管理** -- 1 つのパネルで 4 つのアプリの MCP サーバーと Skills を双方向同期で管理
|
||||
- **統一 MCP・Skills 管理** -- 1 つのパネルで Claude、Codex、Gemini、OpenCode、Hermes の MCP サーバーと Skills を双方向同期で管理
|
||||
- **システムトレイでクイック切り替え** -- トレイメニューから即座にプロバイダを切り替え。アプリを開く必要なし
|
||||
- **クラウド同期** -- Dropbox、OneDrive、iCloud、または WebDAV サーバー経由でデバイス間のプロバイダデータを同期
|
||||
- **クロスプラットフォーム** -- Tauri 2 で構築された Windows、macOS、Linux 対応のネイティブデスクトップアプリ
|
||||
@@ -171,12 +171,12 @@ Claude Code / Codex / Gemini 公式チャンネルが最安で元価格の 38% /
|
||||
|
||||
## 特長
|
||||
|
||||
[完全な更新履歴](CHANGELOG.md) | [リリースノート](docs/release-notes/v3.15.0-ja.md)
|
||||
[完全な更新履歴](CHANGELOG.md) | [リリースノート](docs/release-notes/v3.16.0-ja.md)
|
||||
|
||||
### プロバイダ管理
|
||||
|
||||
- **5 つの CLI ツール、50 以上のプリセット** -- Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw。キーをコピーしてワンクリックでインポート
|
||||
- **ユニバーサルプロバイダ** -- 1 つの設定を複数アプリに同期(OpenCode、OpenClaw)
|
||||
- **7 つの対応ツール、50 以上のプリセット** -- Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes。キーをコピーしてワンクリックでインポート
|
||||
- **ユニバーサルプロバイダ** -- 1 つの設定を Claude Code、Codex、Gemini CLI に同期
|
||||
- ワンクリック切り替え、システムトレイクイックアクセス、ドラッグ&ドロップ並び替え、インポート/エクスポート
|
||||
|
||||
### プロキシ & フェイルオーバー
|
||||
@@ -186,7 +186,7 @@ Claude Code / Codex / Gemini 公式チャンネルが最安で元価格の 38% /
|
||||
|
||||
### MCP、Prompts & Skills
|
||||
|
||||
- **統一 MCP パネル** -- 4 つのアプリの MCP サーバーを管理、双方向同期、Deep Link インポート対応
|
||||
- **統一 MCP パネル** -- Claude、Codex、Gemini、OpenCode、Hermes の MCP サーバーを管理、双方向同期、Deep Link インポート対応
|
||||
- **Prompts** -- Markdown エディタ、クロスアプリ同期(CLAUDE.md / AGENTS.md / GEMINI.md)、バックフィル保護
|
||||
- **Skills** -- GitHub リポジトリまたは ZIP ファイルからワンクリックインストール、カスタムリポジトリ管理、シンボリックリンクとファイルコピーに対応
|
||||
|
||||
@@ -196,21 +196,21 @@ Claude Code / Codex / Gemini 公式チャンネルが最安で元価格の 38% /
|
||||
|
||||
### Session Manager & ワークスペース
|
||||
|
||||
- すべてのアプリの会話履歴を閲覧・検索・復元
|
||||
- 対応するセッションソースの会話履歴を閲覧・検索・復元
|
||||
- **ワークスペースエディタ**(OpenClaw)-- エージェントファイル(AGENTS.md、SOUL.md など)を Markdown プレビュー付きで編集
|
||||
|
||||
### システム & プラットフォーム
|
||||
|
||||
- **クラウド同期** -- カスタム設定ディレクトリ(Dropbox、OneDrive、iCloud、NAS)および WebDAV サーバー同期
|
||||
- **Deep Link** (`ccswitch://`) -- URL 経由でプロバイダ、MCP サーバー、Prompts、Skills をワンクリックインポート
|
||||
- ダーク / ライト / システムテーマ、自動起動、自動アップデーター、アトミック書き込み、自動バックアップ、多言語対応(中/英/日)
|
||||
- ダーク / ライト / システムテーマ、自動起動、自動アップデーター、アトミック書き込み、自動バックアップ、多言語対応(簡体中文/繁體中文/英/日)
|
||||
|
||||
## よくある質問
|
||||
|
||||
<details>
|
||||
<summary><strong>CC Switch はどの AI CLI ツールに対応していますか?</strong></summary>
|
||||
<summary><strong>CC Switch はどの AI ツールに対応していますか?</strong></summary>
|
||||
|
||||
CC Switch は **Claude Code**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw** の 5 つのツールに対応しています。各ツールに専用のプロバイダプリセットと設定管理が用意されています。
|
||||
CC Switch は **Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw**、**Hermes** の 7 つのツールに対応しています。各ツールに専用のプロバイダプリセットと設定管理が用意されています。
|
||||
|
||||
</details>
|
||||
|
||||
@@ -279,8 +279,8 @@ CC Switch は「最小限の介入」という設計原則に従っています
|
||||
|
||||
- **MCP**: 「MCP」ボタンをクリック → テンプレートまたはカスタム設定でサーバーを追加 → アプリごとの同期をトグルで切り替え
|
||||
- **Prompts**: 「Prompts」をクリック → Markdown エディタでプリセットを作成 → 有効化してライブファイルに同期
|
||||
- **Skills**: 「Skills」をクリック → GitHub リポジトリを閲覧 → ワンクリックですべてのアプリにインストール
|
||||
- **Sessions**: 「Sessions」をクリック → すべてのアプリの会話履歴を閲覧・検索・復元
|
||||
- **Skills**: 「Skills」をクリック → GitHub リポジトリを閲覧 → 対応アプリへワンクリックでインストール
|
||||
- **Sessions**: 「Sessions」をクリック → 対応するセッションソースの会話履歴を閲覧・検索・復元
|
||||
|
||||
> **補足**: 初回起動時に、既存の CLI ツール設定を手動でインポートしてデフォルトプロバイダとして使用できます。
|
||||
|
||||
@@ -493,7 +493,7 @@ pnpm test:unit --coverage
|
||||
│ ├── lib/
|
||||
│ │ ├── api/ # Tauri API ラッパー(型安全)
|
||||
│ │ └── query/ # TanStack Query 設定
|
||||
│ ├── locales/ # 翻訳 (zh/en/ja)
|
||||
│ ├── locales/ # 翻訳 (zh/zh-TW/en/ja)
|
||||
│ ├── config/ # プリセット (providers/mcp)
|
||||
│ └── types/ # TypeScript 型定義
|
||||
├── src-tauri/ # バックエンド (Rust)
|
||||
|
||||
+16
-16
@@ -2,7 +2,7 @@
|
||||
|
||||
# CC Switch
|
||||
|
||||
### Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw 和 Hermes Agent 的全方位管理工具
|
||||
### Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw 和 Hermes Agent 的全方位管理工具
|
||||
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
[](https://github.com/farion1231/cc-switch/releases)
|
||||
@@ -152,13 +152,13 @@ Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更
|
||||
|
||||
## 为什么选择 CC Switch?
|
||||
|
||||
现代 AI 编程依赖于 Claude Code、Codex、Gemini CLI、OpenCode 和 OpenClaw 等 CLI 工具——但每个工具都有自己的配置格式。切换 API 供应商意味着手动编辑 JSON、TOML 或 `.env` 文件,而在多个工具之间缺乏一个统一管理 MCP, SKILLS 的方式。
|
||||
现代 AI 编程依赖于 Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw 和 Hermes 等工具——但每个工具都有自己的配置格式。切换 API 供应商意味着手动编辑 JSON、TOML 或 `.env` 文件,而在多个工具之间缺乏一个统一管理 MCP, SKILLS 的方式。
|
||||
|
||||
**CC Switch** 为你提供一个桌面应用来管理所有五个 CLI 工具。无需手动编辑配置文件,你将获得一个可视化界面,一键将供应商导入应用,一键在不同的供应商之间进行切换,内置 50+ 供应商预设、统一的 MCP, SKILLS 管理以及系统托盘即时切换功能——所有操作都基于可靠的 SQLite 数据库和原子写入机制,保护你的配置不被损坏。
|
||||
**CC Switch** 为你提供一个桌面应用来管理所有支持的 AI 工具。无需手动编辑配置文件,你将获得一个可视化界面,一键将供应商导入应用,一键在不同的供应商之间进行切换,内置 50+ 供应商预设、统一的 MCP, SKILLS 管理以及系统托盘即时切换功能——所有操作都基于可靠的 SQLite 数据库和原子写入机制,保护你的配置不被损坏。
|
||||
|
||||
- **一个应用,五个 CLI 工具** — 在单一界面中管理 Claude Code、Codex、Gemini CLI、OpenCode 和 OpenClaw
|
||||
- **一个应用,七个工具** — 在单一界面中管理 Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw 和 Hermes
|
||||
- **告别手动编辑** — 50+ 供应商预设,包括 AWS Bedrock、NVIDIA NIM 和社区中转服务;一键即可切换
|
||||
- **统一 MCP, SKILLS 管理** — 一个面板管理四个应用的 MCP, SKILLS, 支持双向同步
|
||||
- **统一 MCP, SKILLS 管理** — 一个面板管理 Claude、Codex、Gemini、OpenCode 和 Hermes 的 MCP, SKILLS, 支持双向同步
|
||||
- **系统托盘快速切换** — 从托盘菜单即时切换供应商,无需打开完整应用
|
||||
- **云同步** — 通过 Dropbox、OneDrive、iCloud 或 WebDAV 服务器在不同设备之间同步供应商数据
|
||||
- **跨平台** — 基于 Tauri 2 构建的原生桌面应用,支持 Windows、macOS 和 Linux
|
||||
@@ -172,12 +172,12 @@ Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更
|
||||
|
||||
## 功能特性
|
||||
|
||||
[完整更新日志](CHANGELOG.md) | [发布说明](docs/release-notes/v3.15.0-zh.md)
|
||||
[完整更新日志](CHANGELOG.md) | [发布说明](docs/release-notes/v3.16.0-zh.md)
|
||||
|
||||
### 供应商管理
|
||||
|
||||
- **5 个 CLI 工具,50+ 预设** — Claude Code、Codex、Gemini CLI、OpenCode、OpenClaw;复制 key 即可一键导入
|
||||
- **通用供应商** — 一份配置同步到多个应用(OpenCode、OpenClaw)
|
||||
- **7 个支持工具,50+ 预设** — Claude Code、Claude Desktop、Codex、Gemini CLI、OpenCode、OpenClaw、Hermes;复制 key 即可一键导入
|
||||
- **通用供应商** — 一份配置同步到 Claude Code、Codex 和 Gemini CLI
|
||||
- 一键切换、系统托盘快速访问、拖拽排序、导入导出
|
||||
|
||||
### 代理与故障转移
|
||||
@@ -187,7 +187,7 @@ Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更
|
||||
|
||||
### MCP、Prompts 与 Skills
|
||||
|
||||
- **统一 MCP 面板** — 管理 4 个应用的 MCP 服务器,双向同步,支持 Deep Link 导入
|
||||
- **统一 MCP 面板** — 管理 Claude、Codex、Gemini、OpenCode 和 Hermes 的 MCP 服务器,双向同步,支持 Deep Link 导入
|
||||
- **Prompts** — Markdown 编辑器,跨应用同步(CLAUDE.md / AGENTS.md / GEMINI.md),回填保护
|
||||
- **Skills** — 从 GitHub 仓库或 ZIP 文件一键安装,自定义仓库管理,支持软连接和文件复制
|
||||
|
||||
@@ -197,21 +197,21 @@ Claude Code / Codex / Gemini 官方渠道低至 3.8 / 0.2 / 0.9 折,充值更
|
||||
|
||||
### 会话管理器与工作区
|
||||
|
||||
- 浏览、搜索和恢复全部应用对话历史
|
||||
- 浏览、搜索和恢复支持的会话来源
|
||||
- **工作区编辑器**(OpenClaw)— 编辑 Agent 文件(AGENTS.md、SOUL.md 等),支持 Markdown 预览
|
||||
|
||||
### 系统与平台
|
||||
|
||||
- **云同步** — 自定义配置目录(Dropbox、OneDrive、iCloud、坚果云、NAS)及 WebDAV 服务器同步
|
||||
- **Deep Link** (`ccswitch://`) — 通过 URL 一键导入供应商、MCP 服务器、提示词和技能
|
||||
- 深色 / 浅色 / 跟随系统主题、开机自启、自动更新、原子写入、自动备份、国际化(中/英/日)
|
||||
- 深色 / 浅色 / 跟随系统主题、开机自启、自动更新、原子写入、自动备份、国际化(简中/繁中/英/日)
|
||||
|
||||
## 常见问题
|
||||
|
||||
<details>
|
||||
<summary><strong>CC Switch 支持哪些 AI CLI 工具?</strong></summary>
|
||||
<summary><strong>CC Switch 支持哪些 AI 工具?</strong></summary>
|
||||
|
||||
CC Switch 支持五个工具:**Claude Code**、**Codex**、**Gemini CLI**、**OpenCode** 和 **OpenClaw**。每个工具都有专属的供应商预设和配置管理。
|
||||
CC Switch 支持七个工具:**Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw** 和 **Hermes**。每个工具都有专属的供应商预设和配置管理。
|
||||
|
||||
</details>
|
||||
|
||||
@@ -282,8 +282,8 @@ CC Switch macOS 版本已通过 Apple 代码签名和公证,可直接下载安
|
||||
|
||||
- **MCP**:点击"MCP"按钮 → 通过模板或自定义配置添加服务器 → 切换各应用同步开关
|
||||
- **Prompts**:点击"Prompts" → 使用 Markdown 编辑器创建预设 → 激活后同步到 live 文件
|
||||
- **Skills**:点击"Skills" → 浏览 GitHub 仓库 → 一键安装到全部应用
|
||||
- **会话**:点击"Sessions" → 浏览和搜索和恢复全部应用对话历史
|
||||
- **Skills**:点击"Skills" → 浏览 GitHub 仓库 → 一键安装到支持的应用
|
||||
- **会话**:点击"Sessions" → 浏览、搜索和恢复支持的会话来源
|
||||
|
||||
> **注意**:首次启动可以手动导入现有 CLI 工具配置作为默认供应商。
|
||||
|
||||
@@ -496,7 +496,7 @@ pnpm test:unit --coverage
|
||||
│ ├── lib/
|
||||
│ │ ├── api/ # Tauri API 封装(类型安全)
|
||||
│ │ └── query/ # TanStack Query 配置
|
||||
│ ├── locales/ # 翻译 (zh/en/ja)
|
||||
│ ├── locales/ # 翻译 (zh/zh-TW/en/ja)
|
||||
│ ├── config/ # 预设 (providers/mcp)
|
||||
│ └── types/ # TypeScript 类型定义
|
||||
├── src-tauri/ # 后端 (Rust)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CC Switch User Manual / 用户手册 / ユーザーマニュアル
|
||||
|
||||
> Claude Code / Codex / Gemini CLI / OpenCode / OpenClaw
|
||||
> Claude Code / Claude Desktop / Codex / Gemini CLI / OpenCode / OpenClaw / Hermes
|
||||
|
||||
## Language / 语言 / 言語
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
## Version / 版本 / バージョン
|
||||
|
||||
- Documentation version: v3.15.0
|
||||
- Last updated: 2026-05-16
|
||||
- Compatible with CC Switch v3.15.0+
|
||||
- Documentation version: v3.16.0
|
||||
- Last updated: 2026-05-29
|
||||
- Compatible with CC Switch v3.16.0+
|
||||
|
||||
## Links
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## What is CC Switch
|
||||
|
||||
CC Switch is a cross-platform desktop application designed for developers who use AI coding tools. It helps you centrally manage configurations for **Claude Code**, **Claude Desktop**, **Codex**, **Gemini CLI**, **OpenCode**, **OpenClaw**, and **Hermes**.
|
||||
CC Switch is a cross-platform desktop application designed for developers who use AI tools. It helps you centrally manage configurations for **Claude Code**, **Claude Desktop**, **Codex**, **Gemini CLI**, **OpenCode**, **OpenClaw**, and **Hermes**.
|
||||
|
||||
## What Problems Does It Solve
|
||||
|
||||
@@ -45,7 +45,7 @@ CC Switch solves these problems through a unified interface.
|
||||
| **Codex** | OpenAI's code generation tool |
|
||||
| **Gemini CLI** | Google's AI command-line tool |
|
||||
| **OpenCode** | Open-source AI coding terminal tool |
|
||||
| **OpenClaw** | Open-source AI coding assistant (multi-provider gateway) |
|
||||
| **OpenClaw** | Open-source AI assistant (multi-provider gateway) |
|
||||
| **Hermes** | Hermes Agent provider, MCP, Skills, and Memory management |
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| 2 | Settings Button | Open the settings page (shortcut `Cmd/Ctrl + ,`) |
|
||||
| 3 | Proxy Toggle | Start/stop the local proxy service |
|
||||
| 4 | App Switcher | Switch between Claude / Claude Desktop / Codex / Gemini / OpenCode / OpenClaw / Hermes |
|
||||
| 5 | Feature Area | Skills / Prompts / MCP entry points |
|
||||
| 5 | Feature Area | App-specific feature entry points |
|
||||
| 6 | Add Button | Add a new provider |
|
||||
|
||||
### App Switcher
|
||||
@@ -33,9 +33,9 @@ After switching, the provider list displays the configurations for the selected
|
||||
|
||||
| Button | Function | Visibility |
|
||||
|--------|----------|------------|
|
||||
| Skills | Skill extension management | Always visible |
|
||||
| Prompts | System prompt management | Always visible |
|
||||
| MCP | MCP server management | Always visible |
|
||||
| Skills | Skill extension management | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
| Prompts | System prompt management | Claude / Codex / Gemini / OpenCode |
|
||||
| MCP | MCP server management | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
|
||||
## Provider Cards
|
||||
|
||||
@@ -113,13 +113,14 @@ CC Switch displays an icon in the system tray, providing quick access to operati
|
||||
|
||||
### Multi-language Support
|
||||
|
||||
The tray menu supports three languages, automatically switching based on settings:
|
||||
The tray menu supports four languages, automatically switching based on settings:
|
||||
|
||||
| Language | Open Main Window | Quit |
|
||||
|----------|-----------------|------|
|
||||
| Chinese | Open Main Window | Quit |
|
||||
| Simplified Chinese | 打开主界面 | 退出 |
|
||||
| Traditional Chinese | 開啟主介面 | 退出 |
|
||||
| English | Open main window | Quit |
|
||||
| Japanese | Open main window | Quit |
|
||||
| Japanese | メインウィンドウを開く | 終了 |
|
||||
|
||||
### Lightweight Mode
|
||||
|
||||
@@ -147,7 +148,7 @@ The settings page is divided into multiple tabs:
|
||||
|
||||
### General Tab
|
||||
|
||||
- Language settings (Chinese/English/Japanese)
|
||||
- Language settings (Simplified Chinese/Traditional Chinese/English/Japanese)
|
||||
- Theme settings (System/Light/Dark)
|
||||
- Window behavior (launch on startup, close behavior)
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ This section describes how to configure CC Switch according to your preferences.
|
||||
|
||||
## Language Settings
|
||||
|
||||
CC Switch supports three languages:
|
||||
CC Switch supports four languages:
|
||||
|
||||
| Language | Description |
|
||||
|----------|-------------|
|
||||
| Simplified Chinese | Default language |
|
||||
| Traditional Chinese | Traditional Chinese interface |
|
||||
| English | English interface |
|
||||
| Japanese | Japanese interface |
|
||||
|
||||
@@ -124,8 +125,9 @@ You can customize each CLI tool's configuration directory:
|
||||
| Claude Directory | `~/.claude/` | Claude Code configuration directory |
|
||||
| Codex Directory | `~/.codex/` | Codex configuration directory |
|
||||
| Gemini Directory | `~/.gemini/` | Gemini CLI configuration directory |
|
||||
| OpenCode Directory | `~/.opencode/` | OpenCode configuration directory |
|
||||
| OpenCode Directory | `~/.config/opencode/` | OpenCode configuration directory |
|
||||
| OpenClaw Directory | `~/.openclaw/` | OpenClaw configuration directory |
|
||||
| Hermes Directory | `~/.hermes/` | Hermes configuration directory |
|
||||
|
||||
> **Note**: After changing directories, the app must be restarted, and the corresponding CLI tools must also be configured to use the same directory.
|
||||
|
||||
@@ -133,14 +135,15 @@ You can customize each CLI tool's configuration directory:
|
||||
|
||||
### Export Configuration
|
||||
|
||||
Click the "Export" button to save a backup file containing:
|
||||
Click the "Export" button to save a SQL backup file containing:
|
||||
|
||||
- All provider configurations
|
||||
- MCP server configurations
|
||||
- Prompt presets
|
||||
- Usage logs
|
||||
- App settings
|
||||
|
||||
The backup file is in JSON format and can be viewed with a text editor.
|
||||
The exported file name format is `cc-switch-export-{timestamp}.sql`.
|
||||
|
||||
### Import Configuration
|
||||
|
||||
|
||||
@@ -103,15 +103,16 @@ Each MCP server can independently control which apps it is enabled for.
|
||||
| Claude | Sync to Claude Code | `~/.claude.json`'s `mcpServers` |
|
||||
| Codex | Sync to Codex | `~/.codex/config.toml`'s `[mcp_servers]` |
|
||||
| Gemini | Sync to Gemini CLI | `~/.gemini/settings.json`'s `mcpServers` |
|
||||
| OpenCode | Sync to OpenCode | `~/.opencode/config.json`'s `mcpServers` |
|
||||
| OpenCode | Sync to OpenCode | `~/.config/opencode/opencode.json`'s `mcp` |
|
||||
| Hermes | Sync to Hermes | `~/.hermes/config.yaml`'s `mcp_servers` |
|
||||
|
||||
> **Note**: OpenClaw does not currently support MCP server management. MCP functionality is currently only supported for Claude, Codex, Gemini, and OpenCode.
|
||||
> **Note**: OpenClaw and Claude Desktop do not currently support CC Switch MCP sync. MCP functionality is supported for Claude, Codex, Gemini, OpenCode, and Hermes.
|
||||
|
||||
### Toggle Implementation
|
||||
|
||||
When enabling an app's toggle, CC Switch will:
|
||||
|
||||
1. **Update database**: Set the server's `apps.claude/codex/gemini/opencode` status to `true`
|
||||
1. **Update database**: Set the server's `apps.claude/codex/gemini/opencode/hermes` status to `true`
|
||||
2. **Sync to live configuration**: Write the server configuration to the corresponding app's configuration file
|
||||
3. **Take effect immediately**: The new MCP server is automatically loaded the next time the CLI tool starts
|
||||
|
||||
@@ -128,7 +129,8 @@ MCP server sync only executes when the corresponding app is installed:
|
||||
- **Claude**: Requires `~/.claude/` directory or `~/.claude.json` file to exist
|
||||
- **Codex**: Requires `~/.codex/` directory to exist
|
||||
- **Gemini**: Requires `~/.gemini/` directory to exist
|
||||
- **OpenCode**: Requires `~/.opencode/` directory to exist
|
||||
- **OpenCode**: Requires `~/.config/opencode/` directory to exist
|
||||
- **Hermes**: Requires `~/.hermes/` directory to exist
|
||||
|
||||
> **Tip**: If a CLI tool is not installed, enabling its toggle will not cause an error, but the configuration will not be written.
|
||||
|
||||
@@ -154,7 +156,7 @@ After deletion, the configuration is removed from all app configuration files.
|
||||
If you have already configured MCP servers in CLI tools, you can import them into CC Switch:
|
||||
|
||||
1. Click the "Import" button
|
||||
2. Select the app to import from (Claude/Codex/Gemini/OpenCode)
|
||||
2. Select the app to import from (Claude/Codex/Gemini/OpenCode/Hermes)
|
||||
3. CC Switch reads the existing configuration and imports it
|
||||
|
||||
## Configuration File Formats
|
||||
|
||||
@@ -81,8 +81,7 @@ After activation, the prompt is written to the corresponding app's file:
|
||||
| Claude | `~/.claude/CLAUDE.md` |
|
||||
| Codex | `~/.codex/AGENTS.md` |
|
||||
| Gemini | `~/.gemini/GEMINI.md` |
|
||||
| OpenCode | `~/.opencode/AGENTS.md` |
|
||||
| OpenClaw | `~/.openclaw/AGENTS.md` |
|
||||
| OpenCode | `~/.config/opencode/AGENTS.md` |
|
||||
|
||||
## Edit a Preset
|
||||
|
||||
@@ -141,7 +140,6 @@ Prompts are managed separately per app:
|
||||
- When switched to Codex, Codex's presets are shown
|
||||
- When switched to Gemini, Gemini's presets are shown
|
||||
- When switched to OpenCode, OpenCode's presets are shown
|
||||
- When switched to OpenClaw, OpenClaw's presets are shown
|
||||
|
||||
To use the same prompt across multiple apps, you need to create them separately.
|
||||
|
||||
|
||||
@@ -12,18 +12,17 @@ Skills exist as folders containing:
|
||||
|
||||
## Supported Applications
|
||||
|
||||
Skills are supported across all four applications:
|
||||
Skills are supported across five applications:
|
||||
|
||||
- **Claude Code**
|
||||
- **Codex**
|
||||
- **Gemini CLI**
|
||||
- **OpenCode**
|
||||
- **Hermes**
|
||||
|
||||
## Open the Skills Page
|
||||
|
||||
Click the **Skills** button in the top navigation bar.
|
||||
|
||||
> Note: The Skills button is visible in all app modes.
|
||||
Click the **Skills** button in the top navigation bar when the selected app supports Skills.
|
||||
|
||||
## Page Overview
|
||||
|
||||
@@ -93,7 +92,8 @@ Click the "Refresh" button to re-scan repositories for the latest skills.
|
||||
| Claude | `~/.claude/skills/` |
|
||||
| Codex | `~/.codex/skills/` |
|
||||
| Gemini | `~/.gemini/skills/` |
|
||||
| OpenCode | `~/.opencode/skills/` |
|
||||
| OpenCode | `~/.config/opencode/skills/` |
|
||||
| Hermes | `~/.hermes/skills/` |
|
||||
|
||||
### Installation Contents
|
||||
|
||||
@@ -119,7 +119,7 @@ Installation copies the skill folder to your local machine:
|
||||
### Uninstall Effect
|
||||
|
||||
- **Automatic backup**: Before deletion, the skill is backed up to `~/.cc-switch/skill-backups/`
|
||||
- Removes the skill from all app directories (Claude, Codex, Gemini, OpenCode)
|
||||
- Removes the skill from all app directories (Claude, Codex, Gemini, OpenCode, Hermes)
|
||||
- Removes the skill from the SSOT directory (`~/.cc-switch/skills/`)
|
||||
- Deletes the skill record from the database
|
||||
|
||||
|
||||
@@ -215,9 +215,11 @@ Set prices for each model (per million tokens):
|
||||
|
||||
Before matching pricing, CC Switch normalizes the requested model ID:
|
||||
|
||||
- Remove everything before the last `/`
|
||||
- Remove everything after `:`
|
||||
- Remove everything before the last `/` and convert to lowercase
|
||||
- Remove everything after `:` and trim a trailing `[1m]`
|
||||
- Replace `@` with `-`
|
||||
- Remove common wrapper prefixes, version suffixes, and date suffixes (`-YYYY-MM-DD`, `-YYYYMMDD`)
|
||||
- Some model families can match a short ID to a versioned pricing entry
|
||||
|
||||
When adding pricing entries, enter the normalized Model ID rather than the full raw model name from the request.
|
||||
|
||||
@@ -226,6 +228,10 @@ When adding pricing entries, enter the normalized Model ID rather than the full
|
||||
| `stepfun-ai/step-3.5-flash` | `step-3.5-flash` | Removes the provider prefix |
|
||||
| `moonshotai/kimi-k2-0905:exa` | `kimi-k2-0905` | Removes the prefix and the `:` suffix |
|
||||
| `gpt-5.2-codex@low` | `gpt-5.2-codex-low` | Replaces `@` with `-` |
|
||||
| `OpenAI/GPT-5.5-2026-05-14` | `gpt-5.5` | Removes the prefix and date suffix |
|
||||
| `anthropic/claude-opus-4.8` | `claude-opus-4-8` | Removes the prefix and matches dotted format |
|
||||
| `global.anthropic.claude-opus-4-8-v1:0` | `claude-opus-4-8` | Removes wrapper prefix, version suffix, and `:` suffix |
|
||||
| `claude-haiku-4-5` | `claude-haiku-4-5-20251001` | Matches a short ID to versioned pricing |
|
||||
|
||||
### Operations
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Customizable location in settings (for cloud sync).
|
||||
├── settings.json # Device-level settings
|
||||
├── skills/ # Skill SSOT directory
|
||||
├── skill-backups/ # Skill backups (created on uninstall)
|
||||
└── db_backup_*.db # Database backups
|
||||
└── backups/ # Database backups
|
||||
```
|
||||
|
||||
### Database Contents
|
||||
@@ -51,7 +51,8 @@ Customizable location in settings (for cloud sync).
|
||||
"codexConfigDir": null,
|
||||
"geminiConfigDir": null,
|
||||
"opencodeConfigDir": null,
|
||||
"openclawConfigDir": null
|
||||
"openclawConfigDir": null,
|
||||
"hermesConfigDir": null
|
||||
}
|
||||
```
|
||||
|
||||
@@ -196,17 +197,41 @@ GEMINI_MODEL=gemini-pro
|
||||
|
||||
### Configuration Directory
|
||||
|
||||
Default: `~/.opencode/`
|
||||
Default: `~/.config/opencode/`
|
||||
|
||||
### Key Files
|
||||
|
||||
```
|
||||
~/.opencode/
|
||||
├── config.json # Main configuration file
|
||||
~/.config/opencode/
|
||||
├── opencode.json # Main configuration file
|
||||
├── AGENTS.md # System prompt
|
||||
└── skills/ # Skills directory
|
||||
└── ...
|
||||
```
|
||||
## Hermes Configuration
|
||||
|
||||
### Configuration Directory
|
||||
|
||||
Default: `~/.hermes/`
|
||||
|
||||
### Key Files
|
||||
|
||||
```
|
||||
~/.hermes/
|
||||
├── config.yaml # Main settings, providers, and MCP configuration
|
||||
├── .env # API keys and secrets
|
||||
├── SOUL.md # Profile identity/persona
|
||||
├── memories/
|
||||
│ ├── MEMORY.md # Agent memory
|
||||
│ └── USER.md # User profile memory
|
||||
├── skills/ # Active skills directory
|
||||
├── state.db # SQLite session database
|
||||
└── sessions/ # Gateway transcripts and optional JSON snapshots
|
||||
```
|
||||
|
||||
### config.yaml
|
||||
|
||||
Hermes uses YAML configuration. CC Switch writes MCP servers to `mcp_servers`, writes editable provider entries to `custom_providers`, reads read-only entries from Hermes' `providers` dict, and updates `model.provider` / `model.default` when switching providers.
|
||||
|
||||
## OpenClaw Configuration
|
||||
|
||||
@@ -219,7 +244,6 @@ Default: `~/.openclaw/`
|
||||
```
|
||||
~/.openclaw/
|
||||
├── openclaw.json # Main configuration file (JSON5 format)
|
||||
├── AGENTS.md # System prompt
|
||||
└── skills/ # Skills directory
|
||||
└── ...
|
||||
```
|
||||
@@ -246,18 +270,17 @@ OpenClaw uses a JSON5 format configuration file with the following main sections
|
||||
env: {
|
||||
ANTHROPIC_API_KEY: "sk-..."
|
||||
},
|
||||
// Agent default model configuration
|
||||
// Agent default configuration
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "provider/model"
|
||||
}
|
||||
},
|
||||
workspace: "~/.openclaw/workspace"
|
||||
}
|
||||
},
|
||||
// Tool configuration
|
||||
tools: {},
|
||||
// Workspace file configuration
|
||||
workspace: {}
|
||||
tools: {}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,7 +290,7 @@ OpenClaw uses a JSON5 format configuration file with the following main sections
|
||||
| `env` | Environment variable configuration |
|
||||
| `agents.defaults` | Agent default model settings |
|
||||
| `tools` | Tool configuration |
|
||||
| `workspace` | Workspace file management |
|
||||
| `agents.defaults.workspace` | Workspace directory path |
|
||||
|
||||
## Configuration Priority
|
||||
|
||||
|
||||
@@ -106,15 +106,15 @@ CC Switch User Manual
|
||||
|
||||
## Version Information
|
||||
|
||||
- Documentation version: v3.15.0
|
||||
- Last updated: 2026-05-16
|
||||
- Applicable to CC Switch v3.15.0+
|
||||
- Documentation version: v3.16.0
|
||||
- Last updated: 2026-05-29
|
||||
- Applicable to CC Switch v3.16.0+
|
||||
|
||||
### v3.15.0 Highlights
|
||||
### v3.16.0 Highlights
|
||||
|
||||
- **First-class Claude Desktop panel**: supports third-party providers, direct / model mapping modes, Copilot / Codex OAuth reuse, and 3P profile writing. See [2.6 Claude Desktop](./2-providers/2.6-claude-desktop.md)
|
||||
- **Role-based model mapping**: adapts Claude Desktop model validation with Sonnet / Opus / Haiku routes and `supports1m`
|
||||
- **Claude Desktop local routing**: provides a local gateway at `127.0.0.1:15721/claude-desktop` for providers that need conversion
|
||||
- **Codex Chat Completions routing**: route Chat-only providers such as DeepSeek, Kimi, GLM, and MiniMax through Codex. See [2.1 Add Provider](./2-providers/2.1-add.md)
|
||||
- **Managed CLI tool lifecycle**: install, update, update all, and diagnose Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes from Settings / About. See [1.5 Personalization](./1-getting-started/1.5-settings.md)
|
||||
- **Provider and model refresh**: new partner presets, refreshed default models and pricing, Claude Opus 4.8 defaults, and GPT 5.5 defaults where applicable
|
||||
- **Routing support badges**: Claude Code / Codex provider cards indicate whether a provider can be served through Local Routing
|
||||
- **Codex OAuth live model discovery**: ChatGPT Codex providers fetch available models from the ChatGPT backend on demand
|
||||
- **Filter-driven Usage Hero**: shows cache-normalized real total tokens and cache hit rate, updating with date / provider / model filters — see [4.4 Usage Statistics](./4-proxy/4.4-usage.md)
|
||||
@@ -124,7 +124,7 @@ CC Switch User Manual
|
||||
- **Per-App Tray Submenus**: Claude / Codex / Gemini submenus show the current provider and available usage summaries — see [2.2 Switch Provider](./2-providers/2.2-switch.md)
|
||||
- **Skills Discovery & Batch Updates**: SHA-256 update detection, batch updates, skills.sh public registry search — see [3.3 Skills Management](./3-extensions/3.3-skills.md)
|
||||
- **Full URL Endpoint Mode**: Advanced option to treat `base_url` as the full upstream endpoint — see [2.1 Add Provider](./2-providers/2.1-add.md)
|
||||
- **OpenCode / OpenClaw Stream Check Coverage**: Stream Check covers Claude / Codex / Gemini / OpenCode / OpenClaw — see [4.5 Model Test](./4-proxy/4.5-model-test.md)
|
||||
- **OpenCode / OpenClaw / Hermes Stream Check Coverage**: Stream Check covers Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes — see [4.5 Model Test](./4-proxy/4.5-model-test.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## CC Switch とは
|
||||
|
||||
CC Switch はクロスプラットフォームのデスクトップアプリケーションで、AI プログラミングツールを使用する開発者向けに設計されています。**Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw**、**Hermes** などの管理対象アプリの設定を統一的に管理できます。
|
||||
CC Switch はクロスプラットフォームのデスクトップアプリケーションで、AI ツールを使用する開発者向けに設計されています。**Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw**、**Hermes** などの管理対象アプリの設定を統一的に管理できます。
|
||||
|
||||
## どのような問題を解決するか
|
||||
|
||||
@@ -45,7 +45,7 @@ CC Switch は統一されたインターフェースでこれらの問題を解
|
||||
| **Codex** | OpenAI のコード生成ツール |
|
||||
| **Gemini CLI** | Google の AI コマンドラインツール |
|
||||
| **OpenCode** | オープンソース AI プログラミングターミナルツール |
|
||||
| **OpenClaw** | オープンソース AI プログラミングアシスタント(マルチプロバイダーゲートウェイ) |
|
||||
| **OpenClaw** | オープンソース AI アシスタント(マルチプロバイダーゲートウェイ) |
|
||||
| **Hermes** | Hermes Agent のプロバイダー、MCP、Skills、Memory 管理 |
|
||||
|
||||
## 対応プラットフォーム
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| ② | 設定ボタン | 設定ページを開く(ショートカット `Cmd/Ctrl + ,`) |
|
||||
| ③ | プロキシスイッチ | ローカルプロキシサービスの起動/停止 |
|
||||
| ④ | アプリ切り替え | Claude / Claude Desktop / Codex / Gemini / OpenCode / OpenClaw / Hermes を切り替え |
|
||||
| ⑤ | 機能エリア | Skills / Prompts / MCP の入口 |
|
||||
| ⑤ | 機能エリア | 現在のアプリで利用できる機能入口 |
|
||||
| ⑥ | 追加ボタン | 新しいプロバイダーを追加 |
|
||||
|
||||
### アプリ切り替え
|
||||
@@ -33,9 +33,9 @@
|
||||
|
||||
| ボタン | 機能 | 表示条件 |
|
||||
|------|------|----------|
|
||||
| Skills | スキル拡張管理 | 常に表示 |
|
||||
| Prompts | システムプロンプト管理 | 常に表示 |
|
||||
| MCP | MCP サーバー管理 | 常に表示 |
|
||||
| Skills | スキル拡張管理 | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
| Prompts | システムプロンプト管理 | Claude / Codex / Gemini / OpenCode |
|
||||
| MCP | MCP サーバー管理 | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
|
||||
## プロバイダーカード
|
||||
|
||||
@@ -113,11 +113,12 @@ CC Switch はシステムトレイにアイコンを表示し、クイック操
|
||||
|
||||
### 多言語対応
|
||||
|
||||
トレイメニューは 3 つの言語に対応し、設定に応じて自動的に切り替わります:
|
||||
トレイメニューは 4 つの言語に対応し、設定に応じて自動的に切り替わります:
|
||||
|
||||
| 言語 | メインウィンドウを開く | 終了 |
|
||||
|------|-----------|------|
|
||||
| 中文 | 打开主界面 | 退出 |
|
||||
| 簡体中文 | 打开主界面 | 退出 |
|
||||
| 繁體中文 | 開啟主介面 | 退出 |
|
||||
| English | Open main window | Quit |
|
||||
| 日本語 | メインウィンドウを開く | 終了 |
|
||||
|
||||
@@ -147,7 +148,7 @@ CC Switch はシステムトレイにアイコンを表示し、クイック操
|
||||
|
||||
### 一般タブ
|
||||
|
||||
- 言語設定(中文/English/日本語)
|
||||
- 言語設定(簡体中文/繁體中文/English/日本語)
|
||||
- テーマ設定(システムに合わせる/ライト/ダーク)
|
||||
- ウィンドウ動作(起動時に自動実行、閉じる動作)
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
|
||||
## 言語設定
|
||||
|
||||
CC Switch は 3 つの言語に対応しています:
|
||||
CC Switch は 4 つの言語に対応しています:
|
||||
|
||||
| 言語 | 説明 |
|
||||
| -------- | -------- |
|
||||
| 簡体中文 | デフォルト言語 |
|
||||
| 繁體中文 | 繁体字中国語インターフェース |
|
||||
| English | 英語インターフェース |
|
||||
| 日本語 | 日本語インターフェース |
|
||||
|
||||
@@ -124,8 +125,9 @@ CC Switch 自体のデータの保存場所で、デフォルトは `~/.cc-switc
|
||||
| Claude ディレクトリ | `~/.claude/` | Claude Code 設定ディレクトリ |
|
||||
| Codex ディレクトリ | `~/.codex/` | Codex 設定ディレクトリ |
|
||||
| Gemini ディレクトリ | `~/.gemini/` | Gemini CLI 設定ディレクトリ |
|
||||
| OpenCode ディレクトリ | `~/.opencode/` | OpenCode 設定ディレクトリ |
|
||||
| OpenCode ディレクトリ | `~/.config/opencode/` | OpenCode 設定ディレクトリ |
|
||||
| OpenClaw ディレクトリ | `~/.openclaw/` | OpenClaw 設定ディレクトリ |
|
||||
| Hermes ディレクトリ | `~/.hermes/` | Hermes 設定ディレクトリ |
|
||||
|
||||
> **注意**:ディレクトリを変更した後はアプリの再起動が必要で、対応する CLI ツールも同じディレクトリを設定する必要があります。
|
||||
|
||||
@@ -133,14 +135,15 @@ CC Switch 自体のデータの保存場所で、デフォルトは `~/.cc-switc
|
||||
|
||||
### 設定のエクスポート
|
||||
|
||||
「エクスポート」ボタンをクリックして、以下の内容を含むバックアップファイルを保存します:
|
||||
「エクスポート」ボタンをクリックして、以下の内容を含む SQL バックアップファイルを保存します:
|
||||
|
||||
- すべてのプロバイダー設定
|
||||
- MCP サーバー設定
|
||||
- Prompts プリセット
|
||||
- 使用量ログ
|
||||
- アプリ設定
|
||||
|
||||
バックアップファイルは JSON 形式で、テキストエディタで確認できます。
|
||||
エクスポートされるファイル名の形式は `cc-switch-export-{timestamp}.sql` です。
|
||||
|
||||
### 設定のインポート
|
||||
|
||||
|
||||
@@ -103,15 +103,16 @@ SSE プロトコルでサーバーと通信し、リアルタイムプッシュ
|
||||
| Claude | Claude Code に同期 | `~/.claude.json` の `mcpServers` |
|
||||
| Codex | Codex に同期 | `~/.codex/config.toml` の `[mcp_servers]` |
|
||||
| Gemini | Gemini CLI に同期 | `~/.gemini/settings.json` の `mcpServers` |
|
||||
| OpenCode | OpenCode に同期 | `~/.opencode/config.json` の `mcpServers` |
|
||||
| OpenCode | OpenCode に同期 | `~/.config/opencode/opencode.json` の `mcp` |
|
||||
| Hermes | Hermes に同期 | `~/.hermes/config.yaml` の `mcp_servers` |
|
||||
|
||||
> **注意**:OpenClaw は現在 MCP サーバー管理に対応していません。MCP 機能は現在 Claude、Codex、Gemini、OpenCode の 4 つのアプリのみサポートしています。
|
||||
> **注意**:OpenClaw と Claude Desktop は現在 CC Switch MCP 同期に対応していません。MCP 機能は Claude、Codex、Gemini、OpenCode、Hermes に対応しています。
|
||||
|
||||
### スイッチの動作
|
||||
|
||||
あるアプリのスイッチをオンにすると、CC Switch は以下を実行します:
|
||||
|
||||
1. **データベースの更新**:サーバーの `apps.claude/codex/gemini/opencode` のステータスを `true` に設定
|
||||
1. **データベースの更新**:サーバーの `apps.claude/codex/gemini/opencode/hermes` のステータスを `true` に設定
|
||||
2. **Live 設定に同期**:サーバー設定を対応アプリの設定ファイルに書き込み
|
||||
3. **即時反映**:次回 CLI ツール起動時に新しい MCP サーバーが自動的にロード
|
||||
|
||||
@@ -128,7 +129,8 @@ MCP サーバーの同期は、対応アプリがインストールされてい
|
||||
- **Claude**:`~/.claude/` ディレクトリまたは `~/.claude.json` ファイルが存在する必要あり
|
||||
- **Codex**:`~/.codex/` ディレクトリが存在する必要あり
|
||||
- **Gemini**:`~/.gemini/` ディレクトリが存在する必要あり
|
||||
- **OpenCode**:`~/.opencode/` ディレクトリが存在する必要あり
|
||||
- **OpenCode**:`~/.config/opencode/` ディレクトリが存在する必要あり
|
||||
- **Hermes**:`~/.hermes/` ディレクトリが存在する必要あり
|
||||
|
||||
> **ヒント**:CLI ツールがインストールされていない場合、対応するスイッチをオンにしてもエラーにはなりませんが、設定は書き込まれません。
|
||||
|
||||
@@ -154,7 +156,7 @@ MCP サーバーの同期は、対応アプリがインストールされてい
|
||||
CLI ツールで既に MCP サーバーを設定している場合、CC Switch にインポートできます:
|
||||
|
||||
1. 「インポート」ボタンをクリック
|
||||
2. インポートするアプリを選択(Claude/Codex/Gemini/OpenCode)
|
||||
2. インポートするアプリを選択(Claude/Codex/Gemini/OpenCode/Hermes)
|
||||
3. CC Switch が既存の設定を読み取ってインポート
|
||||
|
||||
## 設定ファイル形式
|
||||
|
||||
@@ -81,8 +81,7 @@ CC Switch を使用すると:
|
||||
| Claude | `~/.claude/CLAUDE.md` |
|
||||
| Codex | `~/.codex/AGENTS.md` |
|
||||
| Gemini | `~/.gemini/GEMINI.md` |
|
||||
| OpenCode | `~/.opencode/AGENTS.md` |
|
||||
| OpenClaw | `~/.openclaw/AGENTS.md` |
|
||||
| OpenCode | `~/.config/opencode/AGENTS.md` |
|
||||
|
||||
## プリセットの編集
|
||||
|
||||
@@ -141,7 +140,6 @@ Prompts はアプリごとに個別に管理されます:
|
||||
- Codex に切り替えると、Codex のプリセットが表示
|
||||
- Gemini に切り替えると、Gemini のプリセットが表示
|
||||
- OpenCode に切り替えると、OpenCode のプリセットが表示
|
||||
- OpenClaw に切り替えると、OpenClaw のプリセットが表示
|
||||
|
||||
複数のアプリで同じプロンプトを使用する場合は、それぞれで作成する必要があります。
|
||||
|
||||
|
||||
@@ -12,18 +12,17 @@ Skills は再利用可能な機能拡張で、AI ツールに特定分野の専
|
||||
|
||||
## 対応アプリ
|
||||
|
||||
Skills 機能は以下の 4 つのアプリに対応しています:
|
||||
Skills 機能は以下の 5 つのアプリに対応しています:
|
||||
|
||||
- **Claude Code**
|
||||
- **Codex**
|
||||
- **Gemini CLI**
|
||||
- **OpenCode**
|
||||
- **Hermes**
|
||||
|
||||
## Skills ページを開く
|
||||
|
||||
上部ナビゲーションバーの **Skills** ボタンをクリックします。
|
||||
|
||||
> 注意:Skills ボタンはすべてのアプリモードで表示されます。
|
||||
選択中のアプリが Skills に対応している場合、上部ナビゲーションバーの **Skills** ボタンをクリックします。
|
||||
|
||||
## ページ概要
|
||||
|
||||
@@ -93,7 +92,8 @@ CC Switch は強力な検索とフィルタリング機能を提供していま
|
||||
| Claude | `~/.claude/skills/` |
|
||||
| Codex | `~/.codex/skills/` |
|
||||
| Gemini | `~/.gemini/skills/` |
|
||||
| OpenCode | `~/.opencode/skills/` |
|
||||
| OpenCode | `~/.config/opencode/skills/` |
|
||||
| Hermes | `~/.hermes/skills/` |
|
||||
|
||||
### インストール内容
|
||||
|
||||
@@ -119,7 +119,7 @@ CC Switch は強力な検索とフィルタリング機能を提供していま
|
||||
### アンインストールの効果
|
||||
|
||||
- **自動バックアップ**:削除前にスキルが `~/.cc-switch/skill-backups/` にバックアップされる
|
||||
- すべてのアプリディレクトリ(Claude、Codex、Gemini、OpenCode)からスキルを削除
|
||||
- すべてのアプリディレクトリ(Claude、Codex、Gemini、OpenCode、Hermes)からスキルを削除
|
||||
- SSOT ディレクトリ(`~/.cc-switch/skills/`)からスキルを削除
|
||||
- データベースからスキルレコードを削除
|
||||
|
||||
|
||||
@@ -215,9 +215,11 @@ Token 使用量の変化を表示:
|
||||
|
||||
料金を照合する前に、CC Switch はリクエスト内のモデル ID を正規化します:
|
||||
|
||||
- 最後の `/` より前の接頭辞を削除
|
||||
- `:` 以降の接尾辞を削除
|
||||
- 最後の `/` より前の接頭辞を削除し、小文字に変換
|
||||
- `:` 以降の接尾辞を削除し、末尾の `[1m]` を削除
|
||||
- `@` を `-` に置換
|
||||
- 一般的なラッパー接頭辞、バージョン接尾辞、日付接尾辞(`-YYYY-MM-DD`、`-YYYYMMDD`)を削除
|
||||
- 一部のモデルファミリーでは、短い ID からバージョン付き価格エントリに照合できます
|
||||
|
||||
料金設定では、リクエスト内の完全な元のモデル名ではなく、正規化後のモデル ID を入力してください。
|
||||
|
||||
@@ -226,6 +228,10 @@ Token 使用量の変化を表示:
|
||||
| `stepfun-ai/step-3.5-flash` | `step-3.5-flash` | プロバイダー接頭辞を削除 |
|
||||
| `moonshotai/kimi-k2-0905:exa` | `kimi-k2-0905` | 接頭辞と `:` 以降を削除 |
|
||||
| `gpt-5.2-codex@low` | `gpt-5.2-codex-low` | `@` を `-` に置換 |
|
||||
| `OpenAI/GPT-5.5-2026-05-14` | `gpt-5.5` | 接頭辞と日付接尾辞を削除 |
|
||||
| `anthropic/claude-opus-4.8` | `claude-opus-4-8` | 接頭辞を削除し、ドット形式に照合 |
|
||||
| `global.anthropic.claude-opus-4-8-v1:0` | `claude-opus-4-8` | ラッパー接頭辞、バージョン接尾辞、`:` 以降を削除 |
|
||||
| `claude-haiku-4-5` | `claude-haiku-4-5-20251001` | 短い ID からバージョン付き価格に照合 |
|
||||
|
||||
### 操作
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
├── settings.json # デバイスレベルの設定
|
||||
├── skills/ # スキル SSOT ディレクトリ
|
||||
├── skill-backups/ # スキルバックアップ(アンインストール時に作成)
|
||||
└── db_backup_*.db # データベースバックアップ
|
||||
└── backups/ # データベースバックアップ
|
||||
```
|
||||
|
||||
### データベースの内容
|
||||
@@ -51,7 +51,8 @@
|
||||
"codexConfigDir": null,
|
||||
"geminiConfigDir": null,
|
||||
"opencodeConfigDir": null,
|
||||
"openclawConfigDir": null
|
||||
"openclawConfigDir": null,
|
||||
"hermesConfigDir": null
|
||||
}
|
||||
```
|
||||
|
||||
@@ -196,17 +197,41 @@ GEMINI_MODEL=gemini-pro
|
||||
|
||||
### 設定ディレクトリ
|
||||
|
||||
デフォルト:`~/.opencode/`
|
||||
デフォルト:`~/.config/opencode/`
|
||||
|
||||
### 主要ファイル
|
||||
|
||||
```
|
||||
~/.opencode/
|
||||
├── config.json # メイン設定ファイル
|
||||
~/.config/opencode/
|
||||
├── opencode.json # メイン設定ファイル
|
||||
├── AGENTS.md # システムプロンプト
|
||||
└── skills/ # スキルディレクトリ
|
||||
└── ...
|
||||
```
|
||||
## Hermes の設定
|
||||
|
||||
### 設定ディレクトリ
|
||||
|
||||
デフォルト:`~/.hermes/`
|
||||
|
||||
### 主要ファイル
|
||||
|
||||
```
|
||||
~/.hermes/
|
||||
├── config.yaml # メイン設定、プロバイダー、MCP 設定
|
||||
├── .env # API キーとシークレット
|
||||
├── SOUL.md # Profile identity/persona
|
||||
├── memories/
|
||||
│ ├── MEMORY.md # エージェント記憶
|
||||
│ └── USER.md # ユーザープロファイル記憶
|
||||
├── skills/ # 有効なスキルディレクトリ
|
||||
├── state.db # SQLite セッションデータベース
|
||||
└── sessions/ # Gateway transcript と任意の JSON snapshot
|
||||
```
|
||||
|
||||
### config.yaml
|
||||
|
||||
Hermes は YAML 設定を使用します。CC Switch は MCP サーバーを `mcp_servers` に書き込み、編集可能なプロバイダーエントリを `custom_providers` に書き込み、Hermes の `providers` dict にある読み取り専用エントリを読み取り、プロバイダー切り替え時に `model.provider` / `model.default` を更新します。
|
||||
|
||||
## OpenClaw の設定
|
||||
|
||||
@@ -219,7 +244,6 @@ GEMINI_MODEL=gemini-pro
|
||||
```
|
||||
~/.openclaw/
|
||||
├── openclaw.json # メイン設定ファイル(JSON5 形式)
|
||||
├── AGENTS.md # システムプロンプト
|
||||
└── skills/ # スキルディレクトリ
|
||||
└── ...
|
||||
```
|
||||
@@ -246,18 +270,17 @@ OpenClaw は JSON5 形式の設定ファイルを使用し、主に以下のセ
|
||||
env: {
|
||||
ANTHROPIC_API_KEY: "sk-..."
|
||||
},
|
||||
// Agent デフォルトモデル設定
|
||||
// Agent デフォルト設定
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "provider/model"
|
||||
}
|
||||
},
|
||||
workspace: "~/.openclaw/workspace"
|
||||
}
|
||||
},
|
||||
// ツール設定
|
||||
tools: {},
|
||||
// ワークスペースファイル設定
|
||||
workspace: {}
|
||||
tools: {}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,7 +290,7 @@ OpenClaw は JSON5 形式の設定ファイルを使用し、主に以下のセ
|
||||
| `env` | 環境変数設定 |
|
||||
| `agents.defaults` | Agent デフォルトモデル設定 |
|
||||
| `tools` | ツール設定 |
|
||||
| `workspace` | ワークスペースファイル管理 |
|
||||
| `agents.defaults.workspace` | ワークスペースディレクトリパス |
|
||||
|
||||
## 設定の優先順位
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ chmod +x CC-Switch-*.AppImage
|
||||
- バージョンの非互換性
|
||||
|
||||
**解決方法**:
|
||||
1. ファイルが CC Switch からエクスポートされた JSON ファイルであることを確認
|
||||
1. ファイルが CC Switch からエクスポートされた SQL バックアップファイルであることを確認
|
||||
2. ファイル内容が完全であるか確認
|
||||
3. テキストエディタで開いてフォーマットを確認
|
||||
|
||||
|
||||
@@ -106,15 +106,15 @@ CC Switch ユーザーマニュアル
|
||||
|
||||
## バージョン情報
|
||||
|
||||
- ドキュメントバージョン:v3.15.0
|
||||
- 最終更新:2026-05-16
|
||||
- CC Switch v3.15.0+ 対応
|
||||
- ドキュメントバージョン:v3.16.0
|
||||
- 最終更新:2026-05-29
|
||||
- CC Switch v3.16.0+ 対応
|
||||
|
||||
### v3.15.0 の注目機能
|
||||
### v3.16.0 の注目機能
|
||||
|
||||
- **Claude Desktop の一等管理パネル**:サードパーティプロバイダー、直結 / モデルマッピングの 2 モード、Copilot / Codex OAuth 再利用、3P profile 書き込みに対応 — 詳細は [2.6 Claude Desktop](./2-providers/2.6-claude-desktop.md)
|
||||
- **役割別モデルマッピング**:Sonnet / Opus / Haiku ルートと `supports1m` フラグで Claude Desktop のモデル検証に対応
|
||||
- **Claude Desktop ローカルルーティング**:変換が必要なプロバイダー向けに `127.0.0.1:15721/claude-desktop` のローカルゲートウェイを提供
|
||||
- **Codex Chat Completions ルーティング**:DeepSeek、Kimi、GLM、MiniMax など Chat 専用プロバイダーを Codex で利用可能 — 詳細は [2.1 プロバイダーの追加](./2-providers/2.1-add.md)
|
||||
- **管理対象 CLI ツールのライフサイクル**:設定 / About で Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes のインストール、更新、一括更新、診断に対応 — 詳細は [1.5 個人設定](./1-getting-started/1.5-settings.md)
|
||||
- **プロバイダーとモデルマトリクス更新**:提携プリセットを追加し、既定モデルと価格表を更新。Claude Opus は 4.8、該当する GPT 既定値は 5.5 に更新
|
||||
- **ルーティング対応バッジ**:Claude Code / Codex のプロバイダーカードで Local Routing 対応可否を確認可能
|
||||
- **Codex OAuth ライブモデル検出**:ChatGPT Codex 系プロバイダーは必要に応じて ChatGPT バックエンドから利用可能モデルを取得
|
||||
- **フィルター連動 Usage Hero**:キャッシュ正規化後の実消費 Token とキャッシュヒット率を表示し、日付 / プロバイダー / モデルフィルターに追従 — 詳細は [4.4 使用量統計](./4-proxy/4.4-usage.md)
|
||||
@@ -124,7 +124,7 @@ CC Switch ユーザーマニュアル
|
||||
- **アプリ別トレイサブメニュー**:Claude / Codex / Gemini のサブメニューで現在のプロバイダーと使用量サマリーを確認可能 — 詳細は [2.2 プロバイダーの切り替え](./2-providers/2.2-switch.md)
|
||||
- **Skills の発見と一括更新**:SHA-256 ハッシュによる更新検出、一括更新、skills.sh 公式レジストリ検索 — 詳細は [3.3 Skills スキル管理](./3-extensions/3.3-skills.md)
|
||||
- **完全URLエンドポイントモード**:高度なオプションで `base_url` を完全なアップストリームエンドポイントとして扱う — 詳細は [2.1 プロバイダーの追加](./2-providers/2.1-add.md)
|
||||
- **OpenCode / OpenClaw ストリームチェック対応**:Stream Check は Claude / Codex / Gemini / OpenCode / OpenClaw をカバー — 詳細は [4.5 モデルテスト](./4-proxy/4.5-model-test.md)
|
||||
- **OpenCode / OpenClaw / Hermes ストリームチェック対応**:Stream Check は Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes をカバー — 詳細は [4.5 モデルテスト](./4-proxy/4.5-model-test.md)
|
||||
|
||||
## コントリビュート
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 什么是 CC Switch
|
||||
|
||||
CC Switch 是一款跨平台桌面应用,专为使用 AI 编程工具的开发者设计。它帮助你统一管理 **Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw** 和 **Hermes** 等受管应用的配置。
|
||||
CC Switch 是一款跨平台桌面应用,专为使用 AI 工具的开发者设计。它帮助你统一管理 **Claude Code**、**Claude Desktop**、**Codex**、**Gemini CLI**、**OpenCode**、**OpenClaw** 和 **Hermes** 等受管应用的配置。
|
||||
|
||||
## 解决什么问题
|
||||
|
||||
@@ -45,7 +45,7 @@ CC Switch 通过统一的界面解决这些问题。
|
||||
| **Codex** | OpenAI 的代码生成工具 |
|
||||
| **Gemini CLI** | Google 的 AI 命令行工具 |
|
||||
| **OpenCode** | 开源 AI 编程终端工具 |
|
||||
| **OpenClaw** | 开源 AI 编程助手(多供应商网关) |
|
||||
| **OpenClaw** | 开源 AI 助手(多供应商网关) |
|
||||
| **Hermes** | Hermes Agent,支持供应商、MCP、Skills 和 Memory 管理 |
|
||||
|
||||
## 支持的平台
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| ② | 设置按钮 | 打开设置页面(快捷键 `Cmd/Ctrl + ,`) |
|
||||
| ③ | 代理开关 | 启动/停止本地代理服务 |
|
||||
| ④ | 应用切换器 | 切换 Claude / Claude Desktop / Codex / Gemini / OpenCode / OpenClaw / Hermes |
|
||||
| ⑤ | 功能区 | Skills / Prompts / MCP 入口 |
|
||||
| ⑤ | 功能区 | 当前应用支持的功能入口 |
|
||||
| ⑥ | 添加按钮 | 添加新供应商 |
|
||||
|
||||
### 应用切换器
|
||||
@@ -33,9 +33,9 @@
|
||||
|
||||
| 按钮 | 功能 | 可见条件 |
|
||||
|------|------|----------|
|
||||
| Skills | 技能扩展管理 | 始终可见 |
|
||||
| Prompts | 系统提示词管理 | 始终可见 |
|
||||
| MCP | MCP 服务器管理 | 始终可见 |
|
||||
| Skills | 技能扩展管理 | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
| Prompts | 系统提示词管理 | Claude / Codex / Gemini / OpenCode |
|
||||
| MCP | MCP 服务器管理 | Claude / Codex / Gemini / OpenCode / Hermes |
|
||||
|
||||
## 供应商卡片
|
||||
|
||||
@@ -113,11 +113,12 @@ CC Switch 在系统托盘显示图标,提供快速操作入口。
|
||||
|
||||
### 多语言支持
|
||||
|
||||
托盘菜单支持三种语言,根据设置自动切换:
|
||||
托盘菜单支持四种语言,根据设置自动切换:
|
||||
|
||||
| 语言 | 打开主界面 | 退出 |
|
||||
|------|-----------|------|
|
||||
| 中文 | 打开主界面 | 退出 |
|
||||
| 简体中文 | 打开主界面 | 退出 |
|
||||
| 繁體中文 | 開啟主介面 | 退出 |
|
||||
| English | Open main window | Quit |
|
||||
| 日本語 | メインウィンドウを開く | 終了 |
|
||||
|
||||
@@ -147,7 +148,7 @@ CC Switch 在系统托盘显示图标,提供快速操作入口。
|
||||
|
||||
### 通用 Tab
|
||||
|
||||
- 语言设置(中文/English/日本語)
|
||||
- 语言设置(简体中文/繁體中文/English/日本語)
|
||||
- 主题设置(跟随系统/浅色/深色)
|
||||
- 窗口行为(开机自启、关闭行为)
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
|
||||
## 语言设置
|
||||
|
||||
CC Switch 支持三种语言:
|
||||
CC Switch 支持四种语言:
|
||||
|
||||
| 语言 | 说明 |
|
||||
| -------- | -------- |
|
||||
| 简体中文 | 默认语言 |
|
||||
| 繁體中文 | 繁体中文界面 |
|
||||
| English | 英文界面 |
|
||||
| 日本語 | 日文界面 |
|
||||
|
||||
@@ -124,8 +125,9 @@ CC Switch 自身数据的存储位置,默认为 `~/.cc-switch/`。
|
||||
| Claude 目录 | `~/.claude/` | Claude Code 配置目录 |
|
||||
| Codex 目录 | `~/.codex/` | Codex 配置目录 |
|
||||
| Gemini 目录 | `~/.gemini/` | Gemini CLI 配置目录 |
|
||||
| OpenCode 目录 | `~/.opencode/` | OpenCode 配置目录 |
|
||||
| OpenCode 目录 | `~/.config/opencode/` | OpenCode 配置目录 |
|
||||
| OpenClaw 目录 | `~/.openclaw/` | OpenClaw 配置目录 |
|
||||
| Hermes 目录 | `~/.hermes/` | Hermes 配置目录 |
|
||||
|
||||
> ⚠️ **注意**:修改目录后需要重启应用,且对应的 CLI 工具也需要配置相同的目录。
|
||||
|
||||
@@ -133,14 +135,15 @@ CC Switch 自身数据的存储位置,默认为 `~/.cc-switch/`。
|
||||
|
||||
### 导出配置
|
||||
|
||||
点击「导出」按钮,保存包含以下内容的备份文件:
|
||||
点击「导出」按钮,保存包含以下内容的 SQL 备份文件:
|
||||
|
||||
- 所有供应商配置
|
||||
- MCP 服务器配置
|
||||
- Prompts 预设
|
||||
- 用量日志
|
||||
- 应用设置
|
||||
|
||||
备份文件格式为 JSON,可以用文本编辑器查看。
|
||||
导出文件名格式为 `cc-switch-export-{timestamp}.sql`。
|
||||
|
||||
### 导入配置
|
||||
|
||||
|
||||
@@ -103,15 +103,16 @@ MCP (Model Context Protocol) 是一种协议,允许 AI 工具访问外部数
|
||||
| Claude | 同步到 Claude Code | `~/.claude.json` 的 `mcpServers` |
|
||||
| Codex | 同步到 Codex | `~/.codex/config.toml` 的 `[mcp_servers]` |
|
||||
| Gemini | 同步到 Gemini CLI | `~/.gemini/settings.json` 的 `mcpServers` |
|
||||
| OpenCode | 同步到 OpenCode | `~/.opencode/config.json` 的 `mcpServers` |
|
||||
| OpenCode | 同步到 OpenCode | `~/.config/opencode/opencode.json` 的 `mcp` |
|
||||
| Hermes | 同步到 Hermes | `~/.hermes/config.yaml` 的 `mcp_servers` |
|
||||
|
||||
> ⚠️ **注意**:OpenClaw 暂不支持 MCP 服务器管理。MCP 功能目前仅支持 Claude、Codex、Gemini 和 OpenCode 四个应用。
|
||||
> ⚠️ **注意**:OpenClaw 和 Claude Desktop 暂不支持 CC Switch MCP 同步。MCP 功能支持 Claude、Codex、Gemini、OpenCode 和 Hermes。
|
||||
|
||||
### 开关实现机制
|
||||
|
||||
当开启某个应用的开关时,CC Switch 会:
|
||||
|
||||
1. **更新数据库**:将服务器的 `apps.claude/codex/gemini/opencode` 状态设为 `true`
|
||||
1. **更新数据库**:将服务器的 `apps.claude/codex/gemini/opencode/hermes` 状态设为 `true`
|
||||
2. **同步到 Live 配置**:将服务器配置写入对应应用的配置文件
|
||||
3. **即时生效**:下次启动 CLI 工具时自动加载新的 MCP 服务器
|
||||
|
||||
@@ -128,7 +129,8 @@ MCP 服务器同步仅在对应应用已安装时执行:
|
||||
- **Claude**:需存在 `~/.claude/` 目录或 `~/.claude.json` 文件
|
||||
- **Codex**:需存在 `~/.codex/` 目录
|
||||
- **Gemini**:需存在 `~/.gemini/` 目录
|
||||
- **OpenCode**:需存在 `~/.opencode/` 目录
|
||||
- **OpenCode**:需存在 `~/.config/opencode/` 目录
|
||||
- **Hermes**:需存在 `~/.hermes/` 目录
|
||||
|
||||
> 💡 **提示**:如果某个 CLI 工具未安装,开启对应开关不会报错,但配置不会写入。
|
||||
|
||||
@@ -154,7 +156,7 @@ MCP 服务器同步仅在对应应用已安装时执行:
|
||||
如果你已经在 CLI 工具中配置了 MCP 服务器,可以导入到 CC Switch:
|
||||
|
||||
1. 点击「导入」按钮
|
||||
2. 选择要导入的应用(Claude/Codex/Gemini/OpenCode)
|
||||
2. 选择要导入的应用(Claude/Codex/Gemini/OpenCode/Hermes)
|
||||
3. CC Switch 会读取现有配置并导入
|
||||
|
||||
## 配置文件格式
|
||||
|
||||
@@ -81,8 +81,7 @@ Prompts 功能用于管理系统提示词预设。系统提示词会影响 AI
|
||||
| Claude | `~/.claude/CLAUDE.md` |
|
||||
| Codex | `~/.codex/AGENTS.md` |
|
||||
| Gemini | `~/.gemini/GEMINI.md` |
|
||||
| OpenCode | `~/.opencode/AGENTS.md` |
|
||||
| OpenClaw | `~/.openclaw/AGENTS.md` |
|
||||
| OpenCode | `~/.config/opencode/AGENTS.md` |
|
||||
|
||||
## 编辑预设
|
||||
|
||||
@@ -141,7 +140,6 @@ Prompts 是按应用分开管理的:
|
||||
- 切换到 Codex 时,显示 Codex 的预设
|
||||
- 切换到 Gemini 时,显示 Gemini 的预设
|
||||
- 切换到 OpenCode 时,显示 OpenCode 的预设
|
||||
- 切换到 OpenClaw 时,显示 OpenClaw 的预设
|
||||
|
||||
如需在多个应用使用相同的提示词,需要分别创建。
|
||||
|
||||
|
||||
@@ -12,18 +12,17 @@ Skills 是可复用的能力扩展,让 AI 工具获得特定领域的专业能
|
||||
|
||||
## 支持的应用
|
||||
|
||||
Skills 功能支持所有四种应用:
|
||||
Skills 功能支持五种应用:
|
||||
|
||||
- **Claude Code**
|
||||
- **Codex**
|
||||
- **Gemini CLI**
|
||||
- **OpenCode**
|
||||
- **Hermes**
|
||||
|
||||
## 打开 Skills 页面
|
||||
|
||||
点击顶部导航栏的 **Skills** 按钮。
|
||||
|
||||
> 注意:Skills 按钮在所有应用模式下均可见。
|
||||
当当前应用支持 Skills 时,点击顶部导航栏的 **Skills** 按钮。
|
||||
|
||||
## 页面概览
|
||||
|
||||
@@ -93,7 +92,8 @@ CC Switch 提供强大的搜索和过滤功能:
|
||||
| Claude | `~/.claude/skills/` |
|
||||
| Codex | `~/.codex/skills/` |
|
||||
| Gemini | `~/.gemini/skills/` |
|
||||
| OpenCode | `~/.opencode/skills/` |
|
||||
| OpenCode | `~/.config/opencode/skills/` |
|
||||
| Hermes | `~/.hermes/skills/` |
|
||||
|
||||
### 安装内容
|
||||
|
||||
@@ -119,7 +119,7 @@ CC Switch 提供强大的搜索和过滤功能:
|
||||
### 卸载效果
|
||||
|
||||
- **自动备份**:删除前,技能会被备份到 `~/.cc-switch/skill-backups/`
|
||||
- 从所有应用目录(Claude、Codex、Gemini、OpenCode)移除技能
|
||||
- 从所有应用目录(Claude、Codex、Gemini、OpenCode、Hermes)移除技能
|
||||
- 从 SSOT 目录(`~/.cc-switch/skills/`)移除技能
|
||||
- 从数据库删除技能记录
|
||||
|
||||
|
||||
@@ -215,9 +215,11 @@ v3.15.0 起,用量页顶部改为筛选驱动的 Hero 卡。切换日期范围
|
||||
|
||||
在匹配定价前,CC Switch 会先对请求中的模型 ID 做标准化处理:
|
||||
|
||||
- 去掉最后一个 `/` 之前的前缀
|
||||
- 去掉 `:` 之后的后缀
|
||||
- 去掉最后一个 `/` 之前的前缀,并转成小写
|
||||
- 去掉 `:` 之后的后缀,去掉末尾的 `[1m]`
|
||||
- 将 `@` 替换为 `-`
|
||||
- 去掉常见包装前缀、版本后缀、日期后缀(`-YYYY-MM-DD`、`-YYYYMMDD`)
|
||||
- 部分模型族支持短 ID 匹配带版本的定价项
|
||||
|
||||
因此,在定价配置中请填写清洗后的模型 ID,而不是请求里的完整原始模型名。
|
||||
|
||||
@@ -226,6 +228,10 @@ v3.15.0 起,用量页顶部改为筛选驱动的 Hero 卡。切换日期范围
|
||||
| `stepfun-ai/step-3.5-flash` | `step-3.5-flash` | 去掉供应商前缀 |
|
||||
| `moonshotai/kimi-k2-0905:exa` | `kimi-k2-0905` | 去掉前缀和 `:` 后缀 |
|
||||
| `gpt-5.2-codex@low` | `gpt-5.2-codex-low` | 将 `@` 替换为 `-` |
|
||||
| `OpenAI/GPT-5.5-2026-05-14` | `gpt-5.5` | 去掉前缀和日期后缀 |
|
||||
| `anthropic/claude-opus-4.8` | `claude-opus-4-8` | 去掉前缀并匹配点号格式 |
|
||||
| `global.anthropic.claude-opus-4-8-v1:0` | `claude-opus-4-8` | 去掉包装前缀、版本后缀和 `:` 后缀 |
|
||||
| `claude-haiku-4-5` | `claude-haiku-4-5-20251001` | 短 ID 匹配带版本定价 |
|
||||
|
||||
### 操作
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
├── settings.json # 设备级设置
|
||||
├── skills/ # 技能 SSOT 目录
|
||||
├── skill-backups/ # 技能备份(卸载时创建)
|
||||
└── db_backup_*.db # 数据库备份
|
||||
└── backups/ # 数据库备份
|
||||
```
|
||||
|
||||
### 数据库内容
|
||||
@@ -51,7 +51,8 @@
|
||||
"codexConfigDir": null,
|
||||
"geminiConfigDir": null,
|
||||
"opencodeConfigDir": null,
|
||||
"openclawConfigDir": null
|
||||
"openclawConfigDir": null,
|
||||
"hermesConfigDir": null
|
||||
}
|
||||
```
|
||||
|
||||
@@ -196,17 +197,41 @@ GEMINI_MODEL=gemini-pro
|
||||
|
||||
### 配置目录
|
||||
|
||||
默认:`~/.opencode/`
|
||||
默认:`~/.config/opencode/`
|
||||
|
||||
### 主要文件
|
||||
|
||||
```
|
||||
~/.opencode/
|
||||
├── config.json # 主配置文件
|
||||
~/.config/opencode/
|
||||
├── opencode.json # 主配置文件
|
||||
├── AGENTS.md # 系统提示词
|
||||
└── skills/ # 技能目录
|
||||
└── ...
|
||||
```
|
||||
## Hermes 配置
|
||||
|
||||
### 配置目录
|
||||
|
||||
默认:`~/.hermes/`
|
||||
|
||||
### 主要文件
|
||||
|
||||
```
|
||||
~/.hermes/
|
||||
├── config.yaml # 主设置、供应商与 MCP 配置
|
||||
├── .env # API keys 与 secrets
|
||||
├── SOUL.md # Profile 身份/人格
|
||||
├── memories/
|
||||
│ ├── MEMORY.md # Agent 记忆
|
||||
│ └── USER.md # 用户画像记忆
|
||||
├── skills/ # 活跃技能目录
|
||||
├── state.db # SQLite 会话数据库
|
||||
└── sessions/ # Gateway 转录与可选 JSON 快照
|
||||
```
|
||||
|
||||
### config.yaml
|
||||
|
||||
Hermes 使用 YAML 配置。CC Switch 将 MCP 服务器写入 `mcp_servers`,将可编辑的供应商条目写入 `custom_providers`,读取 Hermes `providers` 字典中的只读条目,并在切换供应商时更新 `model.provider` / `model.default`。
|
||||
|
||||
## OpenClaw 配置
|
||||
|
||||
@@ -219,7 +244,6 @@ GEMINI_MODEL=gemini-pro
|
||||
```
|
||||
~/.openclaw/
|
||||
├── openclaw.json # 主配置文件(JSON5 格式)
|
||||
├── AGENTS.md # 系统提示词
|
||||
└── skills/ # 技能目录
|
||||
└── ...
|
||||
```
|
||||
@@ -246,18 +270,17 @@ OpenClaw 使用 JSON5 格式配置文件,主要包含以下部分:
|
||||
env: {
|
||||
ANTHROPIC_API_KEY: "sk-..."
|
||||
},
|
||||
// Agent 默认模型配置
|
||||
// Agent 默认配置
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "provider/model"
|
||||
}
|
||||
},
|
||||
workspace: "~/.openclaw/workspace"
|
||||
}
|
||||
},
|
||||
// 工具配置
|
||||
tools: {},
|
||||
// 工作区文件配置
|
||||
workspace: {}
|
||||
tools: {}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,7 +290,7 @@ OpenClaw 使用 JSON5 格式配置文件,主要包含以下部分:
|
||||
| `env` | 环境变量配置 |
|
||||
| `agents.defaults` | Agent 默认模型设置 |
|
||||
| `tools` | 工具配置 |
|
||||
| `workspace` | 工作区文件管理 |
|
||||
| `agents.defaults.workspace` | 工作区目录路径 |
|
||||
|
||||
## 配置优先级
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ chmod +x CC-Switch-*.AppImage
|
||||
- 版本不兼容
|
||||
|
||||
**解决方法**:
|
||||
1. 确认文件是 CC Switch 导出的 JSON 文件
|
||||
1. 确认文件是 CC Switch 导出的 SQL 备份文件
|
||||
2. 检查文件内容是否完整
|
||||
3. 尝试用文本编辑器打开检查格式
|
||||
|
||||
|
||||
@@ -106,15 +106,15 @@
|
||||
|
||||
## 版本信息
|
||||
|
||||
- 文档版本:v3.15.0
|
||||
- 最后更新:2026-05-16
|
||||
- 适用于 CC Switch v3.15.0+
|
||||
- 文档版本:v3.16.0
|
||||
- 最后更新:2026-05-29
|
||||
- 适用于 CC Switch v3.16.0+
|
||||
|
||||
### v3.15.0 亮点
|
||||
### v3.16.0 亮点
|
||||
|
||||
- **Claude Desktop 一等管理面板**:支持第三方供应商、直连 / 模型映射两种模式、Copilot / Codex OAuth 复用与 3P profile 写入 — 详见 [2.6 Claude Desktop](./2-providers/2.6-claude-desktop.md)
|
||||
- **按角色的模型映射**:用 Sonnet / Opus / Haiku 路由和 `supports1m` 标志适配 Claude Desktop 的模型校验
|
||||
- **Claude Desktop 本地路由**:通过 `127.0.0.1:15721/claude-desktop` 为需要转换的供应商提供本地网关
|
||||
- **Codex Chat Completions 路由**:DeepSeek、Kimi、GLM、MiniMax 等仅支持 Chat 协议的供应商可通过 Codex 使用 — 详见 [2.1 添加供应商](./2-providers/2.1-add.md)
|
||||
- **托管 CLI 工具生命周期**:在设置 / 关于页安装、升级、全部升级并诊断 Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes — 详见 [1.5 个性化配置](./1-getting-started/1.5-settings.md)
|
||||
- **供应商与模型矩阵刷新**:新增合作方预设,刷新默认模型与计费矩阵,Claude Opus 默认升级到 4.8,适用场景下 GPT 默认升级到 5.5
|
||||
- **路由支持徽章**:Claude Code / Codex 供应商卡片会标明是否支持 Local Routing,便于选择可代理的供应商
|
||||
- **Codex OAuth 实时模型发现**:ChatGPT Codex 类供应商按需从 ChatGPT 后端拉取最新模型列表
|
||||
- **用量看板筛选驱动 Hero**:展示缓存归一化后的真实总 token 与缓存命中率,并跟随日期 / 供应商 / 模型筛选实时更新 — 详见 [4.4 用量统计](./4-proxy/4.4-usage.md)
|
||||
@@ -124,7 +124,7 @@
|
||||
- **托盘按应用分级菜单**:Claude / Codex / Gemini 独立子菜单,标题展示当前供应商与可用用量摘要 — 详见 [2.2 切换供应商](./2-providers/2.2-switch.md)
|
||||
- **Skills 发现与批量更新**:SHA-256 更新检测、批量更新、skills.sh 公共注册表搜索 — 详见 [3.3 Skills 技能管理](./3-extensions/3.3-skills.md)
|
||||
- **完整 URL 端点模式**:高级选项支持将 base_url 视作完整上游端点 — 详见 [2.1 添加供应商](./2-providers/2.1-add.md)
|
||||
- **OpenCode / OpenClaw 流式检测覆盖**:Stream Check 面板覆盖 Claude / Codex / Gemini / OpenCode / OpenClaw — 详见 [4.5 模型检查](./4-proxy/4.5-model-test.md)
|
||||
- **OpenCode / OpenClaw / Hermes 流式检测覆盖**:Stream Check 面板覆盖 Claude / Codex / Gemini / OpenCode / OpenClaw / Hermes — 详见 [4.5 模型检查](./4-proxy/4.5-model-test.md)
|
||||
|
||||
## 贡献
|
||||
|
||||
|
||||
+114
-11
@@ -682,20 +682,18 @@ fn set_codex_model_catalog_json_field(
|
||||
let mut doc = config_text
|
||||
.parse::<DocumentMut>()
|
||||
.map_err(|e| AppError::Message(format!("Invalid Codex config.toml: {e}")))?;
|
||||
let generated_path = get_codex_model_catalog_path();
|
||||
|
||||
match catalog_path {
|
||||
Some(path) => {
|
||||
doc["model_catalog_json"] = toml_edit::value(path.to_string_lossy().as_ref());
|
||||
Some(_) => {
|
||||
doc["model_catalog_json"] = toml_edit::value(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME);
|
||||
}
|
||||
None => {
|
||||
let should_remove = doc
|
||||
.get("model_catalog_json")
|
||||
.and_then(|item| item.as_str())
|
||||
.map(|path| {
|
||||
path == generated_path.to_string_lossy().as_ref()
|
||||
|| Path::new(path).file_name().and_then(|name| name.to_str())
|
||||
== Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME)
|
||||
Path::new(path).file_name().and_then(|name| name.to_str())
|
||||
== Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME)
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if should_remove {
|
||||
@@ -780,9 +778,8 @@ fn resolve_cc_switch_catalog_path(config_text: &str, generated_path: &Path) -> O
|
||||
.filter(|s| !s.is_empty())?;
|
||||
|
||||
let referenced_path = Path::new(catalog_path_str);
|
||||
let is_cc_switch_owned = catalog_path_str == generated_path.to_string_lossy().as_ref()
|
||||
|| referenced_path.file_name().and_then(|name| name.to_str())
|
||||
== Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME);
|
||||
let is_cc_switch_owned = referenced_path.file_name().and_then(|name| name.to_str())
|
||||
== Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME);
|
||||
if !is_cc_switch_owned {
|
||||
return None;
|
||||
}
|
||||
@@ -1791,7 +1788,7 @@ base_url = "https://production.api/v1"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_catalog_json_field_operates_on_top_level() {
|
||||
fn model_catalog_json_field_writes_relative_filename() {
|
||||
let input = r#"model_provider = "any"
|
||||
|
||||
[model_providers.any]
|
||||
@@ -1805,7 +1802,7 @@ name = "any"
|
||||
parsed
|
||||
.get("model_catalog_json")
|
||||
.and_then(|value| value.as_str()),
|
||||
Some("/tmp/cc-switch-model-catalog.json")
|
||||
Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME)
|
||||
);
|
||||
assert!(
|
||||
parsed
|
||||
@@ -2026,4 +2023,110 @@ name = "any"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn set_catalog_json_field_writes_filename_ignoring_unc_path() {
|
||||
let input = r#"model_provider = "custom"
|
||||
model = "glm-5"
|
||||
"#;
|
||||
// Simulate a WSL UNC path as cc-switch would see it on Windows;
|
||||
// the function now writes just the relative filename.
|
||||
let unc_path =
|
||||
Path::new(r"\\wsl.localhost\Ubuntu\home\user\.codex\cc-switch-model-catalog.json");
|
||||
|
||||
let result = set_codex_model_catalog_json_field(input, Some(unc_path)).unwrap();
|
||||
let parsed: toml::Value = toml::from_str(&result).unwrap();
|
||||
|
||||
let written_path = parsed
|
||||
.get("model_catalog_json")
|
||||
.and_then(|v| v.as_str())
|
||||
.expect("model_catalog_json should be set");
|
||||
assert_eq!(
|
||||
written_path, CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME,
|
||||
"should write only the relative filename, not the UNC path"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_catalog_json_field_writes_filename_for_any_path() {
|
||||
let input = r#"model_provider = "custom"
|
||||
model = "glm-5"
|
||||
"#;
|
||||
let regular_path = Path::new("/home/user/.codex/cc-switch-model-catalog.json");
|
||||
|
||||
let result = set_codex_model_catalog_json_field(input, Some(regular_path)).unwrap();
|
||||
let parsed: toml::Value = toml::from_str(&result).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
parsed.get("model_catalog_json").and_then(|v| v.as_str()),
|
||||
Some(CC_SWITCH_CODEX_MODEL_CATALOG_FILENAME),
|
||||
"should write only the relative filename, not the full path"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_catalog_json_none_removes_cc_switch_owned_by_filename() {
|
||||
// After the WSL fix, TOML may contain a Linux-style path.
|
||||
// The None arm must still remove it (file_name match catches any format).
|
||||
let input = r#"model_catalog_json = "/home/user/.codex/cc-switch-model-catalog.json"
|
||||
"#;
|
||||
let result = set_codex_model_catalog_json_field(input, None).unwrap();
|
||||
let parsed: toml::Value = toml::from_str(&result).unwrap();
|
||||
assert!(
|
||||
parsed.get("model_catalog_json").is_none(),
|
||||
"None arm should remove cc-switch-owned field regardless of path format"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_catalog_json_none_preserves_user_owned_catalog() {
|
||||
let input = r#"model_catalog_json = "/Users/me/.codex/my-custom-catalog.json"
|
||||
"#;
|
||||
let result = set_codex_model_catalog_json_field(input, None).unwrap();
|
||||
let parsed: toml::Value = toml::from_str(&result).unwrap();
|
||||
assert_eq!(
|
||||
parsed.get("model_catalog_json").and_then(|v| v.as_str()),
|
||||
Some("/Users/me/.codex/my-custom-catalog.json"),
|
||||
"None arm should NOT remove user-owned catalog"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_catalog_finds_relative_filename() {
|
||||
let config_text = r#"model_provider = "custom"
|
||||
model_catalog_json = "cc-switch-model-catalog.json"
|
||||
"#;
|
||||
let generated_path = PathBuf::from("/home/user/.codex/cc-switch-model-catalog.json");
|
||||
let result = resolve_cc_switch_catalog_path(config_text, &generated_path);
|
||||
assert_eq!(
|
||||
result,
|
||||
Some(generated_path),
|
||||
"relative filename should resolve to generated_path for file I/O"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_catalog_ignores_user_owned_relative() {
|
||||
let config_text = r#"model_catalog_json = "my-custom-catalog.json"
|
||||
"#;
|
||||
let generated_path = PathBuf::from("/home/user/.codex/cc-switch-model-catalog.json");
|
||||
let result = resolve_cc_switch_catalog_path(config_text, &generated_path);
|
||||
assert_eq!(
|
||||
result, None,
|
||||
"user-owned catalog should not be claimed by cc-switch"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_catalog_json_none_removes_relative_path() {
|
||||
let input = r#"model_catalog_json = "cc-switch-model-catalog.json"
|
||||
"#;
|
||||
let result = set_codex_model_catalog_json_field(input, None).unwrap();
|
||||
let parsed: toml::Value = toml::from_str(&result).unwrap();
|
||||
assert!(
|
||||
parsed.get("model_catalog_json").is_none(),
|
||||
"None arm should remove relative cc-switch-owned field"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +417,42 @@ fn resolve_native_credentials(app_type: &AppType, provider: Option<&Provider>) -
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn resolve_coding_plan_credentials(
|
||||
app_type: &AppType,
|
||||
provider: Option<&Provider>,
|
||||
usage_script: Option<&crate::provider::UsageScript>,
|
||||
) -> (String, String) {
|
||||
let is_zenmux = usage_script
|
||||
.and_then(|s| s.coding_plan_provider.as_deref())
|
||||
.map(|provider| provider.eq_ignore_ascii_case("zenmux"))
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_zenmux {
|
||||
return resolve_native_credentials(app_type, provider);
|
||||
}
|
||||
|
||||
let script_base_url = usage_script
|
||||
.and_then(|s| s.base_url.as_deref())
|
||||
.unwrap_or("")
|
||||
.trim_end_matches('/')
|
||||
.to_string();
|
||||
let script_api_key = usage_script
|
||||
.and_then(|s| s.api_key.as_deref())
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
|
||||
if !script_base_url.is_empty() && !script_api_key.is_empty() {
|
||||
return (script_base_url, script_api_key);
|
||||
}
|
||||
|
||||
let native = resolve_native_credentials(app_type, provider);
|
||||
if !native.0.is_empty() && !native.1.is_empty() {
|
||||
native
|
||||
} else {
|
||||
(script_base_url, script_api_key)
|
||||
}
|
||||
}
|
||||
|
||||
async fn query_provider_usage_inner(
|
||||
state: &AppState,
|
||||
copilot_state: &CopilotAuthState,
|
||||
@@ -474,8 +510,8 @@ async fn query_provider_usage_inner(
|
||||
|
||||
// ── Coding Plan 专用路径 ──
|
||||
if template_type == TEMPLATE_TYPE_TOKEN_PLAN {
|
||||
// 从供应商配置中提取 API Key 和 Base URL(按 app 区分存储格式)
|
||||
let (base_url, api_key) = resolve_native_credentials(&app_type, provider);
|
||||
let (base_url, api_key) =
|
||||
resolve_coding_plan_credentials(&app_type, provider, usage_script);
|
||||
|
||||
let quota = crate::services::coding_plan::get_coding_plan_quota(&base_url, &api_key)
|
||||
.await
|
||||
@@ -490,6 +526,19 @@ async fn query_provider_usage_inner(
|
||||
});
|
||||
}
|
||||
|
||||
// ZenMux 的 tier 携带 USD 额度信息,需要编码为 JSON extra
|
||||
let has_usd = quota
|
||||
.tiers
|
||||
.first()
|
||||
.map(|t| t.used_value_usd.is_some())
|
||||
.unwrap_or(false);
|
||||
let plan_label = quota
|
||||
.credential_message
|
||||
.as_deref()
|
||||
.and_then(|msg| msg.split(' ').next())
|
||||
.map(|tier| format!("ZenMux·{}", tier.to_uppercase()));
|
||||
let mut first_tier = true;
|
||||
|
||||
let data: Vec<crate::provider::UsageData> = quota
|
||||
.tiers
|
||||
.iter()
|
||||
@@ -497,6 +546,26 @@ async fn query_provider_usage_inner(
|
||||
let total = 100.0;
|
||||
let used = tier.utilization;
|
||||
let remaining = total - used;
|
||||
let extra = if has_usd {
|
||||
let mut extra_json = serde_json::json!({
|
||||
"resetsAt": tier.resets_at,
|
||||
});
|
||||
if let Some(v) = tier.used_value_usd {
|
||||
extra_json["usedValueUsd"] = serde_json::json!(v);
|
||||
}
|
||||
if let Some(v) = tier.max_value_usd {
|
||||
extra_json["maxValueUsd"] = serde_json::json!(v);
|
||||
}
|
||||
if first_tier {
|
||||
if let Some(ref label) = plan_label {
|
||||
extra_json["planLabel"] = serde_json::json!(label);
|
||||
}
|
||||
first_tier = false;
|
||||
}
|
||||
Some(extra_json.to_string())
|
||||
} else {
|
||||
tier.resets_at.clone()
|
||||
};
|
||||
crate::provider::UsageData {
|
||||
plan_name: Some(tier.name.clone()),
|
||||
remaining: Some(remaining),
|
||||
@@ -505,7 +574,7 @@ async fn query_provider_usage_inner(
|
||||
unit: Some("%".to_string()),
|
||||
is_valid: Some(true),
|
||||
invalid_message: None,
|
||||
extra: tier.resets_at.clone(),
|
||||
extra,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -950,11 +1019,31 @@ mod import_claude_desktop_tests {
|
||||
|
||||
#[cfg(test)]
|
||||
mod native_query_credentials_tests {
|
||||
use super::resolve_native_credentials;
|
||||
use super::{resolve_coding_plan_credentials, resolve_native_credentials};
|
||||
use crate::app_config::AppType;
|
||||
use crate::provider::Provider;
|
||||
use crate::provider::{Provider, UsageScript};
|
||||
use serde_json::json;
|
||||
|
||||
fn usage_script(
|
||||
coding_plan_provider: Option<&str>,
|
||||
base_url: Option<&str>,
|
||||
api_key: Option<&str>,
|
||||
) -> UsageScript {
|
||||
UsageScript {
|
||||
enabled: true,
|
||||
language: "javascript".to_string(),
|
||||
code: String::new(),
|
||||
timeout: Some(10),
|
||||
api_key: api_key.map(str::to_string),
|
||||
base_url: base_url.map(str::to_string),
|
||||
access_token: None,
|
||||
user_id: None,
|
||||
template_type: Some("token_plan".to_string()),
|
||||
auto_query_interval: None,
|
||||
coding_plan_provider: coding_plan_provider.map(str::to_string),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delegates_to_provider_for_codex() {
|
||||
let provider = Provider::with_id(
|
||||
@@ -979,4 +1068,52 @@ mod native_query_credentials_tests {
|
||||
assert!(base_url.is_empty());
|
||||
assert!(api_key.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zenmux_coding_plan_uses_script_credentials_first() {
|
||||
let provider = Provider::with_id(
|
||||
"test".to_string(),
|
||||
"Test".to_string(),
|
||||
json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://provider.zenmux.example/v1",
|
||||
"ANTHROPIC_AUTH_TOKEN": "sk-provider"
|
||||
}
|
||||
}),
|
||||
None,
|
||||
);
|
||||
let script = usage_script(
|
||||
Some("zenmux"),
|
||||
Some("https://script.zenmux.example/api/usage/"),
|
||||
Some("sk-script"),
|
||||
);
|
||||
|
||||
let (base_url, api_key) =
|
||||
resolve_coding_plan_credentials(&AppType::Claude, Some(&provider), Some(&script));
|
||||
|
||||
assert_eq!(base_url, "https://script.zenmux.example/api/usage");
|
||||
assert_eq!(api_key, "sk-script");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zenmux_coding_plan_falls_back_to_provider_credentials() {
|
||||
let provider = Provider::with_id(
|
||||
"test".to_string(),
|
||||
"Test".to_string(),
|
||||
json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://provider.zenmux.example/v1",
|
||||
"ANTHROPIC_AUTH_TOKEN": "sk-provider"
|
||||
}
|
||||
}),
|
||||
None,
|
||||
);
|
||||
let script = usage_script(Some("zenmux"), Some("https://script.zenmux.example"), None);
|
||||
|
||||
let (base_url, api_key) =
|
||||
resolve_coding_plan_credentials(&AppType::Claude, Some(&provider), Some(&script));
|
||||
|
||||
assert_eq!(base_url, "https://provider.zenmux.example/v1");
|
||||
assert_eq!(api_key, "sk-provider");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,6 +1744,7 @@ impl Database {
|
||||
"0.06",
|
||||
"0.375",
|
||||
),
|
||||
("minimax-m3", "MiniMax M3", "0.60", "2.40", "0.12", "0"),
|
||||
// GLM (智谱)
|
||||
("glm-4.7", "GLM-4.7", "0.39", "1.75", "0.04", "0"),
|
||||
("glm-4.6", "GLM-4.6", "0.28", "1.11", "0.03", "0"),
|
||||
|
||||
@@ -9,7 +9,51 @@ use super::DeepLinkImportRequest;
|
||||
use crate::AppType;
|
||||
use crate::{store::AppState, Database};
|
||||
use base64::prelude::*;
|
||||
use std::sync::Arc;
|
||||
use std::{env, ffi::OsString, sync::Arc};
|
||||
|
||||
struct TestHomeGuard {
|
||||
_dir: tempfile::TempDir,
|
||||
original_home: Option<OsString>,
|
||||
original_userprofile: Option<OsString>,
|
||||
original_test_home: Option<OsString>,
|
||||
}
|
||||
|
||||
impl TestHomeGuard {
|
||||
fn new() -> Self {
|
||||
let dir = tempfile::tempdir().expect("create isolated test home");
|
||||
let original_home = env::var_os("HOME");
|
||||
let original_userprofile = env::var_os("USERPROFILE");
|
||||
let original_test_home = env::var_os("CC_SWITCH_TEST_HOME");
|
||||
|
||||
env::set_var("HOME", dir.path());
|
||||
env::set_var("USERPROFILE", dir.path());
|
||||
env::set_var("CC_SWITCH_TEST_HOME", dir.path());
|
||||
|
||||
Self {
|
||||
_dir: dir,
|
||||
original_home,
|
||||
original_userprofile,
|
||||
original_test_home,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestHomeGuard {
|
||||
fn drop(&mut self) {
|
||||
match &self.original_test_home {
|
||||
Some(value) => env::set_var("CC_SWITCH_TEST_HOME", value),
|
||||
None => env::remove_var("CC_SWITCH_TEST_HOME"),
|
||||
}
|
||||
match &self.original_userprofile {
|
||||
Some(value) => env::set_var("USERPROFILE", value),
|
||||
None => env::remove_var("USERPROFILE"),
|
||||
}
|
||||
match &self.original_home {
|
||||
Some(value) => env::set_var("HOME", value),
|
||||
None => env::remove_var("HOME"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Parser Tests
|
||||
@@ -477,8 +521,12 @@ fn test_build_claude_provider_without_config_unchanged() {
|
||||
// Prompt Tests
|
||||
// =============================================================================
|
||||
|
||||
// Integration-style unit test: prompt import reaches PromptService and resolves
|
||||
// live config file paths, so HOME must be isolated before it runs.
|
||||
#[test]
|
||||
#[serial_test::serial]
|
||||
fn test_import_prompt_allows_space_in_base64_content() {
|
||||
let _test_home = TestHomeGuard::new();
|
||||
let url = "ccswitch://v1/import?resource=prompt&app=codex&name=PromptPlus&content=Pj4+";
|
||||
let request = parse_deeplink_url(url).unwrap();
|
||||
|
||||
|
||||
@@ -801,7 +801,8 @@ impl ChatToResponsesState {
|
||||
json!({
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"total_tokens": 0
|
||||
"total_tokens": 0,
|
||||
"output_tokens_details": { "reasoning_tokens": 0 }
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1507,7 +1507,8 @@ pub(crate) fn chat_usage_to_responses_usage(usage: Option<&Value>) -> Value {
|
||||
return json!({
|
||||
"input_tokens": 0,
|
||||
"output_tokens": 0,
|
||||
"total_tokens": 0
|
||||
"total_tokens": 0,
|
||||
"output_tokens_details": { "reasoning_tokens": 0 }
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1540,8 +1541,17 @@ pub(crate) fn chat_usage_to_responses_usage(usage: Option<&Value>) -> Value {
|
||||
result["input_tokens_details"] = json!({ "cached_tokens": cached });
|
||||
}
|
||||
|
||||
if let Some(details) = usage.get("completion_tokens_details") {
|
||||
result["output_tokens_details"] = details.clone();
|
||||
if let Some(details) = usage
|
||||
.get("completion_tokens_details")
|
||||
.filter(|v| v.is_object())
|
||||
{
|
||||
let mut details = details.clone();
|
||||
if details.get("reasoning_tokens").is_none() {
|
||||
details["reasoning_tokens"] = json!(0);
|
||||
}
|
||||
result["output_tokens_details"] = details;
|
||||
} else {
|
||||
result["output_tokens_details"] = json!({ "reasoning_tokens": 0 });
|
||||
}
|
||||
|
||||
if let Some(cache_read) = usage.get("cache_read_input_tokens") {
|
||||
|
||||
@@ -16,6 +16,7 @@ enum CodingPlanProvider {
|
||||
ZhipuEn,
|
||||
MiniMaxCn,
|
||||
MiniMaxEn,
|
||||
ZenMux,
|
||||
}
|
||||
|
||||
fn detect_provider(base_url: &str) -> Option<CodingPlanProvider> {
|
||||
@@ -30,6 +31,8 @@ fn detect_provider(base_url: &str) -> Option<CodingPlanProvider> {
|
||||
Some(CodingPlanProvider::MiniMaxCn)
|
||||
} else if url.contains("api.minimax.io") {
|
||||
Some(CodingPlanProvider::MiniMaxEn)
|
||||
} else if url.contains("zenmux") {
|
||||
Some(CodingPlanProvider::ZenMux)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -145,6 +148,8 @@ async fn query_kimi(api_key: &str) -> SubscriptionQuota {
|
||||
name: "five_hour".to_string(),
|
||||
utilization,
|
||||
resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -166,6 +171,8 @@ async fn query_kimi(api_key: &str) -> SubscriptionQuota {
|
||||
name: "weekly_limit".to_string(),
|
||||
utilization,
|
||||
resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -225,6 +232,8 @@ fn parse_zhipu_token_tiers(data: &serde_json::Value) -> Vec<QuotaTier> {
|
||||
name: name.to_string(),
|
||||
utilization: percentage,
|
||||
resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -370,50 +379,8 @@ async fn query_minimax(api_key: &str, is_cn: bool) -> SubscriptionQuota {
|
||||
}
|
||||
}
|
||||
|
||||
let mut tiers = Vec::new();
|
||||
|
||||
if let Some(model_remains) = body.get("model_remains").and_then(|v| v.as_array()) {
|
||||
// 只取第一个模型(MiniMax-M*,主力编程模型)
|
||||
if let Some(item) = model_remains.first() {
|
||||
// usage_count 是剩余量(满额=total,用完=0),需反转为已用百分比
|
||||
let interval_total = item
|
||||
.get("current_interval_total_count")
|
||||
.and_then(|v| v.as_f64())
|
||||
.unwrap_or(0.0);
|
||||
let interval_remaining = item
|
||||
.get("current_interval_usage_count")
|
||||
.and_then(|v| v.as_f64())
|
||||
.unwrap_or(0.0);
|
||||
let end_time = item.get("end_time").and_then(|v| v.as_i64());
|
||||
|
||||
if interval_total > 0.0 {
|
||||
tiers.push(QuotaTier {
|
||||
name: "five_hour".to_string(),
|
||||
utilization: ((interval_total - interval_remaining) / interval_total) * 100.0,
|
||||
resets_at: end_time.and_then(millis_to_iso8601),
|
||||
});
|
||||
}
|
||||
|
||||
// 周额度
|
||||
let weekly_total = item
|
||||
.get("current_weekly_total_count")
|
||||
.and_then(|v| v.as_f64())
|
||||
.unwrap_or(0.0);
|
||||
let weekly_remaining = item
|
||||
.get("current_weekly_usage_count")
|
||||
.and_then(|v| v.as_f64())
|
||||
.unwrap_or(0.0);
|
||||
let weekly_end = item.get("weekly_end_time").and_then(|v| v.as_i64());
|
||||
|
||||
if weekly_total > 0.0 {
|
||||
tiers.push(QuotaTier {
|
||||
name: "weekly_limit".to_string(),
|
||||
utilization: ((weekly_total - weekly_remaining) / weekly_total) * 100.0,
|
||||
resets_at: weekly_end.and_then(millis_to_iso8601),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 提取纯函数便于无 mock 单元测试;新接口直接给"剩余百分比",反转为已用百分比
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
|
||||
SubscriptionQuota {
|
||||
tool: "coding_plan".to_string(),
|
||||
@@ -427,6 +394,204 @@ async fn query_minimax(api_key: &str, is_cn: bool) -> SubscriptionQuota {
|
||||
}
|
||||
}
|
||||
|
||||
// ── ZenMux ──────────────────────────────────────────────────
|
||||
|
||||
async fn query_zenmux(base_url: &str, api_key: &str) -> SubscriptionQuota {
|
||||
let client = crate::proxy::http_client::get();
|
||||
|
||||
let resp = client
|
||||
.get(base_url)
|
||||
.header("Authorization", format!("Bearer {api_key}"))
|
||||
.header("Accept", "application/json")
|
||||
.timeout(std::time::Duration::from_secs(10))
|
||||
.send()
|
||||
.await;
|
||||
|
||||
let resp = match resp {
|
||||
Ok(r) => r,
|
||||
Err(e) => return make_error(format!("Network error: {e}")),
|
||||
};
|
||||
|
||||
let status = resp.status();
|
||||
if status == reqwest::StatusCode::UNAUTHORIZED || status == reqwest::StatusCode::FORBIDDEN {
|
||||
return SubscriptionQuota {
|
||||
tool: "coding_plan".to_string(),
|
||||
credential_status: CredentialStatus::Expired,
|
||||
credential_message: Some("Invalid API key".to_string()),
|
||||
success: false,
|
||||
tiers: vec![],
|
||||
extra_usage: None,
|
||||
error: Some(format!("Authentication failed (HTTP {status})")),
|
||||
queried_at: Some(now_millis()),
|
||||
};
|
||||
}
|
||||
|
||||
if !status.is_success() {
|
||||
let body = resp.text().await.unwrap_or_default();
|
||||
return make_error(format!("API error (HTTP {status}): {body}"));
|
||||
}
|
||||
|
||||
let body: serde_json::Value = match resp.json().await {
|
||||
Ok(v) => v,
|
||||
Err(e) => return make_error(format!("Failed to parse response: {e}")),
|
||||
};
|
||||
|
||||
// 检查业务级别错误
|
||||
if body.get("success").and_then(|v| v.as_bool()) != Some(true) {
|
||||
let msg = body
|
||||
.get("message")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("Unknown error");
|
||||
return make_error(format!("API error: {msg}"));
|
||||
}
|
||||
|
||||
let data = match body.get("data") {
|
||||
Some(d) => d,
|
||||
None => return make_error("Missing 'data' field in response".to_string()),
|
||||
};
|
||||
|
||||
let mut tiers = Vec::new();
|
||||
|
||||
// 5 小时窗口限额
|
||||
if let Some(q5h) = data.get("quota_5_hour") {
|
||||
let usage_pct = q5h
|
||||
.get("usage_percentage")
|
||||
.and_then(parse_f64)
|
||||
.unwrap_or(0.0);
|
||||
let resets_at = q5h
|
||||
.get("resets_at")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(String::from);
|
||||
let used_usd = q5h.get("used_value_usd").and_then(parse_f64);
|
||||
let max_usd = q5h.get("max_value_usd").and_then(parse_f64);
|
||||
tiers.push(QuotaTier {
|
||||
name: "five_hour".to_string(),
|
||||
utilization: usage_pct * 100.0,
|
||||
resets_at,
|
||||
used_value_usd: used_usd,
|
||||
max_value_usd: max_usd,
|
||||
});
|
||||
}
|
||||
|
||||
// 7 天窗口限额
|
||||
if let Some(q7d) = data.get("quota_7_day") {
|
||||
let usage_pct = q7d
|
||||
.get("usage_percentage")
|
||||
.and_then(parse_f64)
|
||||
.unwrap_or(0.0);
|
||||
let resets_at = q7d
|
||||
.get("resets_at")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(String::from);
|
||||
let used_usd = q7d.get("used_value_usd").and_then(parse_f64);
|
||||
let max_usd = q7d.get("max_value_usd").and_then(parse_f64);
|
||||
tiers.push(QuotaTier {
|
||||
name: "weekly_limit".to_string(),
|
||||
utilization: usage_pct * 100.0,
|
||||
resets_at,
|
||||
used_value_usd: used_usd,
|
||||
max_value_usd: max_usd,
|
||||
});
|
||||
}
|
||||
|
||||
// 套餐等级和账户状态存入 credential_message
|
||||
let plan_tier = data
|
||||
.get("plan")
|
||||
.and_then(|p| p.get("tier"))
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
let account_status = data
|
||||
.get("account_status")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
let plan_info = if !plan_tier.is_empty() {
|
||||
format!("{plan_tier} ({account_status})")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
SubscriptionQuota {
|
||||
tool: "coding_plan".to_string(),
|
||||
credential_status: CredentialStatus::Valid,
|
||||
credential_message: if plan_info.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(plan_info)
|
||||
},
|
||||
success: true,
|
||||
tiers,
|
||||
extra_usage: None,
|
||||
error: None,
|
||||
queried_at: Some(now_millis()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 从 `/coding_plan/remains` 响应中解析 MiniMax 编程套餐的额度 tier。
|
||||
///
|
||||
/// 新接口语义:`current_*_remaining_percent` 是"剩余百分比"(0-100),
|
||||
/// `model_remains` 数组里有 `general`(编程套餐)和 `video` 等其他模型,
|
||||
/// 这里只取 `general`,跳过 video。
|
||||
///
|
||||
/// 5h 桶始终存在;周桶并非所有套餐都有,靠 `current_weekly_status == 1`
|
||||
/// 判定激活(无周限额套餐该字段为 3,`remaining_percent` 恒为 100,不应展示)。
|
||||
fn parse_minimax_tiers(body: &serde_json::Value) -> Vec<QuotaTier> {
|
||||
let mut tiers = Vec::new();
|
||||
|
||||
let Some(model_remains) = body.get("model_remains").and_then(|v| v.as_array()) else {
|
||||
return tiers;
|
||||
};
|
||||
|
||||
// 只取 model_name == "general" 的条目,跳过 video 等非编程模型
|
||||
let Some(item) = model_remains.iter().find(|item| {
|
||||
item.get("model_name")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s == "general")
|
||||
.unwrap_or(false)
|
||||
}) else {
|
||||
return tiers;
|
||||
};
|
||||
|
||||
// 5h 桶:剩余百分比 → 已用百分比
|
||||
if let Some(remain_pct) = item
|
||||
.get("current_interval_remaining_percent")
|
||||
.and_then(|v| v.as_f64())
|
||||
{
|
||||
let resets_at = item
|
||||
.get("end_time")
|
||||
.and_then(|v| v.as_i64())
|
||||
.and_then(millis_to_iso8601);
|
||||
tiers.push(QuotaTier {
|
||||
name: TIER_FIVE_HOUR.to_string(),
|
||||
utilization: 100.0 - remain_pct,
|
||||
resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
|
||||
// 周桶:仅当 status=1 时激活;status=3 等表示该套餐无周限额,跳过
|
||||
if item.get("current_weekly_status").and_then(|v| v.as_i64()) == Some(1) {
|
||||
if let Some(remain_pct) = item
|
||||
.get("current_weekly_remaining_percent")
|
||||
.and_then(|v| v.as_f64())
|
||||
{
|
||||
let resets_at = item
|
||||
.get("weekly_end_time")
|
||||
.and_then(|v| v.as_i64())
|
||||
.and_then(millis_to_iso8601);
|
||||
tiers.push(QuotaTier {
|
||||
name: TIER_WEEKLY_LIMIT.to_string(),
|
||||
utilization: 100.0 - remain_pct,
|
||||
resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tiers
|
||||
}
|
||||
|
||||
// ── 公开入口 ────────────────────────────────────────────────
|
||||
|
||||
pub async fn get_coding_plan_quota(
|
||||
@@ -467,6 +632,7 @@ pub async fn get_coding_plan_quota(
|
||||
CodingPlanProvider::ZhipuCn | CodingPlanProvider::ZhipuEn => query_zhipu(api_key).await,
|
||||
CodingPlanProvider::MiniMaxCn => query_minimax(api_key, true).await,
|
||||
CodingPlanProvider::MiniMaxEn => query_minimax(api_key, false).await,
|
||||
CodingPlanProvider::ZenMux => query_zenmux(base_url, api_key).await,
|
||||
};
|
||||
|
||||
Ok(quota)
|
||||
@@ -474,7 +640,7 @@ pub async fn get_coding_plan_quota(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{parse_zhipu_token_tiers, TIER_FIVE_HOUR, TIER_WEEKLY_LIMIT};
|
||||
use super::{parse_minimax_tiers, parse_zhipu_token_tiers, TIER_FIVE_HOUR, TIER_WEEKLY_LIMIT};
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
@@ -604,4 +770,174 @@ mod tests {
|
||||
assert_eq!(tiers[0].name, TIER_FIVE_HOUR);
|
||||
assert_eq!(tiers[1].name, TIER_WEEKLY_LIMIT);
|
||||
}
|
||||
|
||||
// ── MiniMax ──
|
||||
|
||||
#[test]
|
||||
fn minimax_general_two_tiers_from_remaining_percent() {
|
||||
// 主路径:general 桶 5h 剩 98% / weekly 剩 95% → 已用 2% / 5%
|
||||
let body = json!({
|
||||
"model_remains": [
|
||||
{
|
||||
"model_name": "general",
|
||||
"current_interval_remaining_percent": 98.0,
|
||||
"current_weekly_remaining_percent": 95.0,
|
||||
"current_interval_status": 1,
|
||||
"current_weekly_status": 1,
|
||||
"end_time": 1_780_329_600_000_i64,
|
||||
"weekly_end_time": 1_780_848_000_000_i64
|
||||
},
|
||||
{
|
||||
"model_name": "video",
|
||||
"current_interval_remaining_percent": 100.0,
|
||||
"current_weekly_remaining_percent": 100.0
|
||||
}
|
||||
],
|
||||
"base_resp": { "status_code": 0, "status_msg": "success" }
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 2);
|
||||
assert_eq!(tiers[0].name, TIER_FIVE_HOUR);
|
||||
assert_eq!(tiers[0].utilization, 2.0);
|
||||
assert!(tiers[0].resets_at.is_some());
|
||||
assert_eq!(tiers[1].name, TIER_WEEKLY_LIMIT);
|
||||
assert_eq!(tiers[1].utilization, 5.0);
|
||||
assert!(tiers[1].resets_at.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_skips_video_and_finds_general_in_any_position() {
|
||||
// 防御性:即使 video 排在数组前面,general 排在后面,仍应被定位到。
|
||||
let body = json!({
|
||||
"model_remains": [
|
||||
{
|
||||
"model_name": "video",
|
||||
"current_interval_remaining_percent": 50.0,
|
||||
"current_weekly_remaining_percent": 50.0
|
||||
},
|
||||
{
|
||||
"model_name": "general",
|
||||
"current_interval_remaining_percent": 80.0,
|
||||
"current_weekly_remaining_percent": 70.0,
|
||||
"current_interval_status": 1,
|
||||
"current_weekly_status": 1
|
||||
}
|
||||
]
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 2);
|
||||
// 取的是 general 桶,不是 video(20%/30% 而非 50%/50%)
|
||||
assert_eq!(tiers[0].utilization, 20.0);
|
||||
assert_eq!(tiers[1].utilization, 30.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_missing_general_returns_empty() {
|
||||
// model_remains 只有 video / 空 / 缺字段 → 不应崩溃,tiers 为空
|
||||
let body = json!({
|
||||
"model_remains": [
|
||||
{
|
||||
"model_name": "video",
|
||||
"current_interval_remaining_percent": 100.0,
|
||||
"current_weekly_remaining_percent": 100.0
|
||||
}
|
||||
]
|
||||
});
|
||||
assert!(parse_minimax_tiers(&body).is_empty());
|
||||
|
||||
let body_empty: serde_json::Value = json!({ "model_remains": [] });
|
||||
assert!(parse_minimax_tiers(&body_empty).is_empty());
|
||||
|
||||
let body_no_field = json!({});
|
||||
assert!(parse_minimax_tiers(&body_no_field).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_missing_percent_fields_skips_tier() {
|
||||
// 字段缺失时只跳过对应桶,另一边仍能展示
|
||||
let body = json!({
|
||||
"model_remains": [{
|
||||
"model_name": "general",
|
||||
"current_interval_remaining_percent": 60.0,
|
||||
"current_weekly_status": 1
|
||||
// 缺 current_weekly_remaining_percent
|
||||
}]
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 1);
|
||||
assert_eq!(tiers[0].name, TIER_FIVE_HOUR);
|
||||
assert_eq!(tiers[0].utilization, 40.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_negative_percent_passes_through() {
|
||||
// 防御性:与 parse_zhipu_token_tiers 约定一致,负数 / 超 100 不做范围裁剪
|
||||
let body = json!({
|
||||
"model_remains": [{
|
||||
"model_name": "general",
|
||||
"current_interval_remaining_percent": -5.0,
|
||||
"current_weekly_remaining_percent": 150.0,
|
||||
"current_interval_status": 1,
|
||||
"current_weekly_status": 1
|
||||
}]
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 2);
|
||||
assert_eq!(tiers[0].utilization, 105.0); // 100 - (-5)
|
||||
assert_eq!(tiers[1].utilization, -50.0); // 100 - 150
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_weekly_status_3_skips_weekly_tier() {
|
||||
// 无周限额套餐:current_weekly_status=3,remaining_percent 恒为 100,
|
||||
// 不应推 weekly_limit tier(否则会显示"0% 已用"的假周桶)
|
||||
let body = json!({
|
||||
"model_remains": [
|
||||
{
|
||||
"model_name": "general",
|
||||
"start_time": 1_780_347_600_000_i64,
|
||||
"end_time": 1_780_365_600_000_i64,
|
||||
"remains_time": 4_161_372_i64,
|
||||
"current_interval_remaining_percent": 99,
|
||||
"current_interval_status": 1,
|
||||
"current_weekly_total_count": 0,
|
||||
"current_weekly_usage_count": 0,
|
||||
"weekly_start_time": 1_780_243_200_000_i64,
|
||||
"weekly_end_time": 1_780_848_000_000_i64,
|
||||
"weekly_remains_time": 486_561_372_i64,
|
||||
"current_weekly_status": 3,
|
||||
"current_weekly_remaining_percent": 100
|
||||
},
|
||||
{
|
||||
"model_name": "video",
|
||||
"current_interval_remaining_percent": 100,
|
||||
"current_weekly_status": 3,
|
||||
"current_weekly_remaining_percent": 100
|
||||
}
|
||||
],
|
||||
"base_resp": { "status_code": 0, "status_msg": "success" }
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 1);
|
||||
assert_eq!(tiers[0].name, TIER_FIVE_HOUR);
|
||||
assert_eq!(tiers[0].utilization, 1.0);
|
||||
assert!(tiers[0].resets_at.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimax_weekly_status_2_also_skips_weekly_tier() {
|
||||
// 防御性:除 1 之外的 status 都视为周桶未激活,跳过
|
||||
let body = json!({
|
||||
"model_remains": [{
|
||||
"model_name": "general",
|
||||
"current_interval_remaining_percent": 80.0,
|
||||
"current_weekly_remaining_percent": 50.0,
|
||||
"current_weekly_status": 2
|
||||
}]
|
||||
});
|
||||
let tiers = parse_minimax_tiers(&body);
|
||||
assert_eq!(tiers.len(), 1);
|
||||
assert_eq!(tiers[0].name, TIER_FIVE_HOUR);
|
||||
assert_eq!(tiers[0].utilization, 20.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,9 +121,10 @@ pub async fn fetch_models(
|
||||
///
|
||||
/// 候选顺序:
|
||||
/// 1. `models_url_override` 非空 → 只返回它
|
||||
/// 2. baseURL 直接拼 `/v1/models`(若已有 `/v1` 结尾则拼 `/models`)
|
||||
/// 3. 若 baseURL 命中 [`KNOWN_COMPAT_SUFFIXES`],剥离后缀再拼 `/v1/models`
|
||||
/// 4. 同上,但拼 `/models`(部分站点如 DeepSeek 官方只暴露 `/models`)
|
||||
/// 2. baseURL 拼 `/v1/models`;若已以版本段 `/v{N}` 结尾(`/v1`、智谱
|
||||
/// `/api/coding/paas/v4` 等),版本号已在路径里,改拼 `/models`
|
||||
/// 3. 版本段非 `/v1`(如 `/v4`)时再追加 `/v1/models` 作为兜底次候选
|
||||
/// 4. 若 baseURL 命中 [`KNOWN_COMPAT_SUFFIXES`],剥离后缀再拼 `/v1/models`、`/models`
|
||||
///
|
||||
/// 结果已去重且保持首次出现顺序。
|
||||
pub fn build_models_url_candidates(
|
||||
@@ -160,12 +161,18 @@ pub fn build_models_url_candidates(
|
||||
return Ok(candidates);
|
||||
}
|
||||
|
||||
let primary = if trimmed.ends_with("/v1") {
|
||||
format!("{trimmed}/models")
|
||||
// baseURL 已以版本段 /v{N} 结尾时(如 `/v1`、智谱 `/api/coding/paas/v4`),
|
||||
// OpenAI 惯例的模型端点是 `{base}/models`,不能再补 `/v1`
|
||||
// (否则 .../coding/paas/v4/v1/models → 404)。
|
||||
if ends_with_version_segment(trimmed) {
|
||||
candidates.push(format!("{trimmed}/models"));
|
||||
// 版本段非 /v1 时,保留旧的 /v1/models 作为兜底次候选(正确路径已在前)。
|
||||
if !trimmed.ends_with("/v1") {
|
||||
candidates.push(format!("{trimmed}/v1/models"));
|
||||
}
|
||||
} else {
|
||||
format!("{trimmed}/v1/models")
|
||||
};
|
||||
candidates.push(primary);
|
||||
candidates.push(format!("{trimmed}/v1/models"));
|
||||
}
|
||||
|
||||
if let Some(stripped) = strip_compat_suffix(trimmed) {
|
||||
let root = stripped.trim_end_matches('/');
|
||||
@@ -210,6 +217,15 @@ fn strip_compat_suffix(base_url: &str) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
/// 判断 baseURL 是否以 OpenAI 风格的版本段 `/v{N}` 结尾(`N` 为一个或多个数字),
|
||||
/// 例如 `/v1`、`.../paas/v4`。这类 URL 版本号已在路径中,模型端点应为
|
||||
/// `{base}/models`,不能再补 `/v1`(智谱 Coding Plan 即 `.../coding/paas/v4`)。
|
||||
fn ends_with_version_segment(url: &str) -> bool {
|
||||
let last = url.rsplit('/').next().unwrap_or("");
|
||||
last.strip_prefix('v')
|
||||
.is_some_and(|digits| !digits.is_empty() && digits.bytes().all(|b| b.is_ascii_digit()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -232,6 +248,48 @@ mod tests {
|
||||
assert_eq!(c, vec!["https://api.example.com/v1/models"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_candidates_zhipu_coding_paas_v4() {
|
||||
// 智谱 Coding Plan 端点以 /v4 版本段结尾:模型端点是 {base}/models,
|
||||
// 正确路径必须排在 .../v4/v1/models(404)之前。
|
||||
let c =
|
||||
build_models_url_candidates("https://open.bigmodel.cn/api/coding/paas/v4", false, None)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
c,
|
||||
vec![
|
||||
"https://open.bigmodel.cn/api/coding/paas/v4/models",
|
||||
"https://open.bigmodel.cn/api/coding/paas/v4/v1/models",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_candidates_zai_coding_paas_v4() {
|
||||
let c = build_models_url_candidates("https://api.z.ai/api/coding/paas/v4", false, None)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
c,
|
||||
vec![
|
||||
"https://api.z.ai/api/coding/paas/v4/models",
|
||||
"https://api.z.ai/api/coding/paas/v4/v1/models",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ends_with_version_segment() {
|
||||
assert!(ends_with_version_segment("https://x.com/v1"));
|
||||
assert!(ends_with_version_segment(
|
||||
"https://open.bigmodel.cn/api/coding/paas/v4"
|
||||
));
|
||||
assert!(ends_with_version_segment("https://x.com/v10"));
|
||||
assert!(!ends_with_version_segment("https://x.com/api"));
|
||||
assert!(!ends_with_version_segment("https://x.com/vX"));
|
||||
assert!(!ends_with_version_segment("https://x.com/models"));
|
||||
assert!(!ends_with_version_segment("https://api.siliconflow.cn"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_candidates_full_url() {
|
||||
let c = build_models_url_candidates(
|
||||
|
||||
@@ -32,6 +32,12 @@ pub struct QuotaTier {
|
||||
pub utilization: f64,
|
||||
/// ISO 8601 重置时间
|
||||
pub resets_at: Option<String>,
|
||||
/// ZenMux: 已用额度(USD)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub used_value_usd: Option<f64>,
|
||||
/// ZenMux: 窗口上限(USD)
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub max_value_usd: Option<f64>,
|
||||
}
|
||||
|
||||
/// 超额使用信息
|
||||
@@ -377,6 +383,8 @@ async fn query_claude_quota(access_token: &str) -> SubscriptionQuota {
|
||||
name: tier_name.to_string(),
|
||||
utilization: util,
|
||||
resets_at: w.resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -395,6 +403,8 @@ async fn query_claude_quota(access_token: &str) -> SubscriptionQuota {
|
||||
name: key.clone(),
|
||||
utilization: util,
|
||||
resets_at: w.resets_at,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -714,6 +724,8 @@ pub(crate) async fn query_codex_quota(
|
||||
.unwrap_or_else(|| "unknown".to_string()),
|
||||
utilization: used,
|
||||
resets_at: window.reset_at.and_then(unix_ts_to_iso),
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1179,6 +1191,8 @@ async fn query_gemini_quota(access_token: &str) -> SubscriptionQuota {
|
||||
name,
|
||||
utilization: (1.0 - remaining) * 100.0,
|
||||
resets_at: reset_time,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@@ -902,6 +902,8 @@ mod tests {
|
||||
name: name.to_string(),
|
||||
utilization,
|
||||
resets_at: None,
|
||||
used_value_usd: None,
|
||||
max_value_usd: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -309,6 +309,8 @@ export const TierBadge: React.FC<{
|
||||
: tier.name;
|
||||
const countdown = countdownStr(tier.resetsAt);
|
||||
|
||||
const hasUsd = tier.usedValueUsd != null && tier.maxValueUsd != null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-0.5">
|
||||
<span className="text-gray-500 dark:text-gray-400">{label}:</span>
|
||||
@@ -317,6 +319,11 @@ export const TierBadge: React.FC<{
|
||||
>
|
||||
{t("subscription.utilization", { value: Math.round(tier.utilization) })}
|
||||
</span>
|
||||
{hasUsd && (
|
||||
<span className="text-muted-foreground/60">
|
||||
(${tier.usedValueUsd!.toFixed(2)}/${tier.maxValueUsd!.toFixed(2)})
|
||||
</span>
|
||||
)}
|
||||
{countdown && (
|
||||
<span className="text-muted-foreground/60 ml-0.5 flex items-center gap-px">
|
||||
<Clock size={10} />
|
||||
|
||||
@@ -19,10 +19,26 @@ interface UsageFooterProps {
|
||||
|
||||
/** UsageData → QuotaTier 转换(Token Plan 使用) */
|
||||
function toQuotaTier(data: UsageData): QuotaTier {
|
||||
const extra = data.extra;
|
||||
if (extra && extra.startsWith("{")) {
|
||||
try {
|
||||
const parsed = JSON.parse(extra);
|
||||
return {
|
||||
name: data.planName || "",
|
||||
utilization: data.used || 0,
|
||||
resetsAt: parsed.resetsAt || null,
|
||||
usedValueUsd: parsed.usedValueUsd ?? null,
|
||||
maxValueUsd: parsed.maxValueUsd ?? null,
|
||||
planLabel: parsed.planLabel ?? null,
|
||||
};
|
||||
} catch {
|
||||
// fall through to plain string
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: data.planName || "",
|
||||
utilization: data.used || 0,
|
||||
resetsAt: data.extra || null,
|
||||
resetsAt: extra || null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -147,9 +163,22 @@ const UsageFooter: React.FC<UsageFooterProps> = ({
|
||||
</div>
|
||||
{/* 第二行:tier 徽章(复用官方订阅的 TierBadge) */}
|
||||
<div className="flex items-center gap-2">
|
||||
{usageDataList.map((data, index) => (
|
||||
<TierBadge key={index} tier={toQuotaTier(data)} t={t} />
|
||||
))}
|
||||
{(() => {
|
||||
const tiers = usageDataList.map((d) => toQuotaTier(d));
|
||||
const planLabel = tiers[0]?.planLabel;
|
||||
return (
|
||||
<>
|
||||
{planLabel && (
|
||||
<span className="font-semibold text-muted-foreground">
|
||||
💰 {planLabel}
|
||||
</span>
|
||||
)}
|
||||
{tiers.map((tier, index) => (
|
||||
<TierBadge key={index} tier={tier} t={t} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -444,8 +444,14 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
|
||||
// Coding Plan 模板使用专用 API
|
||||
if (selectedTemplate === TEMPLATE_TYPES.TOKEN_PLAN) {
|
||||
const baseUrl = providerCredentials.baseUrl ?? "";
|
||||
const apiKey = providerCredentials.apiKey ?? "";
|
||||
// ZenMux 使用用户在脚本配置中手动填入的 API Key 和 Base URL
|
||||
const isZenMux = script.codingPlanProvider === "zenmux";
|
||||
const baseUrl = isZenMux
|
||||
? (script.baseUrl ?? "")
|
||||
: (providerCredentials.baseUrl ?? "");
|
||||
const apiKey = isZenMux
|
||||
? (script.apiKey ?? "")
|
||||
: (providerCredentials.apiKey ?? "");
|
||||
const { subscriptionApi } = await import("@/lib/api/subscription");
|
||||
const quota = await subscriptionApi.getCodingPlanQuota(baseUrl, apiKey);
|
||||
if (quota.success && quota.tiers.length > 0) {
|
||||
@@ -626,15 +632,17 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
const autoDetected = detectCodingPlanProvider(
|
||||
providerCredentials.baseUrl,
|
||||
);
|
||||
const provider = script.codingPlanProvider || autoDetected || "kimi";
|
||||
// ZenMux 允许手动填写 API Key 和 Base URL,不清除
|
||||
const isZenMux = provider === "zenmux";
|
||||
setScript({
|
||||
...script,
|
||||
code: "",
|
||||
apiKey: undefined,
|
||||
baseUrl: undefined,
|
||||
apiKey: isZenMux ? script.apiKey : undefined,
|
||||
baseUrl: isZenMux ? script.baseUrl : undefined,
|
||||
accessToken: undefined,
|
||||
userId: undefined,
|
||||
codingPlanProvider:
|
||||
script.codingPlanProvider || autoDetected || "kimi",
|
||||
codingPlanProvider: provider,
|
||||
});
|
||||
} else if (presetName === TEMPLATE_TYPES.BALANCE) {
|
||||
// 官方余额查询模板不需要脚本,使用 Rust 原生查询
|
||||
@@ -653,7 +661,9 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
|
||||
const shouldShowCredentialsConfig =
|
||||
selectedTemplate === TEMPLATE_TYPES.GENERAL ||
|
||||
selectedTemplate === TEMPLATE_TYPES.NEW_API;
|
||||
selectedTemplate === TEMPLATE_TYPES.NEW_API ||
|
||||
(selectedTemplate === TEMPLATE_TYPES.TOKEN_PLAN &&
|
||||
script.codingPlanProvider === "zenmux");
|
||||
|
||||
const footer = (
|
||||
<>
|
||||
@@ -1050,6 +1060,66 @@ const UsageScriptModal: React.FC<UsageScriptModalProps> = ({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedTemplate === TEMPLATE_TYPES.TOKEN_PLAN &&
|
||||
script.codingPlanProvider === "zenmux" && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="usage-zenmux-base-url">
|
||||
{t("usageScript.baseUrl")}
|
||||
</Label>
|
||||
<Input
|
||||
id="usage-zenmux-base-url"
|
||||
type="text"
|
||||
value={script.baseUrl || ""}
|
||||
onChange={(e) =>
|
||||
setScript({ ...script, baseUrl: e.target.value })
|
||||
}
|
||||
placeholder="https://api.zenmux.com/v1/..."
|
||||
autoComplete="off"
|
||||
className="border-white/10"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="usage-zenmux-api-key">API Key</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
id="usage-zenmux-api-key"
|
||||
type={showApiKey ? "text" : "password"}
|
||||
value={script.apiKey || ""}
|
||||
onChange={(e) =>
|
||||
setScript({
|
||||
...script,
|
||||
apiKey: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="sk-..."
|
||||
autoComplete="off"
|
||||
className="border-white/10"
|
||||
/>
|
||||
{script.apiKey && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowApiKey(!showApiKey)}
|
||||
className="absolute inset-y-0 right-0 flex items-center pr-3 text-muted-foreground hover:text-foreground transition-colors"
|
||||
aria-label={
|
||||
showApiKey
|
||||
? t("apiKeyInput.hide")
|
||||
: t("apiKeyInput.show")
|
||||
}
|
||||
>
|
||||
{showApiKey ? (
|
||||
<EyeOff size={16} />
|
||||
) : (
|
||||
<Eye size={16} />
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -286,10 +286,10 @@ requires_openai_auth = true`,
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"zhipu_glm",
|
||||
"https://open.bigmodel.cn/api/paas/v4",
|
||||
"https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
"glm-5.1",
|
||||
),
|
||||
endpointCandidates: ["https://open.bigmodel.cn/api/paas/v4"],
|
||||
endpointCandidates: ["https://open.bigmodel.cn/api/coding/paas/v4"],
|
||||
apiFormat: "openai_chat",
|
||||
modelCatalog: modelCatalog([
|
||||
{ model: "glm-5.1", displayName: "GLM-5.1", contextWindow: 200000 },
|
||||
@@ -312,10 +312,10 @@ requires_openai_auth = true`,
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"zhipu_glm_en",
|
||||
"https://api.z.ai/api/paas/v4",
|
||||
"https://api.z.ai/api/coding/paas/v4",
|
||||
"glm-5.1",
|
||||
),
|
||||
endpointCandidates: ["https://api.z.ai/api/paas/v4"],
|
||||
endpointCandidates: ["https://api.z.ai/api/coding/paas/v4"],
|
||||
apiFormat: "openai_chat",
|
||||
modelCatalog: modelCatalog([
|
||||
{ model: "glm-5.1", displayName: "GLM-5.1", contextWindow: 200000 },
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TEMPLATE_TYPES } from "@/config/constants";
|
||||
|
||||
export interface CodingPlanProviderEntry {
|
||||
/** 与后端 QuotaTier 的 `codingPlanProvider` 取值对齐 */
|
||||
id: "kimi" | "zhipu" | "minimax";
|
||||
id: "kimi" | "zhipu" | "minimax" | "zenmux";
|
||||
/** UsageScriptModal 下拉显示用 */
|
||||
label: string;
|
||||
/** base_url 匹配规则 */
|
||||
@@ -30,6 +30,11 @@ export const CODING_PLAN_PROVIDERS: readonly CodingPlanProviderEntry[] = [
|
||||
label: "MiniMax",
|
||||
pattern: /api\.minimaxi?\.com|api\.minimax\.io/i,
|
||||
},
|
||||
{
|
||||
id: "zenmux",
|
||||
label: "ZenMux",
|
||||
pattern: /zenmux\./i,
|
||||
},
|
||||
] as const;
|
||||
|
||||
/** 根据 Base URL 自动检测 Coding Plan 供应商;未命中返回 null */
|
||||
|
||||
@@ -393,7 +393,7 @@ export const hermesProviderPresets: HermesProviderPreset[] = [
|
||||
apiKeyUrl: "https://www.bigmodel.cn/claude-code?ic=RRVJPB5SII",
|
||||
settingsConfig: {
|
||||
name: "zhipu_glm",
|
||||
base_url: "https://open.bigmodel.cn/api/paas/v4",
|
||||
base_url: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
api_key: "",
|
||||
api_mode: "chat_completions",
|
||||
models: [{ id: "glm-5.1", name: "GLM-5.1" }],
|
||||
@@ -411,7 +411,7 @@ export const hermesProviderPresets: HermesProviderPreset[] = [
|
||||
apiKeyUrl: "https://z.ai/subscribe?ic=8JVLJQFSKB",
|
||||
settingsConfig: {
|
||||
name: "zhipu_glm_en",
|
||||
base_url: "https://api.z.ai/api/paas/v4",
|
||||
base_url: "https://api.z.ai/api/coding/paas/v4",
|
||||
api_key: "",
|
||||
api_mode: "chat_completions",
|
||||
models: [{ id: "glm-5.1", name: "GLM-5.1" }],
|
||||
|
||||
@@ -306,7 +306,7 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
websiteUrl: "https://open.bigmodel.cn",
|
||||
apiKeyUrl: "https://www.bigmodel.cn/claude-code?ic=RRVJPB5SII",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
||||
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
apiKey: "",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
@@ -324,8 +324,8 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
templateValues: {
|
||||
baseUrl: {
|
||||
label: "Base URL",
|
||||
placeholder: "https://open.bigmodel.cn/api/paas/v4",
|
||||
defaultValue: "https://open.bigmodel.cn/api/paas/v4",
|
||||
placeholder: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
defaultValue: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
editorValue: "",
|
||||
},
|
||||
apiKey: {
|
||||
@@ -344,7 +344,7 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
websiteUrl: "https://z.ai",
|
||||
apiKeyUrl: "https://z.ai/subscribe?ic=8JVLJQFSKB",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://api.z.ai/v1",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
apiKey: "",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
@@ -362,8 +362,8 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
templateValues: {
|
||||
baseUrl: {
|
||||
label: "Base URL",
|
||||
placeholder: "https://api.z.ai/v1",
|
||||
defaultValue: "https://api.z.ai/v1",
|
||||
placeholder: "https://api.z.ai/api/coding/paas/v4",
|
||||
defaultValue: "https://api.z.ai/api/coding/paas/v4",
|
||||
editorValue: "",
|
||||
},
|
||||
apiKey: {
|
||||
|
||||
@@ -442,7 +442,7 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
name: "Zhipu GLM",
|
||||
options: {
|
||||
baseURL: "https://open.bigmodel.cn/api/paas/v4",
|
||||
baseURL: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
@@ -456,8 +456,8 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
templateValues: {
|
||||
baseURL: {
|
||||
label: "Base URL",
|
||||
placeholder: "https://open.bigmodel.cn/api/paas/v4",
|
||||
defaultValue: "https://open.bigmodel.cn/api/paas/v4",
|
||||
placeholder: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
defaultValue: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
editorValue: "",
|
||||
},
|
||||
apiKey: {
|
||||
@@ -475,7 +475,7 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
name: "Zhipu GLM en",
|
||||
options: {
|
||||
baseURL: "https://api.z.ai/v1",
|
||||
baseURL: "https://api.z.ai/api/coding/paas/v4",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
@@ -489,8 +489,8 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
templateValues: {
|
||||
baseURL: {
|
||||
label: "Base URL",
|
||||
placeholder: "https://api.z.ai/v1",
|
||||
defaultValue: "https://api.z.ai/v1",
|
||||
placeholder: "https://api.z.ai/api/coding/paas/v4",
|
||||
defaultValue: "https://api.z.ai/api/coding/paas/v4",
|
||||
editorValue: "",
|
||||
},
|
||||
apiKey: {
|
||||
|
||||
@@ -559,7 +559,7 @@
|
||||
"useAppWindowControls": "啟用應用程式等級視窗按鈕",
|
||||
"useAppWindowControlsDescription": "開啟後使用應用程式自建的最小化、最大化/還原、關閉按鈕;關閉後沿用系統視窗模式。",
|
||||
"enableClaudePluginIntegration": "套用至 Claude Code 外掛程式",
|
||||
"enableClaudePluginIntegrationDescription": "開啟後 Vscode Claude Code 外掛程式的供應商將隨本軟體切換",
|
||||
"enableClaudePluginIntegrationDescription": "開啟後 VS Code Claude Code 外掛程式的供應商將隨本軟體切換",
|
||||
"skipClaudeOnboarding": "跳過 Claude Code 初次安裝確認",
|
||||
"skipClaudeOnboardingDescription": "開啟後跳過 Claude Code 初次安裝確認",
|
||||
"codexAuth": "Codex 應用增強",
|
||||
|
||||
@@ -559,7 +559,7 @@
|
||||
"useAppWindowControls": "启用应用级窗口按钮",
|
||||
"useAppWindowControlsDescription": "开启后使用应用自建的最小化、最大化/还原、关闭按钮;关闭后沿用系统窗口模式。",
|
||||
"enableClaudePluginIntegration": "应用到 Claude Code 插件",
|
||||
"enableClaudePluginIntegrationDescription": "开启后 Vscode Claude Code 插件的供应商将随本软件切换",
|
||||
"enableClaudePluginIntegrationDescription": "开启后 VS Code Claude Code 插件的供应商将随本软件切换",
|
||||
"skipClaudeOnboarding": "跳过 Claude Code 初次安装确认",
|
||||
"skipClaudeOnboardingDescription": "开启后跳过 Claude Code 初次安装确认",
|
||||
"codexAuth": "Codex 应用增强",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -306,6 +306,13 @@ export const iconMetadata: Record<string, IconMetadata> = {
|
||||
keywords: ["minimax"],
|
||||
defaultColor: "#FF6B6B",
|
||||
},
|
||||
zenmux: {
|
||||
name: "zenmux",
|
||||
displayName: "ZenMux",
|
||||
category: "ai-provider",
|
||||
keywords: ["zenmux", "zen", "mux"],
|
||||
defaultColor: "#6366F1",
|
||||
},
|
||||
mistral: {
|
||||
name: "mistral",
|
||||
displayName: "Mistral",
|
||||
|
||||
@@ -8,6 +8,9 @@ export interface QuotaTier {
|
||||
name: string;
|
||||
utilization: number; // 0-100
|
||||
resetsAt: string | null;
|
||||
usedValueUsd?: number | null;
|
||||
maxValueUsd?: number | null;
|
||||
planLabel?: string | null;
|
||||
}
|
||||
|
||||
export interface ExtraUsage {
|
||||
|
||||
@@ -44,14 +44,14 @@ const expectedChatPresets = new Map<
|
||||
[
|
||||
"Zhipu GLM",
|
||||
{
|
||||
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
||||
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
|
||||
contextWindows: { "glm-5.1": 200000 },
|
||||
},
|
||||
],
|
||||
[
|
||||
"Zhipu GLM en",
|
||||
{
|
||||
baseUrl: "https://api.z.ai/api/paas/v4",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
contextWindows: { "glm-5.1": 200000 },
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user