Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## CC-Switch CLI

**Manage Claude Code, Codex, Gemini, OpenCode, Hermes, OpenClaw, and Pi from one interactive TUI or scriptable CLI.**
**Manage Claude Code, Codex, Gemini, OpenCode, Hermes, OpenClaw, Pi, and OMP (oh-my-pi) from one interactive TUI or scriptable CLI.**

[![Version](https://img.shields.io/badge/version-5.10.4-blue.svg)](https://github.com/saladday/cc-switch-cli/releases)
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](https://github.com/saladday/cc-switch-cli/releases)
Expand Down Expand Up @@ -185,8 +185,13 @@ cc-switch --app gemini prompts list # List Gemini prompts
cc-switch --app hermes provider list # Manage Hermes providers
cc-switch --app openclaw provider list # Manage OpenClaw providers
cc-switch --app pi provider list # Manage Pi providers
cc-switch --app omp provider list # Manage OMP providers
cc-switch --app omp provider set-default <provider> [--model <model>] # Set modelRoles.default
cc-switch --app omp model list # List models and show the active native path
cc-switch --app omp role list # List model roles and show the active native path
cc-switch --app omp env check # Compare CC-Switch and official OMP paths

# Supported apps: `claude` (default), `codex`, `gemini`, `opencode`, `hermes`, `openclaw`, `pi`
# Supported apps: `claude` (default), `codex`, `gemini`, `opencode`, `hermes`, `openclaw`, `pi`, `omp`
```

Use `cc-switch start` when you want different providers in multiple terminals. It only affects the Claude or Codex session launched by that command; `provider switch` and `use` still change the global provider. In the TUI, select a provider on the Providers page and press `o` for the same behavior.
Expand Down Expand Up @@ -318,7 +323,9 @@ copy target\release\cc-switch.exe C:\Windows\System32\

### 🔌 Provider Management

Manage API configurations for **Claude Code**, **Codex**, **Gemini**, **OpenCode**, **Hermes**, **OpenClaw**, and **Pi**.
Manage API configurations for **Claude Code**, **Codex**, **Gemini**, **OpenCode**, **Hermes**, **OpenClaw**, **Pi**, and **OMP**.

OMP uses native additive YAML files. CC-Switch manages explicit `providers` and `models` in `models.yml`, and OMP's effective `modelRoles` in `config.yml`; providers remain side-by-side and the `default` role selects the active `provider/model` (or an OMP role alias such as `@smol`/`*`, optionally with a thinking suffix). When `modelRoleStorage: project` is effective, role assignments are written to the current directory's `.omp/config.yml` and overlaid on global roles. OMP login credentials are never rewritten. The OMP TUI also edits `SYSTEM.md`, `APPEND_SYSTEM.md`, and `TITLE_SYSTEM.md` using OMP's project-first lookup with revision checks, and shows the exact active prompt path. `SYSTEM.md` follows OMP's native provider (nearest non-empty ancestor `.omp` project directory, then the active native agent directory, including `PI_CODING_AGENT_DIR`); `APPEND_SYSTEM.md` and `TITLE_SYSTEM.md` use the generic cwd-only project lookup and profile/config-root user lookup. `disabledProviders` is honored when marking providers and setting defaults. Use `cc-switch --app omp model list`, `cc-switch --app omp role list`, and `cc-switch --app omp env check` to verify the files and effective settings OMP is using. OMP paths always follow the official `PI_CODING_AGENT_DIR`, `PI_CONFIG_DIR`, `OMP_PROFILE`, and legacy `PI_PROFILE` resolution; CC-Switch does not maintain a separate OMP directory override.

Pi provider management follows Pi's native additive model: membership comes from `models.json.providers`. CC-Switch does not modify Pi login credentials or its global default provider/model.
The Pi TUI keeps the same table/form/shortcut conventions as the other apps and exposes Presets, System Prompts, and Prompt Templates as separate pages.
Expand Down Expand Up @@ -391,6 +398,8 @@ cc-switch prompts show <id> # Display full content
cc-switch prompts delete <id> # Delete prompt
cc-switch --app pi prompts system edit append # Edit APPEND_SYSTEM.md
cc-switch --app pi prompts templates list # List Pi prompt templates
cc-switch --app omp prompts system edit append # Edit OMP APPEND_SYSTEM.md
cc-switch --app omp prompts system edit title # Edit OMP TITLE_SYSTEM.md
```

### 🎯 Skills Management
Expand Down Expand Up @@ -517,7 +526,7 @@ Inspect environment conflicts and whether required local CLIs are installed.
```bash
cc-switch env check # Check environment conflicts
cc-switch env list # List relevant environment variables
cc-switch env tools # Check Claude/Codex/Gemini/OpenCode/Hermes/OpenClaw/Pi CLIs
cc-switch env tools # Check Claude/Codex/Gemini/OpenCode/Hermes/OpenClaw/Pi/OMP CLIs
```

### 🌐 Multi-language Support
Expand Down Expand Up @@ -584,6 +593,7 @@ When `CC_SWITCH_CONFIG_DIR` is set, CC-Switch uses that directory as its config
- Hermes: `~/.hermes/config.yaml` (providers + MCP + memory settings), `~/.hermes/AGENTS.md` (prompts), `~/.hermes/skills/` (skills), `~/.hermes/memories/` (memory)
- OpenClaw: `~/.openclaw/openclaw.json` (providers + env/tools/agents defaults), `~/.openclaw/AGENTS.md` (prompts)
- Pi: `~/.pi/agent/models.json` (additive providers), `~/.pi/agent/settings.json` (read-only defaults/session location), `~/.pi/agent/AGENTS.md`, `SYSTEM.md`, `APPEND_SYSTEM.md`, `prompts/`, `skills/`, and `sessions/`
- OMP (oh-my-pi): `~/.omp/agent/models.yml` (additive providers and models; `models.yaml` and legacy `models.json` are also supported), `~/.omp/agent/config.yml` (`modelRoles` and native settings), plus optional `SYSTEM.md`, `APPEND_SYSTEM.md`, and `TITLE_SYSTEM.md` resolved with OMP's project-first lookup. `SYSTEM.md` follows the native nearest-ancestor/provider path (including `PI_CODING_AGENT_DIR`), while `APPEND_SYSTEM.md` and `TITLE_SYSTEM.md` use the generic cwd-only project lookup and profile/config-root user lookup. Model/role files follow `PI_CONFIG_DIR` and profile resolution. `cc-switch env check --app omp` compares the adapter path with `omp config path`.

---

Expand Down
30 changes: 26 additions & 4 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## CC-Switch CLI

**通过交互式 TUI 或脚本化 CLI,统一管理 Claude Code、Codex、Gemini、OpenCode、Hermes、OpenClaw 和 Pi。**
**通过交互式 TUI 或脚本化 CLI,统一管理 Claude Code、Codex、Gemini、OpenCode、Hermes、OpenClaw、PiOMP(oh-my-pi)。**

[![Version](https://img.shields.io/badge/version-5.10.4-blue.svg)](https://github.com/saladday/cc-switch-cli/releases)
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](https://github.com/saladday/cc-switch-cli/releases)
Expand Down Expand Up @@ -184,8 +184,13 @@ cc-switch --app gemini prompts list # 列出 Gemini 提示词
cc-switch --app hermes provider list # 管理 Hermes 供应商
cc-switch --app openclaw provider list # 管理 OpenClaw 供应商
cc-switch --app pi provider list # 管理 Pi 供应商
cc-switch --app omp provider list # 管理 OMP 供应商
cc-switch --app omp provider set-default <provider> [--model <model>] # 设置 OMP 的 modelRoles.default
cc-switch --app omp model list # 列出 models.yml 中的模型并显示实际路径
cc-switch --app omp role list # 列出 config.yml 中的 modelRoles 并显示实际路径
cc-switch --app omp env check # 检查 OMP 官方路径与 CC-Switch 路径是否一致

# 支持的应用:`claude`(默认)、`codex`、`gemini`、`opencode`、`hermes`、`openclaw`、`pi`
# 支持的应用:`claude`(默认)、`codex`、`gemini`、`opencode`、`hermes`、`openclaw`、`pi`、`omp`
```

需要在多个终端同时使用不同供应商时,请使用 `cc-switch start`。它只影响由该命令启动的 Claude 或 Codex 会话;`provider switch` 和 `use` 仍会切换全局供应商。在 TUI 的供应商页选中供应商后按 `o`,效果相同。
Expand Down Expand Up @@ -321,7 +326,21 @@ copy target\release\cc-switch.exe C:\Windows\System32\

### 🔌 供应商管理

管理 **Claude Code**、**Codex**、**Gemini**、**OpenCode**、**Hermes**、**OpenClaw** 与 **Pi** 的 API 配置。
管理 **Claude Code**、**Codex**、**Gemini**、**OpenCode**、**Hermes**、**OpenClaw**、**Pi** 与 **OMP** 的 API 配置。

OMP 供应商遵循原生的累加管理模型:配置保存在 OMP 实际 agent 目录的 `models.yml` 的 `providers` 节点中,多个供应商可以同时存在。活动模型由生效配置中的 `modelRoles.default`(`provider/model[:thinking]`,也支持 `@smol`、`@slow`、`*` 等 OMP 角色别名)决定;如果 `modelRoleStorage: project`,角色会写入当前目录的 `.omp/config.yml` 并覆盖同名全局角色。在 OMP 页面按“设为默认”会更新该角色,不会删除其他供应商;`disabledProviders` 中的供应商会被明确标记为不可用,不能设为默认。CC-Switch 不会修改 OMP 登录凭据。OMP 路径始终遵循官方的 `PI_CODING_AGENT_DIR`、`PI_CONFIG_DIR`、`OMP_PROFILE` 和兼容的 `PI_PROFILE` 解析,CC-Switch 不再维护独立的 OMP 目录覆盖设置。

OMP 的系统提示词文件遵循 project-first 查找:当前目录的 `.omp`、`.claude`、`.codex`、`.gemini` 文件优先,其次才是用户级文件。用户级 `.omp` 提示词目录遵循 `PI_CONFIG_DIR`/profile 解析;官方的 `PI_CODING_AGENT_DIR` 只迁移 OMP 运行时 agent 目录,不改变这类共享配置文件的查找位置。TUI 会显示并编辑实际生效的 `SYSTEM.md`、`APPEND_SYSTEM.md` 和 `TITLE_SYSTEM.md`,同时对 `models.yml`、`config.yml` 与提示词文件使用外部修改检测,发现文件在编辑期间被改动时会拒绝覆盖。

要确认 CC-Switch 与 OMP 使用的是同一份文件,请分别运行:

```bash
cc-switch --app omp model list # 显示 CC-Switch 正在读取的 models.yml
cc-switch --app omp role list # 显示 CC-Switch 正在读取的 config.yml
omp config path # 显示 OMP 官方解析出的 agent 目录
```

旧版 CC-Switch 设置中的“自定义 OMP 目录”仅作为历史字段兼容读取,不会再决定 OMP 文件路径;否则会出现 CC-Switch 显示成功但 `omp` 读取另一份配置的问题。请使用 OMP 官方环境变量 `PI_CODING_AGENT_DIR`、`PI_CONFIG_DIR`、`OMP_PROFILE`(兼容 `PI_PROFILE`),并用 `omp config path` 与 `cc-switch --app omp env check` 校验两者是否一致。

Pi 供应商遵循原生的增量管理模型:是否启用完全取决于 `models.json.providers` 中的成员关系。CC-Switch 不会修改 Pi 的登录凭据或全局默认供应商/模型。
Pi TUI 延续其他应用的表格、表单与快捷键交互,并将预设、系统提示词和 Prompt Templates 分为独立页面。
Expand Down Expand Up @@ -394,6 +413,8 @@ cc-switch prompts show <id> # 显示完整内容
cc-switch prompts delete <id> # 删除提示词
cc-switch --app pi prompts system edit append # 编辑 APPEND_SYSTEM.md
cc-switch --app pi prompts templates list # 列出 Pi prompt templates
cc-switch --app omp prompts system edit append # 编辑 OMP APPEND_SYSTEM.md
cc-switch --app omp prompts system edit title # 编辑 OMP TITLE_SYSTEM.md
```

### 🎯 Skills 管理
Expand Down Expand Up @@ -519,7 +540,7 @@ cc-switch proxy serve --takeover claude # 前台调试模式;存在
```bash
cc-switch env check # 检查环境变量冲突
cc-switch env list # 列出相关环境变量
cc-switch env tools # 检查 Claude/Codex/Gemini/OpenCode/Hermes/OpenClaw/Pi CLI
cc-switch env tools # 检查 Claude/Codex/Gemini/OpenCode/Hermes/OpenClaw/Pi/OMP CLI
```

### 🌐 多语言支持
Expand Down Expand Up @@ -586,6 +607,7 @@ cc-switch update --version vX.Y.Z # 更新到指定版本
- Hermes: `~/.hermes/config.yaml`(供应商 + MCP + 记忆设置), `~/.hermes/AGENTS.md`(提示词), `~/.hermes/skills/`(技能), `~/.hermes/memories/`(记忆)
- OpenClaw: `~/.openclaw/openclaw.json`(供应商 + Env/Tools/Agents Defaults), `~/.openclaw/AGENTS.md`(提示词)
- Pi: `~/.pi/agent/models.json`(增量供应商), `~/.pi/agent/settings.json`(只读默认项 / 会话位置), `~/.pi/agent/AGENTS.md`、`SYSTEM.md`、`APPEND_SYSTEM.md`、`prompts/`、`skills/` 与 `sessions/`
- OMP(oh-my-pi): agent 目录下的 `models.yml`(增量供应商与模型;兼容 `models.yaml`/旧版 `models.json`)、`config.yml`(`modelRoles` 与原生设置),以及按 OMP project-first 规则查找的 `SYSTEM.md`、`APPEND_SYSTEM.md`、`TITLE_SYSTEM.md`。其中 `SYSTEM.md` 遵循原生 provider 的最近非空祖先 `.omp` 查找,并使用当前 native agent 目录(包括 `PI_CODING_AGENT_DIR`);`APPEND_SYSTEM.md` 与 `TITLE_SYSTEM.md` 使用当前目录的通用 project-first 查找和 profile/config-root 用户目录。模型/角色 agent 目录由 `~/.omp/agent`、`PI_CONFIG_DIR` 与 profile 决定。CC-Switch 设置里的 OMP 配置目录不会自动改变已启动 shell 中 `omp` 的环境变量。

---

Expand Down
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- **OMP / Provider Form**: Derive provider IDs from the visible Name field and remove direct ID editing from add and edit forms.

## [5.10.4] - 2026-08-30

### Added
Expand Down
57 changes: 53 additions & 4 deletions src-tauri/src/app_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl McpApps {
AppType::Hermes => self.hermes,
AppType::OpenClaw => false,
AppType::Pi => false,
AppType::Omp => false,
}
}

Expand All @@ -43,6 +44,7 @@ impl McpApps {
AppType::Hermes => self.hermes = enabled,
AppType::OpenClaw => {}
AppType::Pi => {}
AppType::Omp => {}
}
}

Expand Down Expand Up @@ -88,6 +90,8 @@ pub struct SkillApps {
pub hermes: bool,
#[serde(default)]
pub pi: bool,
#[serde(default)]
pub omp: bool,
}

impl SkillApps {
Expand All @@ -100,6 +104,7 @@ impl SkillApps {
AppType::Hermes => self.hermes,
AppType::OpenClaw => false,
AppType::Pi => self.pi,
AppType::Omp => self.omp,
}
}

Expand All @@ -112,11 +117,18 @@ impl SkillApps {
AppType::Hermes => self.hermes = enabled,
AppType::OpenClaw => {}
AppType::Pi => self.pi = enabled,
AppType::Omp => self.omp = enabled,
}
}

pub fn is_empty(&self) -> bool {
!self.claude && !self.codex && !self.gemini && !self.opencode && !self.hermes && !self.pi
!self.claude
&& !self.codex
&& !self.gemini
&& !self.opencode
&& !self.hermes
&& !self.pi
&& !self.omp
}

pub fn only(app: &AppType) -> Self {
Expand All @@ -142,6 +154,7 @@ impl SkillApps {
self.opencode |= other.opencode;
self.hermes |= other.hermes;
self.pi |= other.pi;
self.omp |= other.omp;
}
}

Expand Down Expand Up @@ -254,6 +267,8 @@ pub struct McpRoot {
pub openclaw: McpConfig,
#[serde(skip)]
pub pi: McpConfig,
#[serde(skip)]
pub omp: McpConfig,
}

impl Default for McpRoot {
Expand All @@ -269,6 +284,7 @@ impl Default for McpRoot {
hermes: McpConfig::default(),
openclaw: McpConfig::default(),
pi: McpConfig::default(),
omp: McpConfig::default(),
}
}
}
Expand Down Expand Up @@ -297,6 +313,8 @@ pub struct PromptRoot {
pub openclaw: PromptConfig,
#[serde(default)]
pub pi: PromptConfig,
#[serde(default)]
pub omp: PromptConfig,
}

use crate::config::{copy_file, get_app_config_dir, get_app_config_path, write_json_file};
Expand All @@ -315,6 +333,8 @@ pub enum AppType {
Hermes,
OpenClaw,
Pi,
#[cfg_attr(feature = "cli", value(alias = "oh-my-pi"))]
Omp,
}

impl AppType {
Expand All @@ -327,13 +347,14 @@ impl AppType {
AppType::Hermes => "hermes",
AppType::OpenClaw => "openclaw",
AppType::Pi => "pi",
AppType::Omp => "omp",
}
}

pub fn is_additive_mode(&self) -> bool {
matches!(
self,
AppType::OpenCode | AppType::Hermes | AppType::OpenClaw | AppType::Pi
AppType::OpenCode | AppType::Hermes | AppType::OpenClaw | AppType::Pi | AppType::Omp
)
}

Expand All @@ -350,6 +371,7 @@ impl AppType {
AppType::Hermes,
AppType::OpenClaw,
AppType::Pi,
AppType::Omp,
]
.into_iter()
}
Expand All @@ -374,13 +396,14 @@ impl FromStr for AppType {
"hermes" => Ok(AppType::Hermes),
"openclaw" => Ok(AppType::OpenClaw),
"pi" => Ok(AppType::Pi),
"omp" | "oh-my-pi" => Ok(AppType::Omp),
other => Err(AppError::localized(
"unsupported_app",
format!(
"不支持的应用标识: '{other}'。可选值: claude, codex, gemini, opencode, hermes, openclaw, pi。"
"不支持的应用标识: '{other}'。可选值: claude, codex, gemini, opencode, hermes, openclaw, pi, omp。"
),
format!(
"Unsupported app id: '{other}'. Allowed: claude, codex, gemini, opencode, hermes, openclaw, pi."
"Unsupported app id: '{other}'. Allowed: claude, codex, gemini, opencode, hermes, openclaw, pi, omp."
),
)),
}
Expand Down Expand Up @@ -420,6 +443,7 @@ impl CommonConfigSnippets {
AppType::Hermes => self.hermes.as_ref(),
AppType::OpenClaw => self.openclaw.as_ref(),
AppType::Pi => None,
AppType::Omp => None,
}
}

Expand All @@ -433,6 +457,7 @@ impl CommonConfigSnippets {
AppType::Hermes => self.hermes = snippet,
AppType::OpenClaw => self.openclaw = snippet,
AppType::Pi => {}
AppType::Omp => {}
}
}
}
Expand Down Expand Up @@ -476,6 +501,7 @@ impl Default for MultiAppConfig {
apps.insert("hermes".to_string(), ProviderManager::default());
apps.insert("openclaw".to_string(), ProviderManager::default());
apps.insert("pi".to_string(), ProviderManager::default());
apps.insert("omp".to_string(), ProviderManager::default());

Self {
version: 2,
Expand Down Expand Up @@ -590,6 +616,13 @@ impl MultiAppConfig {
updated = true;
}

if !config.apps.contains_key("omp") {
config
.apps
.insert("omp".to_string(), ProviderManager::default());
updated = true;
}

// 执行 MCP 迁移(v3.6.x → v3.7.0)
let migrated = config.migrate_mcp_to_unified()?;
if migrated {
Expand Down Expand Up @@ -657,6 +690,7 @@ impl MultiAppConfig {
AppType::Hermes => &self.mcp.hermes,
AppType::OpenClaw => &self.mcp.openclaw,
AppType::Pi => &self.mcp.pi,
AppType::Omp => &self.mcp.omp,
}
}

Expand All @@ -670,6 +704,7 @@ impl MultiAppConfig {
AppType::Hermes => &mut self.mcp.hermes,
AppType::OpenClaw => &mut self.mcp.openclaw,
AppType::Pi => &mut self.mcp.pi,
AppType::Omp => &mut self.mcp.omp,
}
}

Expand Down Expand Up @@ -708,6 +743,7 @@ impl MultiAppConfig {
AppType::Hermes => &self.mcp.hermes.servers,
AppType::OpenClaw => continue,
AppType::Pi => continue,
AppType::Omp => continue,
};

for (id, entry) in old_servers {
Expand Down Expand Up @@ -1065,4 +1101,17 @@ mod tests {
.expect("deserialize MCP root");
assert!(parsed.pi.is_empty());
}

#[test]
fn skill_apps_keep_pi_and_omp_independent_when_merged() {
let mut pi = SkillApps::only(&AppType::Pi);
let omp = SkillApps::only(&AppType::Omp);

assert!(pi.is_enabled_for(&AppType::Pi));
assert!(!pi.is_enabled_for(&AppType::Omp));
pi.merge_enabled(&omp);

assert!(pi.is_enabled_for(&AppType::Pi));
assert!(pi.is_enabled_for(&AppType::Omp));
}
}
Loading