@yhong91/cpac 0.1.37 → 0.1.38

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
@@ -175,7 +175,7 @@ cpac -v | --version
175
175
 
176
176
  - `detect` 列出每个目标是否被检测到、是否已接入 CPAC;`--json` 输出机器可读结果。
177
177
  - `install` 默认作用于检测到的目标;后面直接写 agent 名(`cpac install codex pi`),`--all` 全部。`codex` 写入 catalog 并拉起 loopback 代理;`pi`/`kimi`/`grok` 写入各自配置。`--dry-run` 只打印将要做的事,`--force` 允许重装已安装目标。
178
- - `sync` 按当前 `cpa_url` 和 CPA 目录强制刷新**已经接入**的目标(Codex 重新注入、Pi 确认 `npm:@yhong91/cpac` 并清理旧的 `extensions/pi-cpac.ts`、Kimi 配置重写),用来在 CPA 地址或模型目录变化后一次对齐本地配置。不带参数只动已安装目标;`--all` 会对检测到的目标做同样的强制刷新(尚未安装的会装上)。`--max_context` 仍只对 `cpac install codex` 有效。
178
+ - `sync` 按当前 `cpa_url` 和 CPA 目录强制刷新**已经接入**的目标(Codex 重新注入、Pi CLI 版本决定写入 packages / `pi update` / 跳过,并清理旧的 `extensions/pi-cpac.ts`、Kimi 配置重写),用来在 CPA 地址或模型目录变化后一次对齐本地配置。不带参数只动已安装目标;`--all` 会对检测到的目标做同样的强制刷新(尚未安装的会装上)。`--max_context` 仍只对 `cpac install codex` 有效。
179
179
  - Codex 注入默认开启 multi-agent v2(写入 `[features.multi_agent_v2] enabled = true`,catalog 行打 `multi_agent_version: "v2"`);`install codex --v2_off` 关掉 toml 并去掉 catalog 戳。v2 开着时会剥掉 `[agents] max_threads`(Codex 否则拒启动)。`cpac status` 对照 config 里的 `v2_off` / `max_context` 和 live toml / catalog。服务端还需在 CPA 配置中开启 `codex.optimize-multi-agent-v2`。
180
180
  - `--v2_models` 进入 arrow-key 复选框选择最多 5 个 spawn_agent 模型(勾选顺序即推荐顺序),选择结果存入配置文件的 `spawn_models`,注入时把这些模型排到 `codex-models.json` 最前——Codex 客户端只把 catalog 前 5 个可见模型广告为 spawn 覆盖项。
181
181
  - `restore` 必须带 agent 名或 `--all`,卸掉指定(或全部)已注入目标。`--all` 时未安装的目标静默跳过。
@@ -270,19 +270,14 @@ restore / `<agent> clear` 会删掉该 agent 的备份目录和 state.json 里
270
270
 
271
271
  ### Pi
272
272
 
273
- 安装 CPA provider 扩展到 Pi:
274
-
275
273
  ```bash
276
- cpac pi install
274
+ cpac install pi
275
+ cpac pi
277
276
  ```
278
277
 
279
- `~/.pi/agent/settings.json` 的 `packages` 中加入 `npm:@yhong91/cpac`。Pi 启动时按 npm 包加载 `extensions/pi-cpac.ts`,从 CPA 动态注册模型。旧版写入的 `~/.pi/agent/extensions/pi-cpac.ts` 会在 install / restore 时删掉。卸载:
280
-
281
- ```bash
282
- cpac restore pi
283
- ```
278
+ 未接入时把 `npm:@yhong91/cpac` 写入 `~/.pi/agent/settings.json` 的 `packages`。已接入则比较 `~/.pi/agent/npm/node_modules/@yhong91/cpac` 与当前 CLI 版本:落后则 `pi update npm:@yhong91/cpac`,已是最新(或尚未下载副本)则跳过。`cpac pi` 启动前走同一套判断。Pi 启动时加载 `extensions/pi-cpac.ts` CPA 动态注册模型。旧版 `~/.pi/agent/extensions/pi-cpac.ts` 会在 install / restore 时删掉。
284
279
 
285
- 尊重 `PI_CODING_AGENT_DIR`。扩展代码随 npm 包更新,已装过的副本用 `pi update npm:@yhong91/cpac`(或 `pi update --extensions`)。
280
+ 卸载:`cpac restore pi` `cpac pi clear`。尊重 `PI_CODING_AGENT_DIR`。
286
281
 
287
282
  ### Kimi Code
288
283
 
package/dist/agents.js CHANGED
@@ -7,8 +7,8 @@ import { MAX_SPAWN_MODELS, loadCatalogSlugs, pickSpawnModels, saveCodexSetup, sa
7
7
  import { MANAGED_MARKER, inject, restore } from "./targets/codex.js";
8
8
  import { grokConfigPath, grokHome, installGrokConfig, isGrokConfigInstalled, uninstallGrokConfig, } from "./targets/grok.js";
9
9
  import { installKimiConfig, isKimiConfigInstalled, kimiConfigPath, uninstallKimiConfig, } from "./targets/kimi.js";
10
- import { PI_PACKAGE, installPiExtension, isPiExtensionInstalled, piAgentDir, piSettingsPath, uninstallPiExtension, } from "./targets/pi.js";
11
- import { CPACError, atomicWrite, checkboxPicker, expandUserPath, objectValue, tabWizard, } from "./util.js";
10
+ import { PI_PACKAGE, ensurePiExtension, isPiExtensionInstalled, piAgentDir, piSettingsPath, uninstallPiExtension, } from "./targets/pi.js";
11
+ import { CPACError, atomicWrite, checkboxPicker, compareVersions, expandUserPath, objectValue, tabWizard, } from "./util.js";
12
12
  const CODEX_CTX_STD = "Standard (default input budget, e.g. 200K~272K)";
13
13
  const CODEX_CTX_MAX = "Max Context Window (lift to full upper bound, e.g. 921K~1M, 90% auto-compact limit)";
14
14
  const CODEX_V2_ON = "Enabled (Default)";
@@ -220,11 +220,7 @@ const TARGETS = [
220
220
  installed: () => isPiExtensionInstalled(),
221
221
  version: () => detectClientVersion("pi"),
222
222
  install: async (config, dryRun) => {
223
- if (dryRun) {
224
- console.log(`would add ${PI_PACKAGE} to ${piSettingsPath()}`);
225
- return;
226
- }
227
- await installPiExtension(config);
223
+ await ensurePiExtension(config, CPAC_VERSION, dryRun);
228
224
  },
229
225
  uninstall: async (config, dryRun) => {
230
226
  if (dryRun) {
@@ -321,7 +317,7 @@ export async function runInstall(config, requested, options) {
321
317
  throw new CPACError("--max_context is only valid with codex");
322
318
  }
323
319
  for (const target of selected) {
324
- if (target.installed(config) && !options.force) {
320
+ if (target.installed(config) && !options.force && target.id !== "pi") {
325
321
  console.log(`${target.id}: already installed; use --force to reinstall`);
326
322
  continue;
327
323
  }
@@ -398,17 +394,6 @@ export async function runUninstall(config, options) {
398
394
  }
399
395
  return 0;
400
396
  }
401
- function compareVersions(a, b) {
402
- const left = a.split(".").map(Number);
403
- const right = b.split(".").map(Number);
404
- for (let index = 0; index < Math.max(left.length, right.length); index++) {
405
- const l = left[index] ?? 0;
406
- const r = right[index] ?? 0;
407
- if (l !== r)
408
- return l > r ? 1 : -1;
409
- }
410
- return 0;
411
- }
412
397
  export async function runUpgrade(config, checkOnly) {
413
398
  console.log(`Current version: ${CPAC_VERSION}`);
414
399
  let latest;
package/dist/cpac.js CHANGED
@@ -20,7 +20,7 @@ export { claudeTierSlots, createClaudeProxy, runClaude, } from "./targets/claude
20
20
  export { detectClientVersion, detectTargets, runInstall, runRestore, runSync, runTargetLauncher, } from "./agents.js";
21
21
  export { installGrokConfig, isGrokConfigInstalled, uninstallGrokConfig, } from "./targets/grok.js";
22
22
  export { installKimiConfig, isKimiConfigInstalled, uninstallKimiConfig, } from "./targets/kimi.js";
23
- export { installPiExtension, isPiExtensionInstalled, uninstallPiExtension, } from "./targets/pi.js";
23
+ export { ensurePiExtension, installPiExtension, isPiExtensionInstalled, piPackageAction, piPackageVersion, uninstallPiExtension, } from "./targets/pi.js";
24
24
  export async function status(config) {
25
25
  const apiKey = process.env[config.api_key_env]?.trim();
26
26
  const keyConfigured = !!apiKey;
@@ -1,9 +1,10 @@
1
+ import { spawnSync } from "node:child_process";
1
2
  import { existsSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
2
3
  import { homedir } from "node:os";
3
4
  import { join } from "node:path";
4
5
  import { dropAgent, recordAgent } from "../config.js";
5
6
  import { stopProxyProcess } from "../proxy.js";
6
- import { CPACError, atomicWrite, expandUserPath, objectValue, } from "../util.js";
7
+ import { CPACError, atomicWrite, compareVersions, expandUserPath, objectValue, } from "../util.js";
7
8
  export const PI_PACKAGE = "npm:@yhong91/cpac";
8
9
  const PI_PACKAGE_NAME = "@yhong91/cpac";
9
10
  const LEGACY_EXTENSIONS = ["pi-cpac.ts", "cpac.ts", "pi-cpa.ts"];
@@ -91,6 +92,48 @@ export function isPiExtensionInstalled() {
91
92
  return false;
92
93
  }
93
94
  }
95
+ export function piPackageVersion() {
96
+ const pkg = join(piAgentDir(), "npm", "node_modules", "@yhong91", "cpac", "package.json");
97
+ try {
98
+ const version = JSON.parse(readFileSync(pkg, "utf8")).version;
99
+ return typeof version === "string" ? version : undefined;
100
+ }
101
+ catch {
102
+ return undefined;
103
+ }
104
+ }
105
+ export function piPackageAction(desiredVersion) {
106
+ if (leftoverExtensions().length > 0 || !isPiExtensionInstalled()) {
107
+ return "install";
108
+ }
109
+ const version = piPackageVersion();
110
+ if (version !== undefined && compareVersions(version, desiredVersion) < 0) {
111
+ return "upgrade";
112
+ }
113
+ return "none";
114
+ }
115
+ export async function ensurePiExtension(config, desiredVersion, dryRun = false) {
116
+ const action = piPackageAction(desiredVersion);
117
+ if (action === "none")
118
+ return;
119
+ if (dryRun) {
120
+ console.log(action === "install"
121
+ ? `would add ${PI_PACKAGE} to ${piSettingsPath()}`
122
+ : `would update ${PI_PACKAGE}`);
123
+ return;
124
+ }
125
+ if (action === "install") {
126
+ await installPiExtension(config);
127
+ return;
128
+ }
129
+ const result = spawnSync("pi", ["update", PI_PACKAGE], {
130
+ stdio: "inherit",
131
+ env: { ...process.env, PI_CODING_AGENT_DIR: piAgentDir() },
132
+ });
133
+ if (result.error || (result.status ?? 1) !== 0) {
134
+ console.warn(`warning: pi update ${PI_PACKAGE} failed`);
135
+ }
136
+ }
94
137
  export async function installPiExtension(config) {
95
138
  const path = piSettingsPath();
96
139
  mkdirSync(piAgentDir(), { recursive: true, mode: 0o700 });
package/dist/util.js CHANGED
@@ -205,9 +205,7 @@ export async function tabWizard(tabs) {
205
205
  };
206
206
  const resultOf = () => Object.fromEntries(state.map((tab) => [
207
207
  tab.id,
208
- [...tab.selected]
209
- .sort((a, b) => a - b)
210
- .map((i) => tab.items[i]),
208
+ [...tab.selected].sort((a, b) => a - b).map((i) => tab.items[i]),
211
209
  ]));
212
210
  const goNext = () => {
213
211
  if (index < state.length && state[index].selected.size === 0)
@@ -385,3 +383,14 @@ export function saveApiKeyExport(profile, name, apiKey) {
385
383
  const mode = existsSync(profile) ? statSync(profile).mode & 0o7777 : 0o600;
386
384
  atomicWrite(profile, Buffer.from(content), mode);
387
385
  }
386
+ export function compareVersions(a, b) {
387
+ const left = a.split(".").map(Number);
388
+ const right = b.split(".").map(Number);
389
+ for (let index = 0; index < Math.max(left.length, right.length); index++) {
390
+ const l = left[index] ?? 0;
391
+ const r = right[index] ?? 0;
392
+ if (l !== r)
393
+ return l > r ? 1 : -1;
394
+ }
395
+ return 0;
396
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yhong91/cpac",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {