@yhong91/cpac 0.1.16 → 0.1.18

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.
Files changed (3) hide show
  1. package/README.md +5 -2
  2. package/dist/cpac.js +49 -10
  3. package/package.json +1 -1
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
  查看状态:
@@ -259,6 +260,8 @@ Codex App/CLI 发给本地代理的 ChatGPT bearer 不会转发到 CPA;代理
259
260
 
260
261
  Codex App 的长驻 `app-server` 可能缓存旧目录。`inject` 会删除 `models_cache.json`;如果选择器仍未更新,请重启 Codex App。
261
262
 
263
+ 注入命令可选 `--max_context`(`cpac inject --max_context` 或 `cpac install --target codex --max_context`,默认不带):把 catalog 中 `max_context_window` 高于 `context_window` 的模型提升到上限,并把 `auto_compact_token_limit` 设为上限的 90%。Codex 把 `context_window` 当输入预算而非展示标签,上游默认保留保守运营值(如 GPT-5.6 家族 272k),带上该参数后可用到实测上限(约 921k,opencodex 实测);90% 压缩线确保在硬上限前触发 auto-compact。不带参数注入的仍是原本上下文的目录。该参数仅限 codex,与其他 target 组合使用会直接报错。
264
+
262
265
  第一次注入时,原文件按原始 bytes 备份到 `state_dir/config.toml.backup`。重复注入不会覆盖首次备份,并会保留 CPAC 管理字段之外的用户编辑。`restore` 按原 mode 逐字节恢复首次备份、关闭 CPAC loopback 代理;若原文件不存在,则删除注入创建的 `config.toml`。
263
266
 
264
267
  loopback 代理是 detached 用户进程,不安装系统服务。机器重启或进程意外退出后,`cpac status` 会报告 `loopback proxy stopped`;重新执行 `cpac inject` 即可恢复。
package/dist/cpac.js CHANGED
@@ -258,6 +258,29 @@ export async function fetchCatalog(cpaUrl, apiKey) {
258
258
  modelCount: models.length,
259
259
  };
260
260
  }
261
+ // Codex treats a catalog model's context_window as its input budget, not a
262
+ // display label; upstream keeps it a conservative operating cap while
263
+ // max_context_window holds the real ceiling (gpt-5.6: 272k vs ~921k, measured
264
+ // by opencodex). Opt-in lift: raise context_window to max_context_window and
265
+ // set auto_compact_token_limit at 90% (Codex's own convention), keeping
266
+ // compaction ahead of the hard ceiling.
267
+ export function liftContextWindows(bytes) {
268
+ const document = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
269
+ for (const model of document.models) {
270
+ const maxWindow = typeof model.max_context_window === "number" &&
271
+ model.max_context_window > 0
272
+ ? Math.floor(model.max_context_window)
273
+ : 0;
274
+ const window = typeof model.context_window === "number"
275
+ ? Math.floor(model.context_window)
276
+ : 0;
277
+ if (maxWindow <= window)
278
+ continue;
279
+ model.context_window = maxWindow;
280
+ model.auto_compact_token_limit = Math.floor(maxWindow * 0.9);
281
+ }
282
+ return Buffer.from(`${JSON.stringify(document, null, 2)}\n`);
283
+ }
261
284
  // Move `order` slugs to the front of the rich catalog (stable for the rest),
262
285
  // so the Codex client's first-5 spawn_agent advertisement picks them.
263
286
  export function reorderCatalog(bytes, order) {
@@ -1173,7 +1196,7 @@ function proxyFingerprint(config, apiKey) {
1173
1196
  .update(apiKey)
1174
1197
  .digest("hex");
1175
1198
  }
1176
- export async function inject(config, v2Off = false) {
1199
+ export async function inject(config, v2Off = false, maxContext = false) {
1177
1200
  const apiKey = process.env[config.api_key_env]?.trim();
1178
1201
  if (!apiKey)
1179
1202
  throw new CPACError(`environment variable ${config.api_key_env} is not set`);
@@ -1211,6 +1234,8 @@ export async function inject(config, v2Off = false) {
1211
1234
  const catalog = await fetchCatalog(config.cpa_url, apiKey);
1212
1235
  if (config.spawn_models?.length)
1213
1236
  catalog.bytes = reorderCatalog(catalog.bytes, config.spawn_models);
1237
+ if (maxContext)
1238
+ catalog.bytes = liftContextWindows(catalog.bytes);
1214
1239
  const stateDirExisted = existsSync(config.state_dir);
1215
1240
  if (!state &&
1216
1241
  STATE_FILES.some((name) => existsSync(join(config.state_dir, name)))) {
@@ -1845,12 +1870,12 @@ const TARGETS = [
1845
1870
  return false;
1846
1871
  }
1847
1872
  },
1848
- install: async (config, dryRun, v2Off) => {
1873
+ install: async (config, dryRun, v2Off, maxContext) => {
1849
1874
  if (dryRun) {
1850
1875
  console.log("would inject CPA catalog and loopback proxy into Codex");
1851
1876
  return;
1852
1877
  }
1853
- await inject(config, v2Off);
1878
+ await inject(config, v2Off, maxContext);
1854
1879
  },
1855
1880
  uninstall: async (config, dryRun) => {
1856
1881
  if (dryRun) {
@@ -1934,12 +1959,17 @@ export async function runInstall(config, requested, options) {
1934
1959
  if (selected.length === 0) {
1935
1960
  throw new CPACError(`no supported targets detected; use --target ${TARGETS.map((target) => target.id).join(",")} or --all`);
1936
1961
  }
1962
+ // Catalog context lifting is Codex-specific; refuse to silently skip it on
1963
+ // other targets so the flag never gains cross-agent meaning.
1964
+ if (options.maxContext && selected.some((target) => target.id !== "codex")) {
1965
+ throw new CPACError("--max_context is only valid with --target codex");
1966
+ }
1937
1967
  for (const target of selected) {
1938
1968
  if (target.installed(config) && !options.force) {
1939
1969
  console.log(`${target.id}: already installed; use --force to reinstall`);
1940
1970
  continue;
1941
1971
  }
1942
- await target.install(config, options.dryRun, options.v2Off);
1972
+ await target.install(config, options.dryRun, options.v2Off, options.maxContext);
1943
1973
  }
1944
1974
  return 0;
1945
1975
  }
@@ -2005,7 +2035,7 @@ export async function runUpgrade(checkOnly) {
2005
2035
  function usage() {
2006
2036
  return [
2007
2037
  "Usage: cpac",
2008
- " cpac inject [--v2_off] [--v2_models] [--config PATH]",
2038
+ " cpac inject [--v2_off] [--v2_models] [--max_context] [--config PATH]",
2009
2039
  " cpac <status|restore> [--config PATH]",
2010
2040
  " cpac proxy [--config PATH]",
2011
2041
  " cpac claude [--config PATH] [--] [claude args...]",
@@ -2014,7 +2044,7 @@ function usage() {
2014
2044
  " cpac pi <install|uninstall|status> [--config PATH]",
2015
2045
  " cpac kimi <install|uninstall|status> [--config PATH]",
2016
2046
  " cpac detect [--json] [--home PATH]",
2017
- " cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--home PATH]",
2047
+ " cpac install [--target codex,pi,kimi] [--all] [--dry-run] [--force] [--v2_off] [--v2_models] [--max_context] [--home PATH]",
2018
2048
  " cpac uninstall [--target codex,pi,kimi] [--all] [--dry-run] [--home PATH]",
2019
2049
  " cpac upgrade [--check]",
2020
2050
  " cpac version",
@@ -2043,6 +2073,7 @@ function parseArgs(args) {
2043
2073
  check: false,
2044
2074
  v2Off: false,
2045
2075
  v2Models: false,
2076
+ maxContext: false,
2046
2077
  };
2047
2078
  for (let index = 1; index < args.length; index++) {
2048
2079
  const arg = args[index];
@@ -2083,6 +2114,9 @@ function parseArgs(args) {
2083
2114
  else if (arg === "--v2_models" || arg === "--v2-models") {
2084
2115
  parsed.v2Models = true;
2085
2116
  }
2117
+ else if (arg === "--max_context" || arg === "--max-context") {
2118
+ parsed.maxContext = true;
2119
+ }
2086
2120
  else {
2087
2121
  throw new CPACError(`unknown option: ${arg}`);
2088
2122
  }
@@ -2194,6 +2228,7 @@ function parseArgs(args) {
2194
2228
  const positional = [];
2195
2229
  let v2Off = false;
2196
2230
  let v2Models = false;
2231
+ let maxContext = false;
2197
2232
  for (let index = 0; index < args.length; index += 1) {
2198
2233
  if (args[index] === "--config") {
2199
2234
  const value = args[++index];
@@ -2207,6 +2242,9 @@ function parseArgs(args) {
2207
2242
  else if (args[index] === "--v2_models" || args[index] === "--v2-models") {
2208
2243
  v2Models = true;
2209
2244
  }
2245
+ else if (args[index] === "--max_context" || args[index] === "--max-context") {
2246
+ maxContext = true;
2247
+ }
2210
2248
  else if (args[index].startsWith("-")) {
2211
2249
  throw new CPACError(`unknown option: ${args[index]}`);
2212
2250
  }
@@ -2217,11 +2255,11 @@ function parseArgs(args) {
2217
2255
  !["inject", "status", "restore", "proxy"].includes(positional[0])) {
2218
2256
  throw new CPACError(usage());
2219
2257
  }
2220
- if (positional[0] !== "inject" && (v2Off || v2Models)) {
2221
- throw new CPACError("--v2_off / --v2_models is only valid with inject or install");
2258
+ if (positional[0] !== "inject" && (v2Off || v2Models || maxContext)) {
2259
+ throw new CPACError("--v2_off / --v2_models / --max_context is only valid with inject or install");
2222
2260
  }
2223
2261
  if (positional[0] === "inject") {
2224
- return { command: "inject", configPath, v2Off, v2Models };
2262
+ return { command: "inject", configPath, v2Off, v2Models, maxContext };
2225
2263
  }
2226
2264
  return {
2227
2265
  command: positional[0],
@@ -2259,6 +2297,7 @@ export async function main(args = process.argv.slice(2)) {
2259
2297
  dryRun: parsed.dryRun,
2260
2298
  force: parsed.force,
2261
2299
  v2Off: parsed.v2Off,
2300
+ maxContext: parsed.maxContext,
2262
2301
  });
2263
2302
  }
2264
2303
  if (parsed.command === "uninstall")
@@ -2292,7 +2331,7 @@ export async function main(args = process.argv.slice(2)) {
2292
2331
  console.log(`spawn_models saved to ${parsed.configPath}: ${picked.join(", ")}`);
2293
2332
  injectConfig = { ...config, spawn_models: picked };
2294
2333
  }
2295
- await inject(injectConfig, parsed.v2Off);
2334
+ await inject(injectConfig, parsed.v2Off, parsed.maxContext);
2296
2335
  }
2297
2336
  else if (parsed.command === "restore")
2298
2337
  await restore(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yhong91/cpac",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {