@yhong91/cpac 0.1.33 → 0.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,18 +38,18 @@ cpac status
38
38
 
39
39
  # 4a. 持久注入(长期生效,写入 agent 配置,可完整恢复)
40
40
  cpac install --all # 注入所有检测到的目标(codex/pi/kimi)
41
- cpac install --target codex # 只注入 Codex(默认开启 multi-agent v2)
42
- cpac install --target codex --v2_models # 先多选 spawn_agent 模型再注入
43
- cpac install --target codex --max_context # 注入时把模型上下文提升到实测上限(opt-in,仅限 codex)
44
- cpac restore --target codex # 撤掉注入;注入期间的用户改动会留下
41
+ cpac install codex # 只注入 Codex(默认开启 multi-agent v2)
42
+ cpac install codex --v2_models # 先多选 spawn_agent 模型再注入
43
+ cpac install codex --max_context # 注入时把模型上下文提升到实测上限(opt-in,仅限 codex)
44
+ cpac restore codex # 撤掉注入;注入期间的用户改动会留下
45
45
 
46
46
  # 4b. 临时接管(退出无痕,不写任何配置文件)
47
47
  cpac claude # Claude Code 走 CPA
48
48
  cpac opencode # opencode 走 CPA(模型选 cpac/<模型名>)
49
49
 
50
50
  # 5. 可选:Agent 配置向导与模型选择
51
- cpac codex --setup # Codex 配置向导 → 注入 → 启动
52
- cpac claude --setup # Claude 模型向导 → 启动
51
+ cpac setup codex # Codex 配置向导 → 注入 → 启动
52
+ cpac setup claude # Claude 模型向导 → 启动
53
53
 
54
54
  # 6. 升级(装上新版本后自动 sync 已接入的 agent)
55
55
  cpac upgrade
@@ -80,7 +80,7 @@ cpac status # 验证:CPA_API_KEY 应显示 configured
80
80
  }
81
81
  ```
82
82
 
83
- Claude 槽位(opus/sonnet/haiku)通常不用配:cpac 启动时自动选择——同家族 claude 模型优先,否则 gemini → grok → luna → 目录第一个;opus 无匹配则不设。这个链条在常见目录上正好给出理想结果:sonnet 落在 claude-sonnet-*(它同时充当 Auto mode 分类器的替身,避免分类请求失败后回退到昂贵的会话主模型),haiku 落在快的 gemini flash。只有目录奇怪时才用 `cpac claude --setup` 交互式配置。codex spawn subagent 取三个 GPT + gemini + grok 五席(顺序即优先级,Codex 只广告 catalog 前 5),可通过 `cpac codex --setup` 交互式配置。候选替换:`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)。
83
+ 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)。
84
84
 
85
85
  1. **持久注入**(只对检测到的目标;codex 会应用步骤 3 的 spawn_models):
86
86
 
@@ -91,12 +91,13 @@ cpac status # 验证:各 target 显示 ready/injected
91
91
 
92
92
  1. **统一启动与配置**:
93
93
  - 启动:`cpac <codex|claude|kimi|grok|pi|opencode> [args...]`(所有原生参数如 `-c` 等原样透明传递)
94
- - 配置并启动:`cpac <codex|claude> --setup`(向导结束后注入并拉起)
95
- - 还原:`cpac <agent> clear`(还原或重置配置)
94
+ - `setup` / `--setup`:配置 Codex/Claude,然后启动
95
+ - `clear`:还原原生配置
96
+ - 查看当前设置:`cpac setup`
96
97
 
97
98
  2. **已安装后升级**:npm 发布新版本后,等 publish 成功再执行 `cpac upgrade`。它会按需 `npm install -g`,再对已接入的 Codex / Pi / Kimi / Grok 做 `sync`。不要拆成 `npm install -g @yhong91/cpac` 再手动 `cpac sync`。只刷新配置、不升 CLI 时才用 `cpac sync`。
98
99
 
99
- 失败处理:任何一步报错时先跑 `cpac status`;密钥未配置回到步骤 2;注入后异常用 `cpac <agent> clear` 或 `cpac restore --target <id>` 恢复原配置。
100
+ 失败处理:任何一步报错时先跑 `cpac status`;密钥未配置回到步骤 2;注入后异常用 `cpac <agent> clear` 或 `cpac restore <id>` 恢复原配置。
100
101
 
101
102
  ## 首次引导
102
103
 
@@ -109,10 +110,10 @@ CPA: http://124.223.178.52:8317
109
110
  CPA_API_KEY: configured / not configured
110
111
 
111
112
  Commands:
112
- cpac claude [args...] Launch Claude Code through CPA
113
- cpac inject Inject CPA into Codex
114
- cpac status Show Codex injection status
115
- cpac restore --target <id> | --all Detach injected agents
113
+ cpac <agent> [args...] Launch an agent through CPA
114
+ cpac setup Show current Codex/Claude setup
115
+ cpac status Show agent support status
116
+ cpac restore <id> | --all Detach injected agents
116
117
  cpac --help Show command usage
117
118
  ```
118
119
 
@@ -164,21 +165,21 @@ cpac --help
164
165
 
165
166
  ```bash
166
167
  cpac detect [--json] [--home PATH]
167
- cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]
168
- cpac sync [--target codex,pi,kimi] [--all] [--dry-run] [--v2_off] [--v2_models] [--max_context] [--home PATH]
169
- cpac restore --target <id> | --all [--dry-run] [--home PATH]
168
+ cpac install [codex|pi|kimi|grok...] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]
169
+ cpac sync [codex|pi|kimi|grok...] [--all] [--dry-run] [--v2_off] [--v2_models] [--max_context] [--home PATH]
170
+ cpac restore <id...> | --all [--dry-run] [--home PATH]
170
171
  cpac uninstall [--dry-run]
171
172
  cpac upgrade [--check]
172
173
  cpac -v | --version
173
174
  ```
174
175
 
175
176
  - `detect` 列出每个目标是否被检测到、是否已接入 CPAC;`--json` 输出机器可读结果。
176
- - `install` 默认作用于检测到的目标;`--target` 指定目标、`--all` 全部。各目标映射到既有逻辑:`codex` `cpac inject`,`pi` `cpac pi install`,`kimi` `cpac kimi install`。`--dry-run` 只打印将要做的事,`--force` 允许重装已安装目标。
177
- - `sync` 按当前 `cpa_url` 和 CPA 目录强制刷新**已经接入**的目标(Codex 重新注入、Pi 确认 `npm:@yhong91/cpac` 并清理旧的 `extensions/pi-cpac.ts`、Kimi 配置重写),用来在 CPA 地址或模型目录变化后一次对齐本地配置。不带参数只动已安装目标;`--all` 会对检测到的目标做同样的强制刷新(尚未安装的会装上)。`--max_context` 仍只对 `--target codex` 有效。
178
- - Codex 注入默认开启 multi-agent v2(写入 `[features.multi_agent_v2] enabled = true`,catalog 行打 `multi_agent_version: "v2"`);`install --target 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`。
177
+ - `install` 默认作用于检测到的目标;后面直接写 agent 名(`cpac install codex pi`),`--all` 全部。`codex` 写入 catalog 并拉起 loopback 代理;`pi`/`kimi`/`grok` 写入各自配置。`--dry-run` 只打印将要做的事,`--force` 允许重装已安装目标。
178
+ - `sync` 按当前 `cpa_url` 和 CPA 目录强制刷新**已经接入**的目标(Codex 重新注入、Pi 确认 `npm:@yhong91/cpac` 并清理旧的 `extensions/pi-cpac.ts`、Kimi 配置重写),用来在 CPA 地址或模型目录变化后一次对齐本地配置。不带参数只动已安装目标;`--all` 会对检测到的目标做同样的强制刷新(尚未安装的会装上)。`--max_context` 仍只对 `cpac install codex` 有效。
179
+ - 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`。
179
180
  - `--v2_models` 进入 arrow-key 复选框选择最多 5 个 spawn_agent 模型(勾选顺序即推荐顺序),选择结果存入配置文件的 `spawn_models`,注入时把这些模型排到 `codex-models.json` 最前——Codex 客户端只把 catalog 前 5 个可见模型广告为 spawn 覆盖项。
180
- - `restore` 必须带 `--target` `--all`,卸掉指定(或全部)已注入目标。`--all` 时未安装的目标静默跳过。
181
- - `uninstall` 先用和 `cpac codex --setup` 相同的方向键选择器确认(默认 Cancel),再 `restore --all`,最后 `npm uninstall -g @yhong91/cpac`。不要用 `--target`。非终端取消。`--dry-run` 跳过确认。
181
+ - `restore` 必须带 agent 名或 `--all`,卸掉指定(或全部)已注入目标。`--all` 时未安装的目标静默跳过。
182
+ - `uninstall` 先用和 `cpac setup codex` 相同的方向键选择器确认(默认 Cancel),再 `restore --all`,最后 `npm uninstall -g @yhong91/cpac`。不要跟 agent 名;卸载的是 cpac 包本身。非终端取消。`--dry-run` 跳过确认。
182
183
  - `--home PATH` 临时把 `HOME` 指向给定目录,便于在隔离环境中试验。
183
184
  - `upgrade` 是发布后更新本机的一次性入口:查 npm → 需要时 `npm install -g` → 对**已接入**的 Codex / Pi / Kimi 执行 `sync`。已是最新也会 sync。不要先手动 `npm install -g` 再 `cpac sync`。`--check` 只报告版本,不安装也不 sync。没有已安装目标时跳过 sync,不报错。只刷新配置、不升 CLI 时用 `cpac sync`。
184
185
 
@@ -196,7 +197,7 @@ cpac claude -- -p "检查当前项目"
196
197
  #### 配置与清除
197
198
 
198
199
  ```bash
199
- cpac claude --setup # 交互式依次配置 Sonnet / Haiku / Opus,然后启动
200
+ cpac setup claude # 交互式依次配置 Sonnet / Haiku / Opus,然后启动
200
201
  cpac claude clear # 重置所有覆盖,恢复自动选择
201
202
  ```
202
203
 
@@ -225,18 +226,18 @@ cpac codex exec "帮我写一个测试"
225
226
  #### 配置与清除
226
227
 
227
228
  ```bash
228
- cpac codex --setup # 交互式配置后注入并启动 Codex
229
+ cpac setup codex # 交互式配置后注入并启动 Codex
229
230
  cpac codex clear # 还原 Codex 原生配置并关闭代理
230
231
  ```
231
232
 
232
- #### 传统注入命令
233
+ #### 注入(`cpac install codex`)
233
234
 
234
235
  ```bash
235
- cpac inject [--v2_off] [--v2_models] [--max_context] [--config PATH]
236
- cpac restore --target codex
236
+ cpac install codex [--v2_off] [--v2_models] [--max_context] [--config PATH]
237
+ cpac restore codex
237
238
  ```
238
239
 
239
- `inject` 从远端 `/v1/models?client_version=1` 获取 Codex rich catalog,并启动只监听 `127.0.0.1` 的轻量转发代理。Codex 配置保留内置 `openai` provider,只写入根级 `model_catalog_json` 和:
240
+ `install codex` 从远端 `/v1/models?client_version=1` 获取 Codex rich catalog,并启动只监听 `127.0.0.1` 的轻量转发代理。Codex 配置保留内置 `openai` provider,只写入根级 `model_catalog_json` 和:
240
241
 
241
242
  ```toml
242
243
  openai_base_url = "http://127.0.0.1:10101/v1"
@@ -244,21 +245,13 @@ openai_base_url = "http://127.0.0.1:10101/v1"
244
245
 
245
246
  Codex App/CLI 发给本地代理的 ChatGPT bearer 不会转发到 CPA;代理会改用 `CPA_API_KEY`,并将请求和流式响应原样转发到远端 CPA。这保留了 Codex App 的原生 `openai` provider 身份、历史和账号相关界面。已有用户自定义根级 `openai_base_url` 或非 `openai` 的活动 `model_provider` 时,CPAC 会拒绝覆盖。
246
247
 
247
- Codex App 的长驻 `app-server` 可能缓存旧目录。`inject` 会删除 `models_cache.json`;如果选择器仍未更新,请重启 Codex App。
248
+ Codex App 的长驻 `app-server` 可能缓存旧目录。注入会删除 `models_cache.json`;如果选择器仍未更新,请重启 Codex App。
248
249
 
249
- 注入命令可选 `--max_context`(`cpac inject --max_context` 或 `cpac install --target 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 组合使用会直接报错。
250
+ 注入命令可选 `--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 组合使用会直接报错。
250
251
 
251
- `config.toml` 不存在时拒绝注入。当前是 native 时把原文件备份到 `state_dir/codex/config.toml`(覆盖更旧的 native 快照);已注入后再 inject 不覆盖备份。kimi/grok 同样:没有旧配置不写空备份,native 覆盖旧快照,已接入则保留。Pi 只改 `settings.json` 的 `packages`,不备份。`restore --target codex`:若 `config.toml` 相对注入未改,按原 mode 逐字节还原备份;若用户在注入期间改过文件,只撤掉 CPAC 写入的 catalog、url 和标记。没有其它需要代理的 agent 时才关闭代理。
252
+ `config.toml` 不存在时拒绝注入。当前是 native 时把原文件备份到 `state_dir/codex/config.toml`(覆盖更旧的 native 快照);已注入后再装不覆盖备份。kimi/grok 同样:没有旧配置不写空备份,native 覆盖旧快照,已接入则保留。Pi 只改 `settings.json` 的 `packages`,不备份。`restore codex`:若 `config.toml` 相对注入未改,按原 mode 逐字节还原备份;若用户在注入期间改过文件,只撤掉 CPAC 写入的 catalog、url 和标记。没有其它需要代理的 agent 时才关闭代理。
252
253
 
253
- loopback 代理是 detached 用户进程,不安装系统服务。机器重启或进程意外退出后,`cpac status` 会报告 `loopback proxy stopped`;重新执行 `cpac inject` 或 `cpac kimi` / `cpac grok` 即可恢复。
254
-
255
- 需要由现有进程管理器监督时,可使用前台入口:
256
-
257
- ```bash
258
- cpac proxy
259
- ```
260
-
261
- 它复用 `state.json` 里记录的端口和实例身份;没有 loopback 记录时会拒绝启动。
254
+ loopback 代理是 detached 用户进程,不安装系统服务。机器重启或进程意外退出后,`cpac status` 会报告 `loopback proxy stopped`;重新执行 `cpac install codex` 或 `cpac kimi` / `cpac grok` 即可恢复。
262
255
 
263
256
  默认路径:
264
257
 
@@ -293,7 +286,7 @@ cpac pi install
293
286
  在 `~/.pi/agent/settings.json` 的 `packages` 中加入 `npm:@yhong91/cpac`。Pi 启动时按 npm 包加载 `extensions/pi-cpac.ts`,从 CPA 动态注册模型。旧版写入的 `~/.pi/agent/extensions/pi-cpac.ts` 会在 install / restore 时删掉。卸载:
294
287
 
295
288
  ```bash
296
- cpac restore --target pi
289
+ cpac restore pi
297
290
  ```
298
291
 
299
292
  尊重 `PI_CODING_AGENT_DIR`。扩展代码随 npm 包更新,已装过的副本用 `pi update npm:@yhong91/cpac`(或 `pi update --extensions`)。
@@ -306,10 +299,10 @@ cpac restore --target pi
306
299
  cpac kimi install
307
300
  ```
308
301
 
309
- 它在 `~/.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` 并在需要时启动代理,不必先 `cpac inject`。卸载与状态:
302
+ 它在 `~/.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。卸载与状态:
310
303
 
311
304
  ```bash
312
- cpac restore --target kimi
305
+ cpac restore kimi
313
306
  ```
314
307
 
315
308
  Kimi Code 配置目录尊重 `KIMI_CODE_HOME` 环境变量。首次写入前若 `config.toml` 已存在,会在 `state_dir/kimi/config.toml` 保留一份原始快照(只存最早版本),万一文件损坏可手动复制回去。
@@ -358,7 +351,7 @@ Pi 扩展只从进程环境读取 `CPA_BASE_URL`(默认内置地址)和 `CPA
358
351
  使用自定义配置:
359
352
 
360
353
  ```bash
361
- cpac inject --config ./cpac.json
354
+ cpac install codex --config ./cpac.json
362
355
  cpac claude --config ./cpac.json -- --model claude-sonnet-4-5
363
356
  ```
364
357
 
package/dist/agents.js CHANGED
@@ -313,12 +313,12 @@ export async function runInstall(config, requested, options) {
313
313
  const eligible = TARGETS.filter((target) => target.detected()).map((target) => target.id);
314
314
  const selected = selectTargets(requested, options.all, eligible);
315
315
  if (selected.length === 0) {
316
- throw new CPACError(`no supported targets detected; use --target ${TARGETS.map((target) => target.id).join(",")} or --all`);
316
+ throw new CPACError(`no supported targets detected; use: cpac install ${TARGETS.map((target) => target.id).join(" ")} or --all`);
317
317
  }
318
318
  // Catalog context lifting is Codex-specific; refuse to silently skip it on
319
319
  // other targets so the flag never gains cross-agent meaning.
320
320
  if (options.maxContext && selected.some((target) => target.id !== "codex")) {
321
- throw new CPACError("--max_context is only valid with --target codex");
321
+ throw new CPACError("--max_context is only valid with codex");
322
322
  }
323
323
  for (const target of selected) {
324
324
  if (target.installed(config) && !options.force) {
@@ -353,7 +353,7 @@ export async function runSync(config, requested, options) {
353
353
  }
354
354
  export async function runRestore(config, requested, options) {
355
355
  if (requested.length === 0 && !options.all) {
356
- throw new CPACError("restore requires --target <id> or --all");
356
+ throw new CPACError("restore requires an agent name or --all");
357
357
  }
358
358
  const eligible = TARGETS.filter((target) => target.installed(config)).map((target) => target.id);
359
359
  const selected = selectTargets(requested, options.all, eligible);
package/dist/cpac.js CHANGED
@@ -4,14 +4,14 @@ import { createHash } from "node:crypto";
4
4
  import { join, resolve } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import { CPAC_VERSION, runCodexConfig, runDetect, runInstall, runRestore, runSync, runTargetLauncher, runUninstall, runUpgrade, } from "./agents.js";
7
- import { runClaude, runClaudeConfig, runClaudeModels, } from "./targets/claude.js";
8
- import { inject, multiAgentV2Enabled } from "./targets/codex.js";
7
+ import { runClaude, runClaudeConfig } from "./targets/claude.js";
8
+ import { multiAgentV2Enabled } from "./targets/codex.js";
9
9
  import { isGrokConfigInstalled } from "./targets/grok.js";
10
10
  import { isKimiConfigInstalled } from "./targets/kimi.js";
11
11
  import { runOpencode } from "./targets/opencode.js";
12
12
  import { isPiExtensionInstalled } from "./targets/pi.js";
13
13
  import { defaultConfigPath, loadConfig, originalBytes, pickSpawnModels, readState, saveSpawnModels, stateProxy, catalogMaxContextLive, } from "./config.js";
14
- import { proxyIsHealthy, runProxy, runProxyChild } from "./proxy.js";
14
+ import { proxyIsHealthy, runProxyChild } from "./proxy.js";
15
15
  import { CPACError, expandUserPath, promptSecret, saveApiKeyExport, shellProfile, } from "./util.js";
16
16
  export { PROVIDER, loadConfig, saveSpawnModels, saveCodexSetup, liftContextWindows, reorderCatalog, sanitizeCatalogModalities, stampMultiAgentVersion, catalogMaxContextLive, readState, stateProxy, } from "./config.js";
17
17
  export { saveApiKeyExport } from "./util.js";
@@ -69,11 +69,11 @@ export async function status(config) {
69
69
  }
70
70
  console.log(`claude: ${keyConfigured ? "ready" : "not configured"}`);
71
71
  const piInstalled = isPiExtensionInstalled();
72
- console.log(`pi: ${keyConfigured ? (piInstalled ? "ready" : "extension not installed; run: cpac install --target pi") : "not configured"}`);
72
+ console.log(`pi: ${keyConfigured ? (piInstalled ? "ready" : "extension not installed; run: cpac install pi") : "not configured"}`);
73
73
  const kimiInstalled = isKimiConfigInstalled();
74
- console.log(`kimi: ${keyConfigured ? (kimiInstalled ? "ready" : "config not installed; run: cpac install --target kimi") : "not configured"}`);
74
+ console.log(`kimi: ${keyConfigured ? (kimiInstalled ? "ready" : "config not installed; run: cpac install kimi") : "not configured"}`);
75
75
  const grokInstalled = isGrokConfigInstalled();
76
- console.log(`grok: ${keyConfigured ? (grokInstalled ? "ready" : "config not installed; run: cpac install --target grok") : "not configured"}`);
76
+ console.log(`grok: ${keyConfigured ? (grokInstalled ? "ready" : "config not installed; run: cpac install grok") : "not configured"}`);
77
77
  if (!state)
78
78
  return 1;
79
79
  const proxy = stateProxy(state);
@@ -82,9 +82,9 @@ export async function status(config) {
82
82
  return 0;
83
83
  }
84
84
  async function guide(config) {
85
- console.log(`CPA Companion\n\nCPA: ${config.cpa_url}\nCPA_API_KEY: ${process.env[config.api_key_env]?.trim() ? "configured" : "not configured"}\n\nCommands:\n cpac <agent> [args...] Launch an agent (codex, kimi, grok, pi, claude, opencode) through CPA\n cpac inject Inject CPA into Codex and start its loopback proxy\n cpac proxy Run the injected loopback proxy in the foreground\n cpac status Show agent support status (Codex, Claude, Pi, Kimi, Grok)\n cpac restore --target <id> | --all Detach injected agents
85
+ console.log(`CPA Companion\n\nCPA: ${config.cpa_url}\nCPA_API_KEY: ${process.env[config.api_key_env]?.trim() ? "configured" : "not configured"}\n\nCommands:\n cpac <agent> [args...] Launch an agent (codex, kimi, grok, pi, claude, opencode) through CPA\n cpac setup Show current Codex/Claude setup; cpac setup <codex|claude> to change\n cpac status Show agent support status (Codex, Claude, Pi, Kimi, Grok)\n cpac restore <id> | --all Detach injected agents
86
86
  cpac detect Show supported targets and install status
87
- cpac install Install CPA integration into detected targets
87
+ cpac install [ids...] Install CPA into detected targets, or named agents
88
88
  cpac sync Refresh installed Codex/Pi/Kimi/Grok injections from CPA
89
89
  cpac uninstall Detach all agents, then remove the cpac package (confirms first)\n cpac upgrade Update cpac from npm and sync installed agents\n cpac --help Show command usage`);
90
90
  if (process.env[config.api_key_env]?.trim())
@@ -102,23 +102,52 @@ function usage() {
102
102
  return [
103
103
  "Usage: cpac",
104
104
  " cpac <codex|kimi|grok|pi|claude|opencode> [args...]",
105
- " cpac <codex|claude> --setup [args...]",
106
- " cpac <codex|claude|kimi|grok|pi> clear",
107
- " cpac inject [--v2_off] [--v2_models] [--max_context] [--config PATH]",
108
- " cpac restore --target <id> | --all [--dry-run] [--config PATH]",
105
+ " setup|--setup configure Codex/Claude, then launch",
106
+ " clear restore native config",
107
+ " cpac setup [--config PATH] Show current Codex/Claude setup",
108
+ " claude [--opus [M]] [--sonnet [M]] [--haiku [M]] [--reset]",
109
+ " codex [--v2_off] [--v2_models] [--max_context]",
110
+ " cpac restore <id...> | --all [--dry-run] [--config PATH]",
109
111
  " cpac status [--config PATH]",
110
- " cpac proxy [--config PATH]",
111
112
  " cpac detect [--json] [--home PATH]",
112
- " cpac install [--target codex,pi,kimi,grok] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]",
113
- " cpac sync [--target codex,pi,kimi,grok] [--all] [--dry-run] [--v2_off] [--v2_models] [--max_context] [--home PATH]",
113
+ " cpac install [codex|pi|kimi|grok...] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]",
114
+ " cpac sync [codex|pi|kimi|grok...] [--all] [--dry-run] [--v2_off] [--v2_models] [--max_context] [--home PATH]",
114
115
  " cpac uninstall [--dry-run]",
115
116
  " cpac upgrade [--check]",
116
117
  " cpac -v | --version",
117
118
  "",
118
- "launch an agent directly with `cpac <agent> [args...]` (all args forwarded).",
119
- "configure then launch with `cpac <codex|claude> --setup`; restore with `cpac <agent> clear`.",
119
+ "launch an agent with `cpac <agent> [args...]` (remaining args forwarded).",
120
+ "`setup`/`clear` hang off the agent; `cpac setup` with no agent prints current settings.",
120
121
  ].join("\n");
121
122
  }
123
+ function setupUsage() {
124
+ return [
125
+ "Usage: cpac setup [--config PATH] Show current Codex/Claude setup",
126
+ " claude [--opus [M]] [--sonnet [M]] [--haiku [M]] [--reset]",
127
+ " codex [--v2_off] [--v2_models] [--max_context]",
128
+ "",
129
+ "Claude slots (saved to config, applied on every `cpac claude`):",
130
+ " --opus heavy reasoning / planning fallback (ANTHROPIC_DEFAULT_OPUS_MODEL)",
131
+ " --sonnet main conversation default (ANTHROPIC_DEFAULT_SONNET_MODEL)",
132
+ " --haiku high-frequency small tasks (ANTHROPIC_DEFAULT_HAIKU_MODEL)",
133
+ "",
134
+ "A slot without a value opens an arrow-key picker; --reset clears overrides.",
135
+ "No flags on a TTY opens the wizard, then launches.",
136
+ ].join("\n");
137
+ }
138
+ function printSetup(config, configPath) {
139
+ const claude = config.claude_models ?? {};
140
+ const auto = (value) => typeof value === "string" && value.trim() ? value.trim() : "(auto)";
141
+ console.log(`config ${configPath}`);
142
+ console.log(`codex spawn_models ${(config.spawn_models ?? []).join(", ") || "(catalog order)"}`);
143
+ console.log(`codex max_context ${config.max_context ? "on" : "off"}`);
144
+ console.log(`codex v2 ${config.v2_off ? "off" : "on"}`);
145
+ console.log(`claude opus ${auto(claude.opus)}`);
146
+ console.log(`claude sonnet ${auto(claude.sonnet)}`);
147
+ console.log(`claude haiku ${auto(claude.haiku)}`);
148
+ console.log("");
149
+ console.log(setupUsage());
150
+ }
122
151
  function parseArgs(args) {
123
152
  if (args.length === 0) {
124
153
  return { command: "guide", configPath: defaultConfigPath() };
@@ -184,6 +213,12 @@ function parseArgs(args) {
184
213
  else if (arg === "--max_context" || arg === "--max-context") {
185
214
  parsed.maxContext = true;
186
215
  }
216
+ else if (!arg.startsWith("-")) {
217
+ parsed.targets.push(...arg
218
+ .split(",")
219
+ .map((entry) => entry.trim())
220
+ .filter(Boolean));
221
+ }
187
222
  else {
188
223
  throw new CPACError(`unknown option: ${arg}`);
189
224
  }
@@ -297,7 +332,7 @@ function parseArgs(args) {
297
332
  args: launchArgs,
298
333
  };
299
334
  }
300
- throw new CPACError(`${targetId} does not require setup (all CPA models are auto-synced). Run 'cpac ${targetId}' or 'cpac install --target ${targetId}'.`);
335
+ throw new CPACError(`${targetId} does not require setup (all CPA models are auto-synced). Run 'cpac ${targetId}' or 'cpac install ${targetId}'.`);
301
336
  }
302
337
  const passArgs = rest;
303
338
  if (targetId === "codex") {
@@ -323,31 +358,75 @@ function parseArgs(args) {
323
358
  args: passArgs,
324
359
  };
325
360
  }
326
- if (args[0] === "claude-models") {
361
+ if (args[0] === "setup") {
327
362
  if (args.includes("-h") || args.includes("--help")) {
328
- console.log([
329
- "Usage: cpac claude --config [--opus [M]] [--sonnet [M]] [--haiku [M]] [--reset] [--config PATH]",
330
- "",
331
- "Sets the model Claude Code uses per task tier. Saved to the config file",
332
- "and applied on every `cpac claude` launch:",
333
- " --opus heavy reasoning / planning fallback tier (ANTHROPIC_DEFAULT_OPUS_MODEL)",
334
- " --sonnet main conversation default tier (ANTHROPIC_DEFAULT_SONNET_MODEL)",
335
- " --haiku high-frequency small tasks: titles, summaries, background",
336
- " (ANTHROPIC_DEFAULT_HAIKU_MODEL + ANTHROPIC_SMALL_FAST_MODEL)",
337
- "",
338
- "Unset slots auto-select from the catalog: same-family claude model first,",
339
- "then gemini → grok → luna → first model (opus stays unset without a match).",
340
- "",
341
- "A slot without a value opens an arrow-key picker over the CPA catalog;",
342
- "--reset clears all overrides back to catalog auto-selection.",
343
- ].join("\n"));
363
+ console.log(setupUsage());
344
364
  return null;
345
365
  }
346
366
  let configPath = defaultConfigPath();
367
+ let agent;
368
+ const flags = [];
369
+ for (let index = 1; index < args.length; index++) {
370
+ const arg = args[index];
371
+ if (arg === "--config") {
372
+ const value = args[++index];
373
+ if (!value)
374
+ throw new CPACError("--config requires a path");
375
+ configPath = resolve(expandUserPath(value));
376
+ }
377
+ else if (!arg.startsWith("-") && agent === undefined) {
378
+ agent = arg;
379
+ }
380
+ else {
381
+ flags.push(arg);
382
+ }
383
+ }
384
+ if (agent === undefined) {
385
+ if (flags.length > 0)
386
+ throw new CPACError(`unknown option: ${flags[0]}`);
387
+ return { command: "setup-show", configPath };
388
+ }
389
+ if (agent !== "claude" && agent !== "codex") {
390
+ throw new CPACError("setup requires claude or codex");
391
+ }
392
+ args = ["setup", agent, ...flags];
393
+ if (agent === "codex") {
394
+ let v2Off = false;
395
+ let v2Models = false;
396
+ let maxContext = false;
397
+ for (let index = 2; index < args.length; index++) {
398
+ const arg = args[index];
399
+ if (arg === "--config") {
400
+ const value = args[++index];
401
+ if (!value)
402
+ throw new CPACError("--config requires a path");
403
+ configPath = resolve(expandUserPath(value));
404
+ }
405
+ else if (arg === "--v2_off" || arg === "--v2-off")
406
+ v2Off = true;
407
+ else if (arg === "--v2_models" || arg === "--v2-models")
408
+ v2Models = true;
409
+ else if (arg === "--max_context" || arg === "--max-context")
410
+ maxContext = true;
411
+ else
412
+ throw new CPACError(`unknown option: ${arg}`);
413
+ }
414
+ return {
415
+ command: "codex-config",
416
+ configPath,
417
+ v2Off,
418
+ v2Models,
419
+ maxContext,
420
+ reset: false,
421
+ interactive: true,
422
+ launch: true,
423
+ args: [],
424
+ };
425
+ }
347
426
  const models = {};
348
427
  const pick = [];
349
428
  let reset = false;
350
- for (let index = 1; index < args.length; index += 1) {
429
+ for (let index = 2; index < args.length; index += 1) {
351
430
  const arg = args[index];
352
431
  if (arg === "--config") {
353
432
  const value = args[++index];
@@ -375,15 +454,20 @@ function parseArgs(args) {
375
454
  throw new CPACError(`unknown option: ${arg}`);
376
455
  }
377
456
  }
457
+ const interactive = !reset && Object.keys(models).length === 0 && pick.length === 0;
378
458
  return {
379
459
  command: "claude-config",
380
460
  configPath,
381
461
  models,
382
462
  pick,
383
463
  reset,
384
- interactive: !reset && Object.keys(models).length === 0 && pick.length === 0,
464
+ interactive,
465
+ launch: interactive && !reset,
385
466
  };
386
467
  }
468
+ if (args[0] === "claude-models") {
469
+ throw new CPACError("claude-models was removed; use: cpac setup claude");
470
+ }
387
471
  if (args.includes("-h") || args.includes("--help")) {
388
472
  console.log(usage());
389
473
  return null;
@@ -416,20 +500,19 @@ function parseArgs(args) {
416
500
  else
417
501
  positional.push(args[index]);
418
502
  }
419
- if (positional.length !== 1 ||
420
- !["inject", "status", "proxy"].includes(positional[0])) {
421
- throw new CPACError(usage());
503
+ if (positional.length === 1 && positional[0] === "inject") {
504
+ throw new CPACError("inject was removed; use: cpac install codex");
422
505
  }
423
- if (positional[0] !== "inject" && (v2Off || v2Models || maxContext)) {
424
- throw new CPACError("--v2_off / --v2_models / --max_context is only valid with inject or install");
506
+ if (positional.length === 1 && positional[0] === "proxy") {
507
+ throw new CPACError("proxy was removed; restart with: cpac install codex (or kimi / grok)");
425
508
  }
426
- if (positional[0] === "inject") {
427
- return { command: "inject", configPath, v2Off, v2Models, maxContext };
509
+ if (positional.length !== 1 || positional[0] !== "status") {
510
+ throw new CPACError(usage());
428
511
  }
429
- return {
430
- command: positional[0],
431
- configPath,
432
- };
512
+ if (v2Off || v2Models || maxContext) {
513
+ throw new CPACError("--v2_off / --v2_models / --max_context is only valid with install or setup");
514
+ }
515
+ return { command: "status", configPath };
433
516
  }
434
517
  export async function main(args = process.argv.slice(2)) {
435
518
  try {
@@ -491,10 +574,14 @@ export async function main(args = process.argv.slice(2)) {
491
574
  });
492
575
  if (parsed.command === "uninstall") {
493
576
  if (parsed.targets.length || parsed.all) {
494
- throw new CPACError("uninstall removes the cpac package; detach agents with: cpac restore --target <id> | --all");
577
+ throw new CPACError("uninstall removes the cpac package; detach agents with: cpac restore <id> | --all");
495
578
  }
496
579
  return await runUninstall(config, { dryRun: parsed.dryRun });
497
580
  }
581
+ if (parsed.command === "setup-show") {
582
+ printSetup(config, parsed.configPath);
583
+ return 0;
584
+ }
498
585
  if (parsed.command === "upgrade")
499
586
  return await runUpgrade(config, parsed.check);
500
587
  if (parsed.command === "claude")
@@ -543,23 +630,7 @@ export async function main(args = process.argv.slice(2)) {
543
630
  parsed.command === "pi") {
544
631
  return await runTargetLauncher(config, parsed.command, parsed.args);
545
632
  }
546
- if (parsed.command === "claude-models")
547
- return await runClaudeModels(parsed);
548
- if (parsed.command === "proxy")
549
- return await runProxy(config);
550
- if (parsed.command === "inject") {
551
- let injectConfig = config;
552
- if (parsed.v2Models) {
553
- const picked = await pickSpawnModels(config);
554
- saveSpawnModels(parsed.configPath, picked);
555
- console.log(`spawn_models saved to ${parsed.configPath}: ${picked.join(", ")}`);
556
- injectConfig = { ...config, spawn_models: picked };
557
- }
558
- await inject(injectConfig, parsed.v2Off, parsed.maxContext);
559
- }
560
- else
561
- return await status(config);
562
- return 0;
633
+ return await status(config);
563
634
  }
564
635
  catch (error) {
565
636
  console.error(`cpac: ${error instanceof Error ? error.message : String(error)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yhong91/cpac",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {