claudish 3.7.2 → 3.7.4

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 +126 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -32160,6 +32160,7 @@ class OpenRouterHandler {
32160
32160
  const total = input + output;
32161
32161
  const limit = this.contextWindowCache.get(this.targetModel) || 200000;
32162
32162
  const leftPct = limit > 0 ? Math.max(0, Math.min(100, Math.round((limit - total) / limit * 100))) : 100;
32163
+ const displayModelName = this.targetModel.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
32163
32164
  const data = {
32164
32165
  input_tokens: input,
32165
32166
  output_tokens: output,
@@ -32167,6 +32168,8 @@ class OpenRouterHandler {
32167
32168
  total_cost: this.sessionTotalCost,
32168
32169
  context_window: limit,
32169
32170
  context_left_percent: leftPct,
32171
+ provider_name: "OpenRouter",
32172
+ model_name: displayModelName,
32170
32173
  updated_at: Date.now()
32171
32174
  };
32172
32175
  const claudishDir = join4(homedir(), ".claudish");
@@ -53115,6 +53118,14 @@ class LocalProviderHandler {
53115
53118
  this.sessionOutputTokens += output;
53116
53119
  const sessionTotal = this.sessionInputTokens + this.sessionOutputTokens;
53117
53120
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - sessionTotal) / this.contextWindow * 100))) : 100;
53121
+ const providerNameMap = {
53122
+ ollama: "Ollama",
53123
+ lmstudio: "LM Studio",
53124
+ vllm: "vLLM",
53125
+ mlx: "MLX",
53126
+ custom: "Custom"
53127
+ };
53128
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
53118
53129
  const data = {
53119
53130
  input_tokens: this.sessionInputTokens,
53120
53131
  output_tokens: this.sessionOutputTokens,
@@ -53122,6 +53133,8 @@ class LocalProviderHandler {
53122
53133
  total_cost: 0,
53123
53134
  context_window: this.contextWindow,
53124
53135
  context_left_percent: leftPct,
53136
+ provider_name: providerNameMap[this.provider.name] || "Local",
53137
+ model_name: displayModelName,
53125
53138
  updated_at: Date.now()
53126
53139
  };
53127
53140
  const claudishDir = join5(homedir2(), ".claudish");
@@ -53853,6 +53866,8 @@ class BaseGeminiHandler {
53853
53866
  try {
53854
53867
  const total = input + output;
53855
53868
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
53869
+ const pricing = this.getPricing();
53870
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
53856
53871
  const data = {
53857
53872
  input_tokens: input,
53858
53873
  output_tokens: output,
@@ -53860,6 +53875,10 @@ class BaseGeminiHandler {
53860
53875
  total_cost: this.sessionTotalCost,
53861
53876
  context_window: this.contextWindow,
53862
53877
  context_left_percent: leftPct,
53878
+ is_free: pricing.isFree || false,
53879
+ is_estimated: pricing.isEstimate || false,
53880
+ provider_name: this.getProviderName(),
53881
+ model_name: displayModelName,
53863
53882
  updated_at: Date.now()
53864
53883
  };
53865
53884
  const claudishDir = join6(homedir3(), ".claudish");
@@ -54366,6 +54385,9 @@ var init_gemini_handler = __esm(() => {
54366
54385
  "x-goog-api-key": this.apiKey
54367
54386
  };
54368
54387
  }
54388
+ getProviderName() {
54389
+ return "Gemini API";
54390
+ }
54369
54391
  };
54370
54392
  });
54371
54393
 
@@ -54851,6 +54873,7 @@ class GeminiCodeAssistHandler {
54851
54873
  const total = input + output;
54852
54874
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
54853
54875
  const pricing = this.getPricing();
54876
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
54854
54877
  const data = {
54855
54878
  input_tokens: input,
54856
54879
  output_tokens: output,
@@ -54860,6 +54883,8 @@ class GeminiCodeAssistHandler {
54860
54883
  context_left_percent: leftPct,
54861
54884
  is_free: pricing.isFree || false,
54862
54885
  is_estimated: pricing.isEstimate || false,
54886
+ provider_name: "Gemini Free",
54887
+ model_name: displayModelName,
54863
54888
  updated_at: Date.now()
54864
54889
  };
54865
54890
  const claudishDir = join8(homedir5(), ".claudish");
@@ -55331,6 +55356,7 @@ class OpenAIHandler {
55331
55356
  try {
55332
55357
  const total = input + output;
55333
55358
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
55359
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
55334
55360
  const data = {
55335
55361
  input_tokens: input,
55336
55362
  output_tokens: output,
@@ -55338,6 +55364,8 @@ class OpenAIHandler {
55338
55364
  total_cost: this.sessionTotalCost,
55339
55365
  context_window: this.contextWindow,
55340
55366
  context_left_percent: leftPct,
55367
+ provider_name: "OpenAI",
55368
+ model_name: displayModelName,
55341
55369
  updated_at: Date.now()
55342
55370
  };
55343
55371
  if (isEstimate) {
@@ -55906,6 +55934,17 @@ class AnthropicCompatHandler {
55906
55934
  try {
55907
55935
  const total = input + output;
55908
55936
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
55937
+ const providerNameMap = {
55938
+ minimax: "MiniMax",
55939
+ kimi: "Kimi",
55940
+ moonshot: "Kimi",
55941
+ glm: "GLM",
55942
+ zhipu: "GLM"
55943
+ };
55944
+ const providerKey = this.provider.name.toLowerCase();
55945
+ const providerDisplayName = providerNameMap[providerKey] || this.provider.name;
55946
+ const pricing = this.getPricing();
55947
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
55909
55948
  const data = {
55910
55949
  input_tokens: input,
55911
55950
  output_tokens: output,
@@ -55913,6 +55952,10 @@ class AnthropicCompatHandler {
55913
55952
  total_cost: this.sessionTotalCost,
55914
55953
  context_window: this.contextWindow,
55915
55954
  context_left_percent: leftPct,
55955
+ is_free: pricing.isFree || false,
55956
+ is_estimated: pricing.isEstimate || false,
55957
+ provider_name: providerDisplayName,
55958
+ model_name: displayModelName,
55916
55959
  updated_at: Date.now()
55917
55960
  };
55918
55961
  const claudishDir = join10(homedir7(), ".claudish");
@@ -56245,6 +56288,8 @@ class VertexOAuthHandler {
56245
56288
  try {
56246
56289
  const total = input + output;
56247
56290
  const leftPct = this.contextWindow > 0 ? Math.max(0, Math.min(100, Math.round((this.contextWindow - total) / this.contextWindow * 100))) : 100;
56291
+ const pricing = this.getPricing();
56292
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
56248
56293
  const data = {
56249
56294
  input_tokens: input,
56250
56295
  output_tokens: output,
@@ -56252,6 +56297,10 @@ class VertexOAuthHandler {
56252
56297
  total_cost: this.sessionTotalCost,
56253
56298
  context_window: this.contextWindow,
56254
56299
  context_left_percent: leftPct,
56300
+ is_free: pricing.isFree || false,
56301
+ is_estimated: pricing.isEstimate || false,
56302
+ provider_name: "Vertex AI",
56303
+ model_name: displayModelName,
56255
56304
  updated_at: Date.now()
56256
56305
  };
56257
56306
  const claudishDir = join12(homedir9(), ".claudish");
@@ -57695,6 +57744,7 @@ class OllamaCloudHandler {
57695
57744
  this.sessionOutputTokens += output;
57696
57745
  const sessionTotal = this.sessionInputTokens + this.sessionOutputTokens;
57697
57746
  const cost = calculateCost(this.provider.name, this.modelName, this.sessionInputTokens, this.sessionOutputTokens);
57747
+ const displayModelName = this.modelName.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\/:]/, "");
57698
57748
  const data = {
57699
57749
  input_tokens: this.sessionInputTokens,
57700
57750
  output_tokens: this.sessionOutputTokens,
@@ -57702,6 +57752,8 @@ class OllamaCloudHandler {
57702
57752
  total_cost: cost,
57703
57753
  context_window: 0,
57704
57754
  context_left_percent: 100,
57755
+ provider_name: "OllamaCloud",
57756
+ model_name: displayModelName,
57705
57757
  updated_at: Date.now()
57706
57758
  };
57707
57759
  const claudishDir = join13(homedir10(), ".claudish");
@@ -62287,6 +62339,13 @@ NOTES:
62287
62339
  ENVIRONMENT VARIABLES:
62288
62340
  Claudish automatically loads .env file from current directory.
62289
62341
 
62342
+ Claude Code installation:
62343
+ CLAUDE_PATH Custom path to Claude Code binary (optional)
62344
+ Default search order:
62345
+ 1. CLAUDE_PATH env var
62346
+ 2. ~/.claude/local/claude (local install)
62347
+ 3. Global PATH (npm -g install)
62348
+
62290
62349
  API Keys (at least one required for cloud models):
62291
62350
  OPENROUTER_API_KEY OpenRouter API key (default backend)
62292
62351
  GEMINI_API_KEY Google Gemini API key (for g/ prefix)
@@ -62944,8 +63003,8 @@ __export(exports_claude_runner, {
62944
63003
  checkClaudeInstalled: () => checkClaudeInstalled
62945
63004
  });
62946
63005
  import { spawn } from "node:child_process";
62947
- import { writeFileSync as writeFileSync15, unlinkSync as unlinkSync3, mkdirSync as mkdirSync13 } from "node:fs";
62948
- import { tmpdir as tmpdir2 } from "node:os";
63006
+ import { writeFileSync as writeFileSync15, unlinkSync as unlinkSync3, mkdirSync as mkdirSync13, existsSync as existsSync11 } from "node:fs";
63007
+ import { tmpdir as tmpdir2, homedir as homedir13 } from "node:os";
62949
63008
  import { join as join19 } from "node:path";
62950
63009
  function isWindows2() {
62951
63010
  return process.platform === "win32";
@@ -62964,6 +63023,7 @@ const CYAN = "\\x1b[96m";
62964
63023
  const YELLOW = "\\x1b[93m";
62965
63024
  const GREEN = "\\x1b[92m";
62966
63025
  const MAGENTA = "\\x1b[95m";
63026
+ const BLUE = "\\x1b[94m";
62967
63027
  const DIM = "\\x1b[2m";
62968
63028
  const RESET = "\\x1b[0m";
62969
63029
  const BOLD = "\\x1b[1m";
@@ -62976,8 +63036,7 @@ process.stdin.on('end', () => {
62976
63036
  let dir = path.basename(process.cwd());
62977
63037
  if (dir.length > 15) dir = dir.substring(0, 12) + '...';
62978
63038
 
62979
- let ctx = 100, cost = 0;
62980
- const model = process.env.CLAUDISH_ACTIVE_MODEL_NAME || 'unknown';
63039
+ let ctx = 100, cost = 0, providerName = '', model = 'unknown';
62981
63040
  const isLocal = process.env.CLAUDISH_IS_LOCAL === 'true';
62982
63041
 
62983
63042
  let isFree = false, isEstimated = false;
@@ -62987,7 +63046,15 @@ process.stdin.on('end', () => {
62987
63046
  ctx = tokens.context_left_percent || 100;
62988
63047
  isFree = tokens.is_free || false;
62989
63048
  isEstimated = tokens.is_estimated || false;
63049
+ providerName = tokens.provider_name || '';
63050
+ // Read model_name from token file, fallback to env var
63051
+ model = tokens.model_name || process.env.CLAUDISH_ACTIVE_MODEL_NAME || 'unknown';
63052
+ // Strip provider prefix if not already stripped in token file
63053
+ model = model.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\\/:]/, '');
62990
63054
  } catch (e) {
63055
+ // Fallback to env var if token file not available
63056
+ const rawModel = process.env.CLAUDISH_ACTIVE_MODEL_NAME || 'unknown';
63057
+ model = rawModel.replace(/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\\/:]/, '');
62991
63058
  try {
62992
63059
  const json = JSON.parse(input);
62993
63060
  cost = json.total_cost_usd || 0;
@@ -63004,7 +63071,13 @@ process.stdin.on('end', () => {
63004
63071
  } else {
63005
63072
  costDisplay = '$' + cost.toFixed(3);
63006
63073
  }
63007
- console.log(\`\${CYAN}\${BOLD}\${dir}\${RESET} \${DIM}•\${RESET} \${YELLOW}\${model}\${RESET} \${DIM}•\${RESET} \${GREEN}\${costDisplay}\${RESET} \${DIM}•\${RESET} \${MAGENTA}\${ctx}%\${RESET}\`);
63074
+
63075
+ // Build status line with provider name
63076
+ if (providerName) {
63077
+ console.log(\`\${CYAN}\${BOLD}\${dir}\${RESET} \${DIM}•\${RESET} \${BLUE}\${providerName}\${RESET} \${DIM}•\${RESET} \${YELLOW}\${model}\${RESET} \${DIM}•\${RESET} \${GREEN}\${costDisplay}\${RESET} \${DIM}•\${RESET} \${MAGENTA}\${ctx}%\${RESET}\`);
63078
+ } else {
63079
+ console.log(\`\${CYAN}\${BOLD}\${dir}\${RESET} \${DIM}•\${RESET} \${YELLOW}\${model}\${RESET} \${DIM}•\${RESET} \${GREEN}\${costDisplay}\${RESET} \${DIM}•\${RESET} \${MAGENTA}\${ctx}%\${RESET}\`);
63080
+ }
63008
63081
  } catch (e) {
63009
63082
  console.log('claudish');
63010
63083
  }
@@ -63013,7 +63086,7 @@ process.stdin.on('end', () => {
63013
63086
  writeFileSync15(scriptPath, script, "utf-8");
63014
63087
  return scriptPath;
63015
63088
  }
63016
- function createTempSettingsFile(modelDisplay, port) {
63089
+ function createTempSettingsFile(port) {
63017
63090
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir2();
63018
63091
  const claudishDir = join19(homeDir, ".claudish");
63019
63092
  try {
@@ -63031,10 +63104,11 @@ function createTempSettingsFile(modelDisplay, port) {
63031
63104
  const YELLOW3 = "\\033[93m";
63032
63105
  const GREEN3 = "\\033[92m";
63033
63106
  const MAGENTA = "\\033[95m";
63107
+ const BLUE = "\\033[94m";
63034
63108
  const DIM2 = "\\033[2m";
63035
63109
  const RESET3 = "\\033[0m";
63036
63110
  const BOLD3 = "\\033[1m";
63037
- statusCommand = `JSON=$(cat) && DIR=$(basename "$(pwd)") && [ \${#DIR} -gt 15 ] && DIR="\${DIR:0:12}..." || true && CTX=100 && COST="0" && IS_FREE="false" && IS_EST="false" && 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 && 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); 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 && printf "${CYAN3}${BOLD3}%s${RESET3} ${DIM2}•${RESET3} ${YELLOW3}%s${RESET3} ${DIM2}•${RESET3} ${GREEN3}%s${RESET3} ${DIM2}•${RESET3} ${MAGENTA}%s%%${RESET3}\\n" "$DIR" "$CLAUDISH_ACTIVE_MODEL_NAME" "$COST_DISPLAY" "$CTX"`;
63111
+ 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="" && MODEL="unknown" && 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 && 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: -f2 | tr -d '"') && MODEL=$(echo "$TOKENS" | grep -o '"model_name":"[^"]*"' | cut -d: -f2 | tr -d '"'); fi && if [ -z "$MODEL" ] || [ "$MODEL" = "unknown" ]; then RAW_MODEL="$CLAUDISH_ACTIVE_MODEL_NAME" && MODEL=$(echo "$RAW_MODEL" | sed -E 's/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\\/:]//'); fi && MODEL=$(echo "$MODEL" | sed -E 's/^(go|g|gemini|v|vertex|oai|mmax|mm|kimi|moonshot|glm|zhipu|oc|ollama|lmstudio|vllm|mlx)[\\/:]//') && 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 && if [ ! -z "$PROVIDER" ]; then printf "${CYAN3}${BOLD3}%s${RESET3} ${DIM2}•${RESET3} ${BLUE}%s${RESET3} ${DIM2}•${RESET3} ${YELLOW3}%s${RESET3} ${DIM2}•${RESET3} ${GREEN3}%s${RESET3} ${DIM2}•${RESET3} ${MAGENTA}%s%%${RESET3}\\n" "$DIR" "$PROVIDER" "$MODEL" "$COST_DISPLAY" "$CTX"; else printf "${CYAN3}${BOLD3}%s${RESET3} ${DIM2}•${RESET3} ${YELLOW3}%s${RESET3} ${DIM2}•${RESET3} ${GREEN3}%s${RESET3} ${DIM2}•${RESET3} ${MAGENTA}%s%%${RESET3}\\n" "$DIR" "$MODEL" "$COST_DISPLAY" "$CTX"; fi`;
63038
63112
  }
63039
63113
  const settings = {
63040
63114
  statusLine: {
@@ -63050,7 +63124,7 @@ async function runClaudeWithProxy(config3, proxyUrl) {
63050
63124
  const modelId = config3.model || "unknown";
63051
63125
  const portMatch = proxyUrl.match(/:(\d+)/);
63052
63126
  const port = portMatch ? portMatch[1] : "unknown";
63053
- const tempSettingsPath = createTempSettingsFile(modelId, port);
63127
+ const tempSettingsPath = createTempSettingsFile(port);
63054
63128
  const claudeArgs = [];
63055
63129
  claudeArgs.push("--settings", tempSettingsPath);
63056
63130
  if (config3.interactive) {
@@ -63109,10 +63183,21 @@ async function runClaudeWithProxy(config3, proxyUrl) {
63109
63183
  log2(`[claudish] Arguments: ${claudeArgs.join(" ")}
63110
63184
  `);
63111
63185
  }
63112
- const proc = spawn("claude", claudeArgs, {
63186
+ const claudeBinary = await findClaudeBinary();
63187
+ if (!claudeBinary) {
63188
+ console.error("Error: Claude Code CLI not found");
63189
+ console.error("Install it from: https://claude.com/claude-code");
63190
+ console.error(`
63191
+ Or set CLAUDE_PATH to your custom installation:`);
63192
+ const home = homedir13();
63193
+ const localPath = isWindows2() ? join19(home, ".claude", "local", "claude.exe") : join19(home, ".claude", "local", "claude");
63194
+ console.error(` export CLAUDE_PATH=${localPath}`);
63195
+ process.exit(1);
63196
+ }
63197
+ const proc = spawn(claudeBinary, claudeArgs, {
63113
63198
  env,
63114
63199
  stdio: "inherit",
63115
- shell: isWindows2()
63200
+ shell: false
63116
63201
  });
63117
63202
  setupSignalHandlers(proc, tempSettingsPath, config3.quiet);
63118
63203
  const exitCode = await new Promise((resolve) => {
@@ -63141,23 +63226,43 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet) {
63141
63226
  });
63142
63227
  }
63143
63228
  }
63144
- async function checkClaudeInstalled() {
63229
+ async function findClaudeBinary() {
63230
+ const isWindows3 = process.platform === "win32";
63231
+ if (process.env.CLAUDE_PATH) {
63232
+ if (existsSync11(process.env.CLAUDE_PATH)) {
63233
+ return process.env.CLAUDE_PATH;
63234
+ }
63235
+ }
63236
+ const home = homedir13();
63237
+ const localPath = isWindows3 ? join19(home, ".claude", "local", "claude.exe") : join19(home, ".claude", "local", "claude");
63238
+ if (existsSync11(localPath)) {
63239
+ return localPath;
63240
+ }
63145
63241
  try {
63146
- const isWindows3 = process.platform === "win32";
63147
63242
  const command = isWindows3 ? "where" : "which";
63148
63243
  const proc = spawn(command, ["claude"], {
63149
- stdio: "ignore",
63244
+ stdio: "pipe",
63150
63245
  shell: isWindows3
63151
63246
  });
63247
+ let output = "";
63248
+ proc.stdout?.on("data", (data) => {
63249
+ output += data.toString();
63250
+ });
63152
63251
  const exitCode = await new Promise((resolve) => {
63153
63252
  proc.on("exit", (code) => {
63154
63253
  resolve(code ?? 1);
63155
63254
  });
63156
63255
  });
63157
- return exitCode === 0;
63158
- } catch {
63159
- return false;
63160
- }
63256
+ if (exitCode === 0 && output.trim()) {
63257
+ return output.trim().split(`
63258
+ `)[0];
63259
+ }
63260
+ } catch {}
63261
+ return null;
63262
+ }
63263
+ async function checkClaudeInstalled() {
63264
+ const binary = await findClaudeBinary();
63265
+ return binary !== null;
63161
63266
  }
63162
63267
  var init_claude_runner = __esm(() => {
63163
63268
  init_dist3();
@@ -63275,8 +63380,11 @@ async function runCli() {
63275
63380
  }
63276
63381
  }
63277
63382
  if (!await checkClaudeInstalled2()) {
63278
- console.error("Error: Claude Code CLI is not installed");
63383
+ console.error("Error: Claude Code CLI not found");
63279
63384
  console.error("Install it from: https://claude.com/claude-code");
63385
+ console.error("");
63386
+ console.error("Or if you have a local installation, set CLAUDE_PATH:");
63387
+ console.error(" export CLAUDE_PATH=~/.claude/local/claude");
63280
63388
  process.exit(1);
63281
63389
  }
63282
63390
  if (cliConfig.interactive && !cliConfig.monitor && !cliConfig.openrouterApiKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "3.7.2",
3
+ "version": "3.7.4",
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",