@yhong91/cpac 0.1.18 → 0.1.20
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 +79 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ cpac status # 验证:各 target 显示 ready/injected
|
|
|
101
101
|
```text
|
|
102
102
|
CPA Companion
|
|
103
103
|
|
|
104
|
-
CPA:
|
|
104
|
+
CPA: http://cpa.vibetime.cc:8317
|
|
105
105
|
CPA_API_KEY: configured / not configured
|
|
106
106
|
|
|
107
107
|
Commands:
|
|
@@ -112,7 +112,7 @@ Commands:
|
|
|
112
112
|
cpac --help Show command usage
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
默认 CPA 地址内置为 `
|
|
115
|
+
默认 CPA 地址内置为 `http://cpa.vibetime.cc:8317`,不需要创建 `~/.config/cpac/`。
|
|
116
116
|
|
|
117
117
|
若 `CPA_API_KEY` 尚未设置,交互式引导会隐藏输入密钥,并将受 CPAC 标记管理的 export 区块写入当前 shell 的启动文件:
|
|
118
118
|
|
|
@@ -316,7 +316,7 @@ Pi 扩展尊重 `PI_CODING_AGENT_DIR` 环境变量。
|
|
|
316
316
|
cpac kimi install
|
|
317
317
|
```
|
|
318
318
|
|
|
319
|
-
它在 `~/.kimi-code/config.toml` 追加一个由 CPAC 管理的块,注册 `cpac` OpenAI 兼容 provider,并把 CPA 目录里的每个模型映射为一个 `cpac/<模型名>`
|
|
319
|
+
它在 `~/.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` 指向 Codex 注入使用的 loopback 代理,因此密钥不落盘;代理未运行时 install 会提示先执行 `cpac inject`。卸载与状态:
|
|
320
320
|
|
|
321
321
|
```bash
|
|
322
322
|
cpac kimi uninstall
|
|
@@ -330,7 +330,7 @@ Kimi Code 配置目录尊重 `KIMI_CODE_HOME` 环境变量。首次写入前若
|
|
|
330
330
|
| 变量 | 默认值 | 作用 |
|
|
331
331
|
| --- | --- | --- |
|
|
332
332
|
| `CPA_API_KEY` | 无 | CPA Bearer key;可由 `cpac` 首次引导写入 shell 启动文件 |
|
|
333
|
-
| `CPA_BASE_URL` | `
|
|
333
|
+
| `CPA_BASE_URL` | `http://cpa.vibetime.cc:8317` | 覆盖内置 CPA 地址 |
|
|
334
334
|
| `PI_CODING_AGENT_DIR` | `~/.pi/agent` | 覆盖 Pi agent 目录(影响 `cpac pi install` 写入位置) |
|
|
335
335
|
| `KIMI_CODE_HOME` | `~/.kimi-code` | 覆盖 Kimi Code 目录(影响 `cpac kimi install` 写入位置) |
|
|
336
336
|
| `CPAC_CONFIG` | `~/.config/cpac/config.json` | 指定可选 JSON 配置路径 |
|
|
@@ -342,7 +342,7 @@ CPAC CLI 可临时覆盖 CPA 地址:
|
|
|
342
342
|
CPA_BASE_URL='https://cpa.example.com' cpac claude
|
|
343
343
|
```
|
|
344
344
|
|
|
345
|
-
`pi-cpa.ts` 插件不读取此变量,固定连接远程 `
|
|
345
|
+
`pi-cpa.ts` 插件不读取此变量,固定连接远程 `http://cpa.vibetime.cc:8317`,并且只从 Pi 进程环境读取 `CPA_API_KEY`;不读取用户 home 中的私有文件。
|
|
346
346
|
|
|
347
347
|
## 可选 JSON 配置
|
|
348
348
|
|
package/dist/cpac.js
CHANGED
|
@@ -10,7 +10,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
10
10
|
import { createInterface } from "node:readline/promises";
|
|
11
11
|
import { Writable } from "node:stream";
|
|
12
12
|
export const PROVIDER = "cpac_cpa";
|
|
13
|
-
const DEFAULT_CPA_URL = "
|
|
13
|
+
const DEFAULT_CPA_URL = "http://cpa.vibetime.cc:8317";
|
|
14
14
|
const DEFAULT_CODEX_PROXY_PORT = 10101;
|
|
15
15
|
const MAX_CATALOG_BYTES = 16 * 1024 * 1024;
|
|
16
16
|
const CONFIG_KEYS = new Set([
|
|
@@ -402,6 +402,9 @@ export async function pickSpawnModels(config) {
|
|
|
402
402
|
export function tomlString(value) {
|
|
403
403
|
return JSON.stringify(value);
|
|
404
404
|
}
|
|
405
|
+
function tomlStringArray(values) {
|
|
406
|
+
return `[ ${values.map(tomlString).join(", ")} ]`;
|
|
407
|
+
}
|
|
405
408
|
export function dominantEol(content) {
|
|
406
409
|
const crlf = (content.match(/\r\n/g) ?? []).length;
|
|
407
410
|
if (crlf === 0)
|
|
@@ -1751,6 +1754,30 @@ export function isKimiConfigInstalled() {
|
|
|
1751
1754
|
return false;
|
|
1752
1755
|
}
|
|
1753
1756
|
}
|
|
1757
|
+
function isCpacTableHeader(line) {
|
|
1758
|
+
const header = line.match(/^\[([^\]]+)\]\s*$/);
|
|
1759
|
+
if (!header)
|
|
1760
|
+
return false;
|
|
1761
|
+
const name = header[1];
|
|
1762
|
+
return (name === "providers.cpac" ||
|
|
1763
|
+
name.startsWith("providers.cpac.") ||
|
|
1764
|
+
/^models\.(?:"cpac\/|'cpac\/)/.test(name));
|
|
1765
|
+
}
|
|
1766
|
+
// Kimi may rewrite config.toml and drop our comment markers, leaving the
|
|
1767
|
+
// [providers.cpac] / [models."cpac/..."] tables behind. A later install would
|
|
1768
|
+
// then append a second copy and make the file invalid TOML.
|
|
1769
|
+
function stripOrphanCpacTables(content) {
|
|
1770
|
+
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
1771
|
+
const out = [];
|
|
1772
|
+
let skipping = false;
|
|
1773
|
+
for (const line of content.split(/\r?\n/)) {
|
|
1774
|
+
if (/^\[[^\]]+\]\s*$/.test(line))
|
|
1775
|
+
skipping = isCpacTableHeader(line);
|
|
1776
|
+
if (!skipping)
|
|
1777
|
+
out.push(line);
|
|
1778
|
+
}
|
|
1779
|
+
return out.join(eol).replace(/(?:\r?\n){3,}/g, `${eol}${eol}`);
|
|
1780
|
+
}
|
|
1754
1781
|
function writeKimiBlock(path, block) {
|
|
1755
1782
|
let content = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
1756
1783
|
content = content.replace(kimiBlockRegex, "");
|
|
@@ -1761,6 +1788,7 @@ function writeKimiBlock(path, block) {
|
|
|
1761
1788
|
const orphan = content.indexOf(KIMI_BLOCK_START);
|
|
1762
1789
|
if (orphan !== -1)
|
|
1763
1790
|
content = content.slice(0, orphan);
|
|
1791
|
+
content = stripOrphanCpacTables(content);
|
|
1764
1792
|
if (block) {
|
|
1765
1793
|
content = `${content}${content && !content.endsWith("\n") ? "\n" : ""}${block}\n`;
|
|
1766
1794
|
}
|
|
@@ -1768,6 +1796,40 @@ function writeKimiBlock(path, block) {
|
|
|
1768
1796
|
const mode = existsSync(path) ? statSync(path).mode & 0o7777 : 0o600;
|
|
1769
1797
|
atomicWrite(path, Buffer.from(content), mode);
|
|
1770
1798
|
}
|
|
1799
|
+
const KIMI_REASONING_EFFORTS = new Set([
|
|
1800
|
+
"minimal",
|
|
1801
|
+
"low",
|
|
1802
|
+
"medium",
|
|
1803
|
+
"high",
|
|
1804
|
+
"xhigh",
|
|
1805
|
+
"max",
|
|
1806
|
+
"ultra",
|
|
1807
|
+
]);
|
|
1808
|
+
function kimiSupportEfforts(row) {
|
|
1809
|
+
const levels = row.supported_reasoning_levels;
|
|
1810
|
+
if (!Array.isArray(levels))
|
|
1811
|
+
return [];
|
|
1812
|
+
const seen = new Set();
|
|
1813
|
+
const efforts = [];
|
|
1814
|
+
for (const level of levels) {
|
|
1815
|
+
const effort = typeof level === "string"
|
|
1816
|
+
? level
|
|
1817
|
+
: objectValue(level) && typeof level.effort === "string"
|
|
1818
|
+
? level.effort
|
|
1819
|
+
: undefined;
|
|
1820
|
+
if (!effort || !KIMI_REASONING_EFFORTS.has(effort) || seen.has(effort))
|
|
1821
|
+
continue;
|
|
1822
|
+
seen.add(effort);
|
|
1823
|
+
efforts.push(effort);
|
|
1824
|
+
}
|
|
1825
|
+
return efforts;
|
|
1826
|
+
}
|
|
1827
|
+
function kimiInputHasImage(row) {
|
|
1828
|
+
const modalities = row.input_modalities;
|
|
1829
|
+
if (!Array.isArray(modalities))
|
|
1830
|
+
return true;
|
|
1831
|
+
return modalities.some((value) => value === "image");
|
|
1832
|
+
}
|
|
1771
1833
|
export async function installKimiConfig(config) {
|
|
1772
1834
|
const apiKey = await resolveApiKey(config.api_key_env);
|
|
1773
1835
|
const catalog = await fetchCatalog(config.cpa_url, apiKey);
|
|
@@ -1797,10 +1859,25 @@ export async function installKimiConfig(config) {
|
|
|
1797
1859
|
const context = typeof row.context_window === "number" && row.context_window > 0
|
|
1798
1860
|
? Math.floor(row.context_window)
|
|
1799
1861
|
: 200000;
|
|
1800
|
-
|
|
1862
|
+
const efforts = kimiSupportEfforts(row);
|
|
1863
|
+
const capabilities = [
|
|
1864
|
+
...(efforts.length > 0 ? ["thinking"] : []),
|
|
1865
|
+
"tool_use",
|
|
1866
|
+
...(kimiInputHasImage(row) ? ["image_in"] : []),
|
|
1867
|
+
];
|
|
1868
|
+
lines.push("", `[models."cpac/${slug}"]`, 'provider = "cpac"', `model = ${tomlString(slug)}`, `max_context_size = ${context}`, `capabilities = ${tomlStringArray(capabilities)}`);
|
|
1801
1869
|
if (typeof row.display_name === "string" && row.display_name.trim()) {
|
|
1802
1870
|
lines.push(`display_name = ${tomlString(row.display_name)}`);
|
|
1803
1871
|
}
|
|
1872
|
+
if (efforts.length > 0) {
|
|
1873
|
+
lines.push(`support_efforts = ${tomlStringArray(efforts)}`);
|
|
1874
|
+
const defaultEffort = typeof row.default_reasoning_level === "string" &&
|
|
1875
|
+
efforts.includes(row.default_reasoning_level)
|
|
1876
|
+
? row.default_reasoning_level
|
|
1877
|
+
: undefined;
|
|
1878
|
+
if (defaultEffort)
|
|
1879
|
+
lines.push(`default_effort = ${tomlString(defaultEffort)}`);
|
|
1880
|
+
}
|
|
1804
1881
|
}
|
|
1805
1882
|
lines.push(KIMI_BLOCK_END);
|
|
1806
1883
|
const target = kimiConfigPath();
|