claudish 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +475 -55
  2. package/package.json +2 -8
package/dist/index.js CHANGED
@@ -31091,7 +31091,12 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
31091
31091
  return { content: [{ type: "text", text: response }] };
31092
31092
  } catch (error46) {
31093
31093
  return {
31094
- content: [{ type: "text", text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}` }],
31094
+ content: [
31095
+ {
31096
+ type: "text",
31097
+ text: `Error: ${error46 instanceof Error ? error46.message : String(error46)}`
31098
+ }
31099
+ ],
31095
31100
  isError: true
31096
31101
  };
31097
31102
  }
@@ -31100,7 +31105,9 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
31100
31105
  const models = loadRecommendedModels();
31101
31106
  if (models.length === 0) {
31102
31107
  return {
31103
- content: [{ type: "text", text: "No recommended models found. Try search_models instead." }]
31108
+ content: [
31109
+ { type: "text", text: "No recommended models found. Try search_models instead." }
31110
+ ]
31104
31111
  };
31105
31112
  }
31106
31113
  let output = `# Recommended Models
@@ -31136,7 +31143,9 @@ Tokens: ${result.usage.input} input, ${result.usage.output} output`;
31136
31143
  const allModels = await loadAllModels();
31137
31144
  if (allModels.length === 0) {
31138
31145
  return {
31139
- content: [{ type: "text", text: "Failed to load models. Check your internet connection." }],
31146
+ content: [
31147
+ { type: "text", text: "Failed to load models. Check your internet connection." }
31148
+ ],
31140
31149
  isError: true
31141
31150
  };
31142
31151
  }
@@ -35367,7 +35376,7 @@ function printVersion() {
35367
35376
  }
35368
35377
  function printHelp() {
35369
35378
  console.log(`
35370
- claudish - Run Claude Code with any AI model (OpenRouter, Gemini, OpenAI, Local)
35379
+ claudish - Run Claude Code with any AI model (OpenRouter, Gemini, OpenAI, MiniMax, Kimi, GLM, Local)
35371
35380
 
35372
35381
  USAGE:
35373
35382
  claudish # Interactive mode (default, shows model selector)
@@ -35376,7 +35385,10 @@ USAGE:
35376
35385
  MODEL ROUTING (prefix-based):
35377
35386
  (no prefix) OpenRouter (default) claudish --model openai/gpt-5.2 "task"
35378
35387
  g/, gemini/ Google Gemini API claudish --model g/gemini-2.0-flash "task"
35379
- oai/, openai/ OpenAI API claudish --model oai/gpt-4o "task"
35388
+ oai/ OpenAI Direct API claudish --model oai/gpt-4o "task"
35389
+ mmax/, mm/ MiniMax Direct API claudish --model mmax/MiniMax-M2.1 "task"
35390
+ kimi/, moonshot/ Kimi Direct API claudish --model kimi/kimi-k2-thinking-turbo "task"
35391
+ glm/, zhipu/ GLM Direct API claudish --model glm/glm-4.7 "task"
35380
35392
  ollama/ Ollama (local) claudish --model ollama/llama3.2 "task"
35381
35393
  lmstudio/ LM Studio (local) claudish --model lmstudio/qwen "task"
35382
35394
  vllm/ vLLM (local) claudish --model vllm/model "task"
@@ -35447,11 +35459,21 @@ ENVIRONMENT VARIABLES:
35447
35459
  OPENROUTER_API_KEY OpenRouter API key (default backend)
35448
35460
  GEMINI_API_KEY Google Gemini API key (for g/ prefix)
35449
35461
  OPENAI_API_KEY OpenAI API key (for oai/ prefix)
35462
+ MINIMAX_API_KEY MiniMax API key (for mmax/, mm/ prefix)
35463
+ MOONSHOT_API_KEY Kimi/Moonshot API key (for kimi/, moonshot/ prefix)
35464
+ KIMI_API_KEY Alias for MOONSHOT_API_KEY
35465
+ ZHIPU_API_KEY GLM/Zhipu API key (for glm/, zhipu/ prefix)
35466
+ GLM_API_KEY Alias for ZHIPU_API_KEY
35450
35467
  ANTHROPIC_API_KEY Placeholder (prevents Claude Code dialog)
35451
35468
 
35452
35469
  Custom endpoints:
35453
35470
  GEMINI_BASE_URL Custom Gemini endpoint
35454
35471
  OPENAI_BASE_URL Custom OpenAI/Azure endpoint
35472
+ MINIMAX_BASE_URL Custom MiniMax endpoint
35473
+ MOONSHOT_BASE_URL Custom Kimi/Moonshot endpoint
35474
+ KIMI_BASE_URL Alias for MOONSHOT_BASE_URL
35475
+ ZHIPU_BASE_URL Custom GLM/Zhipu endpoint
35476
+ GLM_BASE_URL Alias for ZHIPU_BASE_URL
35455
35477
 
35456
35478
  Local providers:
35457
35479
  OLLAMA_BASE_URL Ollama server (default: http://localhost:11434)
@@ -35489,14 +35511,26 @@ EXAMPLES:
35489
35511
 
35490
35512
  # Direct OpenAI API
35491
35513
  claudish --model oai/gpt-4o "implement feature"
35492
- claudish --model openai/o1 "complex reasoning"
35514
+ claudish --model oai/o1 "complex reasoning"
35515
+
35516
+ # Direct MiniMax API
35517
+ claudish --model mmax/MiniMax-M2.1 "implement feature"
35518
+ claudish --model mm/MiniMax-M2 "code review"
35519
+
35520
+ # Direct Kimi API (with reasoning support)
35521
+ claudish --model kimi/kimi-k2-thinking-turbo "complex analysis"
35522
+ claudish --model moonshot/kimi-k2-turbo-preview "implement feature"
35523
+
35524
+ # Direct GLM API
35525
+ claudish --model glm/glm-4.7 "code generation"
35526
+ claudish --model zhipu/glm-4-plus "complex task"
35493
35527
 
35494
35528
  # Local models (free, private)
35495
35529
  claudish --model ollama/llama3.2 "code review"
35496
35530
  claudish --model lmstudio/qwen2.5-coder "refactor"
35497
35531
 
35498
35532
  # Per-role model mapping
35499
- claudish --model-opus openai/gpt-5.2 --model-sonnet deepseek/deepseek-v3.2 --model-haiku minimax/minimax-m2.1
35533
+ claudish --model-opus openai/gpt-5.2 --model-sonnet deepseek/deepseek-v3.2 --model-haiku mmax/MiniMax-M2.1
35500
35534
 
35501
35535
  # Use stdin for large prompts (e.g., git diffs, code review)
35502
35536
  echo "Review this code..." | claudish --stdin --model g/gemini-2.0-flash
@@ -38519,7 +38553,7 @@ var init_openai_adapter = __esm(() => {
38519
38553
  return request;
38520
38554
  }
38521
38555
  shouldHandle(modelId) {
38522
- return modelId.startsWith("openai/") || modelId.includes("o1") || modelId.includes("o3");
38556
+ return modelId.startsWith("oai/") || modelId.includes("o1") || modelId.includes("o3");
38523
38557
  }
38524
38558
  getName() {
38525
38559
  return "OpenAIAdapter";
@@ -39119,7 +39153,17 @@ function extractToolCallsFromText(text) {
39119
39153
  }
39120
39154
  } catch (e) {}
39121
39155
  }
39122
- const knownTools = ["Task", "Read", "Write", "Edit", "Bash", "Grep", "Glob", "WebFetch", "WebSearch"];
39156
+ const knownTools = [
39157
+ "Task",
39158
+ "Read",
39159
+ "Write",
39160
+ "Edit",
39161
+ "Bash",
39162
+ "Grep",
39163
+ "Glob",
39164
+ "WebFetch",
39165
+ "WebSearch"
39166
+ ];
39123
39167
  const nlPatterns = [
39124
39168
  /(?:I(?:'ll| will| am going to)|Let me|Going to)\s+use\s+(?:the\s+)?(\w+)\s+tool\s+(?:with\s+)?(.+?)(?:[.:\n]|$)/gi,
39125
39169
  /use\s+(?:the\s+)?(\w+)\s+tool\s+(?:to\s+)?(.+?)(?:[.:\n]|$)/gi
@@ -39772,7 +39816,10 @@ data: ${JSON.stringify(d)}
39772
39816
  if (tc.function?.name) {
39773
39817
  if (!t) {
39774
39818
  if (state.textStarted) {
39775
- send("content_block_stop", { type: "content_block_stop", index: state.textIdx });
39819
+ send("content_block_stop", {
39820
+ type: "content_block_stop",
39821
+ index: state.textIdx
39822
+ });
39776
39823
  state.textStarted = false;
39777
39824
  }
39778
39825
  t = {
@@ -39801,7 +39848,10 @@ data: ${JSON.stringify(d)}
39801
39848
  send("content_block_delta", {
39802
39849
  type: "content_block_delta",
39803
39850
  index: t.blockIndex,
39804
- delta: { type: "input_json_delta", partial_json: tc.function.arguments }
39851
+ delta: {
39852
+ type: "input_json_delta",
39853
+ partial_json: tc.function.arguments
39854
+ }
39805
39855
  });
39806
39856
  }
39807
39857
  }
@@ -39828,13 +39878,19 @@ data: ${JSON.stringify(d)}
39828
39878
  index: t.blockIndex,
39829
39879
  delta: { type: "input_json_delta", partial_json: repairedJson }
39830
39880
  });
39831
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
39881
+ send("content_block_stop", {
39882
+ type: "content_block_stop",
39883
+ index: t.blockIndex
39884
+ });
39832
39885
  t.started = true;
39833
39886
  t.closed = true;
39834
39887
  continue;
39835
39888
  }
39836
39889
  if (t.started) {
39837
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
39890
+ send("content_block_stop", {
39891
+ type: "content_block_stop",
39892
+ index: t.blockIndex
39893
+ });
39838
39894
  const repairedIdx = state.curIdx++;
39839
39895
  const repairedId = `tool_repaired_${Date.now()}_${repairedIdx}`;
39840
39896
  send("content_block_start", {
@@ -39847,7 +39903,10 @@ data: ${JSON.stringify(d)}
39847
39903
  index: repairedIdx,
39848
39904
  delta: { type: "input_json_delta", partial_json: repairedJson }
39849
39905
  });
39850
- send("content_block_stop", { type: "content_block_stop", index: repairedIdx });
39906
+ send("content_block_stop", {
39907
+ type: "content_block_stop",
39908
+ index: repairedIdx
39909
+ });
39851
39910
  t.closed = true;
39852
39911
  continue;
39853
39912
  }
@@ -39868,9 +39927,15 @@ data: ${JSON.stringify(d)}
39868
39927
  index: errorIdx,
39869
39928
  delta: { type: "text_delta", text: errorMsg }
39870
39929
  });
39871
- send("content_block_stop", { type: "content_block_stop", index: errorIdx });
39930
+ send("content_block_stop", {
39931
+ type: "content_block_stop",
39932
+ index: errorIdx
39933
+ });
39872
39934
  if (t.started && !t.buffered) {
39873
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
39935
+ send("content_block_stop", {
39936
+ type: "content_block_stop",
39937
+ index: t.blockIndex
39938
+ });
39874
39939
  }
39875
39940
  t.closed = true;
39876
39941
  continue;
@@ -39887,14 +39952,20 @@ data: ${JSON.stringify(d)}
39887
39952
  index: t.blockIndex,
39888
39953
  delta: { type: "input_json_delta", partial_json: argsJson }
39889
39954
  });
39890
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
39955
+ send("content_block_stop", {
39956
+ type: "content_block_stop",
39957
+ index: t.blockIndex
39958
+ });
39891
39959
  t.started = true;
39892
39960
  t.closed = true;
39893
39961
  continue;
39894
39962
  }
39895
39963
  }
39896
39964
  if (t.started && !t.closed) {
39897
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
39965
+ send("content_block_stop", {
39966
+ type: "content_block_stop",
39967
+ index: t.blockIndex
39968
+ });
39898
39969
  t.closed = true;
39899
39970
  }
39900
39971
  }
@@ -40106,12 +40177,19 @@ class OpenRouterHandler {
40106
40177
  if (block.type === "text")
40107
40178
  contentParts.push({ type: "text", text: block.text });
40108
40179
  else if (block.type === "image")
40109
- contentParts.push({ type: "image_url", image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` } });
40180
+ contentParts.push({
40181
+ type: "image_url",
40182
+ image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` }
40183
+ });
40110
40184
  else if (block.type === "tool_result") {
40111
40185
  if (seen.has(block.tool_use_id))
40112
40186
  continue;
40113
40187
  seen.add(block.tool_use_id);
40114
- toolResults.push({ role: "tool", content: typeof block.content === "string" ? block.content : JSON.stringify(block.content), tool_call_id: block.tool_use_id });
40188
+ toolResults.push({
40189
+ role: "tool",
40190
+ content: typeof block.content === "string" ? block.content : JSON.stringify(block.content),
40191
+ tool_call_id: block.tool_use_id
40192
+ });
40115
40193
  }
40116
40194
  }
40117
40195
  if (toolResults.length)
@@ -40134,7 +40212,11 @@ class OpenRouterHandler {
40134
40212
  if (seen.has(block.id))
40135
40213
  continue;
40136
40214
  seen.add(block.id);
40137
- toolCalls.push({ id: block.id, type: "function", function: { name: block.name, arguments: JSON.stringify(block.input) } });
40215
+ toolCalls.push({
40216
+ id: block.id,
40217
+ type: "function",
40218
+ function: { name: block.name, arguments: JSON.stringify(block.input) }
40219
+ });
40138
40220
  }
40139
40221
  }
40140
40222
  const m = { role: "assistant" };
@@ -40248,7 +40330,11 @@ data: ${JSON.stringify(d)}
40248
40330
  send("error", { type: "error", error: { type: "api_error", message: err } });
40249
40331
  } else {
40250
40332
  log(`[OpenRouter] Stream complete: ${reason}`);
40251
- send("message_delta", { type: "message_delta", delta: { stop_reason: "end_turn", stop_sequence: null }, usage: { output_tokens: usage?.completion_tokens || 0 } });
40333
+ send("message_delta", {
40334
+ type: "message_delta",
40335
+ delta: { stop_reason: "end_turn", stop_sequence: null },
40336
+ usage: { output_tokens: usage?.completion_tokens || 0 }
40337
+ });
40252
40338
  send("message_stop", { type: "message_stop" });
40253
40339
  }
40254
40340
  if (!isClosed) {
@@ -40324,17 +40410,28 @@ data: ${JSON.stringify(d)}
40324
40410
  if (txt) {
40325
40411
  lastActivity = Date.now();
40326
40412
  if (thinkingStarted) {
40327
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
40413
+ send("content_block_stop", {
40414
+ type: "content_block_stop",
40415
+ index: thinkingIdx
40416
+ });
40328
40417
  thinkingStarted = false;
40329
40418
  }
40330
40419
  if (!textStarted) {
40331
40420
  textIdx = curIdx++;
40332
- send("content_block_start", { type: "content_block_start", index: textIdx, content_block: { type: "text", text: "" } });
40421
+ send("content_block_start", {
40422
+ type: "content_block_start",
40423
+ index: textIdx,
40424
+ content_block: { type: "text", text: "" }
40425
+ });
40333
40426
  textStarted = true;
40334
40427
  }
40335
40428
  const res = adapter.processTextContent(txt, "");
40336
40429
  if (res.cleanedText)
40337
- send("content_block_delta", { type: "content_block_delta", index: textIdx, delta: { type: "text_delta", text: res.cleanedText } });
40430
+ send("content_block_delta", {
40431
+ type: "content_block_delta",
40432
+ index: textIdx,
40433
+ delta: { type: "text_delta", text: res.cleanedText }
40434
+ });
40338
40435
  }
40339
40436
  if (delta.tool_calls) {
40340
40437
  for (const tc of delta.tool_calls) {
@@ -40343,24 +40440,48 @@ data: ${JSON.stringify(d)}
40343
40440
  if (tc.function?.name) {
40344
40441
  if (!t) {
40345
40442
  if (thinkingStarted) {
40346
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
40443
+ send("content_block_stop", {
40444
+ type: "content_block_stop",
40445
+ index: thinkingIdx
40446
+ });
40347
40447
  thinkingStarted = false;
40348
40448
  }
40349
40449
  if (textStarted) {
40350
- send("content_block_stop", { type: "content_block_stop", index: textIdx });
40450
+ send("content_block_stop", {
40451
+ type: "content_block_stop",
40452
+ index: textIdx
40453
+ });
40351
40454
  textStarted = false;
40352
40455
  }
40353
- t = { id: tc.id || `tool_${Date.now()}_${idx}`, name: tc.function.name, blockIndex: curIdx++, started: false, closed: false, arguments: "" };
40456
+ t = {
40457
+ id: tc.id || `tool_${Date.now()}_${idx}`,
40458
+ name: tc.function.name,
40459
+ blockIndex: curIdx++,
40460
+ started: false,
40461
+ closed: false,
40462
+ arguments: ""
40463
+ };
40354
40464
  tools.set(idx, t);
40355
40465
  }
40356
40466
  if (!t.started) {
40357
- send("content_block_start", { type: "content_block_start", index: t.blockIndex, content_block: { type: "tool_use", id: t.id, name: t.name } });
40467
+ send("content_block_start", {
40468
+ type: "content_block_start",
40469
+ index: t.blockIndex,
40470
+ content_block: { type: "tool_use", id: t.id, name: t.name }
40471
+ });
40358
40472
  t.started = true;
40359
40473
  }
40360
40474
  }
40361
40475
  if (tc.function?.arguments && t) {
40362
40476
  t.arguments += tc.function.arguments;
40363
- send("content_block_delta", { type: "content_block_delta", index: t.blockIndex, delta: { type: "input_json_delta", partial_json: tc.function.arguments } });
40477
+ send("content_block_delta", {
40478
+ type: "content_block_delta",
40479
+ index: t.blockIndex,
40480
+ delta: {
40481
+ type: "input_json_delta",
40482
+ partial_json: tc.function.arguments
40483
+ }
40484
+ });
40364
40485
  }
40365
40486
  }
40366
40487
  }
@@ -40378,15 +40499,29 @@ data: ${JSON.stringify(d)}
40378
40499
  const errorMsg = `
40379
40500
 
40380
40501
  ⚠️ Tool call "${t.name}" failed validation: missing required parameters: ${validation.missingParams.join(", ")}. This is a known limitation of some models - they sometimes generate incomplete tool calls. Please try again or use a different model.`;
40381
- send("content_block_start", { type: "content_block_start", index: errorIdx, content_block: { type: "text", text: "" } });
40382
- send("content_block_delta", { type: "content_block_delta", index: errorIdx, delta: { type: "text_delta", text: errorMsg } });
40383
- send("content_block_stop", { type: "content_block_stop", index: errorIdx });
40502
+ send("content_block_start", {
40503
+ type: "content_block_start",
40504
+ index: errorIdx,
40505
+ content_block: { type: "text", text: "" }
40506
+ });
40507
+ send("content_block_delta", {
40508
+ type: "content_block_delta",
40509
+ index: errorIdx,
40510
+ delta: { type: "text_delta", text: errorMsg }
40511
+ });
40512
+ send("content_block_stop", {
40513
+ type: "content_block_stop",
40514
+ index: errorIdx
40515
+ });
40384
40516
  t.closed = true;
40385
40517
  continue;
40386
40518
  }
40387
40519
  }
40388
40520
  log(`[OpenRouter] Tool validated: ${t.name}`);
40389
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
40521
+ send("content_block_stop", {
40522
+ type: "content_block_stop",
40523
+ index: t.blockIndex
40524
+ });
40390
40525
  t.closed = true;
40391
40526
  }
40392
40527
  }
@@ -40404,7 +40539,13 @@ data: ${JSON.stringify(d)}
40404
40539
  if (ping)
40405
40540
  clearInterval(ping);
40406
40541
  }
40407
- }), { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" } });
40542
+ }), {
40543
+ headers: {
40544
+ "Content-Type": "text/event-stream",
40545
+ "Cache-Control": "no-cache",
40546
+ Connection: "keep-alive"
40547
+ }
40548
+ });
40408
40549
  }
40409
40550
  async shutdown() {}
40410
40551
  }
@@ -61099,6 +61240,18 @@ function getModelPricing(provider, modelName) {
61099
61240
  case "oai":
61100
61241
  pricingTable = OPENAI_PRICING;
61101
61242
  break;
61243
+ case "minimax":
61244
+ case "mm":
61245
+ pricingTable = MINIMAX_PRICING;
61246
+ break;
61247
+ case "kimi":
61248
+ case "moonshot":
61249
+ pricingTable = KIMI_PRICING;
61250
+ break;
61251
+ case "glm":
61252
+ case "zhipu":
61253
+ pricingTable = GLM_PRICING;
61254
+ break;
61102
61255
  default:
61103
61256
  return { inputCostPer1M: 1, outputCostPer1M: 4 };
61104
61257
  }
@@ -61110,9 +61263,9 @@ function getModelPricing(provider, modelName) {
61110
61263
  return pricing;
61111
61264
  }
61112
61265
  }
61113
- return pricingTable["default"];
61266
+ return pricingTable.default;
61114
61267
  }
61115
- var GEMINI_PRICING, OPENAI_PRICING;
61268
+ var GEMINI_PRICING, OPENAI_PRICING, MINIMAX_PRICING, KIMI_PRICING, GLM_PRICING;
61116
61269
  var init_remote_provider_types = __esm(() => {
61117
61270
  GEMINI_PRICING = {
61118
61271
  "gemini-2.5-flash": { inputCostPer1M: 0.15, outputCostPer1M: 0.6 },
@@ -61144,6 +61297,25 @@ var init_remote_provider_types = __esm(() => {
61144
61297
  "gpt-3.5-turbo": { inputCostPer1M: 0.5, outputCostPer1M: 1.5 },
61145
61298
  default: { inputCostPer1M: 2, outputCostPer1M: 8 }
61146
61299
  };
61300
+ MINIMAX_PRICING = {
61301
+ "minimax-m2.1": { inputCostPer1M: 0.12, outputCostPer1M: 0.48 },
61302
+ "minimax-m2": { inputCostPer1M: 0.12, outputCostPer1M: 0.48 },
61303
+ default: { inputCostPer1M: 0.12, outputCostPer1M: 0.48 }
61304
+ };
61305
+ KIMI_PRICING = {
61306
+ "kimi-k2-thinking-turbo": { inputCostPer1M: 0.32, outputCostPer1M: 0.48 },
61307
+ "kimi-k2-thinking": { inputCostPer1M: 0.32, outputCostPer1M: 0.48 },
61308
+ "kimi-k2-turbo-preview": { inputCostPer1M: 0.2, outputCostPer1M: 0.4 },
61309
+ "kimi-k2-0905-preview": { inputCostPer1M: 0.2, outputCostPer1M: 0.4 },
61310
+ "kimi-k2": { inputCostPer1M: 0.2, outputCostPer1M: 0.4 },
61311
+ default: { inputCostPer1M: 0.32, outputCostPer1M: 0.48 }
61312
+ };
61313
+ GLM_PRICING = {
61314
+ "glm-4.7": { inputCostPer1M: 0.16, outputCostPer1M: 0.8 },
61315
+ "glm-4": { inputCostPer1M: 0.16, outputCostPer1M: 0.8 },
61316
+ "glm-4-plus": { inputCostPer1M: 0.5, outputCostPer1M: 2 },
61317
+ default: { inputCostPer1M: 0.16, outputCostPer1M: 0.8 }
61318
+ };
61147
61319
  });
61148
61320
 
61149
61321
  // src/handlers/gemini-handler.ts
@@ -61513,7 +61685,10 @@ data: ${JSON.stringify(d)}
61513
61685
  }
61514
61686
  if (part.text) {
61515
61687
  if (thinkingStarted) {
61516
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
61688
+ send("content_block_stop", {
61689
+ type: "content_block_stop",
61690
+ index: thinkingIdx
61691
+ });
61517
61692
  thinkingStarted = false;
61518
61693
  }
61519
61694
  const res = adapter.processTextContent(part.text, accumulatedText);
@@ -61537,11 +61712,17 @@ data: ${JSON.stringify(d)}
61537
61712
  }
61538
61713
  if (part.functionCall) {
61539
61714
  if (thinkingStarted) {
61540
- send("content_block_stop", { type: "content_block_stop", index: thinkingIdx });
61715
+ send("content_block_stop", {
61716
+ type: "content_block_stop",
61717
+ index: thinkingIdx
61718
+ });
61541
61719
  thinkingStarted = false;
61542
61720
  }
61543
61721
  if (textStarted) {
61544
- send("content_block_stop", { type: "content_block_stop", index: textIdx });
61722
+ send("content_block_stop", {
61723
+ type: "content_block_stop",
61724
+ index: textIdx
61725
+ });
61545
61726
  textStarted = false;
61546
61727
  }
61547
61728
  const toolIdx = tools.size;
@@ -61565,7 +61746,10 @@ data: ${JSON.stringify(d)}
61565
61746
  index: t.blockIndex,
61566
61747
  delta: { type: "input_json_delta", partial_json: t.arguments }
61567
61748
  });
61568
- send("content_block_stop", { type: "content_block_stop", index: t.blockIndex });
61749
+ send("content_block_stop", {
61750
+ type: "content_block_stop",
61751
+ index: t.blockIndex
61752
+ });
61569
61753
  t.closed = true;
61570
61754
  }
61571
61755
  }
@@ -61835,6 +62019,182 @@ var init_openai_handler = __esm(() => {
61835
62019
  init_remote_provider_types();
61836
62020
  });
61837
62021
 
62022
+ // src/handlers/anthropic-compat-handler.ts
62023
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync12 } from "node:fs";
62024
+ import { homedir as homedir6 } from "node:os";
62025
+ import { join as join12 } from "node:path";
62026
+
62027
+ class AnthropicCompatHandler {
62028
+ provider;
62029
+ modelName;
62030
+ apiKey;
62031
+ port;
62032
+ sessionTotalCost = 0;
62033
+ sessionInputTokens = 0;
62034
+ sessionOutputTokens = 0;
62035
+ contextWindow = 128000;
62036
+ constructor(provider, modelName, apiKey, port) {
62037
+ this.provider = provider;
62038
+ this.modelName = modelName;
62039
+ this.apiKey = apiKey;
62040
+ this.port = port;
62041
+ this.setContextWindow();
62042
+ }
62043
+ setContextWindow() {
62044
+ const provider = this.provider.name.toLowerCase();
62045
+ const model = this.modelName.toLowerCase();
62046
+ if (provider === "kimi" || provider === "moonshot") {
62047
+ this.contextWindow = 128000;
62048
+ } else if (provider === "minimax") {
62049
+ this.contextWindow = 1e5;
62050
+ } else {
62051
+ this.contextWindow = 128000;
62052
+ }
62053
+ }
62054
+ getPricing() {
62055
+ return getModelPricing(this.provider.name, this.modelName);
62056
+ }
62057
+ getApiEndpoint() {
62058
+ return `${this.provider.baseUrl}${this.provider.apiPath}`;
62059
+ }
62060
+ writeTokenFile(input, output) {
62061
+ try {
62062
+ const total = input + output;
62063
+ const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
62064
+ const data = {
62065
+ input_tokens: input,
62066
+ output_tokens: output,
62067
+ total_tokens: total,
62068
+ total_cost: this.sessionTotalCost,
62069
+ context_window: this.contextWindow,
62070
+ context_left_percent: leftPct,
62071
+ updated_at: Date.now()
62072
+ };
62073
+ const claudishDir = join12(homedir6(), ".claudish");
62074
+ mkdirSync9(claudishDir, { recursive: true });
62075
+ writeFileSync12(join12(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
62076
+ } catch (e) {
62077
+ log(`[AnthropicCompatHandler] Error writing token file: ${e}`);
62078
+ }
62079
+ }
62080
+ updateTokenTracking(inputTokens, outputTokens) {
62081
+ this.sessionInputTokens = inputTokens;
62082
+ this.sessionOutputTokens += outputTokens;
62083
+ const pricing = this.getPricing();
62084
+ const cost = inputTokens / 1e6 * pricing.inputCostPer1M + outputTokens / 1e6 * pricing.outputCostPer1M;
62085
+ this.sessionTotalCost += cost;
62086
+ this.writeTokenFile(inputTokens, this.sessionOutputTokens);
62087
+ }
62088
+ async handle(c, payload) {
62089
+ const systemPromptLength = typeof payload.system === "string" ? payload.system.length : 0;
62090
+ logStructured(`${this.provider.name} Request`, {
62091
+ targetModel: `${this.provider.name}/${this.modelName}`,
62092
+ originalModel: payload.model,
62093
+ messageCount: payload.messages?.length || 0,
62094
+ toolCount: payload.tools?.length || 0,
62095
+ systemPromptLength,
62096
+ maxTokens: payload.max_tokens
62097
+ });
62098
+ const requestPayload = {
62099
+ ...payload,
62100
+ model: this.modelName
62101
+ };
62102
+ const headers = {
62103
+ "Content-Type": "application/json",
62104
+ "x-api-key": this.apiKey,
62105
+ "anthropic-version": "2023-06-01"
62106
+ };
62107
+ if (this.provider.headers) {
62108
+ Object.assign(headers, this.provider.headers);
62109
+ }
62110
+ const endpoint = this.getApiEndpoint();
62111
+ log(`[${this.provider.name}] Calling API: ${endpoint}`);
62112
+ const response = await fetch(endpoint, {
62113
+ method: "POST",
62114
+ headers,
62115
+ body: JSON.stringify(requestPayload)
62116
+ });
62117
+ log(`[${this.provider.name}] Response status: ${response.status}`);
62118
+ if (!response.ok) {
62119
+ const errorText = await response.text();
62120
+ log(`[${this.provider.name}] Error: ${errorText}`);
62121
+ return c.json({ error: errorText }, response.status);
62122
+ }
62123
+ const contentType = response.headers.get("content-type") || "";
62124
+ if (contentType.includes("text/event-stream")) {
62125
+ return this.handleStreamingResponse(c, response);
62126
+ }
62127
+ const data = await response.json();
62128
+ return c.json(data);
62129
+ }
62130
+ handleStreamingResponse(c, response) {
62131
+ const encoder = new TextEncoder;
62132
+ const decoder = new TextDecoder;
62133
+ return c.body(new ReadableStream({
62134
+ start: async (controller) => {
62135
+ const reader = response.body?.getReader();
62136
+ if (!reader) {
62137
+ controller.close();
62138
+ return;
62139
+ }
62140
+ let buffer = "";
62141
+ let hasUsage = false;
62142
+ try {
62143
+ while (true) {
62144
+ const { done, value } = await reader.read();
62145
+ if (done)
62146
+ break;
62147
+ controller.enqueue(value);
62148
+ buffer += decoder.decode(value, { stream: true });
62149
+ const lines = buffer.split(`
62150
+ `);
62151
+ buffer = lines.pop() || "";
62152
+ for (const line of lines) {
62153
+ if (!line.trim() || !line.startsWith("data: "))
62154
+ continue;
62155
+ const dataStr = line.slice(6);
62156
+ if (dataStr === "[DONE]")
62157
+ continue;
62158
+ try {
62159
+ const chunk = JSON.parse(dataStr);
62160
+ if (chunk.type === "message_delta" && chunk.usage && !hasUsage) {
62161
+ const { input_tokens = 0, output_tokens = 0 } = chunk.usage;
62162
+ if (input_tokens > 0 || output_tokens > 0) {
62163
+ this.updateTokenTracking(input_tokens, output_tokens);
62164
+ hasUsage = true;
62165
+ }
62166
+ }
62167
+ if (chunk.type === "message_stop" && chunk.message?.usage && !hasUsage) {
62168
+ const { input_tokens = 0, output_tokens = 0 } = chunk.message.usage;
62169
+ if (input_tokens > 0 || output_tokens > 0) {
62170
+ this.updateTokenTracking(input_tokens, output_tokens);
62171
+ hasUsage = true;
62172
+ }
62173
+ }
62174
+ } catch (e) {}
62175
+ }
62176
+ }
62177
+ controller.close();
62178
+ } catch (e) {
62179
+ log(`[${this.provider.name}] Stream error: ${e}`);
62180
+ controller.close();
62181
+ }
62182
+ }
62183
+ }), {
62184
+ headers: {
62185
+ "Content-Type": "text/event-stream",
62186
+ "Cache-Control": "no-cache",
62187
+ Connection: "keep-alive"
62188
+ }
62189
+ });
62190
+ }
62191
+ async shutdown() {}
62192
+ }
62193
+ var init_anthropic_compat_handler = __esm(() => {
62194
+ init_logger();
62195
+ init_remote_provider_types();
62196
+ });
62197
+
61838
62198
  // src/providers/provider-registry.ts
61839
62199
  function resolveProvider(modelId) {
61840
62200
  const providers = getProviders();
@@ -61967,7 +62327,10 @@ function validateRemoteProviderApiKey(provider) {
61967
62327
  const examples = {
61968
62328
  GEMINI_API_KEY: "export GEMINI_API_KEY='your-key' (get from https://aistudio.google.com/app/apikey)",
61969
62329
  OPENAI_API_KEY: "export OPENAI_API_KEY='sk-...' (get from https://platform.openai.com/api-keys)",
61970
- OPENROUTER_API_KEY: "export OPENROUTER_API_KEY='sk-or-...' (get from https://openrouter.ai/keys)"
62330
+ OPENROUTER_API_KEY: "export OPENROUTER_API_KEY='sk-or-...' (get from https://openrouter.ai/keys)",
62331
+ MINIMAX_API_KEY: "export MINIMAX_API_KEY='your-key' (get from https://www.minimaxi.com/)",
62332
+ MOONSHOT_API_KEY: "export MOONSHOT_API_KEY='your-key' (get from https://platform.moonshot.cn/)",
62333
+ ZHIPU_API_KEY: "export ZHIPU_API_KEY='your-key' (get from https://open.bigmodel.cn/)"
61971
62334
  };
61972
62335
  const example = examples[provider.apiKeyEnvVar] || `export ${provider.apiKeyEnvVar}='your-key'`;
61973
62336
  return `Missing ${provider.apiKeyEnvVar} environment variable.
@@ -61997,7 +62360,7 @@ var getRemoteProviders = () => [
61997
62360
  baseUrl: process.env.OPENAI_BASE_URL || "https://api.openai.com",
61998
62361
  apiPath: "/v1/chat/completions",
61999
62362
  apiKeyEnvVar: "OPENAI_API_KEY",
62000
- prefixes: ["oai/", "openai/"],
62363
+ prefixes: ["oai/"],
62001
62364
  capabilities: {
62002
62365
  supportsTools: true,
62003
62366
  supportsVision: true,
@@ -62023,6 +62386,48 @@ var getRemoteProviders = () => [
62023
62386
  supportsJsonMode: true,
62024
62387
  supportsReasoning: true
62025
62388
  }
62389
+ },
62390
+ {
62391
+ name: "minimax",
62392
+ baseUrl: process.env.MINIMAX_BASE_URL || "https://api.minimax.io",
62393
+ apiPath: "/anthropic/v1/messages",
62394
+ apiKeyEnvVar: "MINIMAX_API_KEY",
62395
+ prefixes: ["mmax/", "mm/"],
62396
+ capabilities: {
62397
+ supportsTools: true,
62398
+ supportsVision: true,
62399
+ supportsStreaming: true,
62400
+ supportsJsonMode: false,
62401
+ supportsReasoning: false
62402
+ }
62403
+ },
62404
+ {
62405
+ name: "kimi",
62406
+ baseUrl: process.env.MOONSHOT_BASE_URL || process.env.KIMI_BASE_URL || "https://api.moonshot.ai",
62407
+ apiPath: "/anthropic/v1/messages",
62408
+ apiKeyEnvVar: "MOONSHOT_API_KEY",
62409
+ prefixes: ["kimi/", "moonshot/"],
62410
+ capabilities: {
62411
+ supportsTools: true,
62412
+ supportsVision: true,
62413
+ supportsStreaming: true,
62414
+ supportsJsonMode: false,
62415
+ supportsReasoning: true
62416
+ }
62417
+ },
62418
+ {
62419
+ name: "glm",
62420
+ baseUrl: process.env.ZHIPU_BASE_URL || process.env.GLM_BASE_URL || "https://open.bigmodel.cn",
62421
+ apiPath: "/api/paas/v4/chat/completions",
62422
+ apiKeyEnvVar: "ZHIPU_API_KEY",
62423
+ prefixes: ["glm/", "zhipu/"],
62424
+ capabilities: {
62425
+ supportsTools: true,
62426
+ supportsVision: true,
62427
+ supportsStreaming: true,
62428
+ supportsJsonMode: true,
62429
+ supportsReasoning: false
62430
+ }
62026
62431
  }
62027
62432
  ];
62028
62433
 
@@ -62089,6 +62494,12 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
62089
62494
  } else if (resolved.provider.name === "openai") {
62090
62495
  handler = new OpenAIHandler(resolved.provider, resolved.modelName, apiKey, port);
62091
62496
  log(`[Proxy] Created OpenAI handler: ${resolved.modelName}`);
62497
+ } else if (resolved.provider.name === "minimax" || resolved.provider.name === "kimi") {
62498
+ handler = new AnthropicCompatHandler(resolved.provider, resolved.modelName, apiKey, port);
62499
+ log(`[Proxy] Created ${resolved.provider.name} handler: ${resolved.modelName}`);
62500
+ } else if (resolved.provider.name === "glm") {
62501
+ handler = new OpenAIHandler(resolved.provider, resolved.modelName, apiKey, port);
62502
+ log(`[Proxy] Created GLM handler: ${resolved.modelName}`);
62092
62503
  } else {
62093
62504
  return null;
62094
62505
  }
@@ -62122,7 +62533,11 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
62122
62533
  };
62123
62534
  const app = new Hono2;
62124
62535
  app.use("*", cors());
62125
- app.get("/", (c) => c.json({ status: "ok", message: "Claudish Proxy", config: { mode: monitorMode ? "monitor" : "hybrid", mappings: modelMap } }));
62536
+ app.get("/", (c) => c.json({
62537
+ status: "ok",
62538
+ message: "Claudish Proxy",
62539
+ config: { mode: monitorMode ? "monitor" : "hybrid", mappings: modelMap }
62540
+ }));
62126
62541
  app.get("/health", (c) => c.json({ status: "ok" }));
62127
62542
  app.post("/v1/messages/count_tokens", async (c) => {
62128
62543
  try {
@@ -62133,7 +62548,11 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
62133
62548
  const headers = { "Content-Type": "application/json" };
62134
62549
  if (anthropicApiKey)
62135
62550
  headers["x-api-key"] = anthropicApiKey;
62136
- const res = await fetch("https://api.anthropic.com/v1/messages/count_tokens", { method: "POST", headers, body: JSON.stringify(body) });
62551
+ const res = await fetch("https://api.anthropic.com/v1/messages/count_tokens", {
62552
+ method: "POST",
62553
+ headers,
62554
+ body: JSON.stringify(body)
62555
+ });
62137
62556
  return c.json(await res.json());
62138
62557
  } else {
62139
62558
  const txt = JSON.stringify(body);
@@ -62177,6 +62596,7 @@ var init_proxy_server = __esm(() => {
62177
62596
  init_local_provider_handler();
62178
62597
  init_gemini_handler();
62179
62598
  init_openai_handler();
62599
+ init_anthropic_compat_handler();
62180
62600
  });
62181
62601
 
62182
62602
  // src/update-checker.ts
@@ -62186,24 +62606,24 @@ __export(exports_update_checker, {
62186
62606
  });
62187
62607
  import { execSync } from "node:child_process";
62188
62608
  import { createInterface as createInterface2 } from "node:readline";
62189
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync12, mkdirSync as mkdirSync9, unlinkSync as unlinkSync2 } from "node:fs";
62190
- import { join as join12 } from "node:path";
62191
- import { tmpdir as tmpdir2, homedir as homedir6, platform } from "node:os";
62609
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync13, mkdirSync as mkdirSync10, unlinkSync as unlinkSync2 } from "node:fs";
62610
+ import { join as join13 } from "node:path";
62611
+ import { tmpdir as tmpdir2, homedir as homedir7, platform } from "node:os";
62192
62612
  function getCacheFilePath() {
62193
62613
  let cacheDir;
62194
62614
  if (isWindows2) {
62195
- const localAppData = process.env.LOCALAPPDATA || join12(homedir6(), "AppData", "Local");
62196
- cacheDir = join12(localAppData, "claudish");
62615
+ const localAppData = process.env.LOCALAPPDATA || join13(homedir7(), "AppData", "Local");
62616
+ cacheDir = join13(localAppData, "claudish");
62197
62617
  } else {
62198
- cacheDir = join12(homedir6(), ".cache", "claudish");
62618
+ cacheDir = join13(homedir7(), ".cache", "claudish");
62199
62619
  }
62200
62620
  try {
62201
62621
  if (!existsSync7(cacheDir)) {
62202
- mkdirSync9(cacheDir, { recursive: true });
62622
+ mkdirSync10(cacheDir, { recursive: true });
62203
62623
  }
62204
- return join12(cacheDir, "update-check.json");
62624
+ return join13(cacheDir, "update-check.json");
62205
62625
  } catch {
62206
- return join12(tmpdir2(), "claudish-update-check.json");
62626
+ return join13(tmpdir2(), "claudish-update-check.json");
62207
62627
  }
62208
62628
  }
62209
62629
  function readCache() {
@@ -62225,7 +62645,7 @@ function writeCache(latestVersion) {
62225
62645
  lastCheck: Date.now(),
62226
62646
  latestVersion
62227
62647
  };
62228
- writeFileSync12(cachePath, JSON.stringify(data), "utf-8");
62648
+ writeFileSync13(cachePath, JSON.stringify(data), "utf-8");
62229
62649
  } catch {}
62230
62650
  }
62231
62651
  function isCacheValid(cache) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "3.1.3",
3
+ "version": "3.2.0",
4
4
  "description": "Run Claude Code with any model - OpenRouter, Ollama, LM Studio & local models",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -47,13 +47,7 @@
47
47
  "jest-environment-node": "^30.2.0",
48
48
  "typescript": "^5.9.3"
49
49
  },
50
- "files": [
51
- "dist/",
52
- "scripts/",
53
- "skills/",
54
- "AI_AGENT_GUIDE.md",
55
- "recommended-models.json"
56
- ],
50
+ "files": ["dist/", "scripts/", "skills/", "AI_AGENT_GUIDE.md", "recommended-models.json"],
57
51
  "engines": {
58
52
  "node": ">=18.0.0",
59
53
  "bun": ">=1.0.0"