@closedrouter/cli 1.1.7 → 1.1.8

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
@@ -203,3 +203,5 @@ Activity shows per-harness requests, tokens, cached tokens, reasoning tokens, la
203
203
  Other integrations may set the same headers directly. Known client user agents provide fallback attribution; unrecognized clients and older logs appear as `unknown`. Playground requests are tagged `playground`.
204
204
 
205
205
  Request inspection also reports streaming mode, tools offered, tool-result messages supplied, and total message count. These counts describe the request, not which tools the client actually executed. Tool names, arguments, outputs, and message contents are not saved.
206
+
207
+ Antigravity launches register a credential-free custom Gemini-compatible model in `~/.gemini/antigravity-cli/settings.json` under `customModelsConfig.customModels`. Its visible label is `ClosedRouter: <selected model>`, while its internal Gemini transport ID stays compatible with agy. The local adapter continues routing every request to the actual selected pool model. This fixes the previous Gemini placeholder in agy's header. Existing preferences and custom models are preserved; request routing still uses the local model adapter and telemetry relay. Re-run `cr start agy` to choose a different pool model.
@@ -0,0 +1,3 @@
1
+ /** agy's custom-model key is also its visible label. Keep the upstream ID separate. */
2
+ export declare function registerAgyLaunchModel(homeDir: string, model: string, transportModel: string): string;
3
+ //# sourceMappingURL=agy-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agy-model.d.ts","sourceRoot":"","sources":["../../src/commands/agy-model.ts"],"names":[],"mappings":"AAQA,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CA4BrG"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;AACrF,KAAK,OAAO,GAAG,SAAS,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzF;AA8BD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAM,EAAO,EACvB,OAAO,SAAY,EACnB,cAAc,CAAC,EAAE,MAAM,EACvB,UAAU,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACxD,UAAU,CAiHZ;AAmBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAKzF;AAiED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDnF"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;AACrF,KAAK,OAAO,GAAG,SAAS,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzF;AA8BD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAM,EAAO,EACvB,OAAO,SAAY,EACnB,cAAc,CAAC,EAAE,MAAM,EACvB,UAAU,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACxD,UAAU,CAiHZ;AAmBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAKzF;AA2ED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDnF"}
package/dist/index.js CHANGED
@@ -5197,7 +5197,7 @@ var {
5197
5197
  } = exports_commander;
5198
5198
 
5199
5199
  // src/index.ts
5200
- import { readFileSync as readFileSync9 } from "node:fs";
5200
+ import { readFileSync as readFileSync10 } from "node:fs";
5201
5201
 
5202
5202
  // ../node_modules/.bun/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs
5203
5203
  import { stripVTControlCharacters as S2 } from "node:util";
@@ -8645,9 +8645,9 @@ to scan and import local subscriptions!`, "Pool Empty");
8645
8645
  var import_picocolors12 = __toESM(require_picocolors(), 1);
8646
8646
  import { spawn as spawn3 } from "node:child_process";
8647
8647
  import { execFileSync } from "node:child_process";
8648
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "node:fs";
8648
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "node:fs";
8649
8649
  import { homedir as homedir9 } from "node:os";
8650
- import { dirname, join as join9 } from "node:path";
8650
+ import { dirname, join as join10 } from "node:path";
8651
8651
 
8652
8652
  // src/bridge/launch-proxy.ts
8653
8653
  import { randomUUID } from "node:crypto";
@@ -8778,6 +8778,47 @@ async function startAgyModelProxy(gatewayUrl, apiKey, model) {
8778
8778
  };
8779
8779
  }
8780
8780
 
8781
+ // src/commands/agy-model.ts
8782
+ import { randomUUID as randomUUID2 } from "node:crypto";
8783
+ import { existsSync as existsSync9, readFileSync as readFileSync8, renameSync, statSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
8784
+ import { join as join9 } from "node:path";
8785
+ function record(value) {
8786
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8787
+ }
8788
+ function registerAgyLaunchModel(homeDir, model, transportModel) {
8789
+ const path = join9(homeDir, ".gemini", "antigravity-cli", "settings.json");
8790
+ const settings = JSON.parse(readFileSync8(path, "utf8"));
8791
+ if (!record(settings) || settings.modelProvider !== "gemini") {
8792
+ throw new Error(`Set "modelProvider": "gemini" in ${path} before starting Antigravity through ClosedRouter.`);
8793
+ }
8794
+ const config = settings.customModelsConfig ?? {};
8795
+ if (!record(config))
8796
+ throw new Error(`customModelsConfig must be an object in ${path}.`);
8797
+ const models = config.customModels ?? {};
8798
+ if (!record(models))
8799
+ throw new Error(`customModelsConfig.customModels must be an object in ${path}.`);
8800
+ const label = `ClosedRouter: ${model}`;
8801
+ const entry = { modelName: transportModel, apiProvider: "gemini" };
8802
+ const existing = models[label];
8803
+ if (existing !== undefined) {
8804
+ if (!record(existing) || existing.modelName !== transportModel || existing.apiProvider !== "gemini" || Object.keys(existing).some((key) => !["modelName", "apiProvider"].includes(key))) {
8805
+ throw new Error(`The custom model '${label}' already has different settings in ${path}. Rename that entry before launching it with ClosedRouter.`);
8806
+ }
8807
+ return label;
8808
+ }
8809
+ settings.customModelsConfig = { ...config, customModels: { ...models, [label]: entry } };
8810
+ const temporary = `${path}.closedrouter-${randomUUID2()}.tmp`;
8811
+ try {
8812
+ writeFileSync2(temporary, `${JSON.stringify(settings, null, 2)}
8813
+ `, { flag: "wx", mode: statSync(path).mode & 511 });
8814
+ renameSync(temporary, path);
8815
+ } finally {
8816
+ if (existsSync9(temporary))
8817
+ unlinkSync(temporary);
8818
+ }
8819
+ return label;
8820
+ }
8821
+
8781
8822
  // src/commands/start.ts
8782
8823
  function isGatewayModelAvailable(availableModels, model) {
8783
8824
  return availableModels.includes(model);
@@ -8825,9 +8866,9 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8825
8866
  }
8826
8867
  if (tool === "codex") {
8827
8868
  assertNoManagedCodexArgs(toolArgs);
8828
- const codexHome = process.env.CODEX_HOME || join9(homeDir, ".codex");
8869
+ const codexHome = process.env.CODEX_HOME || join10(homeDir, ".codex");
8829
8870
  const profileName = "closedrouter-launch";
8830
- const configPath = join9(codexHome, `${profileName}.config.toml`);
8871
+ const configPath = join10(codexHome, `${profileName}.config.toml`);
8831
8872
  const configLines = [
8832
8873
  `model = ${tomlString(model)}`,
8833
8874
  `model_provider = ${tomlString(profileName)}`,
@@ -8853,7 +8894,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8853
8894
  env.GEMINI_API_KEY = apiKey;
8854
8895
  env.GEMINI_MODEL = model;
8855
8896
  env.GOOGLE_GEMINI_BASE_URL = baseUrl;
8856
- const configPath = join9(homeDir, ".closedrouter", "gemini-launch.settings.json");
8897
+ const configPath = join10(homeDir, ".closedrouter", "gemini-launch.settings.json");
8857
8898
  env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
8858
8899
  return {
8859
8900
  tool,
@@ -8918,7 +8959,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8918
8959
  function writeOwnedConfig(file) {
8919
8960
  mkdirSync2(dirname(file.path), { recursive: true, mode: 448 });
8920
8961
  try {
8921
- const existing = readFileSync8(file.path, "utf8");
8962
+ const existing = readFileSync9(file.path, "utf8");
8922
8963
  if (file.path.endsWith(".config.toml") && !existing.includes('name = "ClosedRouter"')) {
8923
8964
  throw new Error(`Refusing to replace an existing Codex profile at ${file.path}.`);
8924
8965
  }
@@ -8926,7 +8967,7 @@ function writeOwnedConfig(file) {
8926
8967
  if (error instanceof Error && error.message.startsWith("Refusing to replace"))
8927
8968
  throw error;
8928
8969
  }
8929
- writeFileSync2(file.path, file.contents, { encoding: "utf8", mode: 384 });
8970
+ writeFileSync3(file.path, file.contents, { encoding: "utf8", mode: 384 });
8930
8971
  }
8931
8972
  function modelId(model) {
8932
8973
  return String(model.id || model.name || "");
@@ -8935,18 +8976,32 @@ function modelSupportsHarness(model, tool) {
8935
8976
  const parameters = model.supported_parameters;
8936
8977
  return (model.status === undefined || model.status === "available") && (model.available_tool_account_count === undefined || model.available_tool_account_count > 0) && (!Array.isArray(parameters) || parameters.includes("tools"));
8937
8978
  }
8938
- function discoverAgyModels(command) {
8979
+ function discoverAgyTransportModel(command, apiKey) {
8980
+ const output = execFileSync(command, ["models"], {
8981
+ encoding: "utf8",
8982
+ timeout: 1e4,
8983
+ stdio: ["ignore", "pipe", "ignore"],
8984
+ env: { ...process.env, GEMINI_API_KEY: apiKey, GOOGLE_GEMINI_BASE_URL: "http://127.0.0.1:1" }
8985
+ });
8986
+ const models = output.split(/\r?\n/).map((line) => line.split("\t")[0]).filter((id) => /^gemini-[\w.-]+-(?:high|medium|low)$/.test(id)).map((id) => id.replace(/-(?:high|medium|low)$/, ""));
8987
+ if (!models.length)
8988
+ throw new Error("Antigravity did not report any Gemini API models. Update agy and select Gemini API key mode.");
8989
+ return models.includes("gemini-3.8-flash") ? "gemini-3.8-flash" : models[0];
8990
+ }
8991
+ function assertAgyCustomModel(command, label, apiKey) {
8939
8992
  try {
8940
- const output = execFileSync(command, ["models"], { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] });
8941
- return new Set(output.split(/\r?\n/).map((line) => line.split(/\s+/)[0]).filter((id) => /^gemini-[\w.-]+-(?:high|medium|low)$/.test(id)).map((id) => id.replace(/-(?:high|medium|low)$/, "")));
8993
+ const output = execFileSync(command, ["models"], { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"], env: { ...process.env, GEMINI_API_KEY: apiKey, GOOGLE_GEMINI_BASE_URL: "http://127.0.0.1:1" } });
8994
+ if (output.split(/\r?\n/).some((line) => line.split("\t")[0] === label))
8995
+ return;
8942
8996
  } catch {
8943
8997
  throw new Error("Could not list Antigravity CLI models. Install or update `agy`, then try `cr start agy` again.");
8944
8998
  }
8999
+ throw new Error(`This version of agy did not recognize '${label}'. Update agy to use ClosedRouter's accurate model display.`);
8945
9000
  }
8946
9001
  function assertAgyGeminiMode(homeDir) {
8947
- const settingsPath = join9(homeDir, ".gemini", "antigravity-cli", "settings.json");
9002
+ const settingsPath = join10(homeDir, ".gemini", "antigravity-cli", "settings.json");
8948
9003
  try {
8949
- const settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
9004
+ const settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
8950
9005
  if (settings?.modelProvider === "gemini")
8951
9006
  return;
8952
9007
  } catch {}
@@ -9019,11 +9074,9 @@ async function startCommand(options = {}) {
9019
9074
  }
9020
9075
  if (tool === "agy")
9021
9076
  assertAgyGeminiMode(homedir9());
9022
- const supportedAgyModels = tool === "agy" ? discoverAgyModels(options.executablePath || "agy") : undefined;
9023
- if (supportedAgyModels && supportedAgyModels.size === 0) {
9024
- throw new Error("Antigravity did not report any Gemini API models. Update `agy` and select Gemini API key mode in its settings.");
9025
- }
9026
- const recognizedModel = supportedAgyModels ? supportedAgyModels.has("gemini-3.8-flash") ? "gemini-3.8-flash" : [...supportedAgyModels][0] : undefined;
9077
+ const recognizedModel = tool === "agy" ? registerAgyLaunchModel(homedir9(), model, discoverAgyTransportModel(options.executablePath || "agy", apiKey)) : undefined;
9078
+ if (recognizedModel)
9079
+ assertAgyCustomModel(options.executablePath || "agy", recognizedModel, apiKey);
9027
9080
  const relay = await startLaunchProxy(serverUrl, apiKey, tool);
9028
9081
  let agyProxy;
9029
9082
  try {
@@ -9085,7 +9138,7 @@ process.on("warning", (warning) => {
9085
9138
  console.warn(warning.name, warning.message);
9086
9139
  });
9087
9140
  var program2 = new Command2;
9088
- var cliVersion = JSON.parse(readFileSync9(new URL("../package.json", import.meta.url), "utf8")).version;
9141
+ var cliVersion = JSON.parse(readFileSync10(new URL("../package.json", import.meta.url), "utf8")).version;
9089
9142
  program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version(cliVersion).option("-s, --server <url>", "ClosedRouter server base URL (default: http://localhost:8000)").action(async (options) => {
9090
9143
  await onboardCommand({ server: options.server });
9091
9144
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@closedrouter/cli",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "ClosedRouter CLI: Onboard and import local AI subscriptions and API keys into your shared token pool",
5
5
  "author": "ClosedRouter Contributors",
6
6
  "repository": {