Skip to content
dsh.fish
Bundle

dsh-ccswitch-sync

Sync CC Switch (cc-switch) providers and models into DeepSeek Harness custom providers (llm-pi-ai)

Source
yu969774
License
MIT
Updated
Updated 2 days ago

Readme

# dsh-ccswitch-sync

把 **CC Switch**(`cc-switch`,Claude Code / Codex 的 API 配置切换器)里配置的服务商/模型,同步成 DeepSeek Harness(DSH)的**自定义提供方**(设置 → 模型 → 添加自定义提供方),并把 API 密钥一并写入凭据库。

- 读取 `~/.cc-switch/cc-switch.db`(SQLite),无需 CC Switch 处于运行状态。
- 每个非官方服务商映射为一条 `llm-pi-ai` 自定义路由(默认前缀 `cc-`),例如 `cc-sub2api`、`cc-deepseek`、`cc-agentplan`。
- 协议自动选择:Codex 类型 → `openai-responses` / `openai-completions`;Claude 类型 → `anthropic-messages`。
- 模型列表来自 CC Switch 的 `modelCatalog`、codex 配置里的 `model` 字段、网关 `/models` 发现(见下文),或 `~/.codex/cc-switch-model-catalog.json`。
- 密钥以凭据引用(`apiKeyEnv`)形式存储到 `~/.dsh/.credentials.yaml`,不进入 `settings.yaml`。
- **默认不自动拉取**:同步会往 `llm-pi-ai` 写入提供方/模型,可能覆盖你在 DSH 设置页手动改的东西,所以一律**由你手动触发**(聊天命令或 CLI),不会在重启或 CC Switch 变化时自动覆盖。

## 安装

插件已安装到 DSH Desktop 的 `desktop` 与 `web` 两个 profile:

```jsonc
// ~/.dsh/profiles/<profile>/package.json
"dependencies": { "dsh-ccswitch-sync": "file:../../plugins/dsh-ccswitch-sync" }
// dsh.profile.bundles 里加入 "dsh-ccswitch-sync"
```

**重启 DSH Desktop 后生效**。默认不自动同步,重启后什么都不改;需要时手动拉取(见下)。

## 使用

### 聊天命令(重启后可用)

| 命令 | 说明 |
| --- | --- |
| `/ccswitch-sync` | 手动执行一次同步(把 CC Switch 当前配置写为自定义提供方) |
| `/ccswitch-status` | 查看当前映射计划:每个提供方 → 路由、协议、模型 |

> 同步会覆盖 `cc-*` 前缀下已有的提供方/模型。如果你已经在 DSH 设置页手动调整过某些模型或删除了某些提供方,同步会按 CC Switch 现状重写它们——不想被重写的用 `excludeRoutes` 排除(见下)。

### 独立 CLI(无需重启应用即可用)

```bash
node cli.mjs --dry-run    # 只预览映射计划(默认)
node cli.mjs --apply      # 实际写入 settings.yaml + .credentials.yaml(自动备份原文件)
node cli.mjs --apply --remove-stale   # 同时删除来源已不存在的 cc-* 路由
node cli.mjs --apply --exclude cc-deepseek,cc-deepseek-codex   # 永不导入指定路由/提供方
node cli.mjs --dry-run --include-official
node cli.mjs --apply --prefix mycc    # 自定义路由前缀
```

CLI 直接编辑 `~/.dsh/settings.yaml` 与 `~/.dsh/.credentials.yaml`,运行中的 DSH 通过文件监听热发布,无需重启。

## 配置项

插件入口(`~/.dsh/profiles/<profile>/cordis.patch.yml` 里对 `ccswitch-sync` 打补丁,或安装时传入):

| 字段 | 默认值 | 说明 |
| --- | --- | --- |
| `ccswitchDbPath` | `~/.cc-switch/cc-switch.db` | CC Switch 数据库路径 |
| `codexModelCatalogDir` | `~/.codex` | codex 模型目录(`model_catalog_json` 相对路径的解析基址) |
| `routePrefix` | `cc` | 导入路由的前缀,如 `cc-sub2api` |
| `syncOnStart` | `false` | 是否在插件启动时自动同步(默认关:避免覆盖手动修改) |
| `watchDb` | `false` | 是否监听 cc-switch.db 变化自动重同步(默认关) |
| `watchDebounceMs` | `2000` | 重同步防抖(毫秒) |
| `removeStale` | `false` | 删除来源已消失的 `cc-*` 路由 |
| `includeOfficial` | `false` | 是否也导入官方服务商(OpenAI/Claude/Google) |
| `excludeRoutes` | `[]` | 永不导入的路由或提供方名(如 `["cc-deepseek"]`),适合与内置提供方重复的情况 |
| `discoverModels` | `true` | 对没有模型目录的 OpenAI 兼容网关,查询其 `/models` 接口拉全模型列表(同 Codex 的做法) |
| `discoverModelsTimeoutMs` | `6000` | 模型发现单次请求超时(毫秒) |
| `maxDiscoveredModels` | `50` | 每个提供方最多导入的发现模型数 |
| `discoveryCachePath` | `~/.dsh/cache/ccswitch-model-discovery.json` | 发现结果磁盘缓存(按 baseURL+密钥哈希键控) |
| `discoveryCacheTtlMs` | `24h` | 发现缓存有效期 |

**模型发现说明**:Sub2API、镜花 Coding 这类网关在 Codex 里能选的模型远不止配置里那一个;同步时插件会调用 `GET {baseURL}/models` 拉取全部可用模型(自动过滤 image/realtime/audio/embedding 等非对话模型),失败时回退到配置中选定的模型(如 AI-Tokens、超级羲和不支持 /models,则只导入配置模型,可在 DSH 设置页手动补充)。查询结果带 24 小时磁盘缓存,不会反复请求。

示例(`~/.dsh/profiles/desktop/cordis.patch.yml`):

```yaml
- patch:
    - id: ccswitch-sync
      config:
        removeStale: true
        excludeRoutes:
          - cc-deepseek
          - cc-deepseek-codex
```

## 推理等级(reasoningEfforts)

导入的模型自动带上推理等级选择(composer 的模型选择器 → 推理等级):

- **模型目录声明了 `supported_reasoning_levels`**(如 `~/.codex/cc-switch-model-catalog.json`):精确映射这些等级(`none`→`off`,其余等级名即线上拼写)。
- **配置里声明了 `model_reasoning_effort`**(OpenAI 兼容网关):提供标准等级集 `off / low / medium / high`,并把配置的等级(如 `max`)一并加入可选集。
- **路由默认等级**:取 `default_reasoning_level` 或 `model_reasoning_effort`,写入 profile 的 `reasoning` 字段,选择器会预选该等级。
- **Claude 协议(anthropic-messages)** 不映射推理等级(Anthropic 端点用 thinking budget,不是 effort 等级)。

## 映射规则

| CC Switch 字段 | DSH `llm-pi-ai` 字段 |
| --- | --- |
| `name` | `displayName` |
| `settings_config.auth.OPENAI_API_KEY`(codex) | 凭据 `CC_<路由>_API_KEY`,profile `apiKeyEnv` |
| `settings_config.env.ANTHROPIC_AUTH_TOKEN`(claude) | 同上 |
| `meta.apiFormat` / `wire_api` | `api`: `openai-responses` / `openai-completions` / `anthropic-messages` |
| `model_providers.custom.base_url` / `provider_endpoints.url` / `website_url` | `baseURL` |
| `settings_config.modelCatalog.models`、`model` 字段、`cc-switch-model-catalog.json` | `models[]`(`id`/`name`/`contextWindow`/`input`) |
| Claude 环境变量里的 `[1m]` 后缀模型 | 剥除后缀并把 `contextWindow` 置为 1000000 |

官方服务商(category 为 `official`)默认跳过——它们在 DSH 内置目录里已有。

## 安全说明

- API 密钥写入 `~/.dsh/.credentials.yaml`(与 DSH 自身存储一致,文件权限 600)。
- 日志与命令输出不会打印完整密钥(CLI 预览脱敏)。
- 卸载:从 profile 的 `package.json` 移除依赖与 bundle 条目,执行 `pnpm install`,重启即可。

## 文件结构

```
index.mjs      插件入口(命令 /ccswitch-sync、/ccswitch-status、启动同步、db 监听)
mapper.mjs     CC Switch 记录 → DSH profile 的映射核心
sync.mjs       同步引擎(seams 写入 / 直写文件两种方式)
config.mjs     配置默认值与归一化
cli.mjs        独立命令行工具
cordis.patch.yml  插件组合补丁
```

Install

dsh plugin --profile web add github:yu969774/dsh-ccswitch-sync#33e15227e8fc285009e8fcdd6f75bdb8db37f088

Profile: web

Source