claudish 4.2.0 → 4.3.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 +92 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -28165,9 +28165,9 @@ var init_profile_config = __esm(() => {
28165
28165
  name: "default",
28166
28166
  description: "Default profile - balanced performance and cost",
28167
28167
  models: {
28168
- opus: "x-ai/grok-3-beta",
28169
- sonnet: "x-ai/grok-code-fast-1",
28170
- haiku: "google/gemini-2.5-flash"
28168
+ opus: "xai@grok-4-0709",
28169
+ sonnet: "xai@grok-4-1-fast-reasoning",
28170
+ haiku: "xai@grok-code-fast-1"
28171
28171
  },
28172
28172
  createdAt: new Date().toISOString(),
28173
28173
  updatedAt: new Date().toISOString()
@@ -31144,6 +31144,13 @@ const DIM = "\\x1b[2m";
31144
31144
  const RESET = "\\x1b[0m";
31145
31145
  const BOLD = "\\x1b[1m";
31146
31146
 
31147
+ // Format token count with k/M suffix
31148
+ function formatTokens(n) {
31149
+ if (n >= 1000000) return (n / 1000000).toFixed(n >= 10000000 ? 0 : 1).replace(/\\.0$/, '') + 'M';
31150
+ if (n >= 1000) return (n / 1000).toFixed(n >= 10000 ? 0 : 1).replace(/\\.0$/, '') + 'k';
31151
+ return String(n);
31152
+ }
31153
+
31147
31154
  let input = '';
31148
31155
  process.stdin.setEncoding('utf8');
31149
31156
  process.stdin.on('data', chunk => input += chunk);
@@ -31152,7 +31159,7 @@ process.stdin.on('end', () => {
31152
31159
  let dir = path.basename(process.cwd());
31153
31160
  if (dir.length > 15) dir = dir.substring(0, 12) + '...';
31154
31161
 
31155
- let ctx = 100, cost = 0;
31162
+ let ctx = 100, cost = 0, inputTokens = 0, contextWindow = 0;
31156
31163
  const model = process.env.CLAUDISH_ACTIVE_MODEL_NAME || 'unknown';
31157
31164
  const isLocal = process.env.CLAUDISH_IS_LOCAL === 'true';
31158
31165
 
@@ -31161,6 +31168,8 @@ process.stdin.on('end', () => {
31161
31168
  const tokens = JSON.parse(fs.readFileSync('${escapedTokenPath}', 'utf-8'));
31162
31169
  cost = tokens.total_cost || 0;
31163
31170
  ctx = tokens.context_left_percent || 100;
31171
+ inputTokens = tokens.input_tokens || 0;
31172
+ contextWindow = tokens.context_window || 0;
31164
31173
  isFree = tokens.is_free || false;
31165
31174
  isEstimated = tokens.is_estimated || false;
31166
31175
  providerName = tokens.provider_name || '';
@@ -31182,7 +31191,12 @@ process.stdin.on('end', () => {
31182
31191
  costDisplay = '$' + cost.toFixed(3);
31183
31192
  }
31184
31193
  const modelDisplay = providerName ? providerName + ' ' + model : model;
31185
- console.log(\`\${CYAN}\${BOLD}\${dir}\${RESET} \${DIM}•\${RESET} \${YELLOW}\${modelDisplay}\${RESET} \${DIM}•\${RESET} \${GREEN}\${costDisplay}\${RESET} \${DIM}•\${RESET} \${MAGENTA}\${ctx}%\${RESET}\`);
31194
+ // Format context display: "96% (37k/1M)" or just "96%" if no token data
31195
+ let ctxDisplay = ctx + '%';
31196
+ if (inputTokens > 0 && contextWindow > 0) {
31197
+ ctxDisplay = ctx + '% (' + formatTokens(inputTokens) + '/' + formatTokens(contextWindow) + ')';
31198
+ }
31199
+ console.log(\`\${CYAN}\${BOLD}\${dir}\${RESET} \${DIM}•\${RESET} \${YELLOW}\${modelDisplay}\${RESET} \${DIM}•\${RESET} \${GREEN}\${costDisplay}\${RESET} \${DIM}•\${RESET} \${MAGENTA}\${ctxDisplay}\${RESET}\`);
31186
31200
  } catch (e) {
31187
31201
  console.log('claudish');
31188
31202
  }
@@ -31212,7 +31226,8 @@ function createTempSettingsFile(modelDisplay, port) {
31212
31226
  const DIM2 = "\\033[2m";
31213
31227
  const RESET2 = "\\033[0m";
31214
31228
  const BOLD2 = "\\033[1m";
31215
- 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="" && 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'"' -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="$CLAUDISH_ACTIVE_MODEL_NAME" && if [ ! -z "$PROVIDER" ]; then MODEL_DISPLAY="$PROVIDER $MODEL_DISPLAY"; fi && printf "${CYAN2}${BOLD2}%s${RESET2} ${DIM2}•${RESET2} ${YELLOW2}%s${RESET2} ${DIM2}•${RESET2} ${GREEN2}%s${RESET2} ${DIM2}•${RESET2} ${MAGENTA}%s%%${RESET2}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX"`;
31229
+ 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; }`;
31230
+ 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="" && 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); 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="$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 "${CYAN2}${BOLD2}%s${RESET2} ${DIM2}•${RESET2} ${YELLOW2}%s${RESET2} ${DIM2}•${RESET2} ${GREEN2}%s${RESET2} ${DIM2}•${RESET2} ${MAGENTA}%s${RESET2}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
31216
31231
  }
31217
31232
  const settings = {
31218
31233
  statusLine: {
@@ -31263,14 +31278,18 @@ async function runClaudeWithProxy(config3, proxyUrl) {
31263
31278
  ...process.env,
31264
31279
  ANTHROPIC_BASE_URL: proxyUrl,
31265
31280
  [ENV.CLAUDISH_ACTIVE_MODEL_NAME]: modelId,
31266
- CLAUDISH_IS_LOCAL: isLocalModel ? "true" : "false",
31267
- [ENV.ANTHROPIC_MODEL]: modelId,
31268
- [ENV.ANTHROPIC_SMALL_FAST_MODEL]: modelId
31281
+ CLAUDISH_IS_LOCAL: isLocalModel ? "true" : "false"
31269
31282
  };
31270
31283
  if (config3.monitor) {
31271
31284
  delete env.ANTHROPIC_API_KEY;
31272
31285
  delete env.ANTHROPIC_AUTH_TOKEN;
31286
+ if (modelId && modelId !== "unknown") {
31287
+ env[ENV.ANTHROPIC_MODEL] = modelId;
31288
+ env[ENV.ANTHROPIC_SMALL_FAST_MODEL] = modelId;
31289
+ }
31273
31290
  } else {
31291
+ env[ENV.ANTHROPIC_MODEL] = modelId;
31292
+ env[ENV.ANTHROPIC_SMALL_FAST_MODEL] = modelId;
31274
31293
  env.ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || "sk-ant-api03-placeholder-not-used-proxy-handles-auth-with-openrouter-key-xxxxxxxxxxxxxxxxxxxxx";
31275
31294
  env.ANTHROPIC_AUTH_TOKEN = process.env.ANTHROPIC_AUTH_TOKEN || "placeholder-token-not-used-proxy-handles-auth";
31276
31295
  }
@@ -32656,14 +32675,11 @@ async function parseArgs(args) {
32656
32675
  if (config3.monitor) {
32657
32676
  if (process.env.ANTHROPIC_API_KEY && process.env.ANTHROPIC_API_KEY.includes("placeholder")) {
32658
32677
  delete process.env.ANTHROPIC_API_KEY;
32659
- if (!config3.quiet) {
32660
- console.log("[claudish] Removed placeholder API key - Claude Code will use native authentication");
32661
- }
32662
32678
  }
32663
32679
  if (!config3.quiet) {
32664
32680
  console.log("[claudish] Monitor mode enabled - proxying to real Anthropic API");
32665
- console.log("[claudish] API key will be extracted from Claude Code's requests");
32666
- console.log("[claudish] Ensure you are logged in to Claude Code (claude auth login)");
32681
+ console.log("[claudish] Using Claude Code's native authentication");
32682
+ console.log("[claudish] Tip: Run with --debug to see request/response details");
32667
32683
  }
32668
32684
  }
32669
32685
  config3.openrouterApiKey = process.env[ENV.OPENROUTER_API_KEY];
@@ -33658,7 +33674,7 @@ async function fetchZenModels() {
33658
33674
  return [];
33659
33675
  }
33660
33676
  }
33661
- var __filename5, __dirname5, VERSION = "4.2.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
33677
+ var __filename5, __dirname5, VERSION = "4.3.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
33662
33678
  var init_cli = __esm(() => {
33663
33679
  init_config();
33664
33680
  init_model_loader();
@@ -35916,20 +35932,15 @@ class NativeHandler {
35916
35932
  baseUrl;
35917
35933
  constructor(apiKey) {
35918
35934
  this.apiKey = apiKey;
35919
- this.baseUrl = process.env.ANTHROPIC_BASE_URL || "https://api.anthropic.com";
35935
+ this.baseUrl = "https://api.anthropic.com";
35920
35936
  }
35921
35937
  async handle(c, payload) {
35922
35938
  const originalHeaders = c.req.header();
35923
35939
  const target = payload.model;
35924
35940
  log(`
35925
35941
  === [NATIVE] Claude Code → Anthropic API Request ===`);
35926
- const extractedApiKey = originalHeaders["x-api-key"] || originalHeaders["authorization"] || this.apiKey;
35927
- if (!extractedApiKey) {
35928
- log("[Native] WARNING: No API key found in headers!");
35929
- log("[Native] Looking for: x-api-key or authorization header");
35930
- } else {
35931
- log(`API Key found: ${maskCredential(extractedApiKey)}`);
35932
- }
35942
+ log(`[Native] x-api-key: ${originalHeaders["x-api-key"] ? maskCredential(originalHeaders["x-api-key"]) : "(not set)"}`);
35943
+ log(`[Native] authorization: ${originalHeaders["authorization"] ? maskCredential(originalHeaders["authorization"]) : "(not set)"}`);
35933
35944
  log(`Request body (Model: ${target}):`);
35934
35945
  log(`=== End Request ===
35935
35946
  `);
@@ -35942,8 +35953,6 @@ class NativeHandler {
35942
35953
  }
35943
35954
  if (originalHeaders["x-api-key"]) {
35944
35955
  headers["x-api-key"] = originalHeaders["x-api-key"];
35945
- } else if (extractedApiKey) {
35946
- headers["x-api-key"] = extractedApiKey;
35947
35956
  }
35948
35957
  if (originalHeaders["anthropic-beta"]) {
35949
35958
  headers["anthropic-beta"] = originalHeaders["anthropic-beta"];
@@ -36238,24 +36247,7 @@ var init_gemini_adapter = __esm(() => {
36238
36247
  this.inReasoningBlock = false;
36239
36248
  this.reasoningBlockDepth = 0;
36240
36249
  }
36241
- prepareRequest(request, originalRequest) {
36242
- if (originalRequest.thinking) {
36243
- const { budget_tokens } = originalRequest.thinking;
36244
- const modelId = this.modelId || "";
36245
- if (modelId.includes("gemini-3")) {
36246
- const level = budget_tokens >= 16000 ? "high" : "low";
36247
- request.thinking_level = level;
36248
- log(`[GeminiAdapter] Mapped budget ${budget_tokens} -> thinking_level: ${level}`);
36249
- } else {
36250
- const MAX_GEMINI_BUDGET = 24576;
36251
- const budget = Math.min(budget_tokens, MAX_GEMINI_BUDGET);
36252
- request.thinking_config = {
36253
- thinking_budget: budget
36254
- };
36255
- log(`[GeminiAdapter] Mapped budget ${budget_tokens} -> thinking_config.thinking_budget: ${budget}`);
36256
- }
36257
- delete request.thinking;
36258
- }
36250
+ prepareRequest(request, _originalRequest) {
36259
36251
  return request;
36260
36252
  }
36261
36253
  extractThoughtSignaturesFromReasoningDetails(reasoningDetails) {
@@ -59592,6 +59584,23 @@ var init_local_provider_handler = __esm(() => {
59592
59584
  });
59593
59585
 
59594
59586
  // src/handlers/shared/gemini-schema.ts
59587
+ function sanitizeToolNameForGemini(name) {
59588
+ if (!name || typeof name !== "string" || name.trim() === "") {
59589
+ log(`[GeminiSchema] Skipping tool with invalid name: ${JSON.stringify(name)}`);
59590
+ return null;
59591
+ }
59592
+ let sanitized = name.replace(/[^a-zA-Z0-9_.\-:]/g, "_");
59593
+ if (!/^[a-zA-Z_]/.test(sanitized)) {
59594
+ sanitized = "_" + sanitized;
59595
+ }
59596
+ if (sanitized.length > 64) {
59597
+ sanitized = sanitized.substring(0, 64);
59598
+ }
59599
+ if (sanitized !== name) {
59600
+ log(`[GeminiSchema] Sanitized tool name: "${name}" -> "${sanitized}"`);
59601
+ }
59602
+ return sanitized;
59603
+ }
59595
59604
  function normalizeType(type) {
59596
59605
  if (!type)
59597
59606
  return "string";
@@ -59641,13 +59650,27 @@ function convertToolsToGemini(tools) {
59641
59650
  if (!tools || tools.length === 0) {
59642
59651
  return;
59643
59652
  }
59644
- const functionDeclarations = tools.map((tool) => ({
59645
- name: tool.name,
59646
- description: tool.description,
59647
- parameters: sanitizeSchemaForGemini(tool.input_schema)
59648
- }));
59653
+ const functionDeclarations = [];
59654
+ for (const tool of tools) {
59655
+ const sanitizedName = sanitizeToolNameForGemini(tool.name);
59656
+ if (!sanitizedName) {
59657
+ log(`[GeminiSchema] Skipping tool without valid name: ${JSON.stringify(tool)}`);
59658
+ continue;
59659
+ }
59660
+ functionDeclarations.push({
59661
+ name: sanitizedName,
59662
+ description: tool.description || "",
59663
+ parameters: sanitizeSchemaForGemini(tool.input_schema)
59664
+ });
59665
+ }
59666
+ if (functionDeclarations.length === 0) {
59667
+ return;
59668
+ }
59649
59669
  return [{ functionDeclarations }];
59650
59670
  }
59671
+ var init_gemini_schema = __esm(() => {
59672
+ init_logger();
59673
+ });
59651
59674
 
59652
59675
  // src/handlers/shared/gemini-queue.ts
59653
59676
  class GeminiRequestQueue {
@@ -60381,6 +60404,7 @@ var init_base_gemini_handler = __esm(() => {
60381
60404
  init_transform();
60382
60405
  init_logger();
60383
60406
  init_openai_compat();
60407
+ init_gemini_schema();
60384
60408
  init_gemini_retry();
60385
60409
  init_remote_provider_types();
60386
60410
  });
@@ -60876,6 +60900,7 @@ var init_gemini_codeassist_handler = __esm(() => {
60876
60900
  init_transform();
60877
60901
  init_logger();
60878
60902
  init_openai_compat();
60903
+ init_gemini_schema();
60879
60904
  init_gemini_retry();
60880
60905
  init_gemini_oauth();
60881
60906
  });
@@ -60909,7 +60934,21 @@ class OpenAIHandler {
60909
60934
  }
60910
60935
  setContextWindow() {
60911
60936
  const model = this.modelName.toLowerCase();
60912
- if (model.includes("gpt-4o") || model.includes("gpt-4-turbo")) {
60937
+ if (model.includes("grok-4.1-fast") || model.includes("grok-4-1-fast")) {
60938
+ this.contextWindow = 2000000;
60939
+ } else if (model.includes("grok-4-fast")) {
60940
+ this.contextWindow = 2000000;
60941
+ } else if (model.includes("grok-code-fast")) {
60942
+ this.contextWindow = 256000;
60943
+ } else if (model.includes("grok-4")) {
60944
+ this.contextWindow = 256000;
60945
+ } else if (model.includes("grok-3")) {
60946
+ this.contextWindow = 131072;
60947
+ } else if (model.includes("grok-2")) {
60948
+ this.contextWindow = 131072;
60949
+ } else if (model.includes("grok")) {
60950
+ this.contextWindow = 131072;
60951
+ } else if (model.includes("gpt-4o") || model.includes("gpt-4-turbo")) {
60913
60952
  this.contextWindow = 128000;
60914
60953
  } else if (model.includes("gpt-5")) {
60915
60954
  this.contextWindow = 256000;
@@ -64307,13 +64346,14 @@ async function runCli() {
64307
64346
  console.error(" export CLAUDE_PATH=~/.claude/local/claude");
64308
64347
  process.exit(1);
64309
64348
  }
64310
- if (cliConfig.interactive && !cliConfig.monitor && !cliConfig.model) {
64349
+ const hasProfileTiers = cliConfig.modelOpus || cliConfig.modelSonnet || cliConfig.modelHaiku || cliConfig.modelSubagent;
64350
+ if (cliConfig.interactive && !cliConfig.monitor && !cliConfig.model && !hasProfileTiers) {
64311
64351
  cliConfig.model = await selectModel2({ freeOnly: cliConfig.freeOnly });
64312
64352
  console.log("");
64313
64353
  }
64314
- if (!cliConfig.interactive && !cliConfig.monitor && !cliConfig.model) {
64354
+ if (!cliConfig.interactive && !cliConfig.monitor && !cliConfig.model && !hasProfileTiers) {
64315
64355
  console.error("Error: Model must be specified in non-interactive mode");
64316
- console.error("Use --model <model> flag or set CLAUDISH_MODEL environment variable");
64356
+ console.error("Use --model <model> flag, set CLAUDISH_MODEL env var, or use --profile");
64317
64357
  console.error("Try: claudish --list-models");
64318
64358
  process.exit(1);
64319
64359
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "4.2.0",
3
+ "version": "4.3.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",