claudish 6.10.1 → 6.11.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.
package/dist/index.js CHANGED
@@ -16928,6 +16928,45 @@ var init_logger = __esm(() => {
16928
16928
  ]);
16929
16929
  });
16930
16930
 
16931
+ // src/handlers/shared/anthropic-error.ts
16932
+ function statusToErrorType(status) {
16933
+ switch (status) {
16934
+ case 400:
16935
+ return "invalid_request_error";
16936
+ case 401:
16937
+ return "authentication_error";
16938
+ case 403:
16939
+ return "permission_error";
16940
+ case 404:
16941
+ return "not_found_error";
16942
+ case 429:
16943
+ return "rate_limit_error";
16944
+ case 503:
16945
+ case 529:
16946
+ return "overloaded_error";
16947
+ default:
16948
+ return "api_error";
16949
+ }
16950
+ }
16951
+ function wrapAnthropicError(status, message, errorType) {
16952
+ const type = errorType || statusToErrorType(status);
16953
+ return {
16954
+ type: "error",
16955
+ error: { type, message }
16956
+ };
16957
+ }
16958
+ function ensureAnthropicErrorFormat(status, body) {
16959
+ if (body?.type === "error" && typeof body?.error?.type === "string" && typeof body?.error?.message === "string") {
16960
+ return body;
16961
+ }
16962
+ if (typeof body?.error?.type === "string" && typeof body?.error?.message === "string") {
16963
+ return { type: "error", error: body.error };
16964
+ }
16965
+ const message = body?.error?.message || body?.message || body?.error || (typeof body === "string" ? body : JSON.stringify(body));
16966
+ const errorType = body?.error?.type || body?.type || body?.code;
16967
+ return wrapAnthropicError(status, String(message), errorType);
16968
+ }
16969
+
16931
16970
  // src/handlers/native-handler.ts
16932
16971
  class NativeHandler {
16933
16972
  apiKey;
@@ -17019,7 +17058,7 @@ class NativeHandler {
17019
17058
  return c.json(data, { status: anthropicResponse.status, headers: responseHeaders });
17020
17059
  } catch (error2) {
17021
17060
  log(`[Native] Fetch Error: ${error2}`);
17022
- return c.json({ error: { type: "api_error", message: String(error2) } }, 500);
17061
+ return c.json(wrapAnthropicError(500, String(error2)), 500);
17023
17062
  }
17024
17063
  }
17025
17064
  async shutdown() {}
@@ -17285,6 +17324,24 @@ function loadRecommendedModelsJSON() {
17285
17324
  if (_cachedRecommendedModels) {
17286
17325
  return _cachedRecommendedModels;
17287
17326
  }
17327
+ if (existsSync3(RECOMMENDED_CACHE_PATH)) {
17328
+ try {
17329
+ const cacheData = JSON.parse(readFileSync2(RECOMMENDED_CACHE_PATH, "utf-8"));
17330
+ if (cacheData.models && cacheData.models.length > 0) {
17331
+ const generatedAt = cacheData.generatedAt;
17332
+ if (generatedAt) {
17333
+ const ageHours = (Date.now() - new Date(generatedAt).getTime()) / (1000 * 60 * 60);
17334
+ if (ageHours <= RECOMMENDED_CACHE_MAX_AGE_HOURS) {
17335
+ _cachedRecommendedModels = cacheData;
17336
+ return cacheData;
17337
+ }
17338
+ } else {
17339
+ _cachedRecommendedModels = cacheData;
17340
+ return cacheData;
17341
+ }
17342
+ }
17343
+ } catch {}
17344
+ }
17288
17345
  const jsonPath = getRecommendedModelsPath();
17289
17346
  if (!existsSync3(jsonPath)) {
17290
17347
  throw new Error(`recommended-models.json not found at ${jsonPath}. ` + `Run 'claudish --update-models' to fetch the latest model list.`);
@@ -17429,10 +17486,11 @@ async function fetchLiteLLMModels(baseUrl, apiKey, forceUpdate = false) {
17429
17486
  return [];
17430
17487
  }
17431
17488
  }
17432
- var __filename2, __dirname2, _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, _cachedOpenRouterModels = null, LITELLM_CACHE_MAX_AGE_HOURS = 24;
17489
+ var __filename2, __dirname2, _cachedModelInfo = null, _cachedModelIds = null, _cachedRecommendedModels = null, RECOMMENDED_CACHE_PATH, RECOMMENDED_CACHE_MAX_AGE_HOURS = 12, _cachedOpenRouterModels = null, LITELLM_CACHE_MAX_AGE_HOURS = 24;
17433
17490
  var init_model_loader = __esm(() => {
17434
17491
  __filename2 = fileURLToPath(import.meta.url);
17435
17492
  __dirname2 = dirname(__filename2);
17493
+ RECOMMENDED_CACHE_PATH = join4(homedir3(), ".claudish", "recommended-models-cache.json");
17436
17494
  });
17437
17495
 
17438
17496
  // src/providers/transport/openrouter.ts
@@ -17467,7 +17525,7 @@ class OpenRouterProviderTransport {
17467
17525
  getContextWindow() {
17468
17526
  const models = this.modelId ? getCachedOpenRouterModels() : null;
17469
17527
  const model = models?.find((m) => m.id === this.modelId);
17470
- return model?.context_length || model?.top_provider?.context_length || 200000;
17528
+ return model?.context_length || model?.top_provider?.context_length || 0;
17471
17529
  }
17472
17530
  }
17473
17531
  var OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions";
@@ -17550,6 +17608,83 @@ var init_remote_provider_types = __esm(() => {
17550
17608
  };
17551
17609
  });
17552
17610
 
17611
+ // src/adapters/model-catalog.ts
17612
+ function lookupModel(modelId) {
17613
+ const lower = modelId.toLowerCase();
17614
+ let unprefixed = lower;
17615
+ if (lower.includes("@"))
17616
+ unprefixed = lower.substring(lower.indexOf("@") + 1);
17617
+ else if (lower.includes("/"))
17618
+ unprefixed = lower.substring(lower.lastIndexOf("/") + 1);
17619
+ for (const entry of MODEL_CATALOG) {
17620
+ if (unprefixed.includes(entry.pattern) || lower.includes(entry.pattern)) {
17621
+ return entry;
17622
+ }
17623
+ }
17624
+ return;
17625
+ }
17626
+ var MODEL_CATALOG;
17627
+ var init_model_catalog = __esm(() => {
17628
+ MODEL_CATALOG = [
17629
+ { pattern: "grok-4.20", contextWindow: 2000000 },
17630
+ { pattern: "grok-4-20", contextWindow: 2000000 },
17631
+ { pattern: "grok-4.1-fast", contextWindow: 2000000 },
17632
+ { pattern: "grok-4-1-fast", contextWindow: 2000000 },
17633
+ { pattern: "grok-4-fast", contextWindow: 2000000 },
17634
+ { pattern: "grok-code-fast", contextWindow: 256000 },
17635
+ { pattern: "grok-4", contextWindow: 256000 },
17636
+ { pattern: "grok-3", contextWindow: 131072 },
17637
+ { pattern: "grok-2", contextWindow: 131072 },
17638
+ { pattern: "glm-5-turbo", contextWindow: 202752 },
17639
+ { pattern: "glm-5", contextWindow: 80000, supportsVision: true },
17640
+ { pattern: "glm-4.7-flash", contextWindow: 202752 },
17641
+ { pattern: "glm-4.7", contextWindow: 202752 },
17642
+ { pattern: "glm-4.6v", contextWindow: 131072, supportsVision: true },
17643
+ { pattern: "glm-4.6", contextWindow: 204800 },
17644
+ { pattern: "glm-4.5v", contextWindow: 65536, supportsVision: true },
17645
+ { pattern: "glm-4.5-flash", contextWindow: 131072 },
17646
+ { pattern: "glm-4.5-air", contextWindow: 131072 },
17647
+ { pattern: "glm-4.5", contextWindow: 131072 },
17648
+ { pattern: "glm-4v-plus", contextWindow: 128000, supportsVision: true },
17649
+ { pattern: "glm-4v", contextWindow: 128000, supportsVision: true },
17650
+ { pattern: "glm-4-long", contextWindow: 1e6 },
17651
+ { pattern: "glm-4-plus", contextWindow: 128000 },
17652
+ { pattern: "glm-4-flash", contextWindow: 128000 },
17653
+ { pattern: "glm-4-32b", contextWindow: 128000 },
17654
+ { pattern: "glm-4", contextWindow: 128000 },
17655
+ { pattern: "glm-3-turbo", contextWindow: 128000 },
17656
+ { pattern: "minimax-01", contextWindow: 1e6, supportsVision: false },
17657
+ { pattern: "minimax-m1", contextWindow: 1e6, supportsVision: false },
17658
+ {
17659
+ pattern: "minimax",
17660
+ contextWindow: 0,
17661
+ supportsVision: false,
17662
+ temperatureRange: { min: 0.01, max: 1 }
17663
+ },
17664
+ { pattern: "gpt-5.4", contextWindow: 1050000, maxToolCount: 128 },
17665
+ { pattern: "gpt-5", contextWindow: 400000, maxToolCount: 128 },
17666
+ { pattern: "o1", contextWindow: 200000, maxToolCount: 128 },
17667
+ { pattern: "o3", contextWindow: 200000, maxToolCount: 128 },
17668
+ { pattern: "o4", contextWindow: 200000, maxToolCount: 128 },
17669
+ { pattern: "gpt-4o", contextWindow: 128000, maxToolCount: 128 },
17670
+ { pattern: "gpt-4-turbo", contextWindow: 128000, maxToolCount: 128 },
17671
+ { pattern: "gpt-3.5", contextWindow: 16385, maxToolCount: 128 },
17672
+ { pattern: "kimi-k2.5", contextWindow: 262144 },
17673
+ { pattern: "kimi-k2-5", contextWindow: 262144 },
17674
+ { pattern: "kimi-k2", contextWindow: 131000 },
17675
+ { pattern: "qwen3.6", contextWindow: 1048576 },
17676
+ { pattern: "qwen3-6", contextWindow: 1048576 },
17677
+ { pattern: "qwen3.5", contextWindow: 262144 },
17678
+ { pattern: "qwen3-5", contextWindow: 262144 },
17679
+ { pattern: "qwen3-coder", contextWindow: 262144 },
17680
+ { pattern: "qwen3", contextWindow: 131072 },
17681
+ { pattern: "qwen2.5", contextWindow: 131072 },
17682
+ { pattern: "qwen2-5", contextWindow: 131072 },
17683
+ { pattern: "xiaomi", contextWindow: 0, toolNameLimit: 64 },
17684
+ { pattern: "mimo", contextWindow: 0, toolNameLimit: 64 }
17685
+ ];
17686
+ });
17687
+
17553
17688
  // src/handlers/shared/format/openai-messages.ts
17554
17689
  function convertMessagesToOpenAI(req, modelId, filterIdentityFn, simpleFormat = false) {
17555
17690
  const messages = [];
@@ -17830,7 +17965,7 @@ var init_openai_tools = __esm(() => {
17830
17965
  function matchesModelFamily(modelId, family) {
17831
17966
  const lower = modelId.toLowerCase();
17832
17967
  const fam = family.toLowerCase();
17833
- return lower.startsWith(fam) || lower.includes(`/${fam}`);
17968
+ return lower.startsWith(fam) || lower.includes(`/${fam}`) || lower.includes(`@${fam}`);
17834
17969
  }
17835
17970
 
17836
17971
  class BaseAPIFormat {
@@ -17881,7 +18016,7 @@ class BaseAPIFormat {
17881
18016
  return "openai-sse";
17882
18017
  }
17883
18018
  getContextWindow() {
17884
- return 200000;
18019
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
17885
18020
  }
17886
18021
  getPricing(providerName) {
17887
18022
  return getModelPricing(providerName, this.modelId);
@@ -17930,6 +18065,7 @@ var DefaultAPIFormat;
17930
18065
  var init_base_api_format = __esm(() => {
17931
18066
  init_tool_name_utils();
17932
18067
  init_remote_provider_types();
18068
+ init_model_catalog();
17933
18069
  init_openai_tools();
17934
18070
  DefaultAPIFormat = class DefaultAPIFormat extends BaseAPIFormat {
17935
18071
  processTextContent(textContent, accumulatedText) {
@@ -17948,74 +18084,6 @@ var init_base_api_format = __esm(() => {
17948
18084
  };
17949
18085
  });
17950
18086
 
17951
- // src/adapters/model-catalog.ts
17952
- function lookupModel(modelId) {
17953
- const lower = modelId.toLowerCase();
17954
- const unprefixed = lower.includes("/") ? lower.substring(lower.lastIndexOf("/") + 1) : lower;
17955
- for (const entry of MODEL_CATALOG) {
17956
- if (unprefixed.includes(entry.pattern) || lower.includes(entry.pattern)) {
17957
- return entry;
17958
- }
17959
- }
17960
- return;
17961
- }
17962
- var MODEL_CATALOG;
17963
- var init_model_catalog = __esm(() => {
17964
- MODEL_CATALOG = [
17965
- { pattern: "grok-4.20", contextWindow: 2000000 },
17966
- { pattern: "grok-4-20", contextWindow: 2000000 },
17967
- { pattern: "grok-4.1-fast", contextWindow: 2000000 },
17968
- { pattern: "grok-4-1-fast", contextWindow: 2000000 },
17969
- { pattern: "grok-4-fast", contextWindow: 2000000 },
17970
- { pattern: "grok-code-fast", contextWindow: 256000 },
17971
- { pattern: "grok-4", contextWindow: 256000 },
17972
- { pattern: "grok-3", contextWindow: 131072 },
17973
- { pattern: "grok-2", contextWindow: 131072 },
17974
- { pattern: "grok", contextWindow: 131072 },
17975
- { pattern: "glm-5-turbo", contextWindow: 202752 },
17976
- { pattern: "glm-5", contextWindow: 80000, supportsVision: true },
17977
- { pattern: "glm-4.7-flash", contextWindow: 202752 },
17978
- { pattern: "glm-4.7", contextWindow: 202752 },
17979
- { pattern: "glm-4.6v", contextWindow: 131072, supportsVision: true },
17980
- { pattern: "glm-4.6", contextWindow: 204800 },
17981
- { pattern: "glm-4.5v", contextWindow: 65536, supportsVision: true },
17982
- { pattern: "glm-4.5-flash", contextWindow: 131072 },
17983
- { pattern: "glm-4.5-air", contextWindow: 131072 },
17984
- { pattern: "glm-4.5", contextWindow: 131072 },
17985
- { pattern: "glm-4v-plus", contextWindow: 128000, supportsVision: true },
17986
- { pattern: "glm-4v", contextWindow: 128000, supportsVision: true },
17987
- { pattern: "glm-4-long", contextWindow: 1e6 },
17988
- { pattern: "glm-4-plus", contextWindow: 128000 },
17989
- { pattern: "glm-4-flash", contextWindow: 128000 },
17990
- { pattern: "glm-4-32b", contextWindow: 128000 },
17991
- { pattern: "glm-4", contextWindow: 128000 },
17992
- { pattern: "glm-3-turbo", contextWindow: 128000 },
17993
- { pattern: "glm-", contextWindow: 131072, supportsVision: false },
17994
- { pattern: "minimax-01", contextWindow: 1e6, supportsVision: false },
17995
- { pattern: "minimax-m1", contextWindow: 1e6, supportsVision: false },
17996
- {
17997
- pattern: "minimax",
17998
- contextWindow: 204800,
17999
- supportsVision: false,
18000
- temperatureRange: { min: 0.01, max: 1 }
18001
- },
18002
- { pattern: "gpt-5.4", contextWindow: 1050000, maxToolCount: 128 },
18003
- { pattern: "gpt-5", contextWindow: 400000, maxToolCount: 128 },
18004
- { pattern: "o1", contextWindow: 200000, maxToolCount: 128 },
18005
- { pattern: "o3", contextWindow: 200000, maxToolCount: 128 },
18006
- { pattern: "o4", contextWindow: 200000, maxToolCount: 128 },
18007
- { pattern: "gpt-4o", contextWindow: 128000, maxToolCount: 128 },
18008
- { pattern: "gpt-4-turbo", contextWindow: 128000, maxToolCount: 128 },
18009
- { pattern: "gpt-3.5", contextWindow: 16385, maxToolCount: 128 },
18010
- { pattern: "kimi-k2.5", contextWindow: 262144 },
18011
- { pattern: "kimi-k2-5", contextWindow: 262144 },
18012
- { pattern: "kimi-k2", contextWindow: 131000 },
18013
- { pattern: "kimi", contextWindow: 131072 },
18014
- { pattern: "xiaomi", contextWindow: 200000, toolNameLimit: 64 },
18015
- { pattern: "mimo", contextWindow: 200000, toolNameLimit: 64 }
18016
- ];
18017
- });
18018
-
18019
18087
  // src/adapters/grok-model-dialect.ts
18020
18088
  var GrokModelDialect;
18021
18089
  var init_grok_model_dialect = __esm(() => {
@@ -18103,7 +18171,7 @@ var init_grok_model_dialect = __esm(() => {
18103
18171
  return "GrokModelDialect";
18104
18172
  }
18105
18173
  getContextWindow() {
18106
- return lookupModel(this.modelId)?.contextWindow ?? 131072;
18174
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
18107
18175
  }
18108
18176
  reset() {
18109
18177
  this.xmlBuffer = "";
@@ -18583,6 +18651,24 @@ var init_tool_call_recovery = __esm(() => {
18583
18651
  init_logger();
18584
18652
  });
18585
18653
 
18654
+ // src/handlers/shared/web-search-detector.ts
18655
+ function isWebSearchToolCall(toolName) {
18656
+ return WEB_SEARCH_NAMES.has(toolName);
18657
+ }
18658
+ function warnWebSearchUnsupported(toolName, modelName) {
18659
+ log(`[WebSearch] Tool call '${toolName}' detected from model '${modelName}' \u2014 not yet supported`);
18660
+ logStderr(`Warning: Model requested web search ('${toolName}') but server-side web search is not yet implemented. ` + `The tool call will pass through to the client as-is.`);
18661
+ }
18662
+ var WEB_SEARCH_NAMES;
18663
+ var init_web_search_detector = __esm(() => {
18664
+ init_logger();
18665
+ WEB_SEARCH_NAMES = new Set([
18666
+ "web_search",
18667
+ "brave_web_search",
18668
+ "tavily_search"
18669
+ ]);
18670
+ });
18671
+
18586
18672
  // src/handlers/shared/stream-parsers/openai-sse.ts
18587
18673
  function validateToolArguments(toolName, argsStr, toolSchemas, textContent) {
18588
18674
  const result = validateAndRepairToolCall(toolName, argsStr, toolSchemas, textContent);
@@ -18913,6 +18999,9 @@ data: ${JSON.stringify(d)}
18913
18999
  buffered: !!toolSchemas && toolSchemas.length > 0
18914
19000
  };
18915
19001
  state.tools.set(idx, t);
19002
+ if (isWebSearchToolCall(restoredName)) {
19003
+ warnWebSearchUnsupported(restoredName, target);
19004
+ }
18916
19005
  }
18917
19006
  if (!t.started && !t.buffered) {
18918
19007
  send("content_block_start", {
@@ -19079,6 +19168,7 @@ function estimateTokens(text) {
19079
19168
  var init_openai_sse = __esm(() => {
19080
19169
  init_logger();
19081
19170
  init_tool_call_recovery();
19171
+ init_web_search_detector();
19082
19172
  });
19083
19173
 
19084
19174
  // src/handlers/shared/openai-compat.ts
@@ -19407,6 +19497,7 @@ CRITICAL INSTRUCTION FOR OUTPUT FORMAT:
19407
19497
  var CodexAPIFormat;
19408
19498
  var init_codex_api_format = __esm(() => {
19409
19499
  init_base_api_format();
19500
+ init_model_catalog();
19410
19501
  CodexAPIFormat = class CodexAPIFormat extends BaseAPIFormat {
19411
19502
  constructor(modelId) {
19412
19503
  super(modelId);
@@ -19428,7 +19519,7 @@ var init_codex_api_format = __esm(() => {
19428
19519
  return "openai-responses-sse";
19429
19520
  }
19430
19521
  getContextWindow() {
19431
- return 200000;
19522
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
19432
19523
  }
19433
19524
  buildPayload(claudeRequest, messages, tools) {
19434
19525
  const convertedMessages = this.convertMessagesToResponsesAPI(messages);
@@ -19583,7 +19674,7 @@ var init_openai_api_format = __esm(() => {
19583
19674
  return "OpenAIAPIFormat";
19584
19675
  }
19585
19676
  getContextWindow() {
19586
- return lookupModel(this.modelId)?.contextWindow ?? 128000;
19677
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
19587
19678
  }
19588
19679
  buildPayload(claudeRequest, messages, tools) {
19589
19680
  return this.buildChatCompletionsPayload(claudeRequest, messages, tools);
@@ -19720,7 +19811,7 @@ var init_minimax_model_dialect = __esm(() => {
19720
19811
  return request;
19721
19812
  }
19722
19813
  getContextWindow() {
19723
- return lookupModel(this.modelId)?.contextWindow ?? 204800;
19814
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
19724
19815
  }
19725
19816
  supportsVision() {
19726
19817
  return lookupModel(this.modelId)?.supportsVision ?? false;
@@ -19791,7 +19882,7 @@ var init_glm_model_dialect = __esm(() => {
19791
19882
  return "GLMModelDialect";
19792
19883
  }
19793
19884
  getContextWindow() {
19794
- return lookupModel(this.modelId)?.contextWindow ?? 128000;
19885
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
19795
19886
  }
19796
19887
  supportsVision() {
19797
19888
  return lookupModel(this.modelId)?.supportsVision ?? false;
@@ -20963,7 +21054,7 @@ class TokenTracker {
20963
21054
  try {
20964
21055
  const total = inputTokens + outputTokens;
20965
21056
  const cw = this.config.contextWindow;
20966
- const leftPct = cw > 0 ? Math.max(0, Math.min(100, Math.round((cw - total) / cw * 100))) : 100;
21057
+ const leftPct = cw > 0 ? Math.max(0, Math.min(100, Math.round((cw - total) / cw * 100))) : -1;
20967
21058
  const pricing = this.getPricing();
20968
21059
  const isFreeModel = pricing.isFree || pricing.inputCostPer1M === 0 && pricing.outputCostPer1M === 0;
20969
21060
  const data = {
@@ -20971,7 +21062,7 @@ class TokenTracker {
20971
21062
  output_tokens: outputTokens,
20972
21063
  total_tokens: total,
20973
21064
  total_cost: this.sessionTotalCost,
20974
- context_window: cw,
21065
+ context_window: cw > 0 ? cw : "unknown",
20975
21066
  context_left_percent: leftPct,
20976
21067
  provider_name: this.getDisplayName(),
20977
21068
  updated_at: Date.now(),
@@ -21001,7 +21092,7 @@ var init_token_tracker = __esm(() => {
21001
21092
  function createResponsesStreamHandler(c, response, opts) {
21002
21093
  const reader = response.body?.getReader();
21003
21094
  if (!reader) {
21004
- return c.json({ error: "No response body" }, 500);
21095
+ return c.json(wrapAnthropicError(500, "No response body"), 500);
21005
21096
  }
21006
21097
  const encoder = new TextEncoder;
21007
21098
  const decoder = new TextDecoder;
@@ -21284,8 +21375,24 @@ function createAnthropicPassthroughStream(c, response, opts) {
21284
21375
  const encoder = new TextEncoder;
21285
21376
  const decoder = new TextDecoder;
21286
21377
  let isClosed = false;
21378
+ let lastActivity = Date.now();
21379
+ let pingInterval = null;
21287
21380
  return c.body(new ReadableStream({
21288
21381
  async start(controller) {
21382
+ const sendPing = () => {
21383
+ if (!isClosed) {
21384
+ controller.enqueue(encoder.encode(`event: ping
21385
+ data: {"type":"ping"}
21386
+
21387
+ `));
21388
+ }
21389
+ };
21390
+ sendPing();
21391
+ pingInterval = setInterval(() => {
21392
+ if (!isClosed && Date.now() - lastActivity > 1000) {
21393
+ sendPing();
21394
+ }
21395
+ }, 1000);
21289
21396
  try {
21290
21397
  const reader = response.body.getReader();
21291
21398
  let buffer = "";
@@ -21300,6 +21407,7 @@ function createAnthropicPassthroughStream(c, response, opts) {
21300
21407
  if (done)
21301
21408
  break;
21302
21409
  buffer += decoder.decode(value, { stream: true });
21410
+ lastActivity = Date.now();
21303
21411
  const lines = buffer.split(`
21304
21412
  `);
21305
21413
  buffer = lines.pop() || "";
@@ -21342,19 +21450,31 @@ function createAnthropicPassthroughStream(c, response, opts) {
21342
21450
  opts.onTokenUpdate(inputTokens, outputTokens);
21343
21451
  }
21344
21452
  if (!isClosed) {
21345
- controller.close();
21346
21453
  isClosed = true;
21454
+ if (pingInterval) {
21455
+ clearInterval(pingInterval);
21456
+ pingInterval = null;
21457
+ }
21458
+ controller.close();
21347
21459
  }
21348
21460
  } catch (e) {
21349
21461
  log(`[AnthropicSSE] Stream error: ${e}`);
21350
21462
  if (!isClosed) {
21351
- controller.close();
21352
21463
  isClosed = true;
21464
+ if (pingInterval) {
21465
+ clearInterval(pingInterval);
21466
+ pingInterval = null;
21467
+ }
21468
+ controller.close();
21353
21469
  }
21354
21470
  }
21355
21471
  },
21356
21472
  cancel() {
21357
21473
  isClosed = true;
21474
+ if (pingInterval) {
21475
+ clearInterval(pingInterval);
21476
+ pingInterval = null;
21477
+ }
21358
21478
  }
21359
21479
  }), {
21360
21480
  headers: {
@@ -22237,7 +22357,7 @@ var init_profile_config = __esm(() => {
22237
22357
  });
22238
22358
 
22239
22359
  // src/version.ts
22240
- var VERSION = "6.10.1";
22360
+ var VERSION = "6.11.1";
22241
22361
 
22242
22362
  // src/telemetry.ts
22243
22363
  var exports_telemetry = {};
@@ -24218,7 +24338,7 @@ class ComposedHandler {
24218
24338
  invocation_mode: this.options.invocationMode ?? "auto-route"
24219
24339
  });
24220
24340
  } catch {}
24221
- return c.json({ error: { type: "connection_error", message: msg } }, 503);
24341
+ return c.json(wrapAnthropicError(503, msg, "connection_error"), 503);
24222
24342
  }
24223
24343
  throw error2;
24224
24344
  }
@@ -24280,7 +24400,7 @@ class ComposedHandler {
24280
24400
  invocation_mode: this.options.invocationMode ?? "auto-route"
24281
24401
  });
24282
24402
  } catch {}
24283
- return c.json({ error: errorText }, retryResp.status);
24403
+ return c.json(wrapAnthropicError(retryResp.status, errorText), retryResp.status);
24284
24404
  }
24285
24405
  } catch (err) {
24286
24406
  log(`[${this.provider.displayName}] Auth refresh failed: ${err.message}`);
@@ -24317,7 +24437,7 @@ class ComposedHandler {
24317
24437
  invocation_mode: this.options.invocationMode ?? "auto-route"
24318
24438
  });
24319
24439
  } catch {}
24320
- return c.json({ error: { type: "authentication_error", message: err.message } }, 401);
24440
+ return c.json(wrapAnthropicError(401, err.message, "authentication_error"), 401);
24321
24441
  }
24322
24442
  } else {
24323
24443
  const errorText = await response.text();
@@ -24370,7 +24490,7 @@ class ComposedHandler {
24370
24490
  } catch {
24371
24491
  errorBody = { error: { type: "api_error", message: errorText } };
24372
24492
  }
24373
- return c.json(errorBody, response.status);
24493
+ return c.json(ensureAnthropicErrorFormat(response.status, errorBody), response.status);
24374
24494
  }
24375
24495
  }
24376
24496
  if (droppedParams.length > 0) {
@@ -26259,16 +26379,6 @@ var init_gemini_apikey = __esm(() => {
26259
26379
  });
26260
26380
 
26261
26381
  // src/auth/gemini-oauth.ts
26262
- var exports_gemini_oauth = {};
26263
- __export(exports_gemini_oauth, {
26264
- setupGeminiUser: () => setupGeminiUser,
26265
- retrieveUserQuota: () => retrieveUserQuota,
26266
- getValidAccessToken: () => getValidAccessToken,
26267
- getGeminiTierFullName: () => getGeminiTierFullName,
26268
- getGeminiTierDisplayName: () => getGeminiTierDisplayName,
26269
- getGeminiOAuth: () => getGeminiOAuth,
26270
- GeminiOAuth: () => GeminiOAuth
26271
- });
26272
26382
  import { createServer } from "http";
26273
26383
  import { randomBytes as randomBytes2, createHash as createHash4 } from "crypto";
26274
26384
  import { readFileSync as readFileSync10, existsSync as existsSync13, unlinkSync as unlinkSync3, openSync, writeSync, closeSync } from "fs";
@@ -26593,9 +26703,6 @@ Please open this URL in your browser to authenticate:`);
26593
26703
  }
26594
26704
  }
26595
26705
  }
26596
- function getGeminiOAuth() {
26597
- return GeminiOAuth.getInstance();
26598
- }
26599
26706
  async function getValidAccessToken() {
26600
26707
  const oauth = GeminiOAuth.getInstance();
26601
26708
  return oauth.getAccessToken();
@@ -26667,7 +26774,7 @@ async function setupGeminiUser(accessToken) {
26667
26774
  async function callLoadCodeAssist(accessToken, projectId) {
26668
26775
  const metadata = {
26669
26776
  pluginType: "GEMINI",
26670
- ideType: "IDE_UNSPECIFIED",
26777
+ ideType: "GEMINI_CLI",
26671
26778
  platform: "PLATFORM_UNSPECIFIED",
26672
26779
  duetProject: projectId
26673
26780
  };
@@ -26687,7 +26794,7 @@ async function callLoadCodeAssist(accessToken, projectId) {
26687
26794
  async function callOnboardUser(accessToken, tierId, projectId) {
26688
26795
  const metadata = {
26689
26796
  pluginType: "GEMINI",
26690
- ideType: "IDE_UNSPECIFIED",
26797
+ ideType: "GEMINI_CLI",
26691
26798
  platform: "PLATFORM_UNSPECIFIED",
26692
26799
  duetProject: projectId
26693
26800
  };
@@ -26863,12 +26970,11 @@ class GeminiCodeAssistProviderTransport {
26863
26970
  };
26864
26971
  }
26865
26972
  async refreshAuth() {
26866
- const { getValidAccessToken: getValidAccessToken2, setupGeminiUser: setupGeminiUser2, getGeminiTierDisplayName: getGeminiTierDisplayName2 } = await Promise.resolve().then(() => (init_gemini_oauth(), exports_gemini_oauth));
26867
- this.accessToken = await getValidAccessToken2();
26868
- const { projectId, tierId } = await setupGeminiUser2(this.accessToken);
26973
+ this.accessToken = await getValidAccessToken();
26974
+ const { projectId, tierId } = await setupGeminiUser(this.accessToken);
26869
26975
  this.projectId = projectId;
26870
26976
  this.tierId = tierId;
26871
- this._displayName = getGeminiTierDisplayName2();
26977
+ this._displayName = getGeminiTierDisplayName();
26872
26978
  log(`[GeminiCodeAssist] Auth refreshed, project: ${this.projectId}, tier: ${this._displayName}`);
26873
26979
  }
26874
26980
  transformPayload(payload) {
@@ -26969,8 +27075,7 @@ class GeminiCodeAssistProviderTransport {
26969
27075
  if (!this.accessToken || !this.projectId)
26970
27076
  return;
26971
27077
  try {
26972
- const { retrieveUserQuota: retrieveUserQuota2 } = await Promise.resolve().then(() => (init_gemini_oauth(), exports_gemini_oauth));
26973
- const data = await retrieveUserQuota2(this.accessToken, this.projectId);
27078
+ const data = await retrieveUserQuota(this.accessToken, this.projectId);
26974
27079
  if (!data?.buckets?.length)
26975
27080
  return;
26976
27081
  const lines = [];
@@ -26995,8 +27100,7 @@ ${lines.join(`
26995
27100
  if (!this.accessToken || !this.projectId)
26996
27101
  return;
26997
27102
  try {
26998
- const { retrieveUserQuota: retrieveUserQuota2 } = await Promise.resolve().then(() => (init_gemini_oauth(), exports_gemini_oauth));
26999
- const data = await retrieveUserQuota2(this.accessToken, this.projectId);
27103
+ const data = await retrieveUserQuota(this.accessToken, this.projectId);
27000
27104
  if (!data?.buckets?.length)
27001
27105
  return;
27002
27106
  const bucket = data.buckets.find((b) => b.modelId === modelName);
@@ -27010,6 +27114,7 @@ var CODE_ASSIST_BASE = "https://cloudcode-pa.googleapis.com", CODE_ASSIST_ENDPOI
27010
27114
  var init_gemini_codeassist = __esm(() => {
27011
27115
  init_gemini_queue();
27012
27116
  init_logger();
27117
+ init_gemini_oauth();
27013
27118
  CODE_ASSIST_ENDPOINT = `${CODE_ASSIST_BASE}/v1internal:streamGenerateContent?alt=sse`;
27014
27119
  CODE_ASSIST_FALLBACK_CHAIN = [
27015
27120
  "gemini-3.1-pro-preview",
@@ -27115,12 +27220,6 @@ var init_openai = __esm(() => {
27115
27220
  });
27116
27221
 
27117
27222
  // src/auth/codex-oauth.ts
27118
- var exports_codex_oauth = {};
27119
- __export(exports_codex_oauth, {
27120
- getValidCodexAccessToken: () => getValidCodexAccessToken,
27121
- getCodexOAuth: () => getCodexOAuth,
27122
- CodexOAuth: () => CodexOAuth
27123
- });
27124
27223
  import { exec as exec2 } from "child_process";
27125
27224
  import { createHash as createHash5, randomBytes as randomBytes3 } from "crypto";
27126
27225
  import { closeSync as closeSync2, existsSync as existsSync14, openSync as openSync2, readFileSync as readFileSync11, unlinkSync as unlinkSync4, writeSync as writeSync2 } from "fs";
@@ -27470,13 +27569,6 @@ Please open this URL in your browser to authenticate:`);
27470
27569
  }
27471
27570
  }
27472
27571
  }
27473
- function getCodexOAuth() {
27474
- return CodexOAuth.getInstance();
27475
- }
27476
- async function getValidCodexAccessToken() {
27477
- const oauth = CodexOAuth.getInstance();
27478
- return oauth.getAccessToken();
27479
- }
27480
27572
  var execAsync2, OAUTH_CONFIG2;
27481
27573
  var init_codex_oauth = __esm(() => {
27482
27574
  init_logger();
@@ -27511,6 +27603,7 @@ var OpenAICodexTransport;
27511
27603
  var init_openai_codex = __esm(() => {
27512
27604
  init_logger();
27513
27605
  init_openai();
27606
+ init_codex_oauth();
27514
27607
  OpenAICodexTransport = class OpenAICodexTransport extends OpenAIProviderTransport {
27515
27608
  async getHeaders() {
27516
27609
  const oauthHeaders = await this.tryOAuthHeaders();
@@ -27528,8 +27621,7 @@ var init_openai_codex = __esm(() => {
27528
27621
  return null;
27529
27622
  const buffer = 5 * 60 * 1000;
27530
27623
  if (creds.expires_at && Date.now() > creds.expires_at - buffer) {
27531
- const { CodexOAuth: CodexOAuth2 } = await Promise.resolve().then(() => (init_codex_oauth(), exports_codex_oauth));
27532
- const oauth = CodexOAuth2.getInstance();
27624
+ const oauth = CodexOAuth.getInstance();
27533
27625
  const token = await oauth.getAccessToken();
27534
27626
  log("[OpenAI Codex] Using refreshed OAuth token");
27535
27627
  return buildOAuthHeaders(token, oauth.getAccountId());
@@ -27545,13 +27637,6 @@ var init_openai_codex = __esm(() => {
27545
27637
  });
27546
27638
 
27547
27639
  // src/auth/kimi-oauth.ts
27548
- var exports_kimi_oauth = {};
27549
- __export(exports_kimi_oauth, {
27550
- hasKimiOAuthCredentials: () => hasKimiOAuthCredentials,
27551
- getValidKimiAccessToken: () => getValidKimiAccessToken,
27552
- getKimiOAuth: () => getKimiOAuth,
27553
- KimiOAuth: () => KimiOAuth
27554
- });
27555
27640
  import { randomBytes as randomBytes4 } from "crypto";
27556
27641
  import { readFileSync as readFileSync13, existsSync as existsSync16, unlinkSync as unlinkSync5, openSync as openSync3, writeSync as writeSync3, closeSync as closeSync3 } from "fs";
27557
27642
  import { homedir as homedir17, hostname, platform, release } from "os";
@@ -27883,26 +27968,6 @@ Waiting for authorization...`);
27883
27968
  log(`[KimiOAuth] Credentials saved to ${credPath}`);
27884
27969
  }
27885
27970
  }
27886
- function getKimiOAuth() {
27887
- return KimiOAuth.getInstance();
27888
- }
27889
- async function getValidKimiAccessToken() {
27890
- const oauth = KimiOAuth.getInstance();
27891
- return oauth.getAccessToken();
27892
- }
27893
- function hasKimiOAuthCredentials() {
27894
- try {
27895
- const credPath = join18(homedir17(), ".claudish", "kimi-oauth.json");
27896
- if (!existsSync16(credPath))
27897
- return false;
27898
- const data = JSON.parse(readFileSync13(credPath, "utf-8"));
27899
- const now = Date.now();
27900
- const bufferMs = 5 * 60 * 1000;
27901
- return !!(data.access_token && data.refresh_token && data.expires_at && data.expires_at > now + bufferMs);
27902
- } catch {
27903
- return false;
27904
- }
27905
- }
27906
27971
  var execAsync3, OAUTH_CONFIG3;
27907
27972
  var init_kimi_oauth = __esm(() => {
27908
27973
  init_logger();
@@ -27916,6 +27981,10 @@ var init_kimi_oauth = __esm(() => {
27916
27981
  });
27917
27982
 
27918
27983
  // src/providers/transport/anthropic-compat.ts
27984
+ import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
27985
+ import { join as join19 } from "path";
27986
+ import { homedir as homedir18 } from "os";
27987
+
27919
27988
  class AnthropicProviderTransport {
27920
27989
  name;
27921
27990
  displayName;
@@ -27945,15 +28014,11 @@ class AnthropicProviderTransport {
27945
28014
  }
27946
28015
  if (this.provider.name === "kimi-coding" && !this.apiKey) {
27947
28016
  try {
27948
- const { existsSync: existsSync17, readFileSync: readFileSync14 } = await import("fs");
27949
- const { join: join19 } = await import("path");
27950
- const { homedir: homedir18 } = await import("os");
27951
28017
  const credPath = join19(homedir18(), ".claudish", "kimi-oauth.json");
27952
28018
  if (existsSync17(credPath)) {
27953
28019
  const data = JSON.parse(readFileSync14(credPath, "utf-8"));
27954
28020
  if (data.access_token && data.refresh_token) {
27955
- const { KimiOAuth: KimiOAuth2 } = await Promise.resolve().then(() => (init_kimi_oauth(), exports_kimi_oauth));
27956
- const oauth = KimiOAuth2.getInstance();
28021
+ const oauth = KimiOAuth.getInstance();
27957
28022
  const accessToken = await oauth.getAccessToken();
27958
28023
  delete headers["x-api-key"];
27959
28024
  headers["Authorization"] = `Bearer ${accessToken}`;
@@ -27981,6 +28046,7 @@ class AnthropicProviderTransport {
27981
28046
  }
27982
28047
  var init_anthropic_compat = __esm(() => {
27983
28048
  init_logger();
28049
+ init_kimi_oauth();
27984
28050
  });
27985
28051
 
27986
28052
  // src/adapters/anthropic-api-format.ts
@@ -28071,7 +28137,7 @@ var init_anthropic_api_format = __esm(() => {
28071
28137
  return 131072;
28072
28138
  if (this.providerName === "minimax" || this.providerName === "minimax-coding")
28073
28139
  return 204800;
28074
- return 128000;
28140
+ return 0;
28075
28141
  }
28076
28142
  supportsVision() {
28077
28143
  return true;
@@ -28251,13 +28317,14 @@ var init_litellm2 = __esm(() => {
28251
28317
  });
28252
28318
 
28253
28319
  // src/adapters/litellm-api-format.ts
28254
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "fs";
28320
+ import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
28255
28321
  import { createHash as createHash6 } from "crypto";
28256
- import { homedir as homedir18 } from "os";
28257
- import { join as join19 } from "path";
28322
+ import { homedir as homedir19 } from "os";
28323
+ import { join as join20 } from "path";
28258
28324
  var INLINE_IMAGE_MODEL_PATTERNS, LiteLLMAPIFormat;
28259
28325
  var init_litellm_api_format = __esm(() => {
28260
28326
  init_base_api_format();
28327
+ init_model_catalog();
28261
28328
  init_logger();
28262
28329
  INLINE_IMAGE_MODEL_PATTERNS = ["minimax"];
28263
28330
  LiteLLMAPIFormat = class LiteLLMAPIFormat extends DefaultAPIFormat {
@@ -28345,15 +28412,15 @@ var init_litellm_api_format = __esm(() => {
28345
28412
  return payload;
28346
28413
  }
28347
28414
  getContextWindow() {
28348
- return 200000;
28415
+ return lookupModel(this.modelId)?.contextWindow ?? 0;
28349
28416
  }
28350
28417
  checkVisionSupport() {
28351
28418
  try {
28352
28419
  const hash = createHash6("sha256").update(this.baseUrl).digest("hex").substring(0, 16);
28353
- const cachePath = join19(homedir18(), ".claudish", `litellm-models-${hash}.json`);
28354
- if (!existsSync17(cachePath))
28420
+ const cachePath = join20(homedir19(), ".claudish", `litellm-models-${hash}.json`);
28421
+ if (!existsSync18(cachePath))
28355
28422
  return true;
28356
- const cacheData = JSON.parse(readFileSync14(cachePath, "utf-8"));
28423
+ const cacheData = JSON.parse(readFileSync15(cachePath, "utf-8"));
28357
28424
  const model = cacheData.models?.find((m) => m.name === this.modelId);
28358
28425
  if (model && model.supportsVision === false) {
28359
28426
  log(`[LiteLLMAPIFormat] Model ${this.modelId} does not support vision`);
@@ -28370,9 +28437,9 @@ var init_litellm_api_format = __esm(() => {
28370
28437
  // src/auth/vertex-auth.ts
28371
28438
  import { exec as exec4 } from "child_process";
28372
28439
  import { promisify as promisify4 } from "util";
28373
- import { existsSync as existsSync18 } from "fs";
28374
- import { homedir as homedir19 } from "os";
28375
- import { join as join20 } from "path";
28440
+ import { existsSync as existsSync19 } from "fs";
28441
+ import { homedir as homedir20 } from "os";
28442
+ import { join as join21 } from "path";
28376
28443
 
28377
28444
  class VertexAuthManager {
28378
28445
  cachedToken = null;
@@ -28426,8 +28493,8 @@ class VertexAuthManager {
28426
28493
  }
28427
28494
  async tryADC() {
28428
28495
  try {
28429
- const adcPath = join20(homedir19(), ".config/gcloud/application_default_credentials.json");
28430
- if (!existsSync18(adcPath)) {
28496
+ const adcPath = join21(homedir20(), ".config/gcloud/application_default_credentials.json");
28497
+ if (!existsSync19(adcPath)) {
28431
28498
  log("[VertexAuth] ADC credentials file not found");
28432
28499
  return null;
28433
28500
  }
@@ -28451,7 +28518,7 @@ class VertexAuthManager {
28451
28518
  if (!credPath) {
28452
28519
  return null;
28453
28520
  }
28454
- if (!existsSync18(credPath)) {
28521
+ if (!existsSync19(credPath)) {
28455
28522
  throw new Error(`Service account file not found: ${credPath}
28456
28523
 
28457
28524
  Check GOOGLE_APPLICATION_CREDENTIALS path.`);
@@ -28490,8 +28557,8 @@ function validateVertexOAuthConfig() {
28490
28557
  ` + ` export VERTEX_PROJECT='your-gcp-project-id'
28491
28558
  ` + " export VERTEX_LOCATION='us-central1' # optional";
28492
28559
  }
28493
- const adcPath = join20(homedir19(), ".config/gcloud/application_default_credentials.json");
28494
- const hasADC = existsSync18(adcPath);
28560
+ const adcPath = join21(homedir20(), ".config/gcloud/application_default_credentials.json");
28561
+ const hasADC = existsSync19(adcPath);
28495
28562
  const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
28496
28563
  if (!hasADC && !hasServiceAccount) {
28497
28564
  return `No Vertex AI credentials found.
@@ -28597,9 +28664,9 @@ var init_vertex_oauth = __esm(() => {
28597
28664
  });
28598
28665
 
28599
28666
  // src/providers/api-key-provenance.ts
28600
- import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
28601
- import { join as join21, resolve as resolve2 } from "path";
28602
- import { homedir as homedir20 } from "os";
28667
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "fs";
28668
+ import { join as join22, resolve as resolve2 } from "path";
28669
+ import { homedir as homedir21 } from "os";
28603
28670
  function maskKey(key) {
28604
28671
  if (!key)
28605
28672
  return null;
@@ -28684,9 +28751,9 @@ function formatProvenanceProbe(p, indent = " ") {
28684
28751
  function readDotenvKey(envVars) {
28685
28752
  try {
28686
28753
  const dotenvPath = resolve2(".env");
28687
- if (!existsSync19(dotenvPath))
28754
+ if (!existsSync20(dotenvPath))
28688
28755
  return null;
28689
- const parsed = import_dotenv.parse(readFileSync16(dotenvPath, "utf-8"));
28756
+ const parsed = import_dotenv.parse(readFileSync17(dotenvPath, "utf-8"));
28690
28757
  for (const v of envVars) {
28691
28758
  if (parsed[v])
28692
28759
  return parsed[v];
@@ -28698,10 +28765,10 @@ function readDotenvKey(envVars) {
28698
28765
  }
28699
28766
  function readConfigKey(envVar) {
28700
28767
  try {
28701
- const configPath = join21(homedir20(), ".claudish", "config.json");
28702
- if (!existsSync19(configPath))
28768
+ const configPath = join22(homedir21(), ".claudish", "config.json");
28769
+ if (!existsSync20(configPath))
28703
28770
  return null;
28704
- const cfg = JSON.parse(readFileSync16(configPath, "utf-8"));
28771
+ const cfg = JSON.parse(readFileSync17(configPath, "utf-8"));
28705
28772
  return cfg.apiKeys?.[envVar] || null;
28706
28773
  } catch {
28707
28774
  return null;
@@ -29224,7 +29291,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29224
29291
  return c.json({ input_tokens: Math.ceil(txt.length / 4) });
29225
29292
  }
29226
29293
  } catch (e) {
29227
- return c.json({ error: String(e) }, 500);
29294
+ return c.json(wrapAnthropicError(500, String(e)), 500);
29228
29295
  }
29229
29296
  });
29230
29297
  app.post("/v1/messages", async (c) => {
@@ -29234,7 +29301,7 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
29234
29301
  return handler.handle(c, body);
29235
29302
  } catch (e) {
29236
29303
  log(`[Proxy] Error: ${e}`);
29237
- return c.json({ error: { type: "server_error", message: String(e) } }, 500);
29304
+ return c.json(wrapAnthropicError(500, String(e)), 500);
29238
29305
  }
29239
29306
  });
29240
29307
  const server = serve({ fetch: app.fetch, port, hostname: "127.0.0.1" });
@@ -29319,14 +29386,22 @@ var exports_mcp_server = {};
29319
29386
  __export(exports_mcp_server, {
29320
29387
  startMcpServer: () => startMcpServer
29321
29388
  });
29322
- import { readFileSync as readFileSync17, existsSync as existsSync20, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readdirSync as readdirSync3 } from "fs";
29323
- import { join as join22, dirname as dirname2 } from "path";
29324
- import { homedir as homedir21 } from "os";
29389
+ import { readFileSync as readFileSync18, existsSync as existsSync21, writeFileSync as writeFileSync10, mkdirSync as mkdirSync10, readdirSync as readdirSync3 } from "fs";
29390
+ import { join as join23, dirname as dirname2 } from "path";
29391
+ import { homedir as homedir22 } from "os";
29325
29392
  import { fileURLToPath as fileURLToPath2 } from "url";
29326
29393
  function loadRecommendedModels() {
29327
- if (existsSync20(RECOMMENDED_MODELS_PATH)) {
29394
+ const cachedPath = join23(CLAUDISH_CACHE_DIR, "recommended-models-cache.json");
29395
+ if (existsSync21(cachedPath)) {
29328
29396
  try {
29329
- const data = JSON.parse(readFileSync17(RECOMMENDED_MODELS_PATH, "utf-8"));
29397
+ const data = JSON.parse(readFileSync18(cachedPath, "utf-8"));
29398
+ if (data.models && data.models.length > 0)
29399
+ return data.models;
29400
+ } catch {}
29401
+ }
29402
+ if (existsSync21(RECOMMENDED_MODELS_PATH)) {
29403
+ try {
29404
+ const data = JSON.parse(readFileSync18(RECOMMENDED_MODELS_PATH, "utf-8"));
29330
29405
  return data.models || [];
29331
29406
  } catch {
29332
29407
  return [];
@@ -29334,10 +29409,28 @@ function loadRecommendedModels() {
29334
29409
  }
29335
29410
  return [];
29336
29411
  }
29412
+ function parsePriceAvg(s) {
29413
+ if (!s || s === "N/A")
29414
+ return Infinity;
29415
+ if (s === "FREE")
29416
+ return 0;
29417
+ const m = s.match(/\$([\d.]+)/);
29418
+ return m ? parseFloat(m[1]) : Infinity;
29419
+ }
29420
+ function parseCtx(s) {
29421
+ if (!s || s === "N/A")
29422
+ return 0;
29423
+ const upper = s.toUpperCase();
29424
+ if (upper.includes("M"))
29425
+ return parseFloat(upper) * 1e6;
29426
+ if (upper.includes("K"))
29427
+ return parseFloat(upper) * 1000;
29428
+ return parseInt(s) || 0;
29429
+ }
29337
29430
  async function loadAllModels(forceRefresh = false) {
29338
- if (!forceRefresh && existsSync20(ALL_MODELS_CACHE_PATH)) {
29431
+ if (!forceRefresh && existsSync21(ALL_MODELS_CACHE_PATH)) {
29339
29432
  try {
29340
- const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH, "utf-8"));
29433
+ const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH, "utf-8"));
29341
29434
  const lastUpdated = new Date(cacheData.lastUpdated);
29342
29435
  const ageInDays = (Date.now() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
29343
29436
  if (ageInDays <= CACHE_MAX_AGE_DAYS) {
@@ -29355,8 +29448,8 @@ async function loadAllModels(forceRefresh = false) {
29355
29448
  writeFileSync10(ALL_MODELS_CACHE_PATH, JSON.stringify({ lastUpdated: new Date().toISOString(), models }), "utf-8");
29356
29449
  return models;
29357
29450
  } catch {
29358
- if (existsSync20(ALL_MODELS_CACHE_PATH)) {
29359
- const cacheData = JSON.parse(readFileSync17(ALL_MODELS_CACHE_PATH, "utf-8"));
29451
+ if (existsSync21(ALL_MODELS_CACHE_PATH)) {
29452
+ const cacheData = JSON.parse(readFileSync18(ALL_MODELS_CACHE_PATH, "utf-8"));
29360
29453
  return cacheData.models || [];
29361
29454
  }
29362
29455
  return [];
@@ -29589,12 +29682,26 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
29589
29682
  output += `
29590
29683
  ## Quick Picks
29591
29684
  `;
29592
- output += "- **Budget**: `minimax-m2.5` ($0.75/1M)\n";
29593
- output += "- **Large context**: `gemini-3.1-pro-preview` (1M tokens)\n";
29594
- output += "- **Most advanced**: `gpt-5.4` ($8.75/1M)\n";
29595
- output += "- **Vision + coding**: `kimi-k2.5` ($1.32/1M)\n";
29596
- output += "- **Agentic**: `glm-5` ($1.68/1M)\n";
29597
- output += "- **Multimodal**: `qwen3.5-plus-02-15` ($1.40/1M)\n";
29685
+ const cheapest = [...models].sort((a, b) => parsePriceAvg(a.pricing?.average) - parsePriceAvg(b.pricing?.average))[0];
29686
+ const bigCtx = [...models].sort((a, b) => parseCtx(b.context) - parseCtx(a.context))[0];
29687
+ const priciest = [...models].sort((a, b) => parsePriceAvg(b.pricing?.average) - parsePriceAvg(a.pricing?.average))[0];
29688
+ const vision = models.find((m) => m.supportsVision);
29689
+ const reasoning = models.find((m) => m.supportsReasoning && m.id !== priciest?.id);
29690
+ if (cheapest)
29691
+ output += `- **Budget**: \`${cheapest.id}\` (${cheapest.pricing?.average || "N/A"})
29692
+ `;
29693
+ if (bigCtx && bigCtx.id !== cheapest?.id)
29694
+ output += `- **Large context**: \`${bigCtx.id}\` (${bigCtx.context || "N/A"} tokens)
29695
+ `;
29696
+ if (priciest && priciest.id !== cheapest?.id)
29697
+ output += `- **Most advanced**: \`${priciest.id}\` (${priciest.pricing?.average || "N/A"})
29698
+ `;
29699
+ if (vision && vision.id !== cheapest?.id && vision.id !== priciest?.id)
29700
+ output += `- **Vision + coding**: \`${vision.id}\` (${vision.pricing?.average || "N/A"})
29701
+ `;
29702
+ if (reasoning && reasoning.id !== cheapest?.id)
29703
+ output += `- **Agentic**: \`${reasoning.id}\` (${reasoning.pricing?.average || "N/A"})
29704
+ `;
29598
29705
  return { content: [{ type: "text", text: output }] };
29599
29706
  }
29600
29707
  });
@@ -29856,7 +29963,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
29856
29963
  let stderrFull = stderr_snippet || "";
29857
29964
  if (error_log_path) {
29858
29965
  try {
29859
- stderrFull = readFileSync17(error_log_path, "utf-8");
29966
+ stderrFull = readFileSync18(error_log_path, "utf-8");
29860
29967
  } catch {}
29861
29968
  }
29862
29969
  let sessionData = {};
@@ -29864,16 +29971,16 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
29864
29971
  const sp = session_path;
29865
29972
  for (const file of ["status.json", "manifest.json", "input.md"]) {
29866
29973
  try {
29867
- sessionData[file] = readFileSync17(join22(sp, file), "utf-8");
29974
+ sessionData[file] = readFileSync18(join23(sp, file), "utf-8");
29868
29975
  } catch {}
29869
29976
  }
29870
29977
  try {
29871
- const errorDir = join22(sp, "errors");
29872
- if (existsSync20(errorDir)) {
29978
+ const errorDir = join23(sp, "errors");
29979
+ if (existsSync21(errorDir)) {
29873
29980
  for (const f of readdirSync3(errorDir)) {
29874
29981
  if (f.endsWith(".log")) {
29875
29982
  try {
29876
- sessionData[`errors/${f}`] = readFileSync17(join22(errorDir, f), "utf-8");
29983
+ sessionData[`errors/${f}`] = readFileSync18(join23(errorDir, f), "utf-8");
29877
29984
  } catch {}
29878
29985
  }
29879
29986
  }
@@ -29883,7 +29990,7 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
29883
29990
  for (const f of readdirSync3(sp)) {
29884
29991
  if (f.startsWith("response-") && f.endsWith(".md")) {
29885
29992
  try {
29886
- const content = readFileSync17(join22(sp, f), "utf-8");
29993
+ const content = readFileSync18(join23(sp, f), "utf-8");
29887
29994
  sessionData[f] = content.slice(0, 200) + (content.length > 200 ? "... (truncated)" : "");
29888
29995
  } catch {}
29889
29996
  }
@@ -29892,9 +29999,9 @@ Use with: run_prompt(model="${results[0].model.id}", prompt="your prompt")`;
29892
29999
  }
29893
30000
  let version2 = "unknown";
29894
30001
  try {
29895
- const pkgPath = join22(__dirname3, "../package.json");
29896
- if (existsSync20(pkgPath)) {
29897
- version2 = JSON.parse(readFileSync17(pkgPath, "utf-8")).version;
30002
+ const pkgPath = join23(__dirname3, "../package.json");
30003
+ if (existsSync21(pkgPath)) {
30004
+ version2 = JSON.parse(readFileSync18(pkgPath, "utf-8")).version;
29898
30005
  }
29899
30006
  } catch {}
29900
30007
  const report = {
@@ -30255,9 +30362,9 @@ var init_mcp_server = __esm(() => {
30255
30362
  import_dotenv2.config();
30256
30363
  __filename3 = fileURLToPath2(import.meta.url);
30257
30364
  __dirname3 = dirname2(__filename3);
30258
- RECOMMENDED_MODELS_PATH = join22(__dirname3, "../recommended-models.json");
30259
- CLAUDISH_CACHE_DIR = join22(homedir21(), ".claudish");
30260
- ALL_MODELS_CACHE_PATH = join22(CLAUDISH_CACHE_DIR, "all-models.json");
30365
+ RECOMMENDED_MODELS_PATH = join23(__dirname3, "../recommended-models.json");
30366
+ CLAUDISH_CACHE_DIR = join23(homedir22(), ".claudish");
30367
+ ALL_MODELS_CACHE_PATH = join23(CLAUDISH_CACHE_DIR, "all-models.json");
30261
30368
  });
30262
30369
 
30263
30370
  // ../../node_modules/.bun/@inquirer+core@11.0.1+04f2146be16c61ef/node_modules/@inquirer/core/dist/lib/key.js
@@ -41531,7 +41638,7 @@ var init_RemoveFileError = __esm(() => {
41531
41638
 
41532
41639
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.1+04f2146be16c61ef/node_modules/@inquirer/external-editor/dist/index.js
41533
41640
  import { spawn as spawn3, spawnSync } from "child_process";
41534
- import { readFileSync as readFileSync18, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
41641
+ import { readFileSync as readFileSync19, unlinkSync as unlinkSync6, writeFileSync as writeFileSync11 } from "fs";
41535
41642
  import path from "path";
41536
41643
  import os from "os";
41537
41644
  import { randomUUID as randomUUID3 } from "crypto";
@@ -41647,7 +41754,7 @@ class ExternalEditor {
41647
41754
  }
41648
41755
  readTemporaryFile() {
41649
41756
  try {
41650
- const tempFileBuffer = readFileSync18(this.tempFile);
41757
+ const tempFileBuffer = readFileSync19(this.tempFile);
41651
41758
  if (tempFileBuffer.length === 0) {
41652
41759
  this.text = "";
41653
41760
  } else {
@@ -42658,8 +42765,7 @@ async function loginCommand(providerArg) {
42658
42765
  process.exit(1);
42659
42766
  }
42660
42767
  try {
42661
- const mod = await import(provider.module);
42662
- const oauth = mod[provider.className].getInstance();
42768
+ const oauth = provider.getInstance();
42663
42769
  await oauth.login();
42664
42770
  console.log(`
42665
42771
  \u2705 ${provider.displayName} OAuth login successful!`);
@@ -42679,8 +42785,7 @@ async function logoutCommand(providerArg) {
42679
42785
  process.exit(1);
42680
42786
  }
42681
42787
  try {
42682
- const mod = await import(provider.module);
42683
- const oauth = mod[provider.className].getInstance();
42788
+ const oauth = provider.getInstance();
42684
42789
  await oauth.logout();
42685
42790
  console.log(`\u2705 ${provider.displayName} OAuth credentials cleared.`);
42686
42791
  process.exit(0);
@@ -42693,29 +42798,29 @@ var AUTH_PROVIDERS;
42693
42798
  var init_auth_commands = __esm(() => {
42694
42799
  init_dist17();
42695
42800
  init_oauth_registry();
42801
+ init_gemini_oauth();
42802
+ init_kimi_oauth();
42803
+ init_codex_oauth();
42696
42804
  AUTH_PROVIDERS = [
42697
42805
  {
42698
42806
  name: "gemini",
42699
42807
  displayName: "Gemini Code Assist",
42700
42808
  prefix: "go@",
42701
- module: "./gemini-oauth.js",
42702
- className: "GeminiOAuth",
42809
+ getInstance: () => GeminiOAuth.getInstance(),
42703
42810
  registryKeys: ["google", "gemini-codeassist"]
42704
42811
  },
42705
42812
  {
42706
42813
  name: "kimi",
42707
42814
  displayName: "Kimi / Moonshot AI",
42708
42815
  prefix: "kc@, kimi@",
42709
- module: "./kimi-oauth.js",
42710
- className: "KimiOAuth",
42816
+ getInstance: () => KimiOAuth.getInstance(),
42711
42817
  registryKeys: ["kimi", "kimi-coding"]
42712
42818
  },
42713
42819
  {
42714
42820
  name: "codex",
42715
42821
  displayName: "OpenAI Codex (ChatGPT Plus/Pro)",
42716
42822
  prefix: "cx@",
42717
- module: "./codex-oauth.js",
42718
- className: "CodexOAuth",
42823
+ getInstance: () => CodexOAuth.getInstance(),
42719
42824
  registryKeys: ["openai-codex"]
42720
42825
  }
42721
42826
  ];
@@ -42756,11 +42861,10 @@ async function geminiQuotaHandler() {
42756
42861
  process.exit(1);
42757
42862
  }
42758
42863
  try {
42759
- const { getValidAccessToken: getValidAccessToken2, setupGeminiUser: setupGeminiUser2, retrieveUserQuota: retrieveUserQuota2, getGeminiTierFullName: getGeminiTierFullName2 } = await Promise.resolve().then(() => (init_gemini_oauth(), exports_gemini_oauth));
42760
- const accessToken = await getValidAccessToken2();
42761
- const { projectId } = await setupGeminiUser2(accessToken);
42762
- const tierName = getGeminiTierFullName2();
42763
- const quota = await retrieveUserQuota2(accessToken, projectId);
42864
+ const accessToken = await getValidAccessToken();
42865
+ const { projectId } = await setupGeminiUser(accessToken);
42866
+ const tierName = getGeminiTierFullName();
42867
+ const quota = await retrieveUserQuota(accessToken, projectId);
42764
42868
  if (!quota?.buckets?.length) {
42765
42869
  console.log(`
42766
42870
  ${D}No quota data available.${R}
@@ -42828,15 +42932,15 @@ async function geminiQuotaHandler() {
42828
42932
  }
42829
42933
  }
42830
42934
  async function codexQuotaHandler() {
42831
- const { readFileSync: readFileSync19, existsSync: existsSync21 } = await import("fs");
42832
- const { join: join23 } = await import("path");
42833
- const { homedir: homedir22 } = await import("os");
42834
- const credPath = join23(homedir22(), ".claudish", "codex-oauth.json");
42835
- if (!existsSync21(credPath)) {
42935
+ const { readFileSync: readFileSync20, existsSync: existsSync22 } = await import("fs");
42936
+ const { join: join24 } = await import("path");
42937
+ const { homedir: homedir23 } = await import("os");
42938
+ const credPath = join24(homedir23(), ".claudish", "codex-oauth.json");
42939
+ if (!existsSync22(credPath)) {
42836
42940
  console.error(`${RED}No Codex credentials found.${R} Run: ${B}claudish login codex${R}`);
42837
42941
  process.exit(1);
42838
42942
  }
42839
- const creds = JSON.parse(readFileSync19(credPath, "utf-8"));
42943
+ const creds = JSON.parse(readFileSync20(credPath, "utf-8"));
42840
42944
  let email2 = "";
42841
42945
  try {
42842
42946
  const parts = creds.access_token.split(".");
@@ -42882,9 +42986,9 @@ async function codexQuotaHandler() {
42882
42986
  }
42883
42987
  let modelSlugs = [];
42884
42988
  try {
42885
- const modelsPath = join23(homedir22(), ".codex", "models_cache.json");
42886
- if (existsSync21(modelsPath)) {
42887
- const cache = JSON.parse(readFileSync19(modelsPath, "utf-8"));
42989
+ const modelsPath = join24(homedir23(), ".codex", "models_cache.json");
42990
+ if (existsSync22(modelsPath)) {
42991
+ const cache = JSON.parse(readFileSync20(modelsPath, "utf-8"));
42888
42992
  modelSlugs = (cache.models || []).map((m) => m.slug || m.id).filter(Boolean);
42889
42993
  }
42890
42994
  } catch {}
@@ -42990,6 +43094,7 @@ function formatRelativeReset(resetTime) {
42990
43094
  var R = "\x1B[0m", B = "\x1B[1m", D = "\x1B[2m", I = "\x1B[3m", RED = "\x1B[31m", GRN = "\x1B[32m", YEL = "\x1B[33m", MAG = "\x1B[35m", CYN = "\x1B[36m", WHT = "\x1B[37m", GRY = "\x1B[90m", FALLBACK_CHAIN, QUOTA_ADAPTERS;
42991
43095
  var init_quota_command = __esm(() => {
42992
43096
  init_oauth_registry();
43097
+ init_gemini_oauth();
42993
43098
  FALLBACK_CHAIN = [
42994
43099
  "gemini-3.1-pro-preview",
42995
43100
  "gemini-3-pro-preview",
@@ -43114,23 +43219,23 @@ __export(exports_cli, {
43114
43219
  getMissingKeyError: () => getMissingKeyError
43115
43220
  });
43116
43221
  import {
43117
- readFileSync as readFileSync19,
43222
+ readFileSync as readFileSync20,
43118
43223
  writeFileSync as writeFileSync12,
43119
- existsSync as existsSync21,
43224
+ existsSync as existsSync22,
43120
43225
  mkdirSync as mkdirSync11,
43121
43226
  copyFileSync,
43122
43227
  readdirSync as readdirSync4,
43123
43228
  unlinkSync as unlinkSync7
43124
43229
  } from "fs";
43125
43230
  import { fileURLToPath as fileURLToPath3 } from "url";
43126
- import { dirname as dirname3, join as join23 } from "path";
43127
- import { homedir as homedir22 } from "os";
43231
+ import { dirname as dirname3, join as join24 } from "path";
43232
+ import { homedir as homedir23 } from "os";
43128
43233
  function getVersion3() {
43129
43234
  return VERSION;
43130
43235
  }
43131
43236
  function clearAllModelCaches() {
43132
- const cacheDir = join23(homedir22(), ".claudish");
43133
- if (!existsSync21(cacheDir))
43237
+ const cacheDir = join24(homedir23(), ".claudish");
43238
+ if (!existsSync22(cacheDir))
43134
43239
  return;
43135
43240
  const cachePatterns = ["all-models.json", "pricing-cache.json"];
43136
43241
  let cleared = 0;
@@ -43138,7 +43243,7 @@ function clearAllModelCaches() {
43138
43243
  const files = readdirSync4(cacheDir);
43139
43244
  for (const file of files) {
43140
43245
  if (cachePatterns.includes(file) || file.startsWith("litellm-models-")) {
43141
- unlinkSync7(join23(cacheDir, file));
43246
+ unlinkSync7(join24(cacheDir, file));
43142
43247
  cleared++;
43143
43248
  }
43144
43249
  }
@@ -43460,9 +43565,9 @@ async function fetchOllamaModels() {
43460
43565
  }
43461
43566
  async function searchAndPrintModels(query, forceUpdate) {
43462
43567
  let models = [];
43463
- if (!forceUpdate && existsSync21(ALL_MODELS_JSON_PATH)) {
43568
+ if (!forceUpdate && existsSync22(ALL_MODELS_JSON_PATH)) {
43464
43569
  try {
43465
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_JSON_PATH, "utf-8"));
43570
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_JSON_PATH, "utf-8"));
43466
43571
  const lastUpdated = new Date(cacheData.lastUpdated);
43467
43572
  const now = new Date;
43468
43573
  const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
@@ -43630,9 +43735,9 @@ Found ${results.length} matching models:
43630
43735
  async function printAllModels(jsonOutput, forceUpdate) {
43631
43736
  let models = [];
43632
43737
  const [ollamaModels, zenModels] = await Promise.all([fetchOllamaModels(), fetchZenModels()]);
43633
- if (!forceUpdate && existsSync21(ALL_MODELS_JSON_PATH)) {
43738
+ if (!forceUpdate && existsSync22(ALL_MODELS_JSON_PATH)) {
43634
43739
  try {
43635
- const cacheData = JSON.parse(readFileSync19(ALL_MODELS_JSON_PATH, "utf-8"));
43740
+ const cacheData = JSON.parse(readFileSync20(ALL_MODELS_JSON_PATH, "utf-8"));
43636
43741
  const lastUpdated = new Date(cacheData.lastUpdated);
43637
43742
  const now = new Date;
43638
43743
  const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
@@ -43833,12 +43938,12 @@ async function printAllModels(jsonOutput, forceUpdate) {
43833
43938
  console.log("Top models: claudish --top-models");
43834
43939
  }
43835
43940
  function isCacheStale() {
43836
- const cachePath = existsSync21(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
43837
- if (!existsSync21(cachePath)) {
43941
+ const cachePath = existsSync22(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
43942
+ if (!existsSync22(cachePath)) {
43838
43943
  return true;
43839
43944
  }
43840
43945
  try {
43841
- const jsonContent = readFileSync19(cachePath, "utf-8");
43946
+ const jsonContent = readFileSync20(cachePath, "utf-8");
43842
43947
  const data = JSON.parse(jsonContent);
43843
43948
  if (!data.lastUpdated) {
43844
43949
  return true;
@@ -43917,10 +44022,10 @@ async function updateModelsFromOpenRouter() {
43917
44022
  providers.add(provider);
43918
44023
  }
43919
44024
  let version2 = "1.2.0";
43920
- const existingPath = existsSync21(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
43921
- if (existsSync21(existingPath)) {
44025
+ const existingPath = existsSync22(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44026
+ if (existsSync22(existingPath)) {
43922
44027
  try {
43923
- const existing = JSON.parse(readFileSync19(existingPath, "utf-8"));
44028
+ const existing = JSON.parse(readFileSync20(existingPath, "utf-8"));
43924
44029
  version2 = existing.version || version2;
43925
44030
  } catch {}
43926
44031
  }
@@ -43949,8 +44054,8 @@ async function checkAndUpdateModelsCache(forceUpdate = false) {
43949
44054
  await updateModelsFromOpenRouter();
43950
44055
  } else {
43951
44056
  try {
43952
- const cachePath = existsSync21(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
43953
- const data = JSON.parse(readFileSync19(cachePath, "utf-8"));
44057
+ const cachePath = existsSync22(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44058
+ const data = JSON.parse(readFileSync20(cachePath, "utf-8"));
43954
44059
  console.error(`\u2713 Using cached models (last updated: ${data.lastUpdated})`);
43955
44060
  } catch {}
43956
44061
  }
@@ -44548,8 +44653,8 @@ MORE INFO:
44548
44653
  }
44549
44654
  function printAIAgentGuide() {
44550
44655
  try {
44551
- const guidePath = join23(__dirname4, "../AI_AGENT_GUIDE.md");
44552
- const guideContent = readFileSync19(guidePath, "utf-8");
44656
+ const guidePath = join24(__dirname4, "../AI_AGENT_GUIDE.md");
44657
+ const guideContent = readFileSync20(guidePath, "utf-8");
44553
44658
  console.log(guideContent);
44554
44659
  } catch (error2) {
44555
44660
  console.error("Error reading AI Agent Guide:");
@@ -44565,19 +44670,19 @@ async function initializeClaudishSkill() {
44565
44670
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
44566
44671
  `);
44567
44672
  const cwd = process.cwd();
44568
- const claudeDir = join23(cwd, ".claude");
44569
- const skillsDir = join23(claudeDir, "skills");
44570
- const claudishSkillDir = join23(skillsDir, "claudish-usage");
44571
- const skillFile = join23(claudishSkillDir, "SKILL.md");
44572
- if (existsSync21(skillFile)) {
44673
+ const claudeDir = join24(cwd, ".claude");
44674
+ const skillsDir = join24(claudeDir, "skills");
44675
+ const claudishSkillDir = join24(skillsDir, "claudish-usage");
44676
+ const skillFile = join24(claudishSkillDir, "SKILL.md");
44677
+ if (existsSync22(skillFile)) {
44573
44678
  console.log("\u2705 Claudish skill already installed at:");
44574
44679
  console.log(` ${skillFile}
44575
44680
  `);
44576
44681
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
44577
44682
  return;
44578
44683
  }
44579
- const sourceSkillPath = join23(__dirname4, "../skills/claudish-usage/SKILL.md");
44580
- if (!existsSync21(sourceSkillPath)) {
44684
+ const sourceSkillPath = join24(__dirname4, "../skills/claudish-usage/SKILL.md");
44685
+ if (!existsSync22(sourceSkillPath)) {
44581
44686
  console.error("\u274C Error: Claudish skill file not found in installation.");
44582
44687
  console.error(` Expected at: ${sourceSkillPath}`);
44583
44688
  console.error(`
@@ -44586,15 +44691,15 @@ async function initializeClaudishSkill() {
44586
44691
  process.exit(1);
44587
44692
  }
44588
44693
  try {
44589
- if (!existsSync21(claudeDir)) {
44694
+ if (!existsSync22(claudeDir)) {
44590
44695
  mkdirSync11(claudeDir, { recursive: true });
44591
44696
  console.log("\uD83D\uDCC1 Created .claude/ directory");
44592
44697
  }
44593
- if (!existsSync21(skillsDir)) {
44698
+ if (!existsSync22(skillsDir)) {
44594
44699
  mkdirSync11(skillsDir, { recursive: true });
44595
44700
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
44596
44701
  }
44597
- if (!existsSync21(claudishSkillDir)) {
44702
+ if (!existsSync22(claudishSkillDir)) {
44598
44703
  mkdirSync11(claudishSkillDir, { recursive: true });
44599
44704
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
44600
44705
  }
@@ -44637,9 +44742,9 @@ function printAvailableModels() {
44637
44742
  let lastUpdated = "unknown";
44638
44743
  let models = [];
44639
44744
  try {
44640
- const cachePath = existsSync21(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44641
- if (existsSync21(cachePath)) {
44642
- const data = JSON.parse(readFileSync19(cachePath, "utf-8"));
44745
+ const cachePath = existsSync22(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44746
+ if (existsSync22(cachePath)) {
44747
+ const data = JSON.parse(readFileSync20(cachePath, "utf-8"));
44643
44748
  lastUpdated = data.lastUpdated || "unknown";
44644
44749
  models = data.models || [];
44645
44750
  }
@@ -44688,9 +44793,9 @@ Force update: claudish --list-models --force-update
44688
44793
  `);
44689
44794
  }
44690
44795
  function printAvailableModelsJSON() {
44691
- const jsonPath = existsSync21(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44796
+ const jsonPath = existsSync22(CACHED_MODELS_PATH) ? CACHED_MODELS_PATH : BUNDLED_MODELS_PATH;
44692
44797
  try {
44693
- const jsonContent = readFileSync19(jsonPath, "utf-8");
44798
+ const jsonContent = readFileSync20(jsonPath, "utf-8");
44694
44799
  const data = JSON.parse(jsonContent);
44695
44800
  console.log(JSON.stringify(data, null, 2));
44696
44801
  } catch (error2) {
@@ -44787,10 +44892,10 @@ var init_cli = __esm(() => {
44787
44892
  init_provider_resolver();
44788
44893
  __filename4 = fileURLToPath3(import.meta.url);
44789
44894
  __dirname4 = dirname3(__filename4);
44790
- CLAUDISH_CACHE_DIR2 = join23(homedir22(), ".claudish");
44791
- BUNDLED_MODELS_PATH = join23(__dirname4, "../recommended-models.json");
44792
- CACHED_MODELS_PATH = join23(CLAUDISH_CACHE_DIR2, "recommended-models.json");
44793
- ALL_MODELS_JSON_PATH = join23(CLAUDISH_CACHE_DIR2, "all-models.json");
44895
+ CLAUDISH_CACHE_DIR2 = join24(homedir23(), ".claudish");
44896
+ BUNDLED_MODELS_PATH = join24(__dirname4, "../recommended-models.json");
44897
+ CACHED_MODELS_PATH = join24(CLAUDISH_CACHE_DIR2, "recommended-models.json");
44898
+ ALL_MODELS_JSON_PATH = join24(CLAUDISH_CACHE_DIR2, "all-models.json");
44794
44899
  });
44795
44900
 
44796
44901
  // src/update-checker.ts
@@ -44801,33 +44906,33 @@ __export(exports_update_checker, {
44801
44906
  clearCache: () => clearCache,
44802
44907
  checkForUpdates: () => checkForUpdates
44803
44908
  });
44804
- import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync20, unlinkSync as unlinkSync8, writeFileSync as writeFileSync13 } from "fs";
44805
- import { homedir as homedir23, platform as platform2, tmpdir } from "os";
44806
- import { join as join24 } from "path";
44909
+ import { existsSync as existsSync23, mkdirSync as mkdirSync12, readFileSync as readFileSync21, unlinkSync as unlinkSync8, writeFileSync as writeFileSync13 } from "fs";
44910
+ import { homedir as homedir24, platform as platform2, tmpdir } from "os";
44911
+ import { join as join25 } from "path";
44807
44912
  function getCacheFilePath() {
44808
44913
  let cacheDir;
44809
44914
  if (isWindows) {
44810
- const localAppData = process.env.LOCALAPPDATA || join24(homedir23(), "AppData", "Local");
44811
- cacheDir = join24(localAppData, "claudish");
44915
+ const localAppData = process.env.LOCALAPPDATA || join25(homedir24(), "AppData", "Local");
44916
+ cacheDir = join25(localAppData, "claudish");
44812
44917
  } else {
44813
- cacheDir = join24(homedir23(), ".cache", "claudish");
44918
+ cacheDir = join25(homedir24(), ".cache", "claudish");
44814
44919
  }
44815
44920
  try {
44816
- if (!existsSync22(cacheDir)) {
44921
+ if (!existsSync23(cacheDir)) {
44817
44922
  mkdirSync12(cacheDir, { recursive: true });
44818
44923
  }
44819
- return join24(cacheDir, "update-check.json");
44924
+ return join25(cacheDir, "update-check.json");
44820
44925
  } catch {
44821
- return join24(tmpdir(), "claudish-update-check.json");
44926
+ return join25(tmpdir(), "claudish-update-check.json");
44822
44927
  }
44823
44928
  }
44824
44929
  function readCache() {
44825
44930
  try {
44826
44931
  const cachePath = getCacheFilePath();
44827
- if (!existsSync22(cachePath)) {
44932
+ if (!existsSync23(cachePath)) {
44828
44933
  return null;
44829
44934
  }
44830
- const data = JSON.parse(readFileSync20(cachePath, "utf-8"));
44935
+ const data = JSON.parse(readFileSync21(cachePath, "utf-8"));
44831
44936
  return data;
44832
44937
  } catch {
44833
44938
  return null;
@@ -44850,7 +44955,7 @@ function isCacheValid(cache) {
44850
44955
  function clearCache() {
44851
44956
  try {
44852
44957
  const cachePath = getCacheFilePath();
44853
- if (existsSync22(cachePath)) {
44958
+ if (existsSync23(cachePath)) {
44854
44959
  unlinkSync8(cachePath);
44855
44960
  }
44856
44961
  } catch {}
@@ -45151,15 +45256,15 @@ __export(exports_model_selector, {
45151
45256
  promptForApiKey: () => promptForApiKey,
45152
45257
  confirmAction: () => confirmAction
45153
45258
  });
45154
- import { readFileSync as readFileSync21, writeFileSync as writeFileSync14, existsSync as existsSync23, mkdirSync as mkdirSync13 } from "fs";
45155
- import { join as join25, dirname as dirname4 } from "path";
45156
- import { homedir as homedir24 } from "os";
45259
+ import { readFileSync as readFileSync22, writeFileSync as writeFileSync14, existsSync as existsSync24, mkdirSync as mkdirSync13 } from "fs";
45260
+ import { join as join26, dirname as dirname4 } from "path";
45261
+ import { homedir as homedir25 } from "os";
45157
45262
  import { fileURLToPath as fileURLToPath4 } from "url";
45158
45263
  function loadRecommendedModels2() {
45159
- const cachedPath = join25(CLAUDISH_CACHE_DIR3, "recommended-models-cache.json");
45160
- if (existsSync23(cachedPath)) {
45264
+ const cachedPath = join26(CLAUDISH_CACHE_DIR3, "recommended-models-cache.json");
45265
+ if (existsSync24(cachedPath)) {
45161
45266
  try {
45162
- const data = JSON.parse(readFileSync21(cachedPath, "utf-8"));
45267
+ const data = JSON.parse(readFileSync22(cachedPath, "utf-8"));
45163
45268
  if (data.models && data.models.length > 0) {
45164
45269
  return data.models.map((model) => ({
45165
45270
  ...model,
@@ -45168,9 +45273,9 @@ function loadRecommendedModels2() {
45168
45273
  }
45169
45274
  } catch {}
45170
45275
  }
45171
- if (existsSync23(RECOMMENDED_MODELS_JSON_PATH)) {
45276
+ if (existsSync24(RECOMMENDED_MODELS_JSON_PATH)) {
45172
45277
  try {
45173
- const content = readFileSync21(RECOMMENDED_MODELS_JSON_PATH, "utf-8");
45278
+ const content = readFileSync22(RECOMMENDED_MODELS_JSON_PATH, "utf-8");
45174
45279
  const data = JSON.parse(content);
45175
45280
  return (data.models || []).map((model) => ({
45176
45281
  ...model,
@@ -45183,9 +45288,9 @@ function loadRecommendedModels2() {
45183
45288
  return [];
45184
45289
  }
45185
45290
  async function fetchAllModels(forceUpdate = false) {
45186
- if (!forceUpdate && existsSync23(ALL_MODELS_JSON_PATH2)) {
45291
+ if (!forceUpdate && existsSync24(ALL_MODELS_JSON_PATH2)) {
45187
45292
  try {
45188
- const cacheData = JSON.parse(readFileSync21(ALL_MODELS_JSON_PATH2, "utf-8"));
45293
+ const cacheData = JSON.parse(readFileSync22(ALL_MODELS_JSON_PATH2, "utf-8"));
45189
45294
  const lastUpdated = new Date(cacheData.lastUpdated);
45190
45295
  const now = new Date;
45191
45296
  const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
@@ -45687,11 +45792,11 @@ async function fetchOllamaCloudModels() {
45687
45792
  }
45688
45793
  }
45689
45794
  function shouldRefreshForFreeModels() {
45690
- if (!existsSync23(ALL_MODELS_JSON_PATH2)) {
45795
+ if (!existsSync24(ALL_MODELS_JSON_PATH2)) {
45691
45796
  return true;
45692
45797
  }
45693
45798
  try {
45694
- const cacheData = JSON.parse(readFileSync21(ALL_MODELS_JSON_PATH2, "utf-8"));
45799
+ const cacheData = JSON.parse(readFileSync22(ALL_MODELS_JSON_PATH2, "utf-8"));
45695
45800
  const lastUpdated = new Date(cacheData.lastUpdated);
45696
45801
  const now = new Date;
45697
45802
  const ageInHours = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60);
@@ -46388,9 +46493,9 @@ var init_model_selector = __esm(() => {
46388
46493
  init_provider_definitions();
46389
46494
  __filename5 = fileURLToPath4(import.meta.url);
46390
46495
  __dirname5 = dirname4(__filename5);
46391
- CLAUDISH_CACHE_DIR3 = join25(homedir24(), ".claudish");
46392
- ALL_MODELS_JSON_PATH2 = join25(CLAUDISH_CACHE_DIR3, "all-models.json");
46393
- RECOMMENDED_MODELS_JSON_PATH = join25(__dirname5, "../recommended-models.json");
46496
+ CLAUDISH_CACHE_DIR3 = join26(homedir25(), ".claudish");
46497
+ ALL_MODELS_JSON_PATH2 = join26(CLAUDISH_CACHE_DIR3, "all-models.json");
46498
+ RECOMMENDED_MODELS_JSON_PATH = join26(__dirname5, "../recommended-models.json");
46394
46499
  PROVIDER_FILTER_ALIASES = {
46395
46500
  zen: "Zen",
46396
46501
  openrouter: "OpenRouter",
@@ -47076,13 +47181,13 @@ import { EventEmitter as EventEmitter2 } from "events";
47076
47181
  import { resolve as resolve3, dirname as dirname5 } from "path";
47077
47182
  import { fileURLToPath as fileURLToPath5 } from "url";
47078
47183
  import { resolve as resolve22, isAbsolute, parse as parse6 } from "path";
47079
- import { existsSync as existsSync24 } from "fs";
47080
- import { basename, join as join26 } from "path";
47184
+ import { existsSync as existsSync25 } from "fs";
47185
+ import { basename, join as join27 } from "path";
47081
47186
  import os2 from "os";
47082
47187
  import path2 from "path";
47083
47188
  import { EventEmitter as EventEmitter3 } from "events";
47084
47189
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr4 } from "bun:ffi";
47085
- import { existsSync as existsSync25, writeFileSync as writeFileSync15 } from "fs";
47190
+ import { existsSync as existsSync26, writeFileSync as writeFileSync15 } from "fs";
47086
47191
  import { EventEmitter as EventEmitter4 } from "events";
47087
47192
  import { toArrayBuffer, ptr } from "bun:ffi";
47088
47193
  import { ptr as ptr2, toArrayBuffer as toArrayBuffer2 } from "bun:ffi";
@@ -49476,7 +49581,7 @@ function getBunfsRootPath() {
49476
49581
  return process.platform === "win32" ? "B:\\~BUN\\root" : "/$bunfs/root";
49477
49582
  }
49478
49583
  function normalizeBunfsPath(fileName) {
49479
- return join26(getBunfsRootPath(), basename(fileName));
49584
+ return join27(getBunfsRootPath(), basename(fileName));
49480
49585
  }
49481
49586
  function isValidDirectoryName(name) {
49482
49587
  if (!name || typeof name !== "string") {
@@ -59672,7 +59777,7 @@ var init_index_0wbvecnk = __esm(async () => {
59672
59777
  worker_path = this.options.workerPath;
59673
59778
  } else {
59674
59779
  worker_path = new URL("./parser.worker.js", import.meta.url).href;
59675
- if (!existsSync24(resolve22(import.meta.dirname, "parser.worker.js"))) {
59780
+ if (!existsSync25(resolve22(import.meta.dirname, "parser.worker.js"))) {
59676
59781
  worker_path = new URL("./parser.worker.ts", import.meta.url).href;
59677
59782
  }
59678
59783
  }
@@ -60373,7 +60478,7 @@ var init_index_0wbvecnk = __esm(async () => {
60373
60478
  if (isBunfsPath(targetLibPath)) {
60374
60479
  targetLibPath = targetLibPath.replace("../", "");
60375
60480
  }
60376
- if (!existsSync25(targetLibPath)) {
60481
+ if (!existsSync26(targetLibPath)) {
60377
60482
  throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
60378
60483
  }
60379
60484
  registerEnvVar({
@@ -105992,9 +106097,9 @@ __export(exports_claude_runner, {
105992
106097
  checkClaudeInstalled: () => checkClaudeInstalled
105993
106098
  });
105994
106099
  import { spawn as spawn4 } from "child_process";
105995
- import { writeFileSync as writeFileSync16, unlinkSync as unlinkSync9, mkdirSync as mkdirSync14, existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
105996
- import { tmpdir as tmpdir2, homedir as homedir25 } from "os";
105997
- import { join as join27 } from "path";
106100
+ import { writeFileSync as writeFileSync16, unlinkSync as unlinkSync9, mkdirSync as mkdirSync14, existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
106101
+ import { tmpdir as tmpdir2, homedir as homedir26 } from "os";
106102
+ import { join as join28 } from "path";
105998
106103
  function hasNativeAnthropicMapping(config3) {
105999
106104
  const models = [
106000
106105
  config3.model,
@@ -106010,9 +106115,9 @@ function isWindows2() {
106010
106115
  }
106011
106116
  function createStatusLineScript(tokenFilePath) {
106012
106117
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
106013
- const claudishDir = join27(homeDir, ".claudish");
106118
+ const claudishDir = join28(homeDir, ".claudish");
106014
106119
  const timestamp = Date.now();
106015
- const scriptPath = join27(claudishDir, `status-${timestamp}.js`);
106120
+ const scriptPath = join28(claudishDir, `status-${timestamp}.js`);
106016
106121
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
106017
106122
  const script = `
106018
106123
  const fs = require('fs');
@@ -106050,9 +106155,9 @@ process.stdin.on('end', () => {
106050
106155
  try {
106051
106156
  const tokens = JSON.parse(fs.readFileSync('${escapedTokenPath}', 'utf-8'));
106052
106157
  cost = tokens.total_cost || 0;
106053
- ctx = tokens.context_left_percent || 100;
106158
+ ctx = tokens.context_left_percent ?? -1;
106054
106159
  inputTokens = tokens.input_tokens || 0;
106055
- contextWindow = tokens.context_window || 0;
106160
+ contextWindow = typeof tokens.context_window === 'number' ? tokens.context_window : 0;
106056
106161
  isFree = tokens.is_free || false;
106057
106162
  isEstimated = tokens.is_estimated || false;
106058
106163
  providerName = tokens.provider_name || '';
@@ -106078,7 +106183,10 @@ process.stdin.on('end', () => {
106078
106183
  const modelDisplay = providerName ? providerName + ' ' + model : model;
106079
106184
  // Format context display as progress bar: [\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591] 116k/1M
106080
106185
  let ctxDisplay = '';
106081
- if (inputTokens > 0 && contextWindow > 0) {
106186
+ if (ctx < 0 || contextWindow <= 0) {
106187
+ // Unknown context window \u2014 show token count only
106188
+ ctxDisplay = inputTokens > 0 ? formatTokens(inputTokens) + ' tokens' : 'N/A';
106189
+ } else if (inputTokens > 0 && contextWindow > 0) {
106082
106190
  const usedPct = 100 - ctx; // ctx is "left", so used = 100 - left
106083
106191
  const barWidth = 15;
106084
106192
  const filled = Math.round((usedPct / 100) * barWidth);
@@ -106106,13 +106214,13 @@ process.stdin.on('end', () => {
106106
106214
  }
106107
106215
  function createTempSettingsFile(modelDisplay, port) {
106108
106216
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
106109
- const claudishDir = join27(homeDir, ".claudish");
106217
+ const claudishDir = join28(homeDir, ".claudish");
106110
106218
  try {
106111
106219
  mkdirSync14(claudishDir, { recursive: true });
106112
106220
  } catch {}
106113
106221
  const timestamp = Date.now();
106114
- const tempPath = join27(claudishDir, `settings-${timestamp}.json`);
106115
- const tokenFilePath = join27(claudishDir, `tokens-${port}.json`);
106222
+ const tempPath = join28(claudishDir, `settings-${timestamp}.json`);
106223
+ const tokenFilePath = join28(claudishDir, `tokens-${port}.json`);
106116
106224
  let statusCommand;
106117
106225
  if (isWindows2()) {
106118
106226
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -106126,7 +106234,7 @@ function createTempSettingsFile(modelDisplay, port) {
106126
106234
  const RESET4 = "\\033[0m";
106127
106235
  const BOLD4 = "\\033[1m";
106128
106236
  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; }`;
106129
- statusCommand = `JSON=$(cat) && DIR=$(basename "$(pwd)") && [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true && CTX=100 && COST="0" && IS_FREE="false" && IS_EST="false" && PROVIDER="" && TOKEN_MODEL="" && IN_TOK=0 && CTX_WIN=0 && ${formatTokensBash} && if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d ' \\n') && REAL_CTX=$(echo "$TOKENS" | grep -o '"context_left_percent":[0-9]*' | grep -o '[0-9]*') && if [ ! -z "$REAL_CTX" ]; then CTX="$REAL_CTX"; fi && REAL_COST=$(echo "$TOKENS" | grep -o '"total_cost":[0-9.]*' | cut -d: -f2) && if [ ! -z "$REAL_COST" ]; then COST="$REAL_COST"; fi && IN_TOK=$(echo "$TOKENS" | grep -o '"input_tokens":[0-9]*' | grep -o '[0-9]*') && CTX_WIN=$(echo "$TOKENS" | grep -o '"context_window":[0-9]*' | grep -o '[0-9]*') && IS_FREE=$(echo "$TOKENS" | grep -o '"is_free":[a-z]*' | cut -d: -f2) && IS_EST=$(echo "$TOKENS" | grep -o '"is_estimated":[a-z]*' | cut -d: -f2) && PROVIDER=$(echo "$TOKENS" | grep -o '"provider_name":"[^"]*"' | cut -d'"' -f4) && TOKEN_MODEL=$(echo "$TOKENS" | grep -o '"model_name":"[^"]*"' | cut -d'"' -f4); 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 [ ! -z "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi && if [ "$IN_TOK" -gt 0 ] 2>/dev/null && [ "$CTX_WIN" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX%"; fi && 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"`;
106237
+ statusCommand = `JSON=$(cat) && DIR=$(basename "$(pwd)") && [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true && CTX=-1 && COST="0" && IS_FREE="false" && IS_EST="false" && PROVIDER="" && TOKEN_MODEL="" && IN_TOK=0 && CTX_WIN=0 && ${formatTokensBash} && if [ -f "${tokenFilePath}" ]; then TOKENS=$(cat "${tokenFilePath}" 2>/dev/null | tr -d ' \\n') && REAL_CTX=$(echo "$TOKENS" | grep -o '"context_left_percent":-\\?[0-9]*' | grep -o '\\-\\?[0-9]*') && if [ ! -z "$REAL_CTX" ]; then CTX="$REAL_CTX"; fi && REAL_COST=$(echo "$TOKENS" | grep -o '"total_cost":[0-9.]*' | cut -d: -f2) && if [ ! -z "$REAL_COST" ]; then COST="$REAL_COST"; fi && IN_TOK=$(echo "$TOKENS" | grep -o '"input_tokens":[0-9]*' | grep -o '[0-9]*') && CTX_WIN=$(echo "$TOKENS" | grep -o '"context_window":[0-9]*' | grep -o '[0-9]*') && IS_FREE=$(echo "$TOKENS" | grep -o '"is_free":[a-z]*' | cut -d: -f2) && IS_EST=$(echo "$TOKENS" | grep -o '"is_estimated":[a-z]*' | cut -d: -f2) && PROVIDER=$(echo "$TOKENS" | grep -o '"provider_name":"[^"]*"' | cut -d'"' -f4) && TOKEN_MODEL=$(echo "$TOKENS" | grep -o '"model_name":"[^"]*"' | cut -d'"' -f4); 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 [ ! -z "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi && if [ "$CTX" -lt 0 ] 2>/dev/null || [ "$CTX_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 && [ "$CTX_WIN" -gt 0 ] 2>/dev/null; then CTX_DISPLAY="$CTX% ($(fmt_tok $IN_TOK)/$(fmt_tok $CTX_WIN))"; else CTX_DISPLAY="$CTX%"; fi && 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"`;
106130
106238
  }
106131
106239
  const statusLine = {
106132
106240
  type: "command",
@@ -106148,7 +106256,7 @@ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
106148
106256
  if (userSettingsValue.trimStart().startsWith("{")) {
106149
106257
  userSettings = JSON.parse(userSettingsValue);
106150
106258
  } else {
106151
- const rawUserSettings = readFileSync22(userSettingsValue, "utf-8");
106259
+ const rawUserSettings = readFileSync23(userSettingsValue, "utf-8");
106152
106260
  userSettings = JSON.parse(rawUserSettings);
106153
106261
  }
106154
106262
  userSettings.statusLine = statusLine;
@@ -106240,8 +106348,8 @@ async function runClaudeWithProxy(config3, proxyUrl, onCleanup) {
106240
106348
  console.error("Install it from: https://claude.com/claude-code");
106241
106349
  console.error(`
106242
106350
  Or set CLAUDE_PATH to your custom installation:`);
106243
- const home = homedir25();
106244
- const localPath = isWindows2() ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
106351
+ const home = homedir26();
106352
+ const localPath = isWindows2() ? join28(home, ".claude", "local", "claude.exe") : join28(home, ".claude", "local", "claude");
106245
106353
  console.error(` export CLAUDE_PATH=${localPath}`);
106246
106354
  process.exit(1);
106247
106355
  }
@@ -106287,23 +106395,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet, onCleanup) {
106287
106395
  async function findClaudeBinary() {
106288
106396
  const isWindows3 = process.platform === "win32";
106289
106397
  if (process.env.CLAUDE_PATH) {
106290
- if (existsSync26(process.env.CLAUDE_PATH)) {
106398
+ if (existsSync27(process.env.CLAUDE_PATH)) {
106291
106399
  return process.env.CLAUDE_PATH;
106292
106400
  }
106293
106401
  }
106294
- const home = homedir25();
106295
- const localPath = isWindows3 ? join27(home, ".claude", "local", "claude.exe") : join27(home, ".claude", "local", "claude");
106296
- if (existsSync26(localPath)) {
106402
+ const home = homedir26();
106403
+ const localPath = isWindows3 ? join28(home, ".claude", "local", "claude.exe") : join28(home, ".claude", "local", "claude");
106404
+ if (existsSync27(localPath)) {
106297
106405
  return localPath;
106298
106406
  }
106299
106407
  if (isWindows3) {
106300
106408
  const windowsPaths = [
106301
- join27(home, "AppData", "Roaming", "npm", "claude.cmd"),
106302
- join27(home, ".npm-global", "claude.cmd"),
106303
- join27(home, "node_modules", ".bin", "claude.cmd")
106409
+ join28(home, "AppData", "Roaming", "npm", "claude.cmd"),
106410
+ join28(home, ".npm-global", "claude.cmd"),
106411
+ join28(home, "node_modules", ".bin", "claude.cmd")
106304
106412
  ];
106305
106413
  for (const path3 of windowsPaths) {
106306
- if (existsSync26(path3)) {
106414
+ if (existsSync27(path3)) {
106307
106415
  return path3;
106308
106416
  }
106309
106417
  }
@@ -106311,14 +106419,14 @@ async function findClaudeBinary() {
106311
106419
  const commonPaths = [
106312
106420
  "/usr/local/bin/claude",
106313
106421
  "/opt/homebrew/bin/claude",
106314
- join27(home, ".npm-global/bin/claude"),
106315
- join27(home, ".local/bin/claude"),
106316
- join27(home, "node_modules/.bin/claude"),
106422
+ join28(home, ".npm-global/bin/claude"),
106423
+ join28(home, ".local/bin/claude"),
106424
+ join28(home, "node_modules/.bin/claude"),
106317
106425
  "/data/data/com.termux/files/usr/bin/claude",
106318
- join27(home, "../usr/bin/claude")
106426
+ join28(home, "../usr/bin/claude")
106319
106427
  ];
106320
106428
  for (const path3 of commonPaths) {
106321
- if (existsSync26(path3)) {
106429
+ if (existsSync27(path3)) {
106322
106430
  return path3;
106323
106431
  }
106324
106432
  }
@@ -106368,17 +106476,17 @@ __export(exports_diag_output, {
106368
106476
  LogFileDiagOutput: () => LogFileDiagOutput
106369
106477
  });
106370
106478
  import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync15, writeFileSync as writeFileSync17, unlinkSync as unlinkSync10 } from "fs";
106371
- import { homedir as homedir26 } from "os";
106372
- import { join as join28 } from "path";
106479
+ import { homedir as homedir27 } from "os";
106480
+ import { join as join29 } from "path";
106373
106481
  function getClaudishDir() {
106374
- const dir = join28(homedir26(), ".claudish");
106482
+ const dir = join29(homedir27(), ".claudish");
106375
106483
  try {
106376
106484
  mkdirSync15(dir, { recursive: true });
106377
106485
  } catch {}
106378
106486
  return dir;
106379
106487
  }
106380
106488
  function getDiagLogPath() {
106381
- return join28(getClaudishDir(), `diag-${process.pid}.log`);
106489
+ return join29(getClaudishDir(), `diag-${process.pid}.log`);
106382
106490
  }
106383
106491
 
106384
106492
  class LogFileDiagOutput {
@@ -106437,42 +106545,112 @@ __export(exports_team_grid, {
106437
106545
  });
106438
106546
  import { spawn as spawn5 } from "child_process";
106439
106547
  import {
106440
- appendFileSync,
106441
- existsSync as existsSync28,
106548
+ existsSync as existsSync29,
106442
106549
  mkdirSync as mkdirSync16,
106443
- readFileSync as readFileSync23,
106550
+ readFileSync as readFileSync24,
106444
106551
  unlinkSync as unlinkSync11,
106445
106552
  writeFileSync as writeFileSync18
106446
106553
  } from "fs";
106447
- import { dirname as dirname6, join as join29 } from "path";
106554
+ import { dirname as dirname6, join as join30 } from "path";
106448
106555
  import { fileURLToPath as fileURLToPath6 } from "url";
106449
106556
  import { execSync as execSync2 } from "child_process";
106450
- function formatElapsed(ms) {
106451
- const s = Math.floor(ms / 1000);
106452
- if (s < 60)
106453
- return `${s}s`;
106454
- const m2 = Math.floor(s / 60);
106455
- const rem = s % 60;
106456
- return `${m2}m ${rem}s`;
106557
+ function resolveRouteInfo(modelId) {
106558
+ const parsed = parseModelSpec(modelId);
106559
+ if (parsed.isExplicitProvider) {
106560
+ return { chain: [parsed.provider], source: "direct" };
106561
+ }
106562
+ const local = loadLocalConfig();
106563
+ if (local?.routing && Object.keys(local.routing).length > 0) {
106564
+ const matched = matchRoutingRule(parsed.model, local.routing);
106565
+ if (matched) {
106566
+ const routes2 = buildRoutingChain(matched, parsed.model);
106567
+ const pattern = Object.keys(local.routing).find((k2) => {
106568
+ if (k2 === parsed.model)
106569
+ return true;
106570
+ if (k2.includes("*")) {
106571
+ const star = k2.indexOf("*");
106572
+ return parsed.model.startsWith(k2.slice(0, star)) && parsed.model.endsWith(k2.slice(star + 1));
106573
+ }
106574
+ return false;
106575
+ });
106576
+ return {
106577
+ chain: routes2.map((r) => r.displayName),
106578
+ source: "project routing",
106579
+ sourceDetail: pattern
106580
+ };
106581
+ }
106582
+ }
106583
+ const global_ = loadConfig();
106584
+ if (global_.routing && Object.keys(global_.routing).length > 0) {
106585
+ const matched = matchRoutingRule(parsed.model, global_.routing);
106586
+ if (matched) {
106587
+ const routes2 = buildRoutingChain(matched, parsed.model);
106588
+ const pattern = Object.keys(global_.routing).find((k2) => {
106589
+ if (k2 === parsed.model)
106590
+ return true;
106591
+ if (k2.includes("*")) {
106592
+ const star = k2.indexOf("*");
106593
+ return parsed.model.startsWith(k2.slice(0, star)) && parsed.model.endsWith(k2.slice(star + 1));
106594
+ }
106595
+ return false;
106596
+ });
106597
+ return {
106598
+ chain: routes2.map((r) => r.displayName),
106599
+ source: "user routing",
106600
+ sourceDetail: pattern
106601
+ };
106602
+ }
106603
+ }
106604
+ const routes = getFallbackChain(parsed.model, parsed.provider);
106605
+ return {
106606
+ chain: routes.map((r) => r.displayName),
106607
+ source: "auto"
106608
+ };
106609
+ }
106610
+ function buildPaneHeader(model, prompt) {
106611
+ const route = resolveRouteInfo(model);
106612
+ const esc2 = (s) => s.replace(/'/g, "'\\''");
106613
+ const bgColors = [
106614
+ "48;2;40;90;180",
106615
+ "48;2;140;60;160",
106616
+ "48;2;30;130;100",
106617
+ "48;2;160;80;40",
106618
+ "48;2;60;120;60",
106619
+ "48;2;160;50;70"
106620
+ ];
106621
+ let hash = 0;
106622
+ for (let i = 0;i < model.length; i++)
106623
+ hash = (hash << 5) - hash + model.charCodeAt(i) | 0;
106624
+ const bg2 = bgColors[Math.abs(hash) % bgColors.length];
106625
+ const chainStr = route.chain.join(" \u2192 ");
106626
+ const sourceLabel = route.sourceDetail ? `${route.source}: ${route.sourceDetail}` : route.source;
106627
+ const lines = [];
106628
+ lines.push(`printf '\\033[1;97;${bg2}m %s \\033[0m\\n' '${esc2(model)}';`);
106629
+ lines.push(`printf '\\033[2m route: ${esc2(chainStr)} (${esc2(sourceLabel)})\\033[0m\\n' ;`);
106630
+ lines.push(`printf '\\033[2m %s\\033[0m\\n' '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500';`);
106631
+ const promptForShell = esc2(prompt).replace(/\n/g, "\\n");
106632
+ lines.push(`printf '%b\\n' '${promptForShell}' | fold -s -w 78 | sed 's/^/ /';`);
106633
+ lines.push(`printf '\\033[2m %s\\033[0m\\n\\n' '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500';`);
106634
+ return lines.join(" ");
106457
106635
  }
106458
106636
  function findMagmuxBinary() {
106459
106637
  const thisFile = fileURLToPath6(import.meta.url);
106460
106638
  const thisDir = dirname6(thisFile);
106461
- const pkgRoot = join29(thisDir, "..");
106639
+ const pkgRoot = join30(thisDir, "..");
106462
106640
  const platform3 = process.platform;
106463
106641
  const arch = process.arch;
106464
- const builtMagmux = join29(pkgRoot, "native", "magmux", "magmux");
106465
- if (existsSync28(builtMagmux))
106642
+ const builtMagmux = join30(pkgRoot, "native", "magmux", "magmux");
106643
+ if (existsSync29(builtMagmux))
106466
106644
  return builtMagmux;
106467
- const bundledMagmux = join29(pkgRoot, "native", "magmux", `magmux-${platform3}-${arch}`);
106468
- if (existsSync28(bundledMagmux))
106645
+ const bundledMagmux = join30(pkgRoot, "native", "magmux", `magmux-${platform3}-${arch}`);
106646
+ if (existsSync29(bundledMagmux))
106469
106647
  return bundledMagmux;
106470
106648
  try {
106471
106649
  const pkgName = `@claudish/magmux-${platform3}-${arch}`;
106472
106650
  let searchDir = pkgRoot;
106473
106651
  for (let i = 0;i < 5; i++) {
106474
- const candidate = join29(searchDir, "node_modules", pkgName, "bin", "magmux");
106475
- if (existsSync28(candidate))
106652
+ const candidate = join30(searchDir, "node_modules", pkgName, "bin", "magmux");
106653
+ if (existsSync29(candidate))
106476
106654
  return candidate;
106477
106655
  const parent = dirname6(searchDir);
106478
106656
  if (parent === searchDir)
@@ -106488,141 +106666,97 @@ function findMagmuxBinary() {
106488
106666
  throw new Error(`magmux not found. Install it:
106489
106667
  brew install MadAppGang/tap/magmux`);
106490
106668
  }
106491
- function renderGridStatusBar(counts) {
106492
- const elapsed = formatElapsed(counts.elapsedMs);
106493
- const { done, running, failed, total, allDone } = counts;
106494
- if (allDone) {
106495
- if (failed > 0) {
106496
- return [
106497
- "C: claudish team",
106498
- `G: ${done} done`,
106499
- `R: ${failed} failed`,
106500
- `D: ${elapsed}`,
106501
- "R: \u2717 issues",
106502
- "D: ctrl-g q to quit"
106503
- ].join("\t");
106504
- }
106505
- return [
106506
- "C: claudish team",
106507
- `G: ${total} done`,
106508
- `D: ${elapsed}`,
106509
- "G: \u2713 complete",
106510
- "D: ctrl-g q to quit"
106511
- ].join("\t");
106512
- }
106513
- return [
106514
- "C: claudish team",
106515
- `G: ${done} done`,
106516
- `C: ${running} running`,
106517
- `R: ${failed} failed`,
106518
- `D: ${elapsed}`
106519
- ].join("\t");
106520
- }
106521
- function pollStatus(state) {
106522
- const { statusCache, statusPath, sessionPath, anonIds, startTime, timeoutMs, statusbarPath } = state;
106523
- const elapsedMs = Date.now() - startTime;
106524
- let changed = false;
106525
- let done = 0;
106526
- let running = 0;
106527
- let failed = 0;
106669
+ function finalizeStatus(statusPath, sessionPath, anonIds) {
106670
+ const statusCache = JSON.parse(readFileSync24(statusPath, "utf-8"));
106528
106671
  for (const anonId of anonIds) {
106529
106672
  const current = statusCache.models[anonId];
106530
- if (current.state === "COMPLETED" || current.state === "FAILED" || current.state === "TIMEOUT") {
106531
- if (current.state === "COMPLETED")
106532
- done++;
106533
- else
106534
- failed++;
106673
+ if (current.state === "COMPLETED" || current.state === "FAILED")
106535
106674
  continue;
106536
- }
106537
- const exitCodePath = join29(sessionPath, "work", anonId, ".exit-code");
106538
- if (existsSync28(exitCodePath)) {
106539
- const codeStr = readFileSync23(exitCodePath, "utf-8").trim();
106540
- const code = parseInt(codeStr, 10);
106541
- const isSuccess = code === 0;
106542
- const newState = {
106675
+ const exitCodePath = join30(sessionPath, "work", anonId, ".exit-code");
106676
+ if (existsSync29(exitCodePath)) {
106677
+ const code = parseInt(readFileSync24(exitCodePath, "utf-8").trim(), 10);
106678
+ statusCache.models[anonId] = {
106543
106679
  ...current,
106544
- state: isSuccess ? "COMPLETED" : "FAILED",
106680
+ state: code === 0 ? "COMPLETED" : "FAILED",
106545
106681
  exitCode: code,
106546
- startedAt: current.startedAt ?? new Date().toISOString(),
106547
- completedAt: new Date().toISOString(),
106548
- outputSize: 0
106682
+ startedAt: current.startedAt ?? statusCache.startedAt,
106683
+ completedAt: new Date().toISOString()
106549
106684
  };
106550
- statusCache.models[anonId] = newState;
106551
- changed = true;
106552
- if (isSuccess)
106553
- done++;
106554
- else
106555
- failed++;
106556
106685
  } else {
106557
- if (!state.interactive && elapsedMs > timeoutMs) {
106558
- const newState = {
106559
- ...current,
106560
- state: "TIMEOUT",
106561
- startedAt: current.startedAt ?? new Date().toISOString(),
106562
- completedAt: new Date().toISOString(),
106563
- outputSize: 0
106564
- };
106565
- statusCache.models[anonId] = newState;
106566
- changed = true;
106567
- failed++;
106568
- } else {
106569
- if (current.state === "PENDING" && elapsedMs > 1000) {
106570
- statusCache.models[anonId] = {
106571
- ...current,
106572
- state: "RUNNING",
106573
- startedAt: current.startedAt ?? new Date().toISOString()
106574
- };
106575
- changed = true;
106576
- }
106577
- running++;
106578
- }
106686
+ statusCache.models[anonId] = { ...current, state: "TIMEOUT" };
106579
106687
  }
106580
106688
  }
106581
- if (changed) {
106582
- writeFileSync18(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
106583
- }
106584
- const total = anonIds.length;
106585
- const allDone = done + failed >= total;
106586
- if (allDone && !state.completedAtMs) {
106587
- state.completedAtMs = elapsedMs;
106588
- }
106589
- const counts = {
106590
- done,
106591
- running,
106592
- failed,
106593
- total,
106594
- elapsedMs: state.completedAtMs ?? elapsedMs,
106595
- allDone
106596
- };
106597
- appendFileSync(statusbarPath, renderGridStatusBar(counts) + `
106598
- `);
106599
- return allDone;
106689
+ writeFileSync18(statusPath, JSON.stringify(statusCache, null, 2), "utf-8");
106600
106690
  }
106601
106691
  async function runWithGrid(sessionPath, models, input, opts) {
106602
- const timeoutMs = (opts?.timeout ?? 300) * 1000;
106603
- const interactive = opts?.interactive ?? false;
106692
+ const mode = opts?.mode ?? "default";
106693
+ const keep = opts?.keep ?? false;
106604
106694
  const manifest = setupSession(sessionPath, models, input);
106605
- mkdirSync16(join29(sessionPath, "errors"), { recursive: true });
106695
+ mkdirSync16(join30(sessionPath, "errors"), { recursive: true });
106606
106696
  for (const anonId of Object.keys(manifest.models)) {
106607
- const stale = join29(sessionPath, "work", anonId, ".exit-code");
106697
+ const stale = join30(sessionPath, "work", anonId, ".exit-code");
106608
106698
  try {
106609
106699
  unlinkSync11(stale);
106610
106700
  } catch {}
106611
106701
  }
106612
- const gridfilePath = join29(sessionPath, "gridfile.txt");
106613
- const prompt = readFileSync23(join29(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
106702
+ const gridfilePath = join30(sessionPath, "gridfile.txt");
106703
+ const prompt = readFileSync24(join30(sessionPath, "input.md"), "utf-8").replace(/'/g, "'\\''").replace(/\n/g, " ");
106704
+ const totalPanes = Object.keys(manifest.models).length;
106705
+ const workDir = join30(sessionPath, "work");
106706
+ const statusFunc = [
106707
+ `_update_bar() {`,
106708
+ `_d=0; _f=0;`,
106709
+ `for _ecf in $(find ${workDir} -name .exit-code 2>/dev/null); do`,
106710
+ `_c=$(cat "$_ecf" 2>/dev/null);`,
106711
+ `if [ "$_c" = "0" ]; then _d=$((_d+1)); else _f=$((_f+1)); fi;`,
106712
+ `done;`,
106713
+ `_r=$((${totalPanes}-_d-_f));`,
106714
+ `_e=$SECONDS;`,
106715
+ `if [ $_e -ge 60 ]; then _ts="$((_e/60))m $((_e%60))s"; else _ts="\${_e}s"; fi;`,
106716
+ `if [ $_r -eq 0 ] && [ $_f -eq 0 ]; then`,
106717
+ `_t="C: claudish team G: ${totalPanes} done G: complete D: \${_ts} D: ctrl-g q to quit";`,
106718
+ `elif [ $_r -eq 0 ] && [ $_f -gt 0 ]; then`,
106719
+ `_t="C: claudish team G: \${_d} done R: \${_f} failed D: \${_ts} D: ctrl-g q to quit";`,
106720
+ `else`,
106721
+ `_t="C: claudish team G: \${_d} done C: \${_r} running R: \${_f} failed D: \${_ts}";`,
106722
+ `fi;`,
106723
+ `_j=$(printf '%s' "$_t" | sed 's/ /\\\\t/g');`,
106724
+ `printf '{"cmd":"status","text":"%s"}' "$_j" | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106725
+ `};`
106726
+ ].join(" ");
106727
+ const rawPrompt = readFileSync24(join30(sessionPath, "input.md"), "utf-8");
106614
106728
  const gridLines = Object.entries(manifest.models).map(([anonId]) => {
106615
- const errorLog = join29(sessionPath, "errors", `${anonId}.log`);
106616
- const exitCodeFile = join29(sessionPath, "work", anonId, ".exit-code");
106729
+ const errorLog = join30(sessionPath, "errors", `${anonId}.log`);
106730
+ const exitCodeFile = join30(sessionPath, "work", anonId, ".exit-code");
106617
106731
  const model = manifest.models[anonId].model;
106618
106732
  const paneIndex = Object.keys(manifest.models).indexOf(anonId);
106619
- if (interactive) {
106620
- return `claudish --model ${model} --dangerously-skip-permissions '${prompt}'`;
106621
- }
106733
+ if (mode === "interactive") {
106734
+ return [
106735
+ `${statusFunc}`,
106736
+ `if [ -n "$MAGMUX_SOCK" ]; then _update_bar; fi;`,
106737
+ `claudish --model ${model} -i --dangerously-skip-permissions '${prompt}' 2>${errorLog};`,
106738
+ `_ec=$?; echo $_ec > ${exitCodeFile};`,
106739
+ `if [ -n "$MAGMUX_SOCK" ]; then`,
106740
+ ` _update_bar;`,
106741
+ ` if [ $_ec -eq 0 ]; then`,
106742
+ ` echo '{"cmd":"tint","pane":${paneIndex},"color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106743
+ ` echo '{"cmd":"overlay","pane":${paneIndex},"text":"DONE","color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106744
+ ` else`,
106745
+ ` echo '{"cmd":"tint","pane":${paneIndex},"color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106746
+ ` echo '{"cmd":"overlay","pane":${paneIndex},"text":"FAIL","color":"red"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106747
+ ` fi;`,
106748
+ `fi`
106749
+ ].join(" ");
106750
+ }
106751
+ const header = buildPaneHeader(model, rawPrompt);
106622
106752
  return [
106623
- `claudish --model ${model} -y -v '${prompt}' 2>${errorLog};`,
106753
+ `${statusFunc}`,
106754
+ `if [ -n "$MAGMUX_SOCK" ]; then _update_bar; fi;`,
106755
+ `${header}`,
106756
+ `claudish --model ${model} -y --quiet '${prompt}' 2>${errorLog};`,
106624
106757
  `_ec=$?; echo $_ec > ${exitCodeFile};`,
106625
106758
  `if [ -n "$MAGMUX_SOCK" ]; then`,
106759
+ ` _update_bar;`,
106626
106760
  ` if [ $_ec -eq 0 ]; then`,
106627
106761
  ` echo '{"cmd":"tint","pane":${paneIndex},"color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
106628
106762
  ` echo '{"cmd":"overlay","pane":${paneIndex},"text":"DONE","color":"green"}' | nc -U "$MAGMUX_SOCK" -w 1 2>/dev/null;`,
@@ -106638,36 +106772,10 @@ async function runWithGrid(sessionPath, models, input, opts) {
106638
106772
  `) + `
106639
106773
  `, "utf-8");
106640
106774
  const magmuxPath = findMagmuxBinary();
106641
- const statusbarPath = join29(sessionPath, "statusbar.txt");
106642
- const statusPath = join29(sessionPath, "status.json");
106643
- const statusCache = JSON.parse(readFileSync23(statusPath, "utf-8"));
106775
+ const statusPath = join30(sessionPath, "status.json");
106644
106776
  const anonIds = Object.keys(manifest.models);
106645
- const startTime = Date.now();
106646
- appendFileSync(statusbarPath, renderGridStatusBar({
106647
- done: 0,
106648
- running: 0,
106649
- failed: 0,
106650
- total: anonIds.length,
106651
- elapsedMs: 0,
106652
- allDone: false
106653
- }) + `
106654
- `);
106655
- const pollState = {
106656
- statusCache,
106657
- statusPath,
106658
- sessionPath,
106659
- anonIds,
106660
- startTime,
106661
- timeoutMs,
106662
- statusbarPath,
106663
- completedAtMs: null,
106664
- interactive
106665
- };
106666
- const pollInterval = setInterval(() => {
106667
- pollStatus(pollState);
106668
- }, 500);
106669
- const spawnArgs = ["-g", gridfilePath, "-S", statusbarPath];
106670
- if (!interactive) {
106777
+ const spawnArgs = ["-g", gridfilePath];
106778
+ if (!keep && mode === "default") {
106671
106779
  spawnArgs.push("-w");
106672
106780
  }
106673
106781
  const proc = spawn5(magmuxPath, spawnArgs, {
@@ -106678,26 +106786,29 @@ async function runWithGrid(sessionPath, models, input, opts) {
106678
106786
  proc.on("exit", () => resolve4());
106679
106787
  proc.on("error", () => resolve4());
106680
106788
  });
106681
- clearInterval(pollInterval);
106682
- pollStatus(pollState);
106683
- return JSON.parse(readFileSync23(statusPath, "utf-8"));
106789
+ finalizeStatus(statusPath, sessionPath, anonIds);
106790
+ return JSON.parse(readFileSync24(statusPath, "utf-8"));
106684
106791
  }
106685
106792
  var init_team_grid = __esm(() => {
106686
106793
  init_team_orchestrator();
106794
+ init_model_parser();
106795
+ init_routing_rules();
106796
+ init_auto_route();
106797
+ init_profile_config();
106687
106798
  });
106688
106799
 
106689
106800
  // src/index.ts
106690
106801
  var import_dotenv3 = __toESM(require_main(), 1);
106691
- import { existsSync as existsSync29, readFileSync as readFileSync24 } from "fs";
106692
- import { homedir as homedir27 } from "os";
106693
- import { join as join30 } from "path";
106802
+ import { existsSync as existsSync30, readFileSync as readFileSync25 } from "fs";
106803
+ import { homedir as homedir28 } from "os";
106804
+ import { join as join31 } from "path";
106694
106805
  import_dotenv3.config({ quiet: true });
106695
106806
  function loadStoredApiKeys() {
106696
106807
  try {
106697
- const configPath = join30(homedir27(), ".claudish", "config.json");
106698
- if (!existsSync29(configPath))
106808
+ const configPath = join31(homedir28(), ".claudish", "config.json");
106809
+ if (!existsSync30(configPath))
106699
106810
  return;
106700
- const raw2 = readFileSync24(configPath, "utf-8");
106811
+ const raw2 = readFileSync25(configPath, "utf-8");
106701
106812
  const cfg = JSON.parse(raw2);
106702
106813
  if (cfg.apiKeys) {
106703
106814
  for (const [envVar, value] of Object.entries(cfg.apiKeys)) {
@@ -106811,14 +106922,14 @@ async function runCli() {
106811
106922
  if (cliConfig.team && cliConfig.team.length > 0) {
106812
106923
  let prompt = cliConfig.claudeArgs.join(" ");
106813
106924
  if (cliConfig.inputFile) {
106814
- prompt = readFileSync24(cliConfig.inputFile, "utf-8");
106925
+ prompt = readFileSync25(cliConfig.inputFile, "utf-8");
106815
106926
  }
106816
106927
  if (!prompt.trim()) {
106817
106928
  console.error("Error: --team requires a prompt (positional args or -f <file>)");
106818
106929
  process.exit(1);
106819
106930
  }
106820
106931
  const mode = cliConfig.teamMode ?? "default";
106821
- const sessionPath = join30(process.cwd(), `.claudish-team-${Date.now()}`);
106932
+ const sessionPath = join31(process.cwd(), `.claudish-team-${Date.now()}`);
106822
106933
  if (mode === "json") {
106823
106934
  const { setupSession: setupSession2, runModels: runModels2 } = await Promise.resolve().then(() => (init_team_orchestrator(), exports_team_orchestrator));
106824
106935
  setupSession2(sessionPath, cliConfig.team, prompt);
@@ -106828,9 +106939,9 @@ async function runCli() {
106828
106939
  });
106829
106940
  const result = { ...status2, responses: {} };
106830
106941
  for (const anonId of Object.keys(status2.models)) {
106831
- const responsePath = join30(sessionPath, `response-${anonId}.md`);
106942
+ const responsePath = join31(sessionPath, `response-${anonId}.md`);
106832
106943
  try {
106833
- const raw2 = readFileSync24(responsePath, "utf-8").trim();
106944
+ const raw2 = readFileSync25(responsePath, "utf-8").trim();
106834
106945
  try {
106835
106946
  result.responses[anonId] = JSON.parse(raw2);
106836
106947
  } catch {