# CPA Companion (cpac)

CPAC 将 Codex 和 Claude Code 接入远端 CLIProxyAPI（CPA）：

- **Codex**：注入模型目录和 loopback 网关，保留内置 `openai` provider。无用户改动时逐字节恢复原配置；注入期间改过文件则只撤掉 CPAC 字段。
- **Claude Code**：通过临时环境变量启动，不修改 Claude Code 配置。

实现基于 TypeScript + Node.js，运行时零依赖。

## 要求

- [Node.js](https://nodejs.org/) 20 或更新版本（npm 随 Node 安装）
- 已安装需要使用的 agent：`codex`、`claude`、`pi`、`kimi`、`grok`、`zed`、`hermes` 或 `codebuddy`
- 有权访问的 CPA API key

## 安装

从 npm 安装后：

```bash
npm install -g @yhong91/cpac
cpac
```

## 快速上手

```bash
# 1. 安装
npm install -g @yhong91/cpac

# 2. 配置密钥：无参数运行进入交互引导，自动写入 shell 启动文件；
#    也可手动写入（zsh 示例）：
cpac
echo 'export CPA_API_KEY="<你的key>"' >> ~/.zshrc && source ~/.zshrc

# 3. 验证
cpac status

# 4a. 持久注入（长期生效，写入 agent 配置，可完整恢复）
cpac install --all                     # 注入所有检测到的目标（codex/pi/kimi/grok/zed/hermes/codebuddy）
cpac install codex                     # 只注入 Codex（默认开启 multi-agent v2）
cpac install codex --v2_models         # 先多选 spawn_agent 模型再注入
cpac install codex --max_context       # 注入时把模型上下文提升到实测上限（opt-in，仅限 codex）
cpac codex clear                     # 撤掉注入；注入期间的用户改动会留下

# 4b. 临时接管（退出无痕，不写任何配置文件）
cpac claude                            # Claude Code 走 CPA

# 5. 可选：Agent 配置向导与模型选择（只写配置，不启动）
cpac setup codex                       # Codex 配置向导 → 注入
cpac setup claude                      # Claude 模型向导
cpac claude setup                      # 配置完再启动（agent 下的 setup 才会 launch）

# 6. 升级（装上新版本后自动 sync 已接入的 agent）
cpac upgrade
```

各命令的完整参数与行为见下方对应章节。

## Agent 自动化安装指南

本节面向 AI agent：按顺序执行即可完成安装与配置，**全程无交互**。注意：`cpac codex --config` 和 `cpac claude --config` 的交互向导是 TTY-only，agent 必须走下方直接写配置 JSON 的路径。

1. **检查前置**：`node --version` ≥ 20；确认用户需要哪些 agent（`codex`/`claude`/`pi`/`kimi`/`grok`/`zed`/`hermes`/`codebuddy` 在 PATH 上）。向用户索取 CPA API key。

2. **安装与密钥**：

```bash
npm install -g @yhong91/cpac
echo 'export CPA_API_KEY="<key>"' >> ~/.zshrc   # bash 用 ~/.bash_profile 或 ~/.bashrc
source ~/.zshrc
cpac status   # 验证：CPA_API_KEY 应显示 configured
```

1. **写入模型配置**（创建或合并 `~/.config/cpac/config.json`，已有键保留）：

```json
{
  "spawn_models": ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gemini-3.7-flash-high", "grok-4.6"]
}
```

   Claude 槽位（opus/sonnet/haiku）通常不用配：cpac 启动时自动选择——同家族 claude 模型优先，否则 gemini → grok → luna → 目录第一个；opus 无匹配则不设。这个链条在常见目录上正好给出理想结果：sonnet 落在 claude-sonnet-*（它同时充当 Auto mode 分类器的替身，避免分类请求失败后回退到昂贵的会话主模型），haiku 落在快的 gemini flash。只有目录奇怪时才用 `cpac setup claude` 交互式配置。codex spawn subagent 取三个 GPT + gemini + grok 五席（顺序即优先级，Codex 只广告 catalog 前 5），可通过 `cpac setup codex` 交互式配置。候选替换：`mimo-v2.5`（haiku）、`grok-4.5`（haiku）。若上述 slug 不在目录中（`curl -s -H "Authorization: Bearer $CPA_API_KEY" "$CPA_BASE_URL/v1/models"` 可查），按家族就近替换。分类器机制细节见 [docs/claude-auto-mode-classifier.md](docs/claude-auto-mode-classifier.md)。

1. **持久注入**（只对检测到的目标；codex 会应用步骤 3 的 spawn_models）：

```bash
cpac install --all
cpac status   # 验证：各 target 显示 ready/injected
```

1. **统一启动与配置**：
   - 启动：`cpac <codex|claude|kimi|grok|pi|zed|hermes|codebuddy> [args...]`（所有原生参数如 `-c` 等原样透明传递）
     - `setup` / `--setup`：配置 Codex/Claude，然后启动
     - `clear`：还原原生配置
   - 只写配置、不启动：`cpac setup [claude|codex]`；查看当前：`cpac setup`

2. **已安装后升级**：npm 发布新版本后，等 publish 成功再执行 `cpac upgrade`。它会按需 `npm install -g`，再对已接入的 Codex / Pi / Kimi / Grok / Zed / Hermes 做 `sync`。不要拆成 `npm install -g @yhong91/cpac` 再手动 `cpac sync`。只刷新配置、不升 CLI 时才用 `cpac sync`。

失败处理：任何一步报错时先跑 `cpac status`；密钥未配置回到步骤 2；注入后异常用 `cpac <agent> clear` 恢复原配置。

## 首次引导

无参数运行 `cpac` 会显示当前 CPA、密钥状态和可用命令：

```text
CPA Companion

CPA: http://124.223.178.52:8317
CPA_API_KEY: configured / not configured

Commands:
  cpac <agent> [args...] Launch an agent through CPA
  cpac setup            Show current Codex/Claude setup
  cpac status            Show agent support status
  cpac models            List remote CPA catalog models
  cpac <agent> clear    Clear setup and restore native configuration
  cpac --help            Show command usage
```

默认 CPA 地址内置为 `http://124.223.178.52:8317`，不需要创建 `~/.config/cpac/`。

若 `CPA_API_KEY` 尚未设置，交互式引导会隐藏输入密钥，并将受 CPAC 标记管理的 export 区块写入当前 shell 的启动文件：

| Shell | 写入位置 |
| --- | --- |
| zsh | `~/.zshrc` |
| bash（macOS） | `~/.bash_profile` |
| bash（Linux 等） | `~/.bashrc` |
| sh / dash / ksh | `~/.profile` |

写入内容形如：

```bash
# >>> CPAC CPA_API_KEY >>>
export CPA_API_KEY='...'
# <<< CPAC CPA_API_KEY <<<
```

CPAC 会保留启动文件中的其他设置；再次运行引导配置密钥时，受管区块会原位更新，不会重复追加。写入后按引导提示打开新终端，或在当前终端执行：

```bash
source ~/.zshrc # 使用引导实际显示的文件
```

程序无法直接修改已经运行的父 shell，所以 `source` 或新终端仍然是必要的。

也可以跳过引导，自行设置：

```bash
export CPA_API_KEY='...'
```

### Windows

CPAC 会按平台自动选择处理方式：

- 密钥引导不写 shell profile（Windows 没有 `source` 语义）。引导会提示改用 `setx CPA_API_KEY "<your-key>"` 或「编辑账户的环境变量」持久化；也可以在 PowerShell 里直接执行：

  ```powershell
  [Environment]::SetEnvironmentVariable("CPA_API_KEY", "<your-key>", "User")
  ```

  设置后需要重开终端。若通过 npm 全局安装，PowerShell 首次运行需要允许本地脚本：`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`。

- 检测 PATH 上的 agent 时使用 `where` 而非 `command -v`。
- 启动 agent 时自动解析 `.cmd` / `.bat` shim（npm 全局安装的 CLI），`.exe` 直接启动。
- `cpac upgrade` / `cpac uninstall` 内部调用 npm 时自动经 shell 启动 `npm.cmd`。
- 清理残留代理进程时通过 PowerShell CIM 读取进程命令行来确认身份，不会误杀无关进程。

## 命令

### 引导和帮助

```bash
cpac
cpac --help
```

### 统一管理（detect / install / sync / clear / uninstall / upgrade）

参考 vibetime 的目标式命令，对 `codex`、`pi`、`kimi`、`grok`、`zed`、`hermes`、`codebuddy` 七个持久注入目标统一管理（claude 是临时接管，用 `cpac claude` 启动，不属于 install 目标）：

```bash
cpac detect [--json]
cpac status
cpac models [--json] [--diff]
cpac install [codex|pi|kimi|grok|zed|hermes|codebuddy...] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context]
cpac sync [codex|pi|kimi|grok|zed|hermes|codebuddy...] [--all] [--dry-run] [--v2_off] [--v2_models] [--max_context]
cpac <agent> clear [--dry-run]
cpac uninstall [--dry-run]
cpac upgrade [--check]
cpac -v | --version
```

- `models` 从远端 CPA 拉取 rich catalog，默认一行一个 slug；`--json` 输出 `cpa_url` 和模型字段（`slug` / `display_name` / `context_window`）。用来核对 catalog 里有没有某个模型（例如 `*-fast`），不写本地配置。`--diff` 拿已保存的 `state_dir/models.json` 和当前 catalog 比 slug：`+` 是新增，`-` 是去掉；没有差别打印 `unchanged`。还没有保存列表时报错，先跑 `cpac sync`。
- `detect` 列出每个目标是否被检测到、是否已接入 CPAC；`--json` 输出机器可读结果。
- 重新注入会保留 Zed 模型的有效 `reasoning_effort` 和 CodeBuddy 模型的 `disabled`；协议、endpoint 和模型能力仍由 CPA 目录刷新。Zed 只编辑 CPAC provider，保留其他 JSONC 注释和格式。配置写入保留 symlink，bytes 和权限都没变化时不触碰文件。
- `install` 默认作用于检测到的目标；后面直接写 agent 名（`cpac install codex pi`），`--all` 全部。`codex` 写入 catalog 并拉起 loopback 代理；`pi`/`kimi`/`grok`/`zed`/`hermes`/`codebuddy` 写入各自配置。`--dry-run` 只打印将要做的事，`--force` 允许重装已安装目标。
- `sync` 把 CPA 模型列表和更新时间写到 `state_dir/models.json`（默认 `~/.cpac/models.json`）。这个时间戳就是模型版本：列表没变则时间戳不变。只有版本相同且 CPAC 管理的 provider、endpoint 和模型目录接线完好时才跳过写入；接线被替换或丢失时，即使目录版本没变也会修复。Pi 的 `enabledModels` / `modelThinkingLevels` 不受这个跳过限制，仍会同步设置及思考强度缓存。不带参数只看已安装目标；`--all` 还会装上检测到但还没接入的目标。`install` 仍总是重写。`spawn_models`、`v2_off`、`max_context` 和代理端口不改这个版本，要马上生效用 `cpac install`。`--max_context` 仍只对 `cpac install codex` 有效。
- `cpac status` 统一检查 CPAC 管理的 provider、endpoint 和模型目录引用；接线丢失显示 `unwired`，被替换显示 `replaced`，退出码为 3。无关的用户配置修改不算故障。此检查不发送推理请求，也不代表运行中的 agent 已加载新配置；必要时重启 agent。`cpac <agent> status` 不是 CPAC 状态查询，会把 `status` 透传给原生 CLI，可能启动 agent 或作为提示词发送。
- Pi 和 Codex 的多文件注入在写入失败时回滚配置、目录、state 和备份，保留原 bytes、权限及文件原先不存在的状态；这是失败回滚，不是断电/进程被杀时的 crash-consistent 事务。
- Codex 注入默认开启 multi-agent v2（写入 `[features.multi_agent_v2] enabled = true`，catalog 行打 `multi_agent_version: "v2"`）；`install codex --v2_off` 关掉 toml 并去掉 catalog 戳。v2 开着时会剥掉 `[agents] max_threads`（Codex 否则拒启动）。`cpac status` 对照 config 里的 `v2_off` / `max_context` 和 live toml / catalog。服务端还需在 CPA 配置中开启 `codex.optimize-multi-agent-v2`。
- `--v2_models` 进入 arrow-key 复选框选择最多 5 个 spawn_agent 模型（勾选顺序即推荐顺序），选择结果存入配置文件的 `spawn_models`，注入时把这些模型排到 `codex-models.json` 最前——Codex 客户端只把 catalog 前 5 个可见模型广告为 spawn 覆盖项。
- `cpac <agent> clear` 撤掉该目标的注入并恢复原生配置。Codex 还会清除 `spawn_models` / `max_context` / `v2_off`，Claude 清除模型槽位覆盖。`--dry-run` 只预览，不修改配置或停止后台。原 `cpac restore` 入口已移除。
- `uninstall` 先用和 `cpac setup codex` 相同的方向键选择器确认（默认 Cancel），再撤掉所有已注入目标，最后 `npm uninstall -g @yhong91/cpac`。不要跟 agent 名；卸载的是 cpac 包本身。非终端取消。`--dry-run` 跳过确认。
- `upgrade` 是发布后更新本机的一次性入口：查 npm → 需要时 `npm install -g` → 对**已接入**的 Codex / Pi / Kimi / Grok / Zed / Hermes / CodeBuddy 执行 `sync`。已是最新也会 sync。不要先手动 `npm install -g` 再 `cpac sync`。`--check` 只报告版本，不安装也不 sync。没有已安装目标时跳过 sync，不报错。只刷新配置、不升 CLI 时用 `cpac sync`。

### Magpie 只读检查

```bash
cpac magpie models                          # 直接模型与 routing group
cpac magpie models --provider qoder-cn      # 按所属 provider 过滤
cpac magpie models --json                   # 机器可读目录
cpac magpie status                         # binary、version、网关与目录统计
cpac magpie status --json
cpac magpie status --url http://127.0.0.1:3426
cpac magpie --help
```

默认读取 `http://127.0.0.1:3425/v1/models`；`--url` 接受 gateway base URL，也接受末尾 `/v1`。这两个命令独立于 CPA 配置，不需要 `CPA_API_KEY`，不读取 Magpie 私有配置、token 或 provider 凭据，也不转发 CPA 密钥。不支持在 URL 中携带凭据、query 或 fragment；需要认证的远程网关会报告 HTTP 状态，不自动获取密钥。

- `models` 显示原始 ID、`display_name`、provider、context/output、vision 与 reasoning；例如 `qoder-cn/qfmodel` 保留为 ID，标准名称 `Qwen3.8-Flash` 使用网关的 `display_name`。不写死名称映射或模型列表。表格中的超长字段截断至 80 字符，完整值保留在 `--json` 中。未知 context/output 显示 `-`（JSON 为 `null`），未知能力显示 `?`；reasoning 为 true 但 effort 列表为空时，不编造可选档位。
- `group/...` 标记为 routing group，不计作直接模型。`--provider` 按网关的 `owned_by` 过滤，因此也包含由该 provider 支撑的 group。`--json` 输出 `magpie_url`、`count` 和规范化的 `models[]`（`id`、`display_name`、`provider`、`type` 及上述能力字段）。
- `status` 检查 **本机 PATH** 中的 Magpie binary/version，以及 **指定 URL** 的目录是否可读取；二者分别报告。模型总数区分 direct/groups，provider 数量只统计直接模型。网关目录可读时退出码为 0，即使本机没有 binary；请求、超时或目录格式错误时为 1。空目录是有效状态，不代表请求失败。JSON 输出 `binary`、`gateway`、`catalog`；目录失败时 `catalog` 为 `null`。

只发 GET 目录请求，`status` 另执行本机 `magpie --version`（若已安装）。不启动或停止 Magpie，不发送推理请求、不验证 provider 登录或配额，不修改 CPAC state 或任何 agent 配置。**目录可见不等于模型调用成功。** 本阶段未增加 `install --source magpie`，现有 install/sync/agent 启动仍使用 CPA。

### Claude Code

通过 CPA 启动 Claude Code，后续所有原生参数原样传递（如 `-c` 继续会话、`--model` 等）：

```bash
cpac claude
cpac claude -c                         # 继续上一次对话（原生 -c 原样直通）
cpac claude --model claude-sonnet-4-5
cpac claude -- -p "检查当前项目"
```

#### 配置与清除

```bash
cpac setup claude                      # 交互式依次配置 Sonnet / Haiku / Opus（不启动）
cpac claude setup                      # 同上，完成后启动
cpac claude clear                      # 重置所有覆盖，恢复自动选择
```

未设置的槽位启动时自动选择：claude 池内同家族模型优先，否则按 gemini → grok → luna → 目录第一个回退；opus 无匹配则不设。

所有设定写入配置文件持久缓存，每次 `cpac claude` 启动自动生效。

`--opus` / `--sonnet` / `--haiku` 对应 `ANTHROPIC_DEFAULT_*_MODEL`（haiku 同时写入 `ANTHROPIC_SMALL_FAST_MODEL`）。旧版的 `--classifier` 已移除：`CLAUDE_CODE_AUTO_MODE_MODEL` 在 Claude Code 2.1.224 上不被读取，Auto mode 分类器由官方自选（默认 Sonnet 5）；现版本唯一能影响分类器替身的旋钮是 `--sonnet`（副作用：同时改 `sonnet` 别名）。完整选择顺序、回退规则与出处见 [docs/claude-auto-mode-classifier.md](docs/claude-auto-mode-classifier.md)。

你自己 export 同名环境变量时以你为准。

Claude Code 的发现协议不携带 context 信息，claude 前缀的未知模型默认按 200K 记账，且 `CLAUDE_CODE_MAX_CONTEXT_TOKENS` 对 claude 前缀的名字不生效。cpac 采用与 opencodex 相同的机制：目录里窗口足够大的别名模型会带 `[1m]` 标记出现在选择器中（Claude Code 按 1M 记账，发请求前自己剥掉标记），同时 `cpac claude` 注入 `CLAUDE_CODE_AUTO_COMPACT_WINDOW`（默认 350K，与 opencodex 一致，接受范围 100K–1M）作为压缩阈值。你自己 export 该变量时以你为准。claude 系模型如需 1M 窗口，在模型名后加 `[1m]`（如 `cpac claude --model claude-sonnet-4-6[1m]`）。

> CPA 服务端必须支持 Claude Code 使用的 Anthropic Messages API（`/v1/messages`）。

### Codex

启动 Codex，后续所有原生参数原样传递（如 `-c` 动态覆盖配置、`exec` 等）：

```bash
cpac codex                             # 自动确保注入和代理后拉起 Codex
cpac codex -c model="gpt-5"            # 动态覆盖 Codex 配置（原生 -c 原样直通）
cpac codex exec "帮我写一个测试"
```

#### 配置与清除

```bash
cpac setup codex                       # 交互式配置后注入（不启动）
cpac codex setup                       # 同上，完成后启动 Codex
cpac codex clear                       # 还原原生配置、停止 Codex 共享后台并清理模型缓存
```

`cpac codex clear` 在还原配置后，会调用 `codex app-server daemon stop` 停止该配置目录的共享后台，并删除 `models_cache.json`。下一次直接运行 `codex` 会重新加载配置和模型目录。停止后台会断开连接它的会话，请在现有任务结束后清理；旧版 Codex 没有共享后台时只清缓存。后台停止或缓存清理失败会返回非零状态，修复后可以重复执行 `cpac codex clear`，即使注入记录已经移除。`--dry-run` 不停止后台、不清缓存。单独运行的 Codex App 或 `--no-daemon` 会话仍需重新启动。

清理后用 `codex` 启动原生模式；`cpac codex` 会重新注入 CPA。旧版 CPAC 清理后仍显示旧目录时，可先运行 `codex --no-daemon`；需要恢复普通启动时，在任务结束后运行 `codex app-server daemon restart`。

#### 注入（`cpac install codex`）

```bash
cpac install codex [--v2_off] [--v2_models] [--max_context]
cpac codex clear
```

`install codex` 从远端 `/v1/models?client_version=1` 获取 Codex rich catalog，并启动只监听 `127.0.0.1` 的轻量转发代理。Codex 配置保留内置 `openai` provider，只写入根级 `model_catalog_json` 和：

```toml
openai_base_url = "http://127.0.0.1:10101/v1"
```

Codex App/CLI 发给本地代理的 ChatGPT bearer 不会转发到 CPA；代理会改用 `CPA_API_KEY`，并将请求和流式响应原样转发到远端 CPA。这保留了 Codex App 的原生 `openai` provider 身份、历史和账号相关界面。已有用户自定义根级 `openai_base_url` 或非 `openai` 的活动 `model_provider` 时，CPAC 会拒绝覆盖。

Codex 共享后台会缓存模型目录，因此注入、更新和移除都需要刷新运行时。每次实际写入 Codex 注入配置后，CPAC 会停止该配置目录的共享后台并删除 `models_cache.json`；下一次启动会读取新配置。停止失败会报错，`cpac codex` 不会在这类自动同步失败后继续启动。模型目录未变而跳过写入的 `sync` 不停止后台。注入或更新前请等待现有任务结束；单独运行的 Codex App 或 `--no-daemon` 会话仍需重启。

注入命令可选 `--max_context`（`cpac install codex --max_context`，默认不带）：把 catalog 中 `max_context_window` 高于 `context_window` 的模型提升到上限，并把 `auto_compact_token_limit` 设为上限的 90%。Codex 把 `context_window` 当输入预算而非展示标签，上游默认保留保守运营值（如 GPT-5.6 家族 272k），带上该参数后可用到实测上限（约 921k，opencodex 实测）；90% 压缩线确保在硬上限前触发 auto-compact。不带参数注入的仍是原本上下文的目录。该参数仅限 codex，与其他 target 组合使用会直接报错。

`config.toml` 不存在时拒绝注入。当前是 native 时把原文件备份到 `state_dir/codex/config.toml`（覆盖更旧的 native 快照）；已注入后再装不覆盖备份。kimi/grok/zed/hermes/pi/codebuddy 同样：没有旧配置不写空备份，native 覆盖旧快照，已接入则保留。所有 target 的 clear 都按 Codex 规则：注入后记下文件 hash；相对注入未改则逐字节还原备份（没有备份则删除我们创建的文件）；注入后改过则只剥 CPAC 字段，用户改动留下。没有其它需要代理的 agent 时才关闭代理。

loopback 代理是 detached 用户进程，不安装系统服务。机器重启或进程意外退出后，`cpac status` 会报告 `loopback proxy stopped`；重新执行 `cpac install codex` 或 `cpac pi` / `cpac kimi` / `cpac grok` / `cpac zed` / `cpac hermes` / `cpac codebuddy` 即可恢复。

默认路径：

```text
Codex 配置：$CODEX_HOME/config.toml，未设置 CODEX_HOME 时为 ~/.codex/config.toml
CPAC state：~/.cpac/state.json（公用 proxy 字段 + 已接入 agent 记录）
各 agent 配置备份：~/.cpac/<agent>/<原文件名>
  Codex  ~/.cpac/codex/config.toml
  Kimi   ~/.cpac/kimi/config.toml
  Grok   ~/.cpac/grok/config.toml
  Zed    ~/.cpac/zed/settings.json
  Hermes ~/.cpac/hermes/config.yaml
  Pi     ~/.cpac/pi/models.json
  CodeBuddy ~/.cpac/codebuddy/models.json
`<agent> clear` 会删掉该 agent 的备份目录和 state.json 里的对应记录
```

为防止误删或覆盖，`state_dir` 不能是文件系统根目录、用户 home、系统临时目录，也不能包含 Codex 配置文件。

### Pi

```bash
cpac install pi
cpac pi
```

它在 `~/.pi/agent/models.json` 的 `providers.cpac` 写入 loopback `baseUrl`、占位 `apiKey`、`api: openai-responses`，以及 CPA catalog 的模型列表。每个模型的 `cost` 是 USD / 百万 token（input / output / cacheRead / cacheWrite）。注入时若 `~/.cpac/model-prices.json` 超过 24 小时会从 [models.dev](https://models.dev) 刷新：拉到的价格与缓存对比，有差异才更新，这次没拉到的条目保留（官方价优先，否则 OpenRouter；拉取失败则用已有缓存或打包快照）；未知模型为 0。不修改 `defaultProvider` / `defaultModel`；切换用 `/model`。密钥由 loopback 注入。旧的 `npm:@yhong91/cpac` package 和 `extensions/pi-cpac.ts` 会在 install / clear 时删掉。

`cpac pi`、`cpac install pi` 和 `cpac sync pi` 也会合并 `settings.json`：`enabledModels` 保留现有顺序、其他 provider 和模型 pattern，追加缺少的 `cpac/<slug>`，移除 CPA 已下架的精确模型项；`modelThinkingLevels` 按 **Pi 当前值 → `state_dir/models.json` 的同名缓存字段 → `xhigh`** 选择。缓存只保存 CPAC 模型的思考强度，不改变模型目录版本；下架模型的思考设置从 Pi 移除，但缓存保留，模型重新出现时可恢复。其他 Pi 设置不变，settings symlink 也会保留。注意 `enabledModels` 同时影响新会话启动选择，已有首项不会被重排。

卸载：`cpac pi clear`，同时移除这两个设置中的 CPAC 项，保留其他 provider 的配置。尊重 `PI_CODING_AGENT_DIR`。

### Kimi Code

写入 CPA provider 配置到 Kimi Code：

```bash
cpac kimi install
```

它在 `~/.kimi-code/config.toml` 追加一个由 CPAC 管理的块，注册 `cpac` OpenAI 兼容 provider，并把 CPA 目录里的每个模型映射为一个 `cpac/<模型名>` 条目。带 `supported_reasoning_levels` 的模型会写入 `capabilities`、`support_efforts` 和 `default_effort`，否则 Kimi 只给 Claude 名套内置 thinking profile，其它模型会停在 thinking off 且无法改 effort。`base_url` 指向共享 loopback 代理，因此密钥不落盘。install 会写入 `state.json` 并在需要时启动代理，不必先单独注入 Codex。`clear` 未改过注入文件则还原备份，改过则只剥 CPAC 块。卸载与状态：

```bash
cpac kimi clear
```

Kimi Code 配置目录尊重 `KIMI_CODE_HOME` 环境变量。首次写入前若 `config.toml` 已存在，会在 `state_dir/kimi/config.toml` 保留一份原始快照（只存最早版本），万一文件损坏可手动复制回去。

### Zed

写入 CPA 的 OpenAI-compatible provider 到 Zed Agent：

```bash
cpac install zed
cpac zed
```

它在 `~/.config/zed/settings.json` 的 `language_models.openai_compatible.cpac` 写入 `api_url`（指向共享 loopback 代理）和 CPA 目录里的 `available_models`。模型走 Responses API（`chat_completions: false`），与 Pi / Grok 一致。密钥不写进 settings：`cpac zed` 会注入占位 `CPAC_API_KEY`；从 Dock 打开 Zed 时在 Agent Settings 里给 `cpac` provider 填任意非空值（loopback 会换成真正的 `CPA_API_KEY`）。这是 Zed 内置 Agent 的 OpenAI-compatible provider，不是 Codex ACP（`codex-acp`）。卸载：

```bash
cpac zed clear
```

配置目录尊重 `ZED_CONFIG_DIR`（否则 `$XDG_CONFIG_HOME/zed` 或 `~/.config/zed`）。首次写入前若 `settings.json` 已存在，会在 `state_dir/zed/settings.json` 保留原始快照。

### Hermes Agent

写入 CPA 的自定义 OpenAI-compatible provider 到 Hermes：

```bash
cpac install hermes
cpac hermes
```

它在 default `~/.hermes/config.yaml` 以及每个 `~/.hermes/profiles/<name>/config.yaml` 的 `providers.cpac` 写入 loopback `base_url`/`api`、占位 `api_key`、`api_mode: responses`，以及 CPA catalog 的 slug 列表（`discover_models: false`）。不改当前默认模型；切换用 `hermes model` 或 `/model`。密钥由 loopback 注入，不写进 `.env`。新建 profile 后再跑一次 `cpac install hermes`（或 `cpac hermes`）即可写入。卸载：

```bash
cpac hermes clear
```

配置目录尊重 `HERMES_HOME`（Windows 默认 `%LOCALAPPDATA%\hermes`）。首次写入前若 default `config.yaml` 已存在，会在 `state_dir/hermes/config.yaml` 保留原始快照。profile 文件不单独备份，clear 只剥 `providers.cpac`。

### CodeBuddy

把 CPA 目录写成 CodeBuddy 的自定义模型：

```bash
cpac install codebuddy
cpac codebuddy                       # 启动；原生参数原样直通
cpac codebuddy -p "检查当前项目"       # 非交互模式
```

`~/.codebuddy/models.json` 是 CodeBuddy 官方放置第三方模型的地方，CPAC 只做**合并**：为每个 catalog slug 写一条 `models[]` 条目（`vendor: "CPAC"`、占位 `apiKey`（`cpac`）、`url` 指向 loopback `/v1/chat/completions`），你在同一文件里自己加的模型条目原样保留。loopback 代理把入站 Authorization 换成真实 `CPA_API_KEY`。

- 字段映射：`name` 和 `id` 都用 catalog slug，不用 `display_name`。CodeBuddy 会把 `id` 改成 `custom-local:<slug>`，`/model` 和 `--model` 只按 `name` 或 `id` 匹配，不认 alias。`maxInputTokens` 取 `context_window`（不是 `max_context_window`），`maxOutputTokens` 取 `max_output_tokens`，catalog 没给就不写这两个键；`supportsImages` / `supportsReasoning` 按 `input_modalities` / `supported_reasoning_levels` 推导，`supportsToolCall` 恒为 true。
- 不写 `relatedModels`：CodeBuddy 的 lite / reasoning 场景因此回落到主模型，而不是借用内置默认值。
- `availableModels` 只在你已经设置过时才改写（缺失即「显示全部」）；改写只并入 CPA slug，不会删掉你列出的 id。
- 归属识别：`apiKey` 为 `cpac` 且 `url` 是 loopback `…/chat/completions` 的条目才算 CPAC 的，`cpac sync codebuddy` 只替换这些条目。
- 恢复：注入后未改 → 逐字节还原原文件（原本没有该文件则删除它）；改过 → 只剥 CPAC 条目，你的模型和 `availableModels` 留下。
- 模型选择仍由 CodeBuddy 决定：用 `/model` 选 CPA 模型或用 `CODEBUDDY_MODEL` 指定默认模型，CPAC 不改 `settings.json`。

配置目录尊重 `CODEBUDDY_CONFIG_DIR`（否则 `~/.codebuddy`）。首次写入前若 `models.json` 已存在，会在 `state_dir/codebuddy/models.json` 保留原始快照。官方字段、`availableModels` 和 2.105.2 的 `custom-local:` 前缀见 `docs/codebuddy-models.md`。

### 手动打开 5h 窗口

本机手动发一条最小请求，用来激活当前 5h 额度。不定时，也不查配额。定时仍在 VPS 的 `scripts/quota-heartbeat.py`。

```bash
cpac ping codex    # 目录里匹配 gpt-*-luna 的一条
cpac ping agy      # 目录里匹配 gemini-*-flash* 的一条，以及 claude-sonnet-4-6
```

用 `CPA_API_KEY`。日志只打模型、HTTP 状态和不含 key 的 `x-cpa-*` trace。CPA 按账号轮询，一次只会落在一个账号上。

## 环境变量

| 变量 | 默认值 | 作用 |
| --- | --- | --- |
| `CPA_API_KEY` | 无 | CPA Bearer key；可由 `cpac` 首次引导写入 shell 启动文件；`cpac ping` 也用它 |
| `CPA_BASE_URL` | `http://124.223.178.52:8317` | 覆盖内置 CPA 地址 |
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | 覆盖 Pi agent 目录（影响 `models.json` 写入位置） |
| `KIMI_CODE_HOME` | `~/.kimi-code` | 覆盖 Kimi Code 目录（影响 `cpac install kimi` 写入位置） |
| `ZED_CONFIG_DIR` | `~/.config/zed` | 覆盖 Zed 配置目录（影响 `cpac install zed` 写入位置） |
| `HERMES_HOME` | `~/.hermes` | 覆盖 Hermes 目录（影响 `cpac install hermes` 写入位置） |
| `CODEBUDDY_CONFIG_DIR` | `~/.codebuddy` | 覆盖 CodeBuddy 配置目录（影响 `cpac install codebuddy` 写入的 `models.json` 位置） |
| `CPAC_CONFIG` | `~/.config/cpac/config.json` | 指定可选 JSON 配置路径 |
| `CODEX_HOME` | `~/.codex` | Codex home 目录 |

CPAC CLI 可临时覆盖 CPA 地址：

```bash
CPA_BASE_URL='https://cpa.example.com' cpac claude
```

Pi 扩展只从进程环境读取 `CPA_BASE_URL`（默认内置地址）和 `CPA_API_KEY`；不读取 `config.json` 的 `cpa_url`，也不读用户 home 中的私有文件。

## 可选 JSON 配置

默认场景不需要配置文件，文件不存在时 CPAC 直接使用内置默认值，也不会创建目录。仅在需要覆盖 Codex 路径、state 目录或密钥变量名时创建配置，例如：

```json
{
  "cpa_url": "https://cpa.example.com",
  "api_key_env": "CPA_API_KEY",
  "codex_config": "~/.codex/config.toml",
  "codex_proxy_port": 10101,
  "state_dir": "~/.cpac"
}
```

支持字段：

- `cpa_url`：可选，绝对 `http(s)` URL，可带或不带 `/v1`
- `api_key_env`：可选，密钥环境变量名，默认 `CPA_API_KEY`
- `codex_config`：可选，Codex 配置路径
- `codex_proxy_port`：可选，本地 Codex 转发端口，默认 `10101`；设为 `0` 时自动选择空闲端口
- `state_dir`：可选，CPAC state 路径

使用自定义配置：

```bash
cpac install codex --config ./cpac.json
cpac claude --config ./cpac.json -- --model claude-sonnet-4-5
```

也可以设置：

```bash
export CPAC_CONFIG=/path/to/cpac.json
```

## 安全行为

- API key 不写入 CPAC JSON、Codex 配置、备份、state、catalog 或日志。
- Codex loopback 代理仅监听 `127.0.0.1`，拒绝非本地浏览器 Origin，并在内存中用 CPA key 替换入站 Authorization。
- 引导输入不回显，写入 shell 时会正确引用特殊字符。
- shell 启动文件和 Codex 配置均通过同目录临时文件原子替换。
- CPA 请求失败、catalog 无效或 key 缺失时，首次注入不会修改 Codex 配置。
- `clear` 只删除 CPAC 自有的 state、backup 和 catalog，不删除 `state_dir` 中的其他文件。
