@yhong91/cpac 0.1.13 → 0.1.15
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 +72 -44
- package/cpac.example.json +1 -2
- package/dist/cpac.js +35 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ CPAC 将 Codex 和 Claude Code 接入远端 CLIProxyAPI(CPA):
|
|
|
10
10
|
## 要求
|
|
11
11
|
|
|
12
12
|
- [Node.js](https://nodejs.org/) 20 或更新版本(npm 随 Node 安装)
|
|
13
|
-
- 已安装需要使用的 agent:`codex` 或 `
|
|
13
|
+
- 已安装需要使用的 agent:`codex`、`claude`、`pi`、`kimi` 或 `opencode`
|
|
14
14
|
- 有权访问的 CPA API key
|
|
15
15
|
|
|
16
16
|
## 安装
|
|
@@ -22,15 +22,77 @@ npm install -g @yhong91/cpac
|
|
|
22
22
|
cpac
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
## 快速上手
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
|
|
29
|
-
npm
|
|
30
|
-
|
|
28
|
+
# 1. 安装
|
|
29
|
+
npm install -g @yhong91/cpac
|
|
30
|
+
|
|
31
|
+
# 2. 配置密钥:无参数运行进入交互引导,自动写入 shell 启动文件;
|
|
32
|
+
# 也可手动写入(zsh 示例):
|
|
31
33
|
cpac
|
|
34
|
+
echo 'export CPA_API_KEY="<你的key>"' >> ~/.zshrc && source ~/.zshrc
|
|
35
|
+
|
|
36
|
+
# 3. 验证
|
|
37
|
+
cpac status
|
|
38
|
+
|
|
39
|
+
# 4a. 持久注入(长期生效,写入 agent 配置,可完整恢复)
|
|
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 uninstall --target codex # 字节级恢复原配置
|
|
44
|
+
|
|
45
|
+
# 4b. 临时接管(退出无痕,不写任何配置文件)
|
|
46
|
+
cpac claude # Claude Code 走 CPA
|
|
47
|
+
cpac opencode # opencode 走 CPA(模型选 cpac/<模型名>)
|
|
48
|
+
|
|
49
|
+
# 5. 可选:Claude 模型槽位覆盖(持久缓存;默认自动选择已覆盖多数场景,见下文)
|
|
50
|
+
cpac claude-models # 查看当前覆盖
|
|
51
|
+
cpac claude-models --haiku # 下拉选择 haiku 槽模型
|
|
52
|
+
|
|
53
|
+
# 6. 升级
|
|
54
|
+
cpac upgrade --check
|
|
55
|
+
npm install -g @yhong91/cpac@latest
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
各命令的完整参数与行为见下方对应章节。
|
|
59
|
+
|
|
60
|
+
## Agent 自动化安装指南
|
|
61
|
+
|
|
62
|
+
本节面向 AI agent:按顺序执行即可完成安装与配置,**全程无交互**。注意:`--v2_models` 复选框和 `claude-models` 不带值的下拉选择是 TTY-only,agent 必须走下方直接写配置 JSON 的路径。
|
|
63
|
+
|
|
64
|
+
1. **检查前置**:`node --version` ≥ 20;确认用户需要哪些 agent(`codex`/`claude`/`pi`/`kimi`/`opencode` 在 PATH 上)。向用户索取 CPA API key。
|
|
65
|
+
|
|
66
|
+
2. **安装与密钥**:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g @yhong91/cpac
|
|
70
|
+
echo 'export CPA_API_KEY="<key>"' >> ~/.zshrc # bash 用 ~/.bash_profile 或 ~/.bashrc
|
|
71
|
+
source ~/.zshrc
|
|
72
|
+
cpac status # 验证:CPA_API_KEY 应显示 configured
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
3. **写入模型配置**(创建或合并 `~/.config/cpac/config.json`,已有键保留):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"spawn_models": ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gemini-3.7-flash-high", "grok-4.6"]
|
|
80
|
+
}
|
|
32
81
|
```
|
|
33
82
|
|
|
83
|
+
Claude 槽位(opus/sonnet/haiku)通常不用配:cpac 启动时自动选择——同家族 claude 模型优先,否则 gemini → grok → luna → 目录第一个;opus 无匹配则不设。这个链条在常见目录上正好给出理想结果:sonnet 落在 claude-sonnet-*(它同时充当 Auto mode 分类器的替身,避免分类请求失败后回退到昂贵的会话主模型),haiku 落在快的 gemini flash。只有目录奇怪时才用 `cpac claude-models --opus/--sonnet/--haiku <模型>` 显式覆盖。codex spawn subagent 取三个 GPT + gemini + grok 五席(顺序即优先级,Codex 只广告 catalog 前 5)。候选替换:`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
|
+
|
|
85
|
+
4. **持久注入**(只对检测到的目标;codex 会应用步骤 3 的 spawn_models):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cpac install --all
|
|
89
|
+
cpac status # 验证:各 target 显示 ready/injected
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
5. **临时接管类 agent 无需安装**,直接告知用户用 `cpac claude` / `cpac opencode` 启动(步骤 3 的 claude_models 自动生效)。
|
|
93
|
+
|
|
94
|
+
失败处理:任何一步报错时先跑 `cpac status`;密钥未配置回到步骤 2;注入后异常用 `cpac uninstall --target <id>` 恢复原配置。
|
|
95
|
+
|
|
34
96
|
## 首次引导
|
|
35
97
|
|
|
36
98
|
无参数运行 `cpac` 会显示当前 CPA、密钥状态和可用命令:
|
|
@@ -140,11 +202,14 @@ CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST=1
|
|
|
140
202
|
cpac claude-models # 查看当前覆盖
|
|
141
203
|
cpac claude-models --opus claude-opus-4-8 --haiku glm-5.3 # 设置/合并
|
|
142
204
|
cpac claude-models --haiku # 不带值:arrow-key 下拉选择
|
|
143
|
-
cpac claude-models --classifier claude-sonnet-4-6 # Auto mode 审批分类器模型
|
|
144
205
|
cpac claude-models --reset # 恢复自动选择
|
|
145
206
|
```
|
|
146
207
|
|
|
147
|
-
|
|
208
|
+
未设置的槽位启动时自动选择:claude 池内同家族模型优先,否则按 gemini → grok → luna → 目录第一个回退;opus 无匹配则不设。
|
|
209
|
+
|
|
210
|
+
所有设定写入配置文件持久缓存,每次 `cpac claude` 启动自动生效。
|
|
211
|
+
|
|
212
|
+
`--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)。
|
|
148
213
|
|
|
149
214
|
你自己 export 同名环境变量时以你为准。
|
|
150
215
|
|
|
@@ -319,40 +384,3 @@ export CPAC_CONFIG=/path/to/cpac.json
|
|
|
319
384
|
- shell 启动文件和 Codex 配置均通过同目录临时文件原子替换。
|
|
320
385
|
- CPA 请求失败、catalog 无效或 key 缺失时,首次注入不会修改 Codex 配置。
|
|
321
386
|
- `restore` 只删除 CPAC 自有的 state、backup 和 catalog,不删除 `state_dir` 中的其他文件。
|
|
322
|
-
|
|
323
|
-
## 开发
|
|
324
|
-
|
|
325
|
-
```bash
|
|
326
|
-
npm install
|
|
327
|
-
npm test
|
|
328
|
-
npm run check
|
|
329
|
-
npm run build
|
|
330
|
-
npm run check:pi
|
|
331
|
-
npm run pack:check
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
发布包的 CLI 入口为 `dist/cpac.js`。`dist/` 是构建产物,不应手工编辑。
|
|
335
|
-
|
|
336
|
-
## npm 发布
|
|
337
|
-
|
|
338
|
-
`.github/workflows/publish.yml` 在推送到 `main` 或手动触发时执行测试、类型检查、构建并发布到 npm。发布前会确认 `package.json` 中的版本尚未存在;因此每次计划发布的 push 都必须先提升版本。普通 PR 仅运行 CI。
|
|
339
|
-
|
|
340
|
-
首次发布前:
|
|
341
|
-
|
|
342
|
-
1. 在 npm 创建账号并启用 2FA。
|
|
343
|
-
2. 因为新包尚不存在,先创建允许 publish 且可绕过 2FA 的 npm granular access token,在仓库的 **Settings → Secrets and variables → Actions** 添加 `NPM_TOKEN`,然后手动运行 `Publish to npm` workflow 完成首次发布。
|
|
344
|
-
3. 首次发布后,在 npm 包 `@yhong91/cpac` 的设置中添加 Trusted Publisher:GitHub 用户 `yhong91`、仓库 `cpac`、workflow 文件 `publish.yml`,允许 `npm publish`。
|
|
345
|
-
4. Trusted Publisher 生效后删除 GitHub 的 `NPM_TOKEN`;后续 workflow 自动使用 OIDC。
|
|
346
|
-
|
|
347
|
-
正常发布新版本:
|
|
348
|
-
|
|
349
|
-
```bash
|
|
350
|
-
npm version patch --no-git-tag-version # 或 minor / major
|
|
351
|
-
git add package.json package-lock.json
|
|
352
|
-
git commit -m 'Release 0.1.1'
|
|
353
|
-
git push
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
也可以手工修改并提交两个版本文件。push 到 `main` 后 Action 自动发布;若忘记提升版本,发布 workflow 会明确失败,不会覆盖 npm 已发布版本。
|
|
357
|
-
|
|
358
|
-
仓库当前为 private,因此 npm Trusted Publishing 可以使用,但 npm 不会为发布包生成 provenance。
|
package/cpac.example.json
CHANGED
package/dist/cpac.js
CHANGED
|
@@ -25,7 +25,7 @@ const CONFIG_KEYS = new Set([
|
|
|
25
25
|
// Codex advertises only the first 5 picker-visible catalog models as
|
|
26
26
|
// spawn_agent overrides (codex-rs MAX_SPAWN_AGENT_MODEL_OVERRIDES).
|
|
27
27
|
const MAX_SPAWN_MODELS = 5;
|
|
28
|
-
const CLAUDE_SLOT_KEYS = ["opus", "sonnet", "haiku"
|
|
28
|
+
const CLAUDE_SLOT_KEYS = ["opus", "sonnet", "haiku"];
|
|
29
29
|
const REQUIRED_STATE_KEYS = new Set([
|
|
30
30
|
"config_path",
|
|
31
31
|
"config_existed",
|
|
@@ -131,7 +131,9 @@ export function loadConfig(path, useDefaultsIfMissing = false) {
|
|
|
131
131
|
if (!objectValue(claudeModelsRaw))
|
|
132
132
|
throw new CPACError("claude_models must be an object");
|
|
133
133
|
const unknownSlots = Object.keys(claudeModelsRaw)
|
|
134
|
-
|
|
134
|
+
// "classifier" was a shipped slot; its env var turned out unread by
|
|
135
|
+
// Claude Code, so the key is dropped on load instead of erroring.
|
|
136
|
+
.filter((key) => key !== "classifier" && !CLAUDE_SLOT_KEYS.includes(key))
|
|
135
137
|
.sort();
|
|
136
138
|
if (unknownSlots.length)
|
|
137
139
|
throw new CPACError(`unknown claude_models slots: ${unknownSlots.join(", ")}`);
|
|
@@ -778,25 +780,29 @@ function shouldMarkOneMillion(id, window, compactWindow) {
|
|
|
778
780
|
return true;
|
|
779
781
|
return compactWindow !== undefined && window > 200_000 && window >= compactWindow;
|
|
780
782
|
}
|
|
781
|
-
// Auto tier defaults
|
|
782
|
-
//
|
|
783
|
-
//
|
|
784
|
-
//
|
|
783
|
+
// Auto tier defaults. Within the claude-family pool (whole catalog when no
|
|
784
|
+
// claude model exists), opus matches its family name or stays unset; sonnet
|
|
785
|
+
// and haiku match their family name first, then fall back through
|
|
786
|
+
// gemini → grok → luna → first catalog row.
|
|
785
787
|
function defaultClaudeSlots(models) {
|
|
786
788
|
if (!models.length)
|
|
787
789
|
return undefined;
|
|
788
790
|
const claudeRows = models.filter((model) => model.id.startsWith("claude"));
|
|
789
791
|
const pool = claudeRows.length ? claudeRows : models;
|
|
790
|
-
const biggest = [...pool].sort((a, b) => b.window - a.window)[0];
|
|
791
|
-
const smallest = pool
|
|
792
|
-
.filter((model) => model.window > 0)
|
|
793
|
-
.sort((a, b) => a.window - b.window)[0];
|
|
794
792
|
const family = (keyword) => pool.find((model) => model.id.includes(keyword));
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
793
|
+
const fallback = (keyword) => family(keyword) ??
|
|
794
|
+
models.find((model) => model.id.includes("gemini")) ??
|
|
795
|
+
models.find((model) => model.id.includes("grok")) ??
|
|
796
|
+
models.find((model) => model.id.includes("luna")) ??
|
|
797
|
+
models[0];
|
|
798
|
+
const slots = {
|
|
799
|
+
sonnet: fallback("sonnet").id,
|
|
800
|
+
haiku: fallback("haiku").id,
|
|
799
801
|
};
|
|
802
|
+
const opus = family("opus");
|
|
803
|
+
if (opus)
|
|
804
|
+
slots.opus = opus.id;
|
|
805
|
+
return slots;
|
|
800
806
|
}
|
|
801
807
|
// Resolve the tier-model env values: config overrides win over catalog
|
|
802
808
|
// defaults; values are [1m]-marked per the predicate above (Claude Code
|
|
@@ -810,11 +816,14 @@ export function claudeTierSlots(override, models, compactWindow) {
|
|
|
810
816
|
shouldMarkOneMillion(id, windowById.get(id) ?? 0, compactWindow)
|
|
811
817
|
? `${id}[1m]`
|
|
812
818
|
: id;
|
|
813
|
-
|
|
814
|
-
opus: mark(override?.opus ?? defaults.opus),
|
|
819
|
+
const slots = {
|
|
815
820
|
sonnet: mark(override?.sonnet ?? defaults.sonnet),
|
|
816
821
|
haiku: mark(override?.haiku ?? defaults.haiku),
|
|
817
822
|
};
|
|
823
|
+
const opus = override?.opus ?? defaults.opus;
|
|
824
|
+
if (opus)
|
|
825
|
+
slots.opus = mark(opus);
|
|
826
|
+
return slots;
|
|
818
827
|
}
|
|
819
828
|
function catalogModelRows(document) {
|
|
820
829
|
if (!objectValue(document))
|
|
@@ -1590,14 +1599,14 @@ export async function runClaude(config, args, executable = "claude") {
|
|
|
1590
1599
|
};
|
|
1591
1600
|
if (slots) {
|
|
1592
1601
|
// Route haiku/subagent tier traffic at catalog models instead of the
|
|
1593
|
-
// stock claude-haiku-* ids the gateway does not carry.
|
|
1594
|
-
|
|
1602
|
+
// stock claude-haiku-* ids the gateway does not carry. The opus slot
|
|
1603
|
+
// stays unset when the catalog has no opus-family model.
|
|
1604
|
+
if (slots.opus)
|
|
1605
|
+
setSlot("ANTHROPIC_DEFAULT_OPUS_MODEL", slots.opus);
|
|
1595
1606
|
setSlot("ANTHROPIC_DEFAULT_SONNET_MODEL", slots.sonnet);
|
|
1596
1607
|
setSlot("ANTHROPIC_DEFAULT_HAIKU_MODEL", slots.haiku);
|
|
1597
1608
|
setSlot("ANTHROPIC_SMALL_FAST_MODEL", slots.haiku);
|
|
1598
1609
|
}
|
|
1599
|
-
if (config.claude_models?.classifier)
|
|
1600
|
-
setSlot("CLAUDE_CODE_AUTO_MODE_MODEL", config.claude_models.classifier);
|
|
1601
1610
|
delete env.ANTHROPIC_API_KEY;
|
|
1602
1611
|
delete env.CLAUDE_CODE_USE_ANTHROPIC_AWS;
|
|
1603
1612
|
delete env.CLAUDE_CODE_USE_BEDROCK;
|
|
@@ -1994,7 +2003,7 @@ function usage() {
|
|
|
1994
2003
|
" cpac proxy [--config PATH]",
|
|
1995
2004
|
" cpac claude [--config PATH] [--] [claude args...]",
|
|
1996
2005
|
" cpac opencode [--config PATH] [--] [opencode args...]",
|
|
1997
|
-
" cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--
|
|
2006
|
+
" cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--reset] [--config PATH]",
|
|
1998
2007
|
" cpac pi <install|uninstall|status> [--config PATH]",
|
|
1999
2008
|
" cpac kimi <install|uninstall|status> [--config PATH]",
|
|
2000
2009
|
" cpac detect [--json] [--home PATH]",
|
|
@@ -2089,7 +2098,7 @@ function parseArgs(args) {
|
|
|
2089
2098
|
if (args[0] === "claude-models") {
|
|
2090
2099
|
if (args.includes("-h") || args.includes("--help")) {
|
|
2091
2100
|
console.log([
|
|
2092
|
-
"Usage: cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--
|
|
2101
|
+
"Usage: cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--reset] [--config PATH]",
|
|
2093
2102
|
"",
|
|
2094
2103
|
"Sets the model Claude Code uses per task tier. Saved to the config file",
|
|
2095
2104
|
"and applied on every `cpac claude` launch:",
|
|
@@ -2097,8 +2106,9 @@ function parseArgs(args) {
|
|
|
2097
2106
|
" --sonnet main conversation default tier (ANTHROPIC_DEFAULT_SONNET_MODEL)",
|
|
2098
2107
|
" --haiku high-frequency small tasks: titles, summaries, background",
|
|
2099
2108
|
" (ANTHROPIC_DEFAULT_HAIKU_MODEL + ANTHROPIC_SMALL_FAST_MODEL)",
|
|
2100
|
-
"
|
|
2101
|
-
"
|
|
2109
|
+
"",
|
|
2110
|
+
"Unset slots auto-select from the catalog: same-family claude model first,",
|
|
2111
|
+
"then gemini → grok → luna → first model (opus stays unset without a match).",
|
|
2102
2112
|
"",
|
|
2103
2113
|
"A slot without a value opens an arrow-key picker over the CPA catalog;",
|
|
2104
2114
|
"--reset clears all overrides back to catalog auto-selection.",
|
|
@@ -2122,8 +2132,7 @@ function parseArgs(args) {
|
|
|
2122
2132
|
}
|
|
2123
2133
|
else if (arg === "--opus" ||
|
|
2124
2134
|
arg === "--sonnet" ||
|
|
2125
|
-
arg === "--haiku"
|
|
2126
|
-
arg === "--classifier") {
|
|
2135
|
+
arg === "--haiku") {
|
|
2127
2136
|
const slot = arg.slice(2);
|
|
2128
2137
|
const value = args[index + 1];
|
|
2129
2138
|
if (value !== undefined && !value.startsWith("-")) {
|