@yhong91/cpac 0.2.8 → 0.2.10

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/dist/agents.js CHANGED
@@ -3,8 +3,9 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { basename, dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { MAX_SPAWN_MODELS, fetchCatalog, loadCatalogSlugs, pickSpawnModels, saveCodexSetup, saveSpawnModels, } from "./config.js";
7
- import { markModelsApplied, refreshModelIndex } from "./models.js";
6
+ import { MAX_SPAWN_MODELS, fetchCatalog, loadCatalogSlugs, pickSpawnModels, readState, saveCodexSetup, saveSpawnModels, saveState, stateProxy, } from "./config.js";
7
+ import { ensureLoopbackProxy } from "./proxy.js";
8
+ import { diffModelSlugs, markModelsApplied, readModelIndex, refreshModelIndex, } from "./models.js";
8
9
  import { MANAGED_MARKER, inject, restore } from "./targets/codex.js";
9
10
  import { grokConfigPath, grokHome, installGrokConfig, isGrokConfigInstalled, uninstallGrokConfig, } from "./targets/grok.js";
10
11
  import { installKimiConfig, isKimiConfigInstalled, kimiConfigPath, uninstallKimiConfig, } from "./targets/kimi.js";
@@ -135,6 +136,7 @@ export async function runTargetLauncher(config, targetId, args, executable = tar
135
136
  await target.install(config, false, options.v2Off, options.maxContext);
136
137
  }
137
138
  }
139
+ await ensureLauncherProxy(config, target, options);
138
140
  return await new Promise((resolvePromise, rejectPromise) => {
139
141
  const env = targetId === "zed"
140
142
  ? { ...process.env, CPAC_API_KEY: process.env.CPAC_API_KEY || "cpac" }
@@ -178,6 +180,28 @@ export function detectClientVersion(binary) {
178
180
  }
179
181
  return undefined;
180
182
  }
183
+ async function ensureLauncherProxy(config, target, options) {
184
+ const apiKey = await resolveApiKey(config.api_key_env);
185
+ const before = readState(config.state_dir);
186
+ const previous = before ? stateProxy(before) : null;
187
+ if (!previous) {
188
+ await target.install(config, false, options.v2Off, options.maxContext);
189
+ return;
190
+ }
191
+ const { proxy, fingerprint, started } = await ensureLoopbackProxy(config, apiKey);
192
+ if (!started)
193
+ return;
194
+ saveState(config.state_dir, {
195
+ ...before,
196
+ proxy_id: proxy.id,
197
+ proxy_pid: proxy.pid,
198
+ proxy_port: proxy.port,
199
+ proxy_fingerprint: fingerprint,
200
+ });
201
+ if (previous.port === proxy.port)
202
+ return;
203
+ await target.install(config, false, options.v2Off, options.maxContext);
204
+ }
181
205
  function binaryOnPath(name) {
182
206
  if (!/^[\w.-]+$/.test(name))
183
207
  return false;
@@ -427,17 +451,34 @@ function syncTargetIds(config, requested, all) {
427
451
  }
428
452
  return selected.map((target) => target.id);
429
453
  }
430
- function formatModelVersion(iso) {
431
- const date = new Date(iso);
432
- if (Number.isNaN(date.getTime()))
433
- return iso;
434
- const pad = (value) => String(value).padStart(2, "0");
435
- const clock = `${pad(date.getHours())}:${pad(date.getMinutes())}`;
436
- // ponytail: minute display; the stored ISO still separates same-minute updates
437
- const monthDay = `${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
438
- return date.getFullYear() === new Date().getFullYear()
439
- ? `${monthDay} ${clock}`
440
- : `${date.getFullYear()}-${monthDay} ${clock}`;
454
+ const MODEL_CHANGE_FIELDS = [
455
+ "display_name",
456
+ "context_window",
457
+ "max_context_window",
458
+ "max_tokens",
459
+ "max_output_tokens",
460
+ "input_modalities",
461
+ "supported_reasoning_levels",
462
+ "default_reasoning_level",
463
+ ];
464
+ function logModelChanges(previous, next) {
465
+ const { added, removed } = diffModelSlugs(previous.map((model) => model.slug), next.map((model) => model.slug));
466
+ const addedSet = new Set(added);
467
+ const previousBySlug = new Map(previous.map((model) => [model.slug, model]));
468
+ for (const slug of added)
469
+ console.log(`+ ${slug}`);
470
+ for (const slug of removed)
471
+ console.log(`- ${slug}`);
472
+ for (const model of next) {
473
+ if (addedSet.has(model.slug))
474
+ continue;
475
+ const before = previousBySlug.get(model.slug);
476
+ if (!before)
477
+ continue;
478
+ const fields = MODEL_CHANGE_FIELDS.filter((key) => JSON.stringify(before[key] ?? null) !== JSON.stringify(model[key] ?? null));
479
+ if (fields.length > 0)
480
+ console.log(`~ ${model.slug} ${fields.join(" ")}`);
481
+ }
441
482
  }
442
483
  export async function runSync(config, requested, options) {
443
484
  const ids = syncTargetIds(config, requested, options.all);
@@ -446,16 +487,11 @@ export async function runSync(config, requested, options) {
446
487
  }
447
488
  const apiKey = await resolveApiKey(config.api_key_env);
448
489
  const catalog = await fetchCatalog(config.cpa_url, apiKey);
490
+ const previous = readModelIndex(config.state_dir);
449
491
  const { index, changed } = refreshModelIndex(config.state_dir, catalog.bytes, new Date().toISOString(), !options.dryRun);
450
- console.log(`models ${formatModelVersion(index.updated_at)}${changed ? (options.dryRun ? " would update" : " updated") : " unchanged"}`);
492
+ if (changed)
493
+ logModelChanges(previous?.models ?? [], index.models);
451
494
  const pending = ids.filter((id) => index.applied[id] !== index.updated_at);
452
- for (const id of ids) {
453
- const applied = index.applied[id];
454
- if (applied === index.updated_at)
455
- console.log(` ${id}: unchanged`);
456
- else if (applied)
457
- console.log(` ${id}: ${formatModelVersion(applied)}`);
458
- }
459
495
  if (pending.length === 0)
460
496
  return 0;
461
497
  // ponytail: version is the model-list timestamp only. spawn_models, v2_off,
package/dist/proxy.js CHANGED
@@ -346,6 +346,9 @@ export async function ensureLoopbackProxy(config, apiKey) {
346
346
  if (existing)
347
347
  await stopProxyProcess(existing);
348
348
  const proxy = await startProxyProcess(config, apiKey);
349
+ if (!existing) {
350
+ console.log(`loopback proxy listening on http://127.0.0.1:${proxy.port}/v1`);
351
+ }
349
352
  return { proxy, fingerprint, started: true };
350
353
  }
351
354
  export async function runProxy(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yhong91/cpac",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Connect Codex and Claude Code to a remote CLIProxyAPI gateway",
5
5
  "type": "module",
6
6
  "bin": {