@yhong91/cpac 0.1.11 → 0.1.13
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 +5 -5
- package/dist/cpac.js +40 -19
- package/dist/pi-extension.template +42 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -93,18 +93,18 @@ cpac --help
|
|
|
93
93
|
|
|
94
94
|
### 统一管理(detect / install / uninstall / upgrade)
|
|
95
95
|
|
|
96
|
-
参考 vibetime 的目标式命令,对 `codex`、`
|
|
96
|
+
参考 vibetime 的目标式命令,对 `codex`、`pi`、`kimi` 三个持久注入目标统一管理(claude/opencode 是临时接管,用 `cpac claude` / `cpac opencode` 启动,不属于 install 目标):
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
99
|
cpac detect [--json] [--home PATH]
|
|
100
|
-
cpac install [--target codex,
|
|
101
|
-
cpac uninstall [--target codex,
|
|
100
|
+
cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--home PATH]
|
|
101
|
+
cpac uninstall [--target codex,pi,kimi] [--all] [--dry-run] [--home PATH]
|
|
102
102
|
cpac upgrade [--check]
|
|
103
103
|
cpac version
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
- `detect` 列出每个目标是否被检测到、是否已接入 CPAC;`--json` 输出机器可读结果。
|
|
107
|
-
- `install` 默认作用于检测到的目标;`--target` 指定目标、`--all` 全部。各目标映射到既有逻辑:`codex` → `cpac inject`,`pi` → `cpac pi install`,`kimi` → `cpac kimi install
|
|
107
|
+
- `install` 默认作用于检测到的目标;`--target` 指定目标、`--all` 全部。各目标映射到既有逻辑:`codex` → `cpac inject`,`pi` → `cpac pi install`,`kimi` → `cpac kimi install`。`--dry-run` 只打印将要做的事,`--force` 允许重装已安装目标。
|
|
108
108
|
- Codex 注入默认开启 multi-agent v2(写入 `[features.multi_agent_v2] enabled = true`);`install --target codex --v2_off` 写入 `enabled = false`。服务端还需在 CPA 配置中开启 `codex.optimize-multi-agent-v2`。
|
|
109
109
|
- `--v2_models` 进入 arrow-key 复选框选择最多 5 个 spawn_agent 模型(勾选顺序即推荐顺序),选择结果存入配置文件的 `spawn_models`,注入时把这些模型排到 `codex-models.json` 最前——Codex 客户端只把 catalog 前 5 个可见模型广告为 spawn 覆盖项。
|
|
110
110
|
- `uninstall` 默认作用于已安装目标,映射到 `cpac restore` / `cpac pi uninstall` / `cpac kimi uninstall`。
|
|
@@ -157,7 +157,7 @@ Claude Code 的发现协议不携带 context 信息,claude 前缀的未知模
|
|
|
157
157
|
注入 CPA 模型目录:
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
cpac inject
|
|
160
|
+
cpac inject [--v2_off] [--v2_models] [--config PATH]
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
查看状态:
|
package/dist/cpac.js
CHANGED
|
@@ -734,6 +734,10 @@ export async function createLoopbackProxy(cpaUrl, apiKey, proxyId, port) {
|
|
|
734
734
|
response.end(JSON.stringify({ error: "CPA upstream request failed" }));
|
|
735
735
|
});
|
|
736
736
|
request.once("aborted", () => upstream.destroy());
|
|
737
|
+
response.once("close", () => {
|
|
738
|
+
if (!response.writableEnded)
|
|
739
|
+
upstream.destroy();
|
|
740
|
+
});
|
|
737
741
|
request.pipe(upstream);
|
|
738
742
|
});
|
|
739
743
|
server.on("upgrade", (_request, socket) => {
|
|
@@ -941,6 +945,11 @@ export async function createClaudeProxy(cpaUrl, apiKey) {
|
|
|
941
945
|
if (!response.writableEnded)
|
|
942
946
|
response.end(JSON.stringify({ error: "CPA upstream request failed" }));
|
|
943
947
|
});
|
|
948
|
+
request.once("aborted", () => upstream.destroy());
|
|
949
|
+
response.once("close", () => {
|
|
950
|
+
if (!response.writableEnded)
|
|
951
|
+
upstream.destroy();
|
|
952
|
+
});
|
|
944
953
|
upstream.end(body);
|
|
945
954
|
});
|
|
946
955
|
});
|
|
@@ -1835,20 +1844,6 @@ const TARGETS = [
|
|
|
1835
1844
|
await restore(config);
|
|
1836
1845
|
},
|
|
1837
1846
|
},
|
|
1838
|
-
{
|
|
1839
|
-
id: "claude",
|
|
1840
|
-
home: () => expandUserPath(process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), ".claude")),
|
|
1841
|
-
detected: () => binaryOnPath("claude") || existsSync(join(homedir(), ".claude")),
|
|
1842
|
-
installed: () => false,
|
|
1843
|
-
install: async (_config, dryRun) => {
|
|
1844
|
-
const message = "claude needs no install; launch it through CPA with: cpac claude";
|
|
1845
|
-
console.log(dryRun ? `would do nothing: ${message}` : message);
|
|
1846
|
-
},
|
|
1847
|
-
uninstall: async (_config, dryRun) => {
|
|
1848
|
-
const message = "claude keeps no persistent CPAC state; nothing to remove";
|
|
1849
|
-
console.log(dryRun ? `would do nothing: ${message}` : message);
|
|
1850
|
-
},
|
|
1851
|
-
},
|
|
1852
1847
|
{
|
|
1853
1848
|
id: "pi",
|
|
1854
1849
|
home: () => piExtensionsDir(),
|
|
@@ -1994,7 +1989,8 @@ export async function runUpgrade(checkOnly) {
|
|
|
1994
1989
|
function usage() {
|
|
1995
1990
|
return [
|
|
1996
1991
|
"Usage: cpac",
|
|
1997
|
-
" cpac
|
|
1992
|
+
" cpac inject [--v2_off] [--v2_models] [--config PATH]",
|
|
1993
|
+
" cpac <status|restore> [--config PATH]",
|
|
1998
1994
|
" cpac proxy [--config PATH]",
|
|
1999
1995
|
" cpac claude [--config PATH] [--] [claude args...]",
|
|
2000
1996
|
" cpac opencode [--config PATH] [--] [opencode args...]",
|
|
@@ -2002,10 +1998,13 @@ function usage() {
|
|
|
2002
1998
|
" cpac pi <install|uninstall|status> [--config PATH]",
|
|
2003
1999
|
" cpac kimi <install|uninstall|status> [--config PATH]",
|
|
2004
2000
|
" cpac detect [--json] [--home PATH]",
|
|
2005
|
-
" cpac install [--target codex,
|
|
2006
|
-
" cpac uninstall [--target codex,
|
|
2001
|
+
" cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--home PATH]",
|
|
2002
|
+
" cpac uninstall [--target codex,pi,kimi] [--all] [--dry-run] [--home PATH]",
|
|
2007
2003
|
" cpac upgrade [--check]",
|
|
2008
2004
|
" cpac version",
|
|
2005
|
+
"",
|
|
2006
|
+
"install/uninstall manage persistent injections only; claude and opencode are",
|
|
2007
|
+
"ephemeral — launch them with `cpac claude` / `cpac opencode` instead.",
|
|
2009
2008
|
].join("\n");
|
|
2010
2009
|
}
|
|
2011
2010
|
function parseArgs(args) {
|
|
@@ -2177,6 +2176,8 @@ function parseArgs(args) {
|
|
|
2177
2176
|
}
|
|
2178
2177
|
let configPath = defaultConfigPath();
|
|
2179
2178
|
const positional = [];
|
|
2179
|
+
let v2Off = false;
|
|
2180
|
+
let v2Models = false;
|
|
2180
2181
|
for (let index = 0; index < args.length; index += 1) {
|
|
2181
2182
|
if (args[index] === "--config") {
|
|
2182
2183
|
const value = args[++index];
|
|
@@ -2184,6 +2185,12 @@ function parseArgs(args) {
|
|
|
2184
2185
|
throw new CPACError("--config requires a path");
|
|
2185
2186
|
configPath = resolve(expandUserPath(value));
|
|
2186
2187
|
}
|
|
2188
|
+
else if (args[index] === "--v2_off" || args[index] === "--v2-off") {
|
|
2189
|
+
v2Off = true;
|
|
2190
|
+
}
|
|
2191
|
+
else if (args[index] === "--v2_models" || args[index] === "--v2-models") {
|
|
2192
|
+
v2Models = true;
|
|
2193
|
+
}
|
|
2187
2194
|
else if (args[index].startsWith("-")) {
|
|
2188
2195
|
throw new CPACError(`unknown option: ${args[index]}`);
|
|
2189
2196
|
}
|
|
@@ -2194,6 +2201,12 @@ function parseArgs(args) {
|
|
|
2194
2201
|
!["inject", "status", "restore", "proxy"].includes(positional[0])) {
|
|
2195
2202
|
throw new CPACError(usage());
|
|
2196
2203
|
}
|
|
2204
|
+
if (positional[0] !== "inject" && (v2Off || v2Models)) {
|
|
2205
|
+
throw new CPACError("--v2_off / --v2_models is only valid with inject or install");
|
|
2206
|
+
}
|
|
2207
|
+
if (positional[0] === "inject") {
|
|
2208
|
+
return { command: "inject", configPath, v2Off, v2Models };
|
|
2209
|
+
}
|
|
2197
2210
|
return {
|
|
2198
2211
|
command: positional[0],
|
|
2199
2212
|
configPath,
|
|
@@ -2255,8 +2268,16 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
2255
2268
|
return await runPi(config, parsed.action);
|
|
2256
2269
|
if (parsed.command === "kimi")
|
|
2257
2270
|
return await runKimi(config, parsed.action);
|
|
2258
|
-
if (parsed.command === "inject")
|
|
2259
|
-
|
|
2271
|
+
if (parsed.command === "inject") {
|
|
2272
|
+
let injectConfig = config;
|
|
2273
|
+
if (parsed.v2Models) {
|
|
2274
|
+
const picked = await pickSpawnModels(config);
|
|
2275
|
+
saveSpawnModels(parsed.configPath, picked);
|
|
2276
|
+
console.log(`spawn_models saved to ${parsed.configPath}: ${picked.join(", ")}`);
|
|
2277
|
+
injectConfig = { ...config, spawn_models: picked };
|
|
2278
|
+
}
|
|
2279
|
+
await inject(injectConfig, parsed.v2Off);
|
|
2280
|
+
}
|
|
2260
2281
|
else if (parsed.command === "restore")
|
|
2261
2282
|
await restore(config);
|
|
2262
2283
|
else
|
|
@@ -5,6 +5,7 @@ const CPA = "__CPA_URL__";
|
|
|
5
5
|
const BUILTIN = new Set(["openai", "github-copilot", "xai", "deepseek", "anthropic", "google"]);
|
|
6
6
|
const VENDOR_PREFIXES = [
|
|
7
7
|
["gpt-", "openai"], ["o1-", "openai"], ["o3-", "openai"], ["o4-", "openai"],
|
|
8
|
+
["gpt-image", "openai"],
|
|
8
9
|
["claude-", "anthropic"], ["gemini-", "google"], ["grok-", "xai"],
|
|
9
10
|
["deepseek-", "deepseek"], ["glm-", "zhipu"], ["kimi-", "moonshot"],
|
|
10
11
|
["mimo-", "xiaomi"], ["doubao-", "volcengine"], ["ark-", "volcengine"],
|
|
@@ -21,6 +22,9 @@ const MAX_TOKENS = {
|
|
|
21
22
|
"doubao-seed-2.0-lite": 128000, "doubao-seed-2.1-turbo": 128000,
|
|
22
23
|
};
|
|
23
24
|
const DEFAULT_MAX_TOKENS = 65536;
|
|
25
|
+
const REASONING_EFFORTS = new Set([
|
|
26
|
+
"minimal", "low", "medium", "high", "xhigh", "max", "ultra",
|
|
27
|
+
]);
|
|
24
28
|
|
|
25
29
|
function vendorFor(slug) {
|
|
26
30
|
for (const [prefix, vendor] of VENDOR_PREFIXES) {
|
|
@@ -33,6 +37,32 @@ function groupName(vendor) {
|
|
|
33
37
|
return BUILTIN.has(vendor) ? vendor + "-cpa" : vendor;
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
function effortsFor(row) {
|
|
41
|
+
const levels = row.supported_reasoning_levels;
|
|
42
|
+
if (!Array.isArray(levels)) return undefined;
|
|
43
|
+
const efforts = levels.flatMap(function (level) {
|
|
44
|
+
if (!level || typeof level !== "object") return [];
|
|
45
|
+
const effort = level.effort;
|
|
46
|
+
return typeof effort === "string" && REASONING_EFFORTS.has(effort) ? [effort] : [];
|
|
47
|
+
});
|
|
48
|
+
return efforts.length > 0 ? efforts : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function thinkingLevelMapFor(efforts) {
|
|
52
|
+
if (!efforts || !efforts.some(function (effort) { return REASONING_EFFORTS.has(effort); })) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const available = new Set(efforts);
|
|
56
|
+
return {
|
|
57
|
+
minimal: available.has("minimal") ? "minimal" : available.has("low") ? "low" : null,
|
|
58
|
+
low: available.has("low") ? "low" : null,
|
|
59
|
+
medium: available.has("medium") ? "medium" : null,
|
|
60
|
+
high: available.has("high") ? "high" : null,
|
|
61
|
+
xhigh: available.has("xhigh") ? "xhigh" : null,
|
|
62
|
+
max: available.has("max") || available.has("ultra") ? "max" : null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
36
66
|
function intField(value) {
|
|
37
67
|
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
38
68
|
? Math.floor(value) : undefined;
|
|
@@ -72,7 +102,12 @@ export default async function (pi) {
|
|
|
72
102
|
const slug = typeof m.slug === "string" && m.slug.trim()
|
|
73
103
|
? m.slug.trim()
|
|
74
104
|
: typeof m.id === "string" && m.id.trim() ? m.id.trim() : null;
|
|
75
|
-
if (slug) rows.push({
|
|
105
|
+
if (slug) rows.push({
|
|
106
|
+
slug: slug,
|
|
107
|
+
display_name: m.display_name,
|
|
108
|
+
supported_reasoning_levels: m.supported_reasoning_levels,
|
|
109
|
+
context_window: m.context_window,
|
|
110
|
+
});
|
|
76
111
|
}
|
|
77
112
|
if (rows.length === 0) {
|
|
78
113
|
console.error("[cpac] CPA models response has no usable models");
|
|
@@ -92,15 +127,19 @@ export default async function (pi) {
|
|
|
92
127
|
apiKey: apiKey,
|
|
93
128
|
api: "openai-responses",
|
|
94
129
|
models: models.map(function (m) {
|
|
95
|
-
|
|
130
|
+
const efforts = effortsFor(m);
|
|
131
|
+
const thinkingLevelMap = thinkingLevelMapFor(efforts);
|
|
132
|
+
const modelObj = {
|
|
96
133
|
id: m.slug,
|
|
97
134
|
name: typeof m.display_name === "string" ? m.display_name : m.slug,
|
|
98
|
-
reasoning:
|
|
135
|
+
reasoning: efforts === undefined || thinkingLevelMap !== undefined,
|
|
99
136
|
input: ["text", "image"],
|
|
100
137
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
101
138
|
contextWindow: intField(m.context_window) || 200000,
|
|
102
139
|
maxTokens: MAX_TOKENS[m.slug] || DEFAULT_MAX_TOKENS,
|
|
103
140
|
};
|
|
141
|
+
if (thinkingLevelMap) modelObj.thinkingLevelMap = thinkingLevelMap;
|
|
142
|
+
return modelObj;
|
|
104
143
|
}),
|
|
105
144
|
});
|
|
106
145
|
}
|