claudish 7.16.0 → 7.17.1

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 +117 -5
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -581,7 +581,7 @@ var init_onepassword_config = __esm(() => {
581
581
  });
582
582
 
583
583
  // src/version.ts
584
- var VERSION = "7.16.0";
584
+ var VERSION = "7.17.1";
585
585
 
586
586
  // src/logger.ts
587
587
  var exports_logger = {};
@@ -37625,6 +37625,61 @@ function ensureAnthropicErrorFormat(status, body) {
37625
37625
  return wrapAnthropicError(status, String(message), errorType);
37626
37626
  }
37627
37627
 
37628
+ // src/handlers/shared/connection-error.ts
37629
+ function findConnectionCode(error46) {
37630
+ let e = error46;
37631
+ const seen = new Set;
37632
+ for (let depth = 0;e && typeof e === "object" && depth < 8 && !seen.has(e); depth++) {
37633
+ seen.add(e);
37634
+ if (typeof e.code === "string" && e.code in CODE_KIND)
37635
+ return e.code;
37636
+ e = e.cause;
37637
+ }
37638
+ const msg = String(error46?.message ?? error46 ?? "");
37639
+ if (/getaddrinfo|ENOTFOUND|EAI_AGAIN|nodename nor servname/i.test(msg))
37640
+ return "ENOTFOUND";
37641
+ return null;
37642
+ }
37643
+ function classifyConnectionError(error46) {
37644
+ const code = findConnectionCode(error46);
37645
+ if (!code)
37646
+ return null;
37647
+ return { kind: CODE_KIND[code] ?? "unreachable", code };
37648
+ }
37649
+ function hostOf(endpoint) {
37650
+ try {
37651
+ return new URL(endpoint).host || endpoint;
37652
+ } catch {
37653
+ return endpoint;
37654
+ }
37655
+ }
37656
+ function buildConnectionErrorMessage(kind, displayName, endpoint) {
37657
+ const host = hostOf(endpoint);
37658
+ switch (kind) {
37659
+ case "dns":
37660
+ return `Cannot resolve ${host} for ${displayName}. This is a DNS/network problem on your machine \u2014 check your internet connection, VPN, or DNS resolver (e.g. Tailscale MagicDNS) \u2014 not ${displayName}.`;
37661
+ case "refused":
37662
+ return `Cannot connect to ${displayName} at ${endpoint}. Make sure the server is running.`;
37663
+ case "unreachable":
37664
+ return `Cannot reach ${displayName} at ${endpoint}. Check your network connection.`;
37665
+ }
37666
+ }
37667
+ var CODE_KIND;
37668
+ var init_connection_error = __esm(() => {
37669
+ CODE_KIND = {
37670
+ ENOTFOUND: "dns",
37671
+ EAI_AGAIN: "dns",
37672
+ ECONNREFUSED: "refused",
37673
+ ETIMEDOUT: "unreachable",
37674
+ ECONNRESET: "unreachable",
37675
+ ENETUNREACH: "unreachable",
37676
+ EHOSTUNREACH: "unreachable",
37677
+ EPIPE: "unreachable",
37678
+ UND_ERR_CONNECT_TIMEOUT: "unreachable",
37679
+ UND_ERR_SOCKET: "unreachable"
37680
+ };
37681
+ });
37682
+
37628
37683
  // src/handlers/shared/stream-parsers/anthropic-sse.ts
37629
37684
  function createAnthropicPassthroughStream(c, response, opts) {
37630
37685
  const encoder = new TextEncoder;
@@ -38960,10 +39015,11 @@ class ComposedHandler {
38960
39015
  try {
38961
39016
  response = this.provider.enqueueRequest ? await this.provider.enqueueRequest(doFetch) : await doFetch();
38962
39017
  } catch (error46) {
38963
- if (error46.code === "ECONNREFUSED" || error46.cause?.code === "ECONNREFUSED") {
38964
- const msg = `Cannot connect to ${this.provider.displayName} at ${endpoint}. Make sure the server is running.`;
38965
- log(`[${this.provider.displayName}] ${msg}`);
38966
- logStderr(`Error: ${msg} Check the server is running.`);
39018
+ const conn = classifyConnectionError(error46);
39019
+ if (conn) {
39020
+ const msg = buildConnectionErrorMessage(conn.kind, this.provider.displayName, endpoint);
39021
+ log(`[${this.provider.displayName}] ${msg} (code=${conn.code})`);
39022
+ logStderr(`Error: ${msg}`);
38967
39023
  reportError({
38968
39024
  error: error46,
38969
39025
  providerName: this.provider.name,
@@ -39332,6 +39388,7 @@ var init_composed_handler = __esm(() => {
39332
39388
  init_stats();
39333
39389
  init_telemetry();
39334
39390
  init_transform();
39391
+ init_connection_error();
39335
39392
  init_openai_compat();
39336
39393
  init_anthropic_sse();
39337
39394
  init_gemini_sse();
@@ -58695,6 +58752,7 @@ var init_config = __esm(() => {
58695
58752
  ANTHROPIC_DEFAULT_SONNET_MODEL: "ANTHROPIC_DEFAULT_SONNET_MODEL",
58696
58753
  ANTHROPIC_DEFAULT_HAIKU_MODEL: "ANTHROPIC_DEFAULT_HAIKU_MODEL",
58697
58754
  CLAUDE_CODE_SUBAGENT_MODEL: "CLAUDE_CODE_SUBAGENT_MODEL",
58755
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "CLAUDE_CODE_AUTO_COMPACT_WINDOW",
58698
58756
  OLLAMA_BASE_URL: "OLLAMA_BASE_URL",
58699
58757
  OLLAMA_HOST: "OLLAMA_HOST",
58700
58758
  LMSTUDIO_BASE_URL: "LMSTUDIO_BASE_URL",
@@ -59874,8 +59932,27 @@ function extractUpstreamStatus(body) {
59874
59932
  return;
59875
59933
  }
59876
59934
  }
59935
+ function extractErrorType(body) {
59936
+ if (!body)
59937
+ return;
59938
+ try {
59939
+ const parsed = JSON.parse(body);
59940
+ const t = parsed?.error?.type;
59941
+ return typeof t === "string" ? t : undefined;
59942
+ } catch {
59943
+ return;
59944
+ }
59945
+ }
59877
59946
  function classifyHttpError(status, body, latencyMs) {
59878
59947
  const lowered = body.toLowerCase();
59948
+ if (extractErrorType(body) === "connection_error") {
59949
+ return {
59950
+ state: "network-error",
59951
+ latencyMs,
59952
+ httpStatus: status,
59953
+ errorMessage: extractErrorMessage(body) || "Cannot reach provider"
59954
+ };
59955
+ }
59879
59956
  const upstream = status === 400 ? extractUpstreamStatus(body) : undefined;
59880
59957
  if (status === 401 || status === 403 || upstream === 401 || upstream === 403) {
59881
59958
  const authStatus = upstream ?? status;
@@ -71380,6 +71457,7 @@ __export(exports_claude_runner, {
71380
71457
  runClaudeWithProxy: () => runClaudeWithProxy,
71381
71458
  managedSettingsForcesClaudeAi: () => managedSettingsForcesClaudeAi,
71382
71459
  isProxyAuthMode: () => isProxyAuthMode,
71460
+ computeMainThreadContextWindow: () => computeMainThreadContextWindow,
71383
71461
  checkClaudeInstalled: () => checkClaudeInstalled,
71384
71462
  buildClaudishSettingsOverlay: () => buildClaudishSettingsOverlay
71385
71463
  });
@@ -71598,6 +71676,29 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine, proxy
71598
71676
  }
71599
71677
  config3.claudeArgs.splice(idx, 2);
71600
71678
  }
71679
+ async function computeMainThreadContextWindow(config3, cachePath) {
71680
+ const specs = [config3.model, config3.modelOpus, config3.modelSonnet].filter((s) => typeof s === "string" && s.length > 0);
71681
+ if (specs.length === 0)
71682
+ return 0;
71683
+ let min = Number.POSITIVE_INFINITY;
71684
+ for (const spec of specs) {
71685
+ try {
71686
+ const parsed = parseModelSpec(spec);
71687
+ let provider = parsed.provider;
71688
+ if (!parsed.isExplicitProvider) {
71689
+ const plan = await route(spec);
71690
+ if (plan.kind !== "ok")
71691
+ continue;
71692
+ provider = plan.primary.provider;
71693
+ }
71694
+ const win = lookupModelForProvider(parsed.model, provider, cachePath);
71695
+ if (typeof win === "number" && win > 0) {
71696
+ min = Math.min(min, win);
71697
+ }
71698
+ } catch {}
71699
+ }
71700
+ return Number.isFinite(min) ? min : 0;
71701
+ }
71601
71702
  async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
71602
71703
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
71603
71704
  const modelId = config3.model || (hasProfileMappings || config3.monitor ? undefined : "unknown");
@@ -71662,6 +71763,15 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
71662
71763
  if (hasNativeAnthropicMapping(config3)) {} else {
71663
71764
  env.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx";
71664
71765
  env.ANTHROPIC_AUTH_TOKEN = process.env.ANTHROPIC_AUTH_TOKEN || "placeholder-token-not-used-proxy-handles-auth";
71766
+ if (!process.env[ENV.CLAUDE_CODE_AUTO_COMPACT_WINDOW]) {
71767
+ const autoCompactWindow = await computeMainThreadContextWindow(config3);
71768
+ if (autoCompactWindow > 0) {
71769
+ env[ENV.CLAUDE_CODE_AUTO_COMPACT_WINDOW] = String(autoCompactWindow);
71770
+ if (!config3.quiet) {
71771
+ console.error(`[claudish] Auto-compact window: ${autoCompactWindow.toLocaleString()} tokens ` + "(Claude Code compacts before the backend's real limit)");
71772
+ }
71773
+ }
71774
+ }
71665
71775
  }
71666
71776
  }
71667
71777
  const log2 = (message) => {
@@ -71835,8 +71945,10 @@ async function checkClaudeInstalled() {
71835
71945
  return binary !== null;
71836
71946
  }
71837
71947
  var init_claude_runner = __esm(() => {
71948
+ init_model_catalog();
71838
71949
  init_config();
71839
71950
  init_model_parser();
71951
+ init_routing_rules();
71840
71952
  init_telemetry();
71841
71953
  });
71842
71954
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "7.16.0",
3
+ "version": "7.17.1",
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.16.0",
64
- "@claudish/magmux-darwin-x64": "7.16.0",
65
- "@claudish/magmux-linux-arm64": "7.16.0",
66
- "@claudish/magmux-linux-x64": "7.16.0"
63
+ "@claudish/magmux-darwin-arm64": "7.17.1",
64
+ "@claudish/magmux-darwin-x64": "7.17.1",
65
+ "@claudish/magmux-linux-arm64": "7.17.1",
66
+ "@claudish/magmux-linux-x64": "7.17.1"
67
67
  },
68
68
  "author": "Jack Rudenko <i@madappgang.com>",
69
69
  "license": "MIT",