@yhong91/cpac 0.1.17 → 0.1.19

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
@@ -40,6 +40,7 @@ cpac status
40
40
  cpac install --all # 注入所有检测到的目标(codex/pi/kimi)
41
41
  cpac install --target codex # 只注入 Codex(默认开启 multi-agent v2)
42
42
  cpac install --target codex --v2_models # 先多选 spawn_agent 模型再注入
43
+ cpac install --target codex --max_context # 注入时把模型上下文提升到实测上限(opt-in,仅限 codex)
43
44
  cpac uninstall --target codex # 字节级恢复原配置
44
45
 
45
46
  # 4b. 临时接管(退出无痕,不写任何配置文件)
@@ -159,7 +160,7 @@ cpac --help
159
160
 
160
161
  ```bash
161
162
  cpac detect [--json] [--home PATH]
162
- cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--home PATH]
163
+ cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]
163
164
  cpac uninstall [--target codex,pi,kimi] [--all] [--dry-run] [--home PATH]
164
165
  cpac upgrade [--check]
165
166
  cpac version
@@ -222,7 +223,7 @@ Claude Code 的发现协议不携带 context 信息,claude 前缀的未知模
222
223
  注入 CPA 模型目录:
223
224
 
224
225
  ```bash
225
- cpac inject [--v2_off] [--v2_models] [--config PATH]
226
+ cpac inject [--v2_off] [--v2_models] [--max_context] [--config PATH]
226
227
  ```
227
228
 
228
229
  查看状态:
@@ -315,7 +316,7 @@ Pi 扩展尊重 `PI_CODING_AGENT_DIR` 环境变量。
315
316
  cpac kimi install
316
317
  ```
317
318
 
318
- 它在 `~/.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`。卸载与状态:
319
320
 
320
321
  ```bash
321
322
  cpac kimi uninstall
package/dist/cpac.js CHANGED
@@ -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.17",
3
+ "version": "0.1.19",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {