@yhong91/cpac 0.1.9 → 0.1.11
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 +8 -0
- package/dist/cpac.js +71 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -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,9 +1427,61 @@ 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
|
-
const config = loadConfig(parsed.configPath);
|
|
1484
|
+
const config = loadConfig(parsed.configPath, true);
|
|
1433
1485
|
const apiKey = process.env[config.api_key_env]?.trim();
|
|
1434
1486
|
if (!apiKey)
|
|
1435
1487
|
throw new CPACError(`environment variable ${config.api_key_env} is not set`);
|
|
@@ -1444,7 +1496,7 @@ export async function runClaudeModels(parsed) {
|
|
|
1444
1496
|
}
|
|
1445
1497
|
}
|
|
1446
1498
|
if (!parsed.reset && !Object.keys(parsed.models).length) {
|
|
1447
|
-
const config = loadConfig(parsed.configPath);
|
|
1499
|
+
const config = loadConfig(parsed.configPath, true);
|
|
1448
1500
|
console.log(config.claude_models
|
|
1449
1501
|
? JSON.stringify(config.claude_models, null, 2)
|
|
1450
1502
|
: "claude_models not set; cpac claude auto-picks tier models from the CPA catalog");
|
|
@@ -1945,6 +1997,7 @@ function usage() {
|
|
|
1945
1997
|
" cpac <inject|status|restore> [--config PATH]",
|
|
1946
1998
|
" cpac proxy [--config PATH]",
|
|
1947
1999
|
" cpac claude [--config PATH] [--] [claude args...]",
|
|
2000
|
+
" cpac opencode [--config PATH] [--] [opencode args...]",
|
|
1948
2001
|
" cpac claude-models [--opus [M]] [--sonnet [M]] [--haiku [M]] [--classifier [M]] [--reset] [--config PATH]",
|
|
1949
2002
|
" cpac pi <install|uninstall|status> [--config PATH]",
|
|
1950
2003
|
" cpac kimi <install|uninstall|status> [--config PATH]",
|
|
@@ -2104,6 +2157,20 @@ function parseArgs(args) {
|
|
|
2104
2157
|
index += 1;
|
|
2105
2158
|
return { command: "claude", configPath, args: args.slice(index) };
|
|
2106
2159
|
}
|
|
2160
|
+
if (args[0] === "opencode") {
|
|
2161
|
+
let configPath = defaultConfigPath();
|
|
2162
|
+
let index = 1;
|
|
2163
|
+
if (args[index] === "--config") {
|
|
2164
|
+
const value = args[++index];
|
|
2165
|
+
if (!value)
|
|
2166
|
+
throw new CPACError("--config requires a path");
|
|
2167
|
+
configPath = resolve(expandUserPath(value));
|
|
2168
|
+
index += 1;
|
|
2169
|
+
}
|
|
2170
|
+
if (args[index] === "--")
|
|
2171
|
+
index += 1;
|
|
2172
|
+
return { command: "opencode", configPath, args: args.slice(index) };
|
|
2173
|
+
}
|
|
2107
2174
|
if (args.includes("-h") || args.includes("--help")) {
|
|
2108
2175
|
console.log(usage());
|
|
2109
2176
|
return null;
|
|
@@ -2178,6 +2245,8 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
2178
2245
|
}
|
|
2179
2246
|
if (parsed.command === "claude")
|
|
2180
2247
|
return await runClaude(config, parsed.args);
|
|
2248
|
+
if (parsed.command === "opencode")
|
|
2249
|
+
return await runOpencode(config, parsed.args);
|
|
2181
2250
|
if (parsed.command === "claude-models")
|
|
2182
2251
|
return await runClaudeModels(parsed);
|
|
2183
2252
|
if (parsed.command === "proxy")
|