@closedrouter/cli 1.1.0 → 1.1.2

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
@@ -142,7 +142,7 @@ cr start opencode --model gpt-4o-mini
142
142
  cr start claude --model claude-sonnet-4-6 -- --resume
143
143
  ```
144
144
 
145
- Claude Code sends an explicit `claude_oauth` provider choice to ClosedRouter so its requests use the local Claude subscription bridge. Codex gets a separate `~/.codex/closedrouter-launch.config.toml` profile using the Responses API. OpenCode gets an app-owned configuration file under `~/.closedrouter/`. The launchers do not change the tools' main configuration files.
145
+ Claude Code sends an explicit `claude_oauth` provider choice to ClosedRouter so its requests use the local Claude subscription bridge. Codex gets a separate `~/.codex/closedrouter-launch.config.toml` profile using the Responses API. Gemini gets an app-owned authentication settings file under `~/.closedrouter/`, and OpenCode receives inline launch configuration. The launchers do not change the tools' main configuration files.
146
146
 
147
147
  Cursor SDK keys can also be connected in the web account dialog or imported from `CURSOR_API_KEY`. ClosedRouter discovers models using Cursor's SDK and sends text-only, tools-disabled SDK runs through its normal gateway and telemetry path. This credential type is separate from Cursor OAuth tokens imported from the editor.
148
148
 
@@ -26,6 +26,7 @@ export interface LaunchPlan {
26
26
  }
27
27
  export declare function isGatewayModelAvailable(availableModels: string[], model: string): boolean;
28
28
  export declare function buildLaunchPlan(tool: CliTool, serverUrl: string, apiKey: string, model: string, toolArgs?: string[], homeDir?: string, executablePath?: string): LaunchPlan;
29
+ export declare function modelSupportsHarness(model: Record<string, any>, tool: StartTool): boolean;
29
30
  export declare function startCommand(options?: StartCommandOptions): Promise<void>;
30
31
  export {};
31
32
  //# sourceMappingURL=start.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAC7E,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;AA6BD,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,GACtB,UAAU,CA4FZ;AA6FD,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCnF"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAC7E,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;AA6BD,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,GACtB,UAAU,CAqGZ;AAmBD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAMzF;AA4ED,wBAAsB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCnF"}
package/dist/index.js CHANGED
@@ -8657,7 +8657,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8657
8657
  assertNoManagedCodexArgs(toolArgs);
8658
8658
  const codexHome = process.env.CODEX_HOME || join9(homeDir, ".codex");
8659
8659
  const profileName = "closedrouter-launch";
8660
- const configPath2 = join9(codexHome, `${profileName}.config.toml`);
8660
+ const configPath = join9(codexHome, `${profileName}.config.toml`);
8661
8661
  const configLines = [
8662
8662
  `model = ${tomlString(model)}`,
8663
8663
  `model_provider = ${tomlString(profileName)}`,
@@ -8675,7 +8675,7 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8675
8675
  command,
8676
8676
  args: ["--profile", profileName, ...toolArgs],
8677
8677
  env,
8678
- configFile: { path: configPath2, contents: configLines.join(`
8678
+ configFile: { path: configPath, contents: configLines.join(`
8679
8679
  `) }
8680
8680
  };
8681
8681
  }
@@ -8683,7 +8683,19 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8683
8683
  env.GEMINI_API_KEY = apiKey;
8684
8684
  env.GEMINI_MODEL = model;
8685
8685
  env.GOOGLE_GEMINI_BASE_URL = baseUrl;
8686
- return { tool, command, args: [...toolArgs], env };
8686
+ const configPath = join9(homeDir, ".closedrouter", "gemini-launch.settings.json");
8687
+ env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
8688
+ return {
8689
+ tool,
8690
+ command,
8691
+ args: [...toolArgs],
8692
+ env,
8693
+ configFile: {
8694
+ path: configPath,
8695
+ contents: `${JSON.stringify({ security: { auth: { selectedType: "gemini-api-key" } } }, null, 2)}
8696
+ `
8697
+ }
8698
+ };
8687
8699
  }
8688
8700
  if (tool === "aider") {
8689
8701
  env.OPENAI_API_BASE = `${baseUrl}/v1`;
@@ -8695,7 +8707,6 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8695
8707
  env
8696
8708
  };
8697
8709
  }
8698
- const configPath = join9(homeDir, ".closedrouter", "opencode-launch.json");
8699
8710
  const config = {
8700
8711
  $schema: "https://opencode.ai/config.json",
8701
8712
  provider: {
@@ -8710,15 +8721,13 @@ function buildLaunchPlan(tool, serverUrl, apiKey, model, toolArgs = [], homeDir
8710
8721
  }
8711
8722
  }
8712
8723
  };
8713
- env.OPENCODE_CONFIG = configPath;
8724
+ env.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);
8714
8725
  env.CLOSEDROUTER_API_KEY = apiKey;
8715
8726
  return {
8716
8727
  tool,
8717
8728
  command,
8718
8729
  args: ["--model", `closedrouter/${model}`, ...toolArgs],
8719
- env,
8720
- configFile: { path: configPath, contents: `${JSON.stringify(config, null, 2)}
8721
- ` }
8730
+ env
8722
8731
  };
8723
8732
  }
8724
8733
  function writeOwnedConfig(file) {
@@ -8737,6 +8746,12 @@ function writeOwnedConfig(file) {
8737
8746
  function modelId(model) {
8738
8747
  return String(model.id || model.name || "");
8739
8748
  }
8749
+ function modelSupportsHarness(model, tool) {
8750
+ if (tool === "claude")
8751
+ return true;
8752
+ const parameters = model.supported_parameters;
8753
+ 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"));
8754
+ }
8740
8755
  async function selectTool(tool) {
8741
8756
  const cleaned = tool?.toLowerCase();
8742
8757
  if (cleaned) {
@@ -8813,7 +8828,7 @@ async function startCommand(options = {}) {
8813
8828
  const apiKey = await ensurePlatformKey(tool, client, options);
8814
8829
  client.setApiKey(apiKey);
8815
8830
  const models = await client.listGatewayModels({ preferApiKey: true });
8816
- const availableModels = models.map(modelId).filter(Boolean).sort();
8831
+ const availableModels = models.filter((item) => modelSupportsHarness(item, tool)).map(modelId).filter(Boolean).sort();
8817
8832
  let model = options.model?.trim();
8818
8833
  if (!model) {
8819
8834
  if (availableModels.length === 0) {
@@ -8831,7 +8846,7 @@ async function startCommand(options = {}) {
8831
8846
  model = String(choice);
8832
8847
  }
8833
8848
  if (!isGatewayModelAvailable(availableModels, model)) {
8834
- throw new Error(`Model '${model}' is not available to this platform key. Choose a model from ClosedRouter's model catalog.`);
8849
+ throw new Error(`Model '${model}' is not available for ${tool} with this platform key. Agent clients require a provider that supports gateway function tools. Choose another model from ClosedRouter's model catalog.`);
8835
8850
  }
8836
8851
  if (tool === "claude")
8837
8852
  await ensureClaudeBridge(client, serverUrl, apiKey);
@@ -8888,7 +8903,7 @@ process.on("warning", (warning) => {
8888
8903
  console.warn(warning.name, warning.message);
8889
8904
  });
8890
8905
  var program2 = new Command;
8891
- program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version("1.1.0").option("-s, --server <url>", "ClosedRouter server base URL (default: http://localhost:8000)").action(async (options) => {
8906
+ program2.name("closedrouter").description("ClosedRouter CLI: Import local AI subscriptions & API keys into your shared token pool").version("1.1.2").option("-s, --server <url>", "ClosedRouter server base URL (default: http://localhost:8000)").action(async (options) => {
8892
8907
  await onboardCommand({ server: options.server });
8893
8908
  });
8894
8909
  program2.command("onboard").description("Run the full interactive onboarding wizard").option("-s, --server <url>", "ClosedRouter server base URL").option("-a, --all", "Automatically import all discovered accounts").option("--shared", "Contribute accounts to the shared team pool").action(async (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@closedrouter/cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
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": {