@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 CHANGED
@@ -101,7 +101,7 @@ cpac status # 验证:各 target 显示 ready/injected
101
101
  ```text
102
102
  CPA Companion
103
103
 
104
- CPA: https://cpa.vibetime.cc
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 地址内置为 `https://cpa.vibetime.cc`,不需要创建 `~/.config/cpac/`。
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/<模型名>` 条目。`base_url` 指向 Codex 注入使用的 loopback 代理,因此密钥不落盘;代理未运行时 install 会提示先执行 `cpac inject`。卸载与状态:
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` | `https://cpa.vibetime.cc` | 覆盖内置 CPA 地址 |
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` 插件不读取此变量,固定连接远程 `https://cpa.vibetime.cc`,并且只从 Pi 进程环境读取 `CPA_API_KEY`;不读取用户 home 中的私有文件。
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 = "https://cpa.vibetime.cc";
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
- lines.push("", `[models."cpac/${slug}"]`, 'provider = "cpac"', `model = ${tomlString(slug)}`, `max_context_size = ${context}`);
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yhong91/cpac",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {