claudish 7.47.0 → 7.48.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 +127 -19
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -729,7 +729,7 @@ var init_onepassword_config = __esm(() => {
729
729
  });
730
730
 
731
731
  // src/version.ts
732
- var VERSION = "7.47.0";
732
+ var VERSION = "7.48.0";
733
733
 
734
734
  // src/logger.ts
735
735
  var exports_logger = {};
@@ -28579,6 +28579,25 @@ var init_provider_definitions = __esm(() => {
28579
28579
  isDirectApi: true,
28580
28580
  description: "Qwen Plan (qc@)"
28581
28581
  },
28582
+ {
28583
+ name: "qwen-payg",
28584
+ displayName: "Qwen PAYG",
28585
+ transport: "anthropic",
28586
+ baseUrl: "https://dashscope-intl.aliyuncs.com",
28587
+ baseUrlEnvVars: ["DASHSCOPE_BASE_URL"],
28588
+ apiPath: "/apps/anthropic/v1/messages",
28589
+ apiKeyEnvVar: "DASHSCOPE_API_KEY",
28590
+ apiKeyAliases: ["QWEN_API_KEY"],
28591
+ apiKeyDescription: "Alibaba Model Studio API Key (pay-as-you-go)",
28592
+ apiKeyUrl: "https://www.alibabacloud.com/help/en/model-studio/get-api-key",
28593
+ authScheme: "bearer",
28594
+ shortcuts: ["qp", "dashscope"],
28595
+ shortestPrefix: "qp",
28596
+ legacyPrefixes: [{ prefix: "qp/", stripPrefix: true }],
28597
+ modelDiscovery: { path: "/compatible-mode/v1/models", format: "openai-models-list" },
28598
+ isDirectApi: true,
28599
+ description: "Alibaba Model Studio pay-as-you-go (qp@)"
28600
+ },
28582
28601
  {
28583
28602
  name: "qwen",
28584
28603
  displayName: "Qwen",
@@ -37579,7 +37598,8 @@ var init_telemetry = __esm(() => {
37579
37598
  "minimax-coding",
37580
37599
  "kimi-coding",
37581
37600
  "glm-coding",
37582
- "qwen-cloud"
37601
+ "qwen-cloud",
37602
+ "qwen-payg"
37583
37603
  ]);
37584
37604
  });
37585
37605
 
@@ -41599,6 +41619,40 @@ function toRosterEntry(model) {
41599
41619
  const { id, ...rest } = model;
41600
41620
  return { wireId: id, ...rest };
41601
41621
  }
41622
+ function recordFailure(failure) {
41623
+ _failures.set(failure.provider, failure);
41624
+ log(`[model-discovery:${failure.provider}] ${describeDiscoveryFailure(failure)}`);
41625
+ return [];
41626
+ }
41627
+ function getDiscoveryFailure(provider) {
41628
+ return _failures.get(provider);
41629
+ }
41630
+ function hasAuthHeader(headers) {
41631
+ return Object.entries(headers).some(([name, value]) => /^(authorization|x-api-key|api-key)$/i.test(name) && (value ?? "").trim().length > 0);
41632
+ }
41633
+ function oneLine(text, max = 200) {
41634
+ const flat = text.replace(/\s+/g, " ").trim();
41635
+ return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
41636
+ }
41637
+ function describeDiscoveryFailure(failure) {
41638
+ const { kind, endpoint, status, detail } = failure;
41639
+ const at = endpoint ? ` at ${endpoint}` : "";
41640
+ const because = detail ? ` \u2014 ${detail}` : "";
41641
+ switch (kind) {
41642
+ case "no-credentials":
41643
+ return `no usable credentials${because}`;
41644
+ case "unauthorized":
41645
+ return `the API key was rejected (HTTP ${status})${at}${because}`;
41646
+ case "http-error":
41647
+ return `the model list returned HTTP ${status}${at}${because}`;
41648
+ case "unreachable":
41649
+ return `the model list was unreachable${at}${because}`;
41650
+ case "malformed":
41651
+ return `the model list was not valid JSON${at}`;
41652
+ case "empty-roster":
41653
+ return `the endpoint answered${at} but listed no models`;
41654
+ }
41655
+ }
41602
41656
  function resolveBaseUrl(catalogName) {
41603
41657
  const def = getProviderByName(catalogName);
41604
41658
  if (!def)
@@ -41662,14 +41716,14 @@ async function discoverProviderModels(providerName) {
41662
41716
  const { getServedDevinModels: getServedDevinModels2 } = await Promise.resolve().then(() => (init_devin_models(), exports_devin_models));
41663
41717
  const served = await getServedDevinModels2();
41664
41718
  if (served.length === 0) {
41665
- log(`[model-discovery:${providerName}] no models for this subscription`);
41666
- return [];
41719
+ return recordFailure({ kind: "empty-roster", provider: providerName });
41667
41720
  }
41668
41721
  const { devinRosterEntry: devinRosterEntry2 } = await Promise.resolve().then(() => (init_devin(), exports_devin));
41669
41722
  const models2 = served.map((model) => {
41670
41723
  const { wireId, ...rest } = devinRosterEntry2(model);
41671
41724
  return { id: wireId, ...rest };
41672
41725
  });
41726
+ _failures.delete(providerName);
41673
41727
  log(`[model-discovery:${providerName}] discovered ${models2.length} models`);
41674
41728
  _cache.set(providerName, { models: models2, expiresAt: Date.now() + CACHE_TTL_MS });
41675
41729
  return models2;
@@ -41677,13 +41731,15 @@ async function discoverProviderModels(providerName) {
41677
41731
  if (descriptor.format === "ollama-tags") {
41678
41732
  const { fetchOllamaModels: fetchOllamaModels2 } = await Promise.resolve().then(() => exports_ollama_discovery);
41679
41733
  const installed = await fetchOllamaModels2({ enrichCapabilities: false });
41680
- if (installed.length === 0)
41681
- return [];
41734
+ if (installed.length === 0) {
41735
+ return recordFailure({ kind: "empty-roster", provider: providerName });
41736
+ }
41682
41737
  const models2 = installed.map((model) => ({
41683
41738
  id: model.name,
41684
41739
  displayName: model.name,
41685
41740
  supportsTools: model.supportsTools
41686
41741
  }));
41742
+ _failures.delete(providerName);
41687
41743
  log(`[model-discovery:${providerName}] discovered ${models2.length} local models`);
41688
41744
  _cache.set(providerName, { models: models2, expiresAt: Date.now() + CACHE_TTL_MS });
41689
41745
  return models2;
@@ -41702,8 +41758,15 @@ async function discoverProviderModels(providerName) {
41702
41758
  const auth = await credentials.getRequestAuth(providerName, { model: "" });
41703
41759
  headers = { ...auth.headers };
41704
41760
  } catch (e) {
41705
- log(`[model-discovery:${providerName}] no credentials, skipping: ${e?.message}`);
41706
- return [];
41761
+ return recordFailure({
41762
+ kind: "no-credentials",
41763
+ provider: providerName,
41764
+ endpoint,
41765
+ detail: oneLine(e?.message ?? "")
41766
+ });
41767
+ }
41768
+ if (!hasAuthHeader(headers)) {
41769
+ return recordFailure({ kind: "no-credentials", provider: providerName, endpoint });
41707
41770
  }
41708
41771
  }
41709
41772
  let response;
@@ -41714,25 +41777,38 @@ async function discoverProviderModels(providerName) {
41714
41777
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
41715
41778
  });
41716
41779
  } catch (e) {
41717
- log(`[model-discovery:${providerName}] fetch failed: ${e?.message}`);
41718
- return [];
41780
+ return recordFailure({
41781
+ kind: "unreachable",
41782
+ provider: providerName,
41783
+ endpoint,
41784
+ detail: oneLine(e?.message ?? "")
41785
+ });
41719
41786
  }
41720
41787
  if (!response.ok) {
41721
- log(`[model-discovery:${providerName}] HTTP ${response.status} from ${endpoint}`);
41722
- return [];
41788
+ const unauthorized = response.status === 401 || response.status === 403;
41789
+ let detail = "";
41790
+ try {
41791
+ detail = oneLine(await response.text());
41792
+ } catch {}
41793
+ return recordFailure({
41794
+ kind: unauthorized ? "unauthorized" : "http-error",
41795
+ provider: providerName,
41796
+ endpoint,
41797
+ status: response.status,
41798
+ detail
41799
+ });
41723
41800
  }
41724
41801
  let body;
41725
41802
  try {
41726
41803
  body = await response.json();
41727
41804
  } catch {
41728
- log(`[model-discovery:${providerName}] response was not JSON`);
41729
- return [];
41805
+ return recordFailure({ kind: "malformed", provider: providerName, endpoint });
41730
41806
  }
41731
41807
  const models = parseOpenAIModelsList(body);
41732
41808
  if (models.length === 0) {
41733
- log(`[model-discovery:${providerName}] endpoint reachable but listed no models`);
41734
- return [];
41809
+ return recordFailure({ kind: "empty-roster", provider: providerName, endpoint });
41735
41810
  }
41811
+ _failures.delete(providerName);
41736
41812
  log(`[model-discovery:${providerName}] discovered ${models.length} models: ` + models.map((m) => `${m.id}(${m.contextWindow ?? "?"})`).join(", "));
41737
41813
  _cache.set(providerName, { models, expiresAt: Date.now() + CACHE_TTL_MS });
41738
41814
  return models;
@@ -41748,13 +41824,14 @@ function rankDiscoveredModels(models) {
41748
41824
  return diff !== 0 ? diff : a.id.localeCompare(b.id);
41749
41825
  });
41750
41826
  }
41751
- var CACHE_TTL_MS, FETCH_TIMEOUT_MS = 5000, _cache, MIN_CREATED_SECONDS = 946684800, MAX_CREATED_SECONDS = 4102444800;
41827
+ var CACHE_TTL_MS, FETCH_TIMEOUT_MS = 5000, _cache, _failures, MIN_CREATED_SECONDS = 946684800, MAX_CREATED_SECONDS = 4102444800;
41752
41828
  var init_model_discovery = __esm(() => {
41753
41829
  init_authority();
41754
41830
  init_logger();
41755
41831
  init_provider_definitions();
41756
41832
  CACHE_TTL_MS = 5 * 60 * 1000;
41757
41833
  _cache = new Map;
41834
+ _failures = new Map;
41758
41835
  });
41759
41836
 
41760
41837
  // src/providers/transport/probe-discovery.ts
@@ -42150,9 +42227,10 @@ class AnthropicProviderTransport {
42150
42227
  }
42151
42228
  const discovered = await discoverProviderModels(this.provider.name);
42152
42229
  if (discovered.length === 0) {
42230
+ const failure = getDiscoveryFailure(this.provider.name);
42153
42231
  return {
42154
42232
  model: null,
42155
- reason: `${this.displayName} listed no models at ${def.modelDiscovery.path} \u2014 check the API key and that the subscription is active`
42233
+ reason: failure ? `${this.displayName}: ${describeDiscoveryFailure(failure)}` : `${this.displayName} listed no models at ${def.modelDiscovery.path} \u2014 check the API key and that the subscription is active`
42156
42234
  };
42157
42235
  }
42158
42236
  const ranked = rankDiscoveredModels(discovered).map((m) => m.id).filter(isChatCapable);
@@ -42205,6 +42283,7 @@ class AnthropicProviderTransport {
42205
42283
  kimi: "Kimi",
42206
42284
  "kimi-coding": "Kimi Coding",
42207
42285
  "qwen-cloud": "Qwen Plan",
42286
+ "qwen-payg": "Qwen PAYG",
42208
42287
  moonshot: "Kimi",
42209
42288
  "z-ai": "Z.AI"
42210
42289
  };
@@ -42751,6 +42830,7 @@ var init_routing_hints = __esm(() => {
42751
42830
  sakana: { apiKeyEnvVar: "SAKANA_API_KEY" },
42752
42831
  "sakana-subscription": { apiKeyEnvVar: "SAKANA_SUBSCRIPTION_API_KEY" },
42753
42832
  "qwen-cloud": { apiKeyEnvVar: "QWEN_CLOUD_PLAN_API_KEY" },
42833
+ "qwen-payg": { apiKeyEnvVar: "DASHSCOPE_API_KEY" },
42754
42834
  ollamacloud: { apiKeyEnvVar: "OLLAMA_API_KEY" },
42755
42835
  "native-anthropic": { apiKeyEnvVar: "ANTHROPIC_API_KEY" },
42756
42836
  openrouter: { apiKeyEnvVar: "OPENROUTER_API_KEY" },
@@ -42799,7 +42879,7 @@ var init_default_routing_rules = __esm(() => {
42799
42879
  "k3*": ["kimi-coding", "opencode-zen-go", "kimi", "openrouter"],
42800
42880
  "minimax-*": ["minimax-coding", "opencode-zen-go", "minimax", "openrouter"],
42801
42881
  "glm-*": ["glm-coding", "opencode-zen-go", "glm", "openrouter"],
42802
- "qwen3.*": ["qwen-cloud", "opencode-zen-go", "openrouter"],
42882
+ "qwen3.*": ["qwen-cloud", "opencode-zen-go", "qwen-payg", "openrouter"],
42803
42883
  "z-ai-*": ["z-ai", "openrouter"],
42804
42884
  "deepseek-*": ["opencode-zen-go", "deepseek", "openrouter"],
42805
42885
  "mimo-*": ["opencode-zen-go", "openrouter"],
@@ -47084,6 +47164,7 @@ var init_api_key_map = __esm(() => {
47084
47164
  aliases: ["SAKANA_CODING_API_KEY"]
47085
47165
  },
47086
47166
  "qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
47167
+ "qwen-payg": { envVar: "DASHSCOPE_API_KEY", aliases: ["QWEN_API_KEY"] },
47087
47168
  ollamacloud: { envVar: "OLLAMA_API_KEY" },
47088
47169
  "opencode-zen": { envVar: "OPENCODE_API_KEY" },
47089
47170
  "opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
@@ -48132,6 +48213,7 @@ var init_provider_profiles = __esm(() => {
48132
48213
  kimi: anthropicCompatProfile,
48133
48214
  "kimi-coding": anthropicCompatProfile,
48134
48215
  "qwen-cloud": anthropicCompatProfile,
48216
+ "qwen-payg": anthropicCompatProfile,
48135
48217
  "z-ai": anthropicCompatProfile,
48136
48218
  glm: glmProfile,
48137
48219
  "glm-coding": glmProfile,
@@ -64684,6 +64766,7 @@ var init_model_catalog2 = __esm(() => {
64684
64766
  // src/model-selector.ts
64685
64767
  var exports_model_selector = {};
64686
64768
  __export(exports_model_selector, {
64769
+ warnDiscoveryFailure: () => warnDiscoveryFailure,
64687
64770
  selectProfile: () => selectProfile,
64688
64771
  selectModelsForProfile: () => selectModelsForProfile,
64689
64772
  selectModel: () => selectModel,
@@ -65235,6 +65318,26 @@ function describeOffer(offer) {
65235
65318
  });
65236
65319
  return `FREE until ${until}`;
65237
65320
  }
65321
+ function warnDiscoveryFailure(provider, displayName, def) {
65322
+ const failure = getDiscoveryFailure(provider);
65323
+ if (!failure || failure.kind === "empty-roster")
65324
+ return;
65325
+ process.stderr.write(`
65326
+ \u26A0 ${displayName} could not list its models: ${describeDiscoveryFailure(failure)}
65327
+ `);
65328
+ if (failure.kind === "unauthorized" || failure.kind === "no-credentials") {
65329
+ if (def.apiKeyEnvVar) {
65330
+ process.stderr.write(` Check ${def.apiKeyEnvVar} (a value in your shell overrides stored credentials).
65331
+ `);
65332
+ }
65333
+ if (def.apiKeyUrl)
65334
+ process.stderr.write(` Get a key: ${def.apiKeyUrl}
65335
+ `);
65336
+ }
65337
+ process.stderr.write(` Falling back to manual model entry.
65338
+
65339
+ `);
65340
+ }
65238
65341
  async function buildDiscoveredModelRows(provider, displayName, catalog) {
65239
65342
  const discovered = rankDiscoveredModels(await discoverProviderModels(provider)).filter((m) => isChatCapable(m.id));
65240
65343
  if (discovered.length === 0)
@@ -65285,6 +65388,8 @@ async function selectModelFromProvider(provider, tierName, recommendedModels, _f
65285
65388
  const picked = await pickModelFromList(provider, displayName, tierName, discoveredModels);
65286
65389
  if (picked)
65287
65390
  return picked;
65391
+ } else {
65392
+ warnDiscoveryFailure(provider, displayName, def);
65288
65393
  }
65289
65394
  }
65290
65395
  if (isUserDeployedProvider(provider)) {
@@ -65499,6 +65604,7 @@ var init_model_selector = __esm(() => {
65499
65604
  kimi: { name: "Kimi / Moonshot", description: "Direct API" },
65500
65605
  "kimi-coding": { name: "Kimi Coding", description: "Coding subscription" },
65501
65606
  "qwen-cloud": { name: "Qwen Plan", description: "Alibaba Model Studio subscription" },
65607
+ "qwen-payg": { name: "Qwen PAYG", description: "Alibaba Model Studio pay-as-you-go" },
65502
65608
  glm: { name: "GLM / Zhipu", description: "Direct API" },
65503
65609
  "glm-coding": { name: "GLM Coding Plan", description: "Coding subscription" },
65504
65610
  "z-ai": { name: "Z.AI", description: "Direct API" },
@@ -65528,6 +65634,7 @@ var init_model_selector = __esm(() => {
65528
65634
  "kimi",
65529
65635
  "kimi-coding",
65530
65636
  "qwen-cloud",
65637
+ "qwen-payg",
65531
65638
  "glm",
65532
65639
  "glm-coding",
65533
65640
  "z-ai",
@@ -69106,6 +69213,7 @@ async function probeModelRouting(models, jsonOutput, options = { live: true, tim
69106
69213
  "kimi",
69107
69214
  "kimi-coding",
69108
69215
  "qwen-cloud",
69216
+ "qwen-payg",
69109
69217
  "z-ai"
69110
69218
  ];
69111
69219
  const isMinimaxModel = modelName.toLowerCase().includes("minimax");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.47.0",
3
+ "version": "7.48.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": "7.47.0",
64
- "@claudish/magmux-darwin-x64": "7.47.0",
65
- "@claudish/magmux-linux-arm64": "7.47.0",
66
- "@claudish/magmux-linux-x64": "7.47.0"
63
+ "@claudish/magmux-darwin-arm64": "7.48.0",
64
+ "@claudish/magmux-darwin-x64": "7.48.0",
65
+ "@claudish/magmux-linux-arm64": "7.48.0",
66
+ "@claudish/magmux-linux-x64": "7.48.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",