claudish 7.39.0 → 7.40.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 +58 -38
  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.39.0";
732
+ var VERSION = "7.40.0";
733
733
 
734
734
  // src/logger.ts
735
735
  var exports_logger = {};
@@ -36683,6 +36683,33 @@ var init_middleware = __esm(() => {
36683
36683
  init_gemini_thought_signature();
36684
36684
  });
36685
36685
 
36686
+ // src/handlers/shared/quota-exhaustion.ts
36687
+ function hasQuotaExhaustionWording(errorBody) {
36688
+ const lower = (errorBody || "").toLowerCase();
36689
+ return EXHAUSTION_PHRASES.some((phrase) => lower.includes(phrase));
36690
+ }
36691
+ function isQuotaExhaustionError(status, errorBody) {
36692
+ if (status !== 401 && status !== 403 && status !== 429)
36693
+ return false;
36694
+ return hasQuotaExhaustionWording(errorBody);
36695
+ }
36696
+ var EXHAUSTION_PHRASES;
36697
+ var init_quota_exhaustion = __esm(() => {
36698
+ EXHAUSTION_PHRASES = [
36699
+ "usage limit",
36700
+ "billing cycle",
36701
+ "quota",
36702
+ "insufficient balance",
36703
+ "insufficient_quota",
36704
+ "upgrade your plan",
36705
+ "exceeded your current",
36706
+ "out of credits",
36707
+ "credit balance",
36708
+ "daily limit",
36709
+ "plan limit"
36710
+ ];
36711
+ });
36712
+
36686
36713
  // src/providers/transport/openai.ts
36687
36714
  class OpenAIProviderTransport {
36688
36715
  name;
@@ -36768,11 +36795,14 @@ class OpenAIProviderTransport {
36768
36795
  function isTerminal429(body) {
36769
36796
  if (!body)
36770
36797
  return false;
36798
+ if (isQuotaExhaustionError(429, body))
36799
+ return true;
36771
36800
  const lower = body.toLowerCase();
36772
36801
  return lower.includes("insufficient balance") || lower.includes("insufficient_balance") || lower.includes("insufficient_quota") || lower.includes("insufficient quota") || lower.includes("billing_not_active") || lower.includes("billing not active") || lower.includes("quota_exceeded") || lower.includes("exceeded your current quota") || lower.includes("out of credits") || lower.includes('"code":"1113"') || lower.includes('"code":1113');
36773
36802
  }
36774
36803
  var OpenAITimeoutError, OpenAIConnectionError;
36775
36804
  var init_openai = __esm(() => {
36805
+ init_quota_exhaustion();
36776
36806
  init_logger();
36777
36807
  OpenAITimeoutError = class OpenAITimeoutError extends Error {
36778
36808
  constructor(baseUrl) {
@@ -38664,28 +38694,6 @@ var init_context_window_fallback = __esm(() => {
38664
38694
  inFlight2 = new Map;
38665
38695
  });
38666
38696
 
38667
- // src/handlers/shared/quota-exhaustion.ts
38668
- function isQuotaExhaustionError(status, errorBody) {
38669
- if (status !== 401 && status !== 403 && status !== 429)
38670
- return false;
38671
- const lower = (errorBody || "").toLowerCase();
38672
- return EXHAUSTION_PHRASES.some((phrase) => lower.includes(phrase));
38673
- }
38674
- var EXHAUSTION_PHRASES;
38675
- var init_quota_exhaustion = __esm(() => {
38676
- EXHAUSTION_PHRASES = [
38677
- "usage limit",
38678
- "billing cycle",
38679
- "quota",
38680
- "insufficient balance",
38681
- "insufficient_quota",
38682
- "upgrade your plan",
38683
- "exceeded your current",
38684
- "out of credits",
38685
- "credit balance"
38686
- ];
38687
- });
38688
-
38689
38697
  // src/handlers/shared/stream-head-sniffer.ts
38690
38698
  function isRetryableStreamError(code, type, message) {
38691
38699
  if (RETRYABLE_ERROR_CODES.has(code))
@@ -40837,6 +40845,9 @@ function getRecoveryHint(status, errorText, providerName) {
40837
40845
  if (status === 429 && isTerminal429(errorText)) {
40838
40846
  return "Out of quota \u2014 check your plan & billing details. This won't recover on retry.";
40839
40847
  }
40848
+ if (isQuotaExhaustionError(status, errorText)) {
40849
+ return "Subscription allowance spent \u2014 this refills on the provider's own schedule (see the message below). Reducing concurrency won't help; switch model/provider or wait.";
40850
+ }
40840
40851
  if (status === 429 || lower.includes("rate limit")) {
40841
40852
  return "Rate limited. Wait, reduce concurrency, or check plan limits.";
40842
40853
  }
@@ -42249,13 +42260,15 @@ var init_default_routing_rules = __esm(() => {
42249
42260
  "o3-*": ["openai-codex", "openai", "openrouter"],
42250
42261
  "gemini-*": ["antigravity", "google", "openrouter"],
42251
42262
  "grok-*": ["x-ai", "openrouter"],
42252
- "kimi-*": ["kimi-coding", "kimi", "openrouter"],
42253
- "k3*": ["kimi-coding", "kimi", "openrouter"],
42254
- "minimax-*": ["minimax-coding", "minimax", "openrouter"],
42255
- "glm-*": ["glm-coding", "glm", "openrouter"],
42256
- "qwen3.*": ["qwen-cloud", "openrouter"],
42263
+ "kimi-*": ["kimi-coding", "opencode-zen-go", "kimi", "openrouter"],
42264
+ "k3*": ["kimi-coding", "opencode-zen-go", "kimi", "openrouter"],
42265
+ "minimax-*": ["minimax-coding", "opencode-zen-go", "minimax", "openrouter"],
42266
+ "glm-*": ["glm-coding", "opencode-zen-go", "glm", "openrouter"],
42267
+ "qwen3.*": ["qwen-cloud", "opencode-zen-go", "openrouter"],
42257
42268
  "z-ai-*": ["z-ai", "openrouter"],
42258
- "deepseek-*": ["deepseek", "openrouter"],
42269
+ "deepseek-*": ["opencode-zen-go", "deepseek", "openrouter"],
42270
+ "mimo-*": ["opencode-zen-go", "openrouter"],
42271
+ "hy3*": ["opencode-zen-go", "openrouter"],
42259
42272
  fugu: ["sakana-subscription", "sakana"],
42260
42273
  "fugu-*": ["sakana-subscription", "sakana"],
42261
42274
  "*-zen": ["opencode-zen"],
@@ -45404,7 +45417,11 @@ class FallbackHandler {
45404
45417
  }
45405
45418
  errors3.push({ provider: name, status: response.status, message: errorBody });
45406
45419
  if (!isLast) {
45407
- logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
45420
+ if (hasQuotaExhaustionWording(errorBody)) {
45421
+ logStderr(`[Fallback] ${name} subscription allowance is spent \u2014 falling through to the next provider, which is billed PER TOKEN. Use a provider prefix (e.g. \`zgo@model\`) to fail instead of switching.`);
45422
+ } else {
45423
+ logStderr(`[Fallback] ${name} failed (HTTP ${response.status}), trying next provider...`);
45424
+ }
45408
45425
  }
45409
45426
  } catch (err) {
45410
45427
  errors3.push({ provider: name, status: 0, message: err.message });
@@ -45441,8 +45458,8 @@ ${summary}`);
45441
45458
  }
45442
45459
  }
45443
45460
  function isRetryableError(status, errorBody) {
45444
- if (isQuotaExhaustionError(status, errorBody))
45445
- return false;
45461
+ if (hasQuotaExhaustionWording(errorBody))
45462
+ return true;
45446
45463
  if (status === 401 || status === 403)
45447
45464
  return true;
45448
45465
  if (status === 402)
@@ -46137,7 +46154,7 @@ var init_api_key_map = __esm(() => {
46137
46154
  "qwen-cloud": { envVar: "QWEN_CLOUD_PLAN_API_KEY" },
46138
46155
  ollamacloud: { envVar: "OLLAMA_API_KEY" },
46139
46156
  "opencode-zen": { envVar: "OPENCODE_API_KEY" },
46140
- "opencode-zen-go": { envVar: "OPENCODE_API_KEY" },
46157
+ "opencode-zen-go": { envVar: "OPENCODE_GO_API_KEY", aliases: ["OPENCODE_API_KEY"] },
46141
46158
  "gemini-codeassist": { envVar: "GEMINI_API_KEY" },
46142
46159
  vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
46143
46160
  poe: { envVar: "POE_API_KEY" }
@@ -46958,7 +46975,8 @@ var init_provider_profiles = __esm(() => {
46958
46975
  const zenApiKey = ctx.apiKey;
46959
46976
  const isGoProvider = ctx.provider.name === "opencode-zen-go";
46960
46977
  if (ctx.modelName.toLowerCase().includes("minimax")) {
46961
- const transport2 = new AnthropicProviderTransport(ctx.provider, zenApiKey);
46978
+ const bearerProvider = { ...ctx.provider, authScheme: "bearer" };
46979
+ const transport2 = new AnthropicProviderTransport(bearerProvider, zenApiKey);
46962
46980
  const adapter2 = new AnthropicAPIFormat(ctx.modelName, ctx.provider.name);
46963
46981
  const handler2 = new ComposedHandler(transport2, ctx.targetModel, ctx.modelName, ctx.port, {
46964
46982
  adapter: adapter2,
@@ -76541,13 +76559,15 @@ function createTempSettingsFile(_modelDisplay, port, proxyAuthMode, userStatusLi
76541
76559
  const DIM4 = "\\033[2m";
76542
76560
  const RESET4 = "\\033[0m";
76543
76561
  const BOLD4 = "\\033[1m";
76562
+ const readPlanBash = `PLAN_PAIR=$(echo "$TOKENS" | grep -o '"id": *"[^"]*", *"used_pct": *[0-9]*' | sed 's/"id": *"\\([^"]*\\)", *"used_pct": *\\([0-9]*\\)/\\2 \\1/' | sort -rn | head -1); if [ -n "$PLAN_PAIR" ]; then PLAN_PCT="\${PLAN_PAIR%% *}"; PLAN_ID="\${PLAN_PAIR#* }"; case "$PLAN_PCT" in ''|*[!0-9]*) PLAN_PCT="" ;; esac; [ -n "$PLAN_PCT" ] && PLAN_DISPLAY="$PLAN_ID:$PLAN_PCT%"; fi;`;
76544
76563
  const formatTokensBash = `fmt_tok() { local n=\${1:-0}; if [ "$n" -ge 1000000 ]; then echo "$((n/1000000))M"; elif [ "$n" -ge 1000 ]; then echo "$((n/1000))k"; else echo "$n"; fi; }`;
76545
76564
  const effWinBash = `eff_win() { local w=\${1:-0}; local m=\${CLAUDE_CODE_MAX_CONTEXT_TOKENS:-}; local a=\${CLAUDE_CODE_AUTO_COMPACT_WINDOW:-}; case "$m" in ''|*[!0-9]*) m=${CLAUDE_CODE_DEFAULT_MAX_CONTEXT};; esac; case "$a" in ''|*[!0-9]*) a=0;; esac; case "$w" in ''|*[!0-9]*) w=0;; esac; if [ "$w" -gt 0 ]; then if [ "$m" -gt 0 ] && [ "$m" -lt "$w" ]; then w=$m; fi; if [ "$a" -gt 0 ] && [ "$a" -lt "$w" ]; then w=$a; fi; fi; echo "$w"; }`;
76546
76565
  const dirPrelude = `DIR=$(basename "$(pwd)"); [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true; `;
76547
- const readState = `CTX=-1; COST="0"; IS_FREE="false"; IS_EST="false"; PROVIDER=""; TOKEN_MODEL=""; IN_TOK=0; CTX_WIN=0; ${formatTokensBash}; ${effWinBash}; if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d '\\n\\r'); V=$(echo "$TOKENS" | grep -o '"context_left_percent": *-\\?[0-9]*' | grep -o '\\-\\?[0-9]*'); [ -n "$V" ] && CTX="$V"; V=$(echo "$TOKENS" | grep -o '"total_cost": *[0-9.]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && COST="$V"; V=$(echo "$TOKENS" | grep -o '"input_tokens": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && IN_TOK="$V"; V=$(echo "$TOKENS" | grep -o '"context_window": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && CTX_WIN="$V"; V=$(echo "$TOKENS" | grep -o '"is_free": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_FREE="$V"; V=$(echo "$TOKENS" | grep -o '"is_estimated": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_EST="$V"; V=$(echo "$TOKENS" | grep -o '"provider_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && PROVIDER="$V"; V=$(echo "$TOKENS" | grep -o '"model_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && TOKEN_MODEL="$V"; fi; if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi; MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}"; if [ -n "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi; EFF_WIN=$(eff_win $CTX_WIN); if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi; if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi`;
76548
- const segmentWithDir = `printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
76549
- const segmentNoDirWithProvider = `printf "${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$PROVIDER" "$COST_DISPLAY" "$CTX_DISPLAY"`;
76550
- const segmentNoDirNoProvider = `printf "${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}\\n" "$COST_DISPLAY" "$CTX_DISPLAY"`;
76566
+ const readState = `CTX=-1; COST="0"; IS_FREE="false"; IS_EST="false"; PROVIDER=""; TOKEN_MODEL=""; IN_TOK=0; CTX_WIN=0; PLAN_DISPLAY=""; ${formatTokensBash}; ${effWinBash}; if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d '\\n\\r'); V=$(echo "$TOKENS" | grep -o '"context_left_percent": *-\\?[0-9]*' | grep -o '\\-\\?[0-9]*'); [ -n "$V" ] && CTX="$V"; V=$(echo "$TOKENS" | grep -o '"total_cost": *[0-9.]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && COST="$V"; V=$(echo "$TOKENS" | grep -o '"input_tokens": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && IN_TOK="$V"; V=$(echo "$TOKENS" | grep -o '"context_window": *[0-9]*' | grep -o '[0-9]*'); [ -n "$V" ] && CTX_WIN="$V"; V=$(echo "$TOKENS" | grep -o '"is_free": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_FREE="$V"; V=$(echo "$TOKENS" | grep -o '"is_estimated": *[a-z]*' | cut -d: -f2 | tr -d ' '); [ -n "$V" ] && IS_EST="$V"; V=$(echo "$TOKENS" | grep -o '"provider_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && PROVIDER="$V"; V=$(echo "$TOKENS" | grep -o '"model_name": *"[^"]*"' | cut -d'"' -f4); [ -n "$V" ] && TOKEN_MODEL="$V"; ${readPlanBash} fi; if [ "$CLAUDISH_IS_LOCAL" = "true" ]; then COST_DISPLAY="LOCAL"; elif [ "$IS_FREE" = "true" ]; then COST_DISPLAY="FREE"; elif [ "$IS_EST" = "true" ]; then COST_DISPLAY=$(printf "~\\$%.3f" "$COST"); else COST_DISPLAY=$(printf "\\$%.3f" "$COST"); fi; MODEL_DISPLAY="\${TOKEN_MODEL:-$CLAUDISH_ACTIVE_MODEL_NAME}"; if [ -n "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi; EFF_WIN=$(eff_win $CTX_WIN); if [ "$EFF_WIN" -gt 0 ] 2>/dev/null && [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX=$(( ((EFF_WIN - IN_TOK) * 200 / EFF_WIN + 1) / 2 )); if [ "$CTX" -lt 0 ]; then CTX=0; fi; fi; if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$EFF_WIN" -le 0 ] 2>/dev/null; then if [ "$IN_TOK" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$(fmt_tok $IN_TOK) tokens"; else CTX_DISPLAY="N/A"; fi; elif [ "$IN_TOK" -gt 0 ] 2>/dev/null; then if [ "$EFF_WIN" -lt "$CTX_WIN" ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN) of $(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $EFF_WIN))"; fi; else CTX_DISPLAY="$CTX%"; fi`;
76567
+ const planSuffix = `if [ -n "$PLAN_DISPLAY" ]; then printf " ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4}" "$PLAN_DISPLAY"; fi`;
76568
+ const segmentWithDir = `printf "${CYAN4}${BOLD4}%s${RESET4} ${DIM4}\u2022${RESET4} ${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
76569
+ const segmentNoDirWithProvider = `printf "${YELLOW3}%s${RESET4} ${DIM4}\u2022${RESET4} ${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$PROVIDER" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
76570
+ const segmentNoDirNoProvider = `printf "${GREEN4}%s${RESET4} ${DIM4}\u2022${RESET4} ${MAGENTA3}%s${RESET4}" "$COST_DISPLAY" "$CTX_DISPLAY"; ${planSuffix}; printf "\\n"`;
76551
76571
  const segmentNoDir = `if [ -n "$PROVIDER" ]; then ${segmentNoDirWithProvider}; else ${segmentNoDirNoProvider}; fi`;
76552
76572
  statusCommand = userStatusLineCommand ? buildChainedStatusCommand(userStatusLineCommand, readState, segmentNoDir) : `JSON=$(cat); ${dirPrelude}${readState}; ${segmentWithDir}`;
76553
76573
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.39.0",
3
+ "version": "7.40.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.39.0",
64
- "@claudish/magmux-darwin-x64": "7.39.0",
65
- "@claudish/magmux-linux-arm64": "7.39.0",
66
- "@claudish/magmux-linux-x64": "7.39.0"
63
+ "@claudish/magmux-darwin-arm64": "7.40.0",
64
+ "@claudish/magmux-darwin-x64": "7.40.0",
65
+ "@claudish/magmux-linux-arm64": "7.40.0",
66
+ "@claudish/magmux-linux-x64": "7.40.0"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",