claudish 8.1.0 → 9.0.0

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 (2) hide show
  1. package/dist/index.js +96 -31
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -731,7 +731,7 @@ var init_onepassword_config = __esm(() => {
731
731
  });
732
732
 
733
733
  // src/version.ts
734
- var VERSION = "8.1.0";
734
+ var VERSION = "9.0.0";
735
735
 
736
736
  // src/logger.ts
737
737
  var exports_logger = {};
@@ -28305,17 +28305,24 @@ var init_runtime_providers = __esm(() => {
28305
28305
  });
28306
28306
 
28307
28307
  // src/handlers/shared/remote-provider-types.ts
28308
+ function registerSubscriptionCredentialProbe(fn) {
28309
+ const previous = _subscriptionCredentialProbe;
28310
+ _subscriptionCredentialProbe = fn;
28311
+ return previous;
28312
+ }
28308
28313
  function isSubscriptionProvider(provider) {
28309
- return SUBSCRIPTION_PROVIDERS.has(provider.toLowerCase());
28314
+ const p = provider.toLowerCase();
28315
+ if (SUBSCRIPTION_PROVIDERS.has(p))
28316
+ return true;
28317
+ if (!CREDENTIAL_DECIDED_PROVIDERS.has(p))
28318
+ return false;
28319
+ return _subscriptionCredentialProbe?.(p) === true;
28310
28320
  }
28311
28321
  function registerDynamicPricingLookup(fn) {
28312
28322
  _dynamicLookup = fn;
28313
28323
  }
28314
28324
  function getModelPricing(provider, modelName) {
28315
28325
  const p = provider.toLowerCase();
28316
- if (FREE_PROVIDERS.has(p)) {
28317
- return { inputCostPer1M: 0, outputCostPer1M: 0, isFree: true };
28318
- }
28319
28326
  if (isSubscriptionProvider(p)) {
28320
28327
  return { inputCostPer1M: 0, outputCostPer1M: 0, isSubscription: true };
28321
28328
  }
@@ -28327,7 +28334,7 @@ function getModelPricing(provider, modelName) {
28327
28334
  const canonical = PROVIDER_ALIAS[p] || p;
28328
28335
  return PROVIDER_DEFAULTS[canonical] || { inputCostPer1M: 1, outputCostPer1M: 4, isEstimate: true };
28329
28336
  }
28330
- var PROVIDER_DEFAULTS, FREE_PROVIDERS, SUBSCRIPTION_PROVIDERS, PROVIDER_ALIAS, _dynamicLookup = null;
28337
+ var PROVIDER_DEFAULTS, SUBSCRIPTION_PROVIDERS, CREDENTIAL_DECIDED_PROVIDERS, _subscriptionCredentialProbe = null, PROVIDER_ALIAS, _dynamicLookup = null;
28331
28338
  var init_remote_provider_types = __esm(() => {
28332
28339
  PROVIDER_DEFAULTS = {
28333
28340
  gemini: { inputCostPer1M: 0.5, outputCostPer1M: 2, isEstimate: true },
@@ -28337,7 +28344,6 @@ var init_remote_provider_types = __esm(() => {
28337
28344
  glm: { inputCostPer1M: 0.16, outputCostPer1M: 0.8, isEstimate: true },
28338
28345
  ollamacloud: { inputCostPer1M: 1, outputCostPer1M: 4, isEstimate: true }
28339
28346
  };
28340
- FREE_PROVIDERS = new Set(["opencode-zen", "zen"]);
28341
28347
  SUBSCRIPTION_PROVIDERS = new Set([
28342
28348
  "minimax-coding",
28343
28349
  "kimi-coding",
@@ -28346,8 +28352,10 @@ var init_remote_provider_types = __esm(() => {
28346
28352
  "devin",
28347
28353
  "antigravity",
28348
28354
  "sakana-subscription",
28349
- "grok-subscription"
28355
+ "grok-subscription",
28356
+ "opencode-zen-go"
28350
28357
  ]);
28358
+ CREDENTIAL_DECIDED_PROVIDERS = new Set(["openai-codex"]);
28351
28359
  PROVIDER_ALIAS = {
28352
28360
  google: "gemini",
28353
28361
  oai: "openai",
@@ -36548,7 +36556,7 @@ class ApiKeyCredentialProvider {
36548
36556
  } else {
36549
36557
  headers = { ...this.staticHeaders };
36550
36558
  }
36551
- return { headers };
36559
+ return { arm: "api-key", headers };
36552
36560
  }
36553
36561
  }
36554
36562
  var init_api_key_credential = __esm(() => {
@@ -36927,6 +36935,34 @@ var init_codex_oauth = __esm(() => {
36927
36935
  };
36928
36936
  });
36929
36937
 
36938
+ // src/auth/credentials/billing-probe.ts
36939
+ function recordSignedArm(provider, arm) {
36940
+ signedArm.set(provider.toLowerCase(), arm);
36941
+ }
36942
+ function clearSignedArm(provider) {
36943
+ if (provider)
36944
+ signedArm.delete(provider.toLowerCase());
36945
+ else
36946
+ signedArm.clear();
36947
+ }
36948
+ function installBillingProbes() {
36949
+ return registerSubscriptionCredentialProbe((p) => {
36950
+ const recorded = signedArm.get(p);
36951
+ if (recorded)
36952
+ return recorded === "subscription";
36953
+ return PROBES[p]?.() === true;
36954
+ });
36955
+ }
36956
+ var signedArm, PROBES;
36957
+ var init_billing_probe = __esm(() => {
36958
+ init_remote_provider_types();
36959
+ init_codex_oauth();
36960
+ signedArm = new Map;
36961
+ PROBES = {
36962
+ "openai-codex": () => CodexOAuth.getInstance().hasCredentials()
36963
+ };
36964
+ });
36965
+
36930
36966
  // src/auth/credentials/composite-credential.ts
36931
36967
  class CompositeCredentialProvider {
36932
36968
  catalogName;
@@ -36994,6 +37030,7 @@ class CodexOAuthHalf {
36994
37030
  const token = await this.oauth.getAccessToken();
36995
37031
  const accountId = this.oauth.getAccountId();
36996
37032
  return {
37033
+ arm: "oauth",
36997
37034
  headers: buildOAuthHeaders(token, accountId),
36998
37035
  endpoint: CODEX_RESPONSES_ENDPOINT,
36999
37036
  transformPayload: (p) => ({
@@ -37483,6 +37520,17 @@ var init_kimi_oauth = __esm(() => {
37483
37520
  import { existsSync as existsSync15, readFileSync as readFileSync14 } from "fs";
37484
37521
  import { homedir as homedir22 } from "os";
37485
37522
  import { join as join22 } from "path";
37523
+ function credentialSatisfies(descriptor, data) {
37524
+ if (!data?.access_token)
37525
+ return false;
37526
+ if (data.refresh_token)
37527
+ return true;
37528
+ if (descriptor.expiresAtField && data[descriptor.expiresAtField]) {
37529
+ const buffer = descriptor.expiryBufferMs ?? 0;
37530
+ return data[descriptor.expiresAtField] > Date.now() + buffer;
37531
+ }
37532
+ return true;
37533
+ }
37486
37534
  function hasValidOAuthCredentials(descriptor) {
37487
37535
  const credPath = join22(homedir22(), ".claudish", descriptor.credentialFile);
37488
37536
  if (!existsSync15(credPath))
@@ -37491,16 +37539,7 @@ function hasValidOAuthCredentials(descriptor) {
37491
37539
  return true;
37492
37540
  }
37493
37541
  try {
37494
- const data = JSON.parse(readFileSync14(credPath, "utf-8"));
37495
- if (!data.access_token)
37496
- return false;
37497
- if (data.refresh_token)
37498
- return true;
37499
- if (descriptor.expiresAtField && data[descriptor.expiresAtField]) {
37500
- const buffer = descriptor.expiryBufferMs ?? 0;
37501
- return data[descriptor.expiresAtField] > Date.now() + buffer;
37502
- }
37503
- return true;
37542
+ return credentialSatisfies(descriptor, JSON.parse(readFileSync14(credPath, "utf-8")));
37504
37543
  } catch {
37505
37544
  return false;
37506
37545
  }
@@ -37551,6 +37590,7 @@ class KimiOAuthHalf {
37551
37590
  async getRequestAuth(_ctx) {
37552
37591
  const token = await this.oauth.getAccessToken();
37553
37592
  return {
37593
+ arm: "oauth",
37554
37594
  headers: {
37555
37595
  "anthropic-version": "2023-06-01",
37556
37596
  Authorization: `Bearer ${token}`,
@@ -37750,6 +37790,7 @@ class CredentialAuthority {
37750
37790
  return p.getRequestAuth(ctx);
37751
37791
  }
37752
37792
  invalidate(name) {
37793
+ clearSignedArm(name);
37753
37794
  if (name) {
37754
37795
  this.registry.get(name)?.invalidate?.();
37755
37796
  return;
@@ -37764,9 +37805,11 @@ class CredentialAuthority {
37764
37805
  }
37765
37806
  async login(name) {
37766
37807
  await this.registry.get(name)?.login?.();
37808
+ clearSignedArm(name);
37767
37809
  }
37768
37810
  async logout(name) {
37769
37811
  await this.registry.get(name)?.logout?.();
37812
+ clearSignedArm(name);
37770
37813
  }
37771
37814
  get(name) {
37772
37815
  return this.registry.get(name);
@@ -37817,6 +37860,7 @@ var init_authority = __esm(() => {
37817
37860
  init_provider_definitions();
37818
37861
  init_antigravity_credential();
37819
37862
  init_api_key_credential();
37863
+ init_billing_probe();
37820
37864
  init_codex_credential();
37821
37865
  init_devin_credential();
37822
37866
  init_grok_credential();
@@ -37829,6 +37873,7 @@ var init_authority = __esm(() => {
37829
37873
  google: ["gemini"]
37830
37874
  };
37831
37875
  credentials = CredentialAuthority.buildDefault();
37876
+ installBillingProbes();
37832
37877
  });
37833
37878
 
37834
37879
  // src/providers/devin/proto-codec.ts
@@ -44976,6 +45021,7 @@ var init_openai_codex = __esm(() => {
44976
45021
  init_codex_api_format();
44977
45022
  init_model_catalog();
44978
45023
  init_authority();
45024
+ init_billing_probe();
44979
45025
  init_harness();
44980
45026
  init_openai();
44981
45027
  FALLBACK_CONVERSATION_KEY = randomBytes6(16).toString("hex");
@@ -44989,6 +45035,8 @@ var init_openai_codex = __esm(() => {
44989
45035
  } catch {
44990
45036
  this.cachedAuth = null;
44991
45037
  }
45038
+ const signedWithOAuth = this.cachedAuth?.arm === "oauth";
45039
+ recordSignedArm("openai-codex", signedWithOAuth ? "subscription" : "metered");
44992
45040
  }
44993
45041
  getEndpoint(_targetModel) {
44994
45042
  return this.cachedAuth?.endpoint ?? super.getEndpoint();
@@ -45477,16 +45525,28 @@ function describeMissingCredential(providerName) {
45477
45525
  const keyNames = info?.envVar ? [info.envVar, ...info.aliases ?? []].join(" or ") : undefined;
45478
45526
  const signup = info?.url ? ` Get one at ${info.url}.` : "";
45479
45527
  const def = getProviderByName(providerName);
45528
+ const sibling = describeSiblingKeys(def);
45480
45529
  if (isLocalTransport(providerName)) {
45481
45530
  const where = def ? ` Claudish will use ${getEffectiveBaseUrl(def)}.` : "";
45482
45531
  const keyClause = keyNames ? ` (Only set ${keyNames} if your local server requires a bearer token.)` : "";
45483
- return `Provider "${providerName}" is a LOCAL server and is not enabled. Enable it in \`claudish config\` (Providers tab), or add "localProviders": ["${providerName}"] to ~/.claudish/config.json.${where}${keyClause}`;
45532
+ return `Provider "${providerName}" is a LOCAL server and is not enabled. Enable it in \`claudish config\` (Providers tab), or add "localProviders": ["${providerName}"] to ~/.claudish/config.json.${where}${keyClause}${sibling}`;
45484
45533
  }
45485
45534
  if (def?.oauthFallback) {
45486
45535
  const keyClause = keyNames ? ` Or set ${keyNames} (env, config, or 1Password import) to use a metered API key instead.${signup}` : "";
45487
- return `No credential for provider "${providerName}". Sign in with \`claudish login ${providerName}\` to use your existing subscription.${keyClause}`;
45536
+ return `No credential for provider "${providerName}". Sign in with \`claudish login ${providerName}\` to use your existing subscription.${keyClause}${sibling}`;
45488
45537
  }
45489
- return keyNames ? `No API key for provider "${providerName}". Set ${keyNames} (env, config, or 1Password import).${signup}` : `No API key for provider "${providerName}".`;
45538
+ return keyNames ? `No API key for provider "${providerName}". Set ${keyNames} (env, config, or 1Password import).${signup}${sibling}` : `No API key for provider "${providerName}".${sibling}`;
45539
+ }
45540
+ function describeSiblingKeys(def) {
45541
+ const vars = def?.siblingKeyEnvVars ?? [];
45542
+ if (vars.length === 0)
45543
+ return "";
45544
+ const all = getAllProviders();
45545
+ const named = vars.map((v) => {
45546
+ const owner = all.find((p) => p.name !== def?.name && p.apiKeyEnvVar === v);
45547
+ return owner ? `${v} (${owner.name})` : v;
45548
+ });
45549
+ return ` Note: ${named.join(" or ")} is a DIFFERENT plan's key and is not accepted here.`;
45490
45550
  }
45491
45551
  function getDisplayName(providerName) {
45492
45552
  const def = getProviderByName(providerName);
@@ -45952,7 +46012,7 @@ var init_provider_definitions = __esm(() => {
45952
46012
  apiPath: "/v1/chat/completions",
45953
46013
  modelDiscovery: { path: "/v1/models", format: "openai-models-list" },
45954
46014
  apiKeyEnvVar: "OPENCODE_GO_API_KEY",
45955
- apiKeyAliases: ["OPENCODE_API_KEY"],
46015
+ siblingKeyEnvVars: ["OPENCODE_API_KEY"],
45956
46016
  apiKeyDescription: "OpenCode Zen Go (Lite Plan) API Key",
45957
46017
  apiKeyUrl: "https://opencode.ai/",
45958
46018
  shortcuts: ["zengo", "zgo"],
@@ -47568,7 +47628,8 @@ var init_routing_hints = __esm(() => {
47568
47628
  openrouter: { apiKeyEnvVar: "OPENROUTER_API_KEY" },
47569
47629
  "x-ai": { apiKeyEnvVar: "XAI_API_KEY" },
47570
47630
  "z-ai": { apiKeyEnvVar: "ZAI_API_KEY" },
47571
- "opencode-zen": { apiKeyEnvVar: "OPENCODE_API_KEY" }
47631
+ "opencode-zen": { apiKeyEnvVar: "OPENCODE_API_KEY" },
47632
+ "opencode-zen-go": { apiKeyEnvVar: "OPENCODE_GO_API_KEY" }
47572
47633
  };
47573
47634
  });
47574
47635
 
@@ -51446,12 +51507,15 @@ function collectRoutingPrefixes(group, getNativePrefix) {
51446
51507
  out.push(native);
51447
51508
  seen.add(native);
51448
51509
  }
51449
- for (const sub of group.subscriptions) {
51450
- const p = sub.subscription?.prefix;
51451
- if (!p || seen.has(p))
51452
- continue;
51453
- seen.add(p);
51454
- out.push(p);
51510
+ for (const subscriptionRow of group.subscriptions) {
51511
+ const routes = subscriptionRow.subscriptions && subscriptionRow.subscriptions.length > 0 ? subscriptionRow.subscriptions : subscriptionRow.subscription ? [subscriptionRow.subscription] : [];
51512
+ for (const route2 of routes) {
51513
+ const p = route2?.prefix;
51514
+ if (!p || seen.has(p))
51515
+ continue;
51516
+ seen.add(p);
51517
+ out.push(p);
51518
+ }
51455
51519
  }
51456
51520
  return out;
51457
51521
  }
@@ -75450,7 +75514,7 @@ var init_api_key_map = __esm(() => {
75450
75514
  "qwen-payg": { envVar: "DASHSCOPE_API_KEY", aliases: ["QWEN_API_KEY"] },
75451
75515
  ollamacloud: { envVar: "OLLAMA_API_KEY" },
75452
75516
  "opencode-zen": { envVar: "OPENCODE_API_KEY" },
75453
- "opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
75517
+ "opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY" },
75454
75518
  vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
75455
75519
  poe: { envVar: "POE_API_KEY" }
75456
75520
  };
@@ -77023,6 +77087,7 @@ ${h("ENVIRONMENT VARIABLES")}
77023
77087
  ${blue("SAKANA_SUBSCRIPTION_API_KEY")} Sakana Fugu Subscription ${dim4("(sc@; separate subscription key)")}
77024
77088
  ${blue("OLLAMA_API_KEY")} OllamaCloud ${dim4("(oc@, llama@)")}
77025
77089
  ${blue("OPENCODE_API_KEY")} OpenCode Zen ${dim4("(zen@)")}
77090
+ ${blue("OPENCODE_GO_API_KEY")} OpenCode Zen Go plan ${dim4("(zgo@, zengo@; separate plan key)")}
77026
77091
  ${blue("POE_API_KEY")} Poe ${dim4("(poe@)")}
77027
77092
  ${blue("LITELLM_API_KEY")} LiteLLM ${dim4("(litellm@, ll@; needs LITELLM_BASE_URL)")}
77028
77093
  ${blue("VERTEX_API_KEY")} Vertex AI Express ${dim4("(v@)")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "8.1.0",
3
+ "version": "9.0.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,10 +60,10 @@
60
60
  "ai"
61
61
  ],
62
62
  "optionalDependencies": {
63
- "@claudish/magmux-darwin-arm64": "8.1.0",
64
- "@claudish/magmux-darwin-x64": "8.1.0",
65
- "@claudish/magmux-linux-arm64": "8.1.0",
66
- "@claudish/magmux-linux-x64": "8.1.0"
63
+ "@claudish/magmux-darwin-arm64": "9.0.0",
64
+ "@claudish/magmux-darwin-x64": "9.0.0",
65
+ "@claudish/magmux-linux-arm64": "9.0.0",
66
+ "@claudish/magmux-linux-x64": "9.0.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",