@yhong91/cpac 0.1.10 → 0.1.12
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 +12 -4
- package/dist/cpac.js +74 -16
- 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`。
|
|
@@ -215,6 +215,14 @@ CPAC state:~/.cpac
|
|
|
215
215
|
|
|
216
216
|
为防止误删或覆盖,`state_dir` 不能是文件系统根目录、用户 home、系统临时目录,也不能包含 Codex 配置文件。
|
|
217
217
|
|
|
218
|
+
### OpenCode(临时接管)
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
cpac opencode [--] [opencode args...]
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
通过 `OPENCODE_CONFIG_CONTENT` 内联注入一个 `cpac` OpenAI 兼容 provider(baseURL 直指 CPA,模型列表来自 CPA 目录),不触碰任何 opencode 配置文件,退出即无痕。首次使用时 opencode 会自行安装 `@ai-sdk/openai-compatible` 适配器。模型选择用 `cpac/<模型名>`。
|
|
225
|
+
|
|
218
226
|
### Pi
|
|
219
227
|
|
|
220
228
|
安装 CPA provider 扩展到 Pi:
|
package/dist/cpac.js
CHANGED
|
@@ -1427,6 +1427,58 @@ async function guide(config) {
|
|
|
1427
1427
|
console.log(`\nSaved ${config.api_key_env} to ${profile}. Open a new terminal or run:\n source ${profile}`);
|
|
1428
1428
|
return 0;
|
|
1429
1429
|
}
|
|
1430
|
+
// opencode's config schema rejects a limit block with context but no output;
|
|
1431
|
+
// the catalog has no output field, so a safe budget stands in, clamped to the
|
|
1432
|
+
// context window (same scheme as opencodex's SCHEMA_REQUIRED_OUTPUT_BUDGET).
|
|
1433
|
+
const OPENCODE_OUTPUT_BUDGET = 32_000;
|
|
1434
|
+
// Ephemeral takeover: inline a CPA provider via OPENCODE_CONFIG_CONTENT so no
|
|
1435
|
+
// opencode config file is touched; the session ends with zero residue.
|
|
1436
|
+
export async function runOpencode(config, args, executable = "opencode") {
|
|
1437
|
+
const apiKey = process.env[config.api_key_env]?.trim();
|
|
1438
|
+
if (!apiKey)
|
|
1439
|
+
throw new CPACError(`environment variable ${config.api_key_env} is not set`);
|
|
1440
|
+
const catalog = await fetchCatalog(config.cpa_url, apiKey);
|
|
1441
|
+
const document = JSON.parse(new TextDecoder().decode(catalog.bytes));
|
|
1442
|
+
const models = {};
|
|
1443
|
+
for (const row of document.models) {
|
|
1444
|
+
const id = catalogModelId(row);
|
|
1445
|
+
if (!id)
|
|
1446
|
+
continue;
|
|
1447
|
+
const window = typeof row.context_window === "number" && row.context_window > 0
|
|
1448
|
+
? Math.floor(row.context_window)
|
|
1449
|
+
: 0;
|
|
1450
|
+
models[id] = window > 0
|
|
1451
|
+
? {
|
|
1452
|
+
limit: {
|
|
1453
|
+
context: window,
|
|
1454
|
+
output: Math.min(OPENCODE_OUTPUT_BUDGET, window),
|
|
1455
|
+
},
|
|
1456
|
+
}
|
|
1457
|
+
: {};
|
|
1458
|
+
}
|
|
1459
|
+
const content = JSON.stringify({
|
|
1460
|
+
provider: {
|
|
1461
|
+
cpac: {
|
|
1462
|
+
npm: "@ai-sdk/openai-compatible",
|
|
1463
|
+
options: { baseURL: apiBase(config.cpa_url), apiKey },
|
|
1464
|
+
models,
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
});
|
|
1468
|
+
const env = {
|
|
1469
|
+
...process.env,
|
|
1470
|
+
OPENCODE_CONFIG_CONTENT: content,
|
|
1471
|
+
};
|
|
1472
|
+
return await new Promise((resolve, reject) => {
|
|
1473
|
+
const child = spawn(executable, args, { env, stdio: "inherit" });
|
|
1474
|
+
child.once("error", (error) => {
|
|
1475
|
+
reject(new CPACError(error instanceof Error && "code" in error && error.code === "ENOENT"
|
|
1476
|
+
? `${executable} not found`
|
|
1477
|
+
: `cannot start ${executable}: ${error.message}`));
|
|
1478
|
+
});
|
|
1479
|
+
child.once("close", (code) => resolve(code ?? 1));
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1430
1482
|
export async function runClaudeModels(parsed) {
|
|
1431
1483
|
if (parsed.pick.length) {
|
|
1432
1484
|
const config = loadConfig(parsed.configPath, true);
|
|
@@ -1783,20 +1835,6 @@ const TARGETS = [
|
|
|
1783
1835
|
await restore(config);
|
|
1784
1836
|
},
|
|
1785
1837
|
},
|
|
1786
|
-
{
|
|
1787
|
-
id: "claude",
|
|
1788
|
-
home: () => expandUserPath(process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), ".claude")),
|
|
1789
|
-
detected: () => binaryOnPath("claude") || existsSync(join(homedir(), ".claude")),
|
|
1790
|
-
installed: () => false,
|
|
1791
|
-
install: async (_config, dryRun) => {
|
|
1792
|
-
const message = "claude needs no install; launch it through CPA with: cpac claude";
|
|
1793
|
-
console.log(dryRun ? `would do nothing: ${message}` : message);
|
|
1794
|
-
},
|
|
1795
|
-
uninstall: async (_config, dryRun) => {
|
|
1796
|
-
const message = "claude keeps no persistent CPAC state; nothing to remove";
|
|
1797
|
-
console.log(dryRun ? `would do nothing: ${message}` : message);
|
|
1798
|
-
},
|
|
1799
|
-
},
|
|
1800
1838
|
{
|
|
1801
1839
|
id: "pi",
|
|
1802
1840
|
home: () => piExtensionsDir(),
|
|
@@ -1945,14 +1983,18 @@ function usage() {
|
|
|
1945
1983
|
" cpac <inject|status|restore> [--config PATH]",
|
|
1946
1984
|
" cpac proxy [--config PATH]",
|
|
1947
1985
|
" cpac claude [--config PATH] [--] [claude args...]",
|
|
1986
|
+
" cpac opencode [--config PATH] [--] [opencode args...]",
|
|
1948
1987
|
" cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--classifier [M]] [--reset] [--config PATH]",
|
|
1949
1988
|
" cpac pi <install|uninstall|status> [--config PATH]",
|
|
1950
1989
|
" cpac kimi <install|uninstall|status> [--config PATH]",
|
|
1951
1990
|
" cpac detect [--json] [--home PATH]",
|
|
1952
|
-
" cpac install [--target codex,
|
|
1953
|
-
" cpac uninstall [--target codex,
|
|
1991
|
+
" cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--home PATH]",
|
|
1992
|
+
" cpac uninstall [--target codex,pi,kimi] [--all] [--dry-run] [--home PATH]",
|
|
1954
1993
|
" cpac upgrade [--check]",
|
|
1955
1994
|
" cpac version",
|
|
1995
|
+
"",
|
|
1996
|
+
"install/uninstall manage persistent injections only; claude and opencode are",
|
|
1997
|
+
"ephemeral — launch them with `cpac claude` / `cpac opencode` instead.",
|
|
1956
1998
|
].join("\n");
|
|
1957
1999
|
}
|
|
1958
2000
|
function parseArgs(args) {
|
|
@@ -2104,6 +2146,20 @@ function parseArgs(args) {
|
|
|
2104
2146
|
index += 1;
|
|
2105
2147
|
return { command: "claude", configPath, args: args.slice(index) };
|
|
2106
2148
|
}
|
|
2149
|
+
if (args[0] === "opencode") {
|
|
2150
|
+
let configPath = defaultConfigPath();
|
|
2151
|
+
let index = 1;
|
|
2152
|
+
if (args[index] === "--config") {
|
|
2153
|
+
const value = args[++index];
|
|
2154
|
+
if (!value)
|
|
2155
|
+
throw new CPACError("--config requires a path");
|
|
2156
|
+
configPath = resolve(expandUserPath(value));
|
|
2157
|
+
index += 1;
|
|
2158
|
+
}
|
|
2159
|
+
if (args[index] === "--")
|
|
2160
|
+
index += 1;
|
|
2161
|
+
return { command: "opencode", configPath, args: args.slice(index) };
|
|
2162
|
+
}
|
|
2107
2163
|
if (args.includes("-h") || args.includes("--help")) {
|
|
2108
2164
|
console.log(usage());
|
|
2109
2165
|
return null;
|
|
@@ -2178,6 +2234,8 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
2178
2234
|
}
|
|
2179
2235
|
if (parsed.command === "claude")
|
|
2180
2236
|
return await runClaude(config, parsed.args);
|
|
2237
|
+
if (parsed.command === "opencode")
|
|
2238
|
+
return await runOpencode(config, parsed.args);
|
|
2181
2239
|
if (parsed.command === "claude-models")
|
|
2182
2240
|
return await runClaudeModels(parsed);
|
|
2183
2241
|
if (parsed.command === "proxy")
|