claudish 5.1.2 → 5.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.
package/AI_AGENT_GUIDE.md CHANGED
@@ -256,6 +256,26 @@ for (const model of models) {
256
256
  | `--debug` / `-d` | Debug logging to file | Disabled |
257
257
  | `--no-auto-approve` | Require prompts | Auto-approve enabled |
258
258
 
259
+ ### Claude Code Flag Passthrough
260
+
261
+ Any Claude Code flag that claudish doesn't recognize is automatically forwarded. This means you can use:
262
+
263
+ ```bash
264
+ # Agent selection
265
+ claudish --model grok --agent code-review --stdin --quiet < prompt.md
266
+
267
+ # Effort and budget control
268
+ claudish --model grok --effort high --max-budget-usd 0.50 --stdin --quiet < prompt.md
269
+
270
+ # Permission mode
271
+ claudish --model grok --permission-mode plan --stdin --quiet < prompt.md
272
+ ```
273
+
274
+ Use `--` separator when flag values start with `-`:
275
+ ```bash
276
+ claudish --model grok -- --system-prompt "-v mode" --stdin --quiet < prompt.md
277
+ ```
278
+
259
279
  ## Common Workflows
260
280
 
261
281
  ### Workflow 1: Quick Code Fix (Grok)
package/dist/index.js CHANGED
@@ -6,39 +6,60 @@ var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ function __accessProp(key) {
10
+ return this[key];
11
+ }
12
+ var __toESMCache_node;
13
+ var __toESMCache_esm;
9
14
  var __toESM = (mod, isNodeMode, target) => {
15
+ var canCache = mod != null && typeof mod === "object";
16
+ if (canCache) {
17
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
18
+ var cached = cache.get(mod);
19
+ if (cached)
20
+ return cached;
21
+ }
10
22
  target = mod != null ? __create(__getProtoOf(mod)) : {};
11
23
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
12
24
  for (let key of __getOwnPropNames(mod))
13
25
  if (!__hasOwnProp.call(to, key))
14
26
  __defProp(to, key, {
15
- get: () => mod[key],
27
+ get: __accessProp.bind(mod, key),
16
28
  enumerable: true
17
29
  });
30
+ if (canCache)
31
+ cache.set(mod, to);
18
32
  return to;
19
33
  };
20
- var __moduleCache = /* @__PURE__ */ new WeakMap;
21
34
  var __toCommonJS = (from) => {
22
- var entry = __moduleCache.get(from), desc;
35
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
23
36
  if (entry)
24
37
  return entry;
25
38
  entry = __defProp({}, "__esModule", { value: true });
26
- if (from && typeof from === "object" || typeof from === "function")
27
- __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
28
- get: () => from[key],
29
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
30
- }));
39
+ if (from && typeof from === "object" || typeof from === "function") {
40
+ for (var key of __getOwnPropNames(from))
41
+ if (!__hasOwnProp.call(entry, key))
42
+ __defProp(entry, key, {
43
+ get: __accessProp.bind(from, key),
44
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
45
+ });
46
+ }
31
47
  __moduleCache.set(from, entry);
32
48
  return entry;
33
49
  };
50
+ var __moduleCache;
34
51
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
52
+ var __returnValue = (v) => v;
53
+ function __exportSetter(name, newValue) {
54
+ this[name] = __returnValue.bind(null, newValue);
55
+ }
35
56
  var __export = (target, all) => {
36
57
  for (var name in all)
37
58
  __defProp(target, name, {
38
59
  get: all[name],
39
60
  enumerable: true,
40
61
  configurable: true,
41
- set: (newValue) => all[name] = () => newValue
62
+ set: __exportSetter.bind(all, name)
42
63
  });
43
64
  };
44
65
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -33320,6 +33341,275 @@ var init_remote_provider_registry = __esm(() => {
33320
33341
  init_model_parser();
33321
33342
  });
33322
33343
 
33344
+ // src/auth/oauth-registry.ts
33345
+ import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
33346
+ import { join as join8 } from "node:path";
33347
+ import { homedir as homedir7 } from "node:os";
33348
+ function hasValidOAuthCredentials(descriptor) {
33349
+ const credPath = join8(homedir7(), ".claudish", descriptor.credentialFile);
33350
+ if (!existsSync8(credPath))
33351
+ return false;
33352
+ if (descriptor.validationMode === "file-exists") {
33353
+ return true;
33354
+ }
33355
+ try {
33356
+ const data = JSON.parse(readFileSync7(credPath, "utf-8"));
33357
+ if (!data.access_token)
33358
+ return false;
33359
+ if (data.refresh_token)
33360
+ return true;
33361
+ if (descriptor.expiresAtField && data[descriptor.expiresAtField]) {
33362
+ const buffer = descriptor.expiryBufferMs ?? 0;
33363
+ return data[descriptor.expiresAtField] > Date.now() + buffer;
33364
+ }
33365
+ return true;
33366
+ } catch {
33367
+ return false;
33368
+ }
33369
+ }
33370
+ function hasOAuthCredentials(providerName) {
33371
+ const descriptor = OAUTH_PROVIDERS[providerName];
33372
+ if (!descriptor)
33373
+ return false;
33374
+ return hasValidOAuthCredentials(descriptor);
33375
+ }
33376
+ var OAUTH_PROVIDERS;
33377
+ var init_oauth_registry = __esm(() => {
33378
+ OAUTH_PROVIDERS = {
33379
+ "kimi-coding": {
33380
+ credentialFile: "kimi-oauth.json",
33381
+ validationMode: "check-expiry",
33382
+ expiresAtField: "expires_at",
33383
+ expiryBufferMs: 5 * 60 * 1000
33384
+ },
33385
+ kimi: {
33386
+ credentialFile: "kimi-oauth.json",
33387
+ validationMode: "check-expiry",
33388
+ expiresAtField: "expires_at",
33389
+ expiryBufferMs: 5 * 60 * 1000
33390
+ },
33391
+ google: {
33392
+ credentialFile: "gemini-oauth.json",
33393
+ validationMode: "check-expiry",
33394
+ expiresAtField: "expires_at",
33395
+ expiryBufferMs: 5 * 60 * 1000
33396
+ },
33397
+ "gemini-codeassist": {
33398
+ credentialFile: "gemini-oauth.json",
33399
+ validationMode: "check-expiry",
33400
+ expiresAtField: "expires_at",
33401
+ expiryBufferMs: 5 * 60 * 1000
33402
+ }
33403
+ };
33404
+ });
33405
+
33406
+ // src/providers/auto-route.ts
33407
+ import { existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
33408
+ import { join as join9 } from "node:path";
33409
+ import { homedir as homedir8 } from "node:os";
33410
+ import { createHash as createHash3 } from "node:crypto";
33411
+ function readLiteLLMCacheSync(baseUrl) {
33412
+ const hash2 = createHash3("sha256").update(baseUrl).digest("hex").substring(0, 16);
33413
+ const cachePath = join9(homedir8(), ".claudish", `litellm-models-${hash2}.json`);
33414
+ if (!existsSync9(cachePath))
33415
+ return null;
33416
+ try {
33417
+ const data = JSON.parse(readFileSync8(cachePath, "utf-8"));
33418
+ if (!Array.isArray(data.models))
33419
+ return null;
33420
+ return data.models;
33421
+ } catch {
33422
+ return null;
33423
+ }
33424
+ }
33425
+ function checkOAuthForProvider(nativeProvider, modelName) {
33426
+ if (!hasOAuthCredentials(nativeProvider))
33427
+ return null;
33428
+ return {
33429
+ provider: nativeProvider,
33430
+ resolvedModelId: modelName,
33431
+ modelName,
33432
+ reason: "oauth-credentials",
33433
+ displayMessage: `Auto-routed: ${modelName} -> ${nativeProvider} (oauth)`
33434
+ };
33435
+ }
33436
+ function checkApiKeyForProvider(nativeProvider, modelName) {
33437
+ const keyInfo = API_KEY_ENV_VARS[nativeProvider];
33438
+ if (!keyInfo)
33439
+ return null;
33440
+ if (keyInfo.envVar && process.env[keyInfo.envVar]) {
33441
+ return {
33442
+ provider: nativeProvider,
33443
+ resolvedModelId: modelName,
33444
+ modelName,
33445
+ reason: "api-key",
33446
+ displayMessage: `Auto-routed: ${modelName} -> ${nativeProvider} (api-key)`
33447
+ };
33448
+ }
33449
+ if (keyInfo.aliases) {
33450
+ for (const alias of keyInfo.aliases) {
33451
+ if (process.env[alias]) {
33452
+ return {
33453
+ provider: nativeProvider,
33454
+ resolvedModelId: modelName,
33455
+ modelName,
33456
+ reason: "api-key",
33457
+ displayMessage: `Auto-routed: ${modelName} -> ${nativeProvider} (api-key)`
33458
+ };
33459
+ }
33460
+ }
33461
+ }
33462
+ return null;
33463
+ }
33464
+ function formatForOpenRouter(modelName, nativeProvider) {
33465
+ if (modelName.includes("/")) {
33466
+ return modelName;
33467
+ }
33468
+ const vendor = OPENROUTER_VENDOR_MAP[nativeProvider];
33469
+ if (vendor) {
33470
+ return `${vendor}/${modelName}`;
33471
+ }
33472
+ return modelName;
33473
+ }
33474
+ function getAutoRouteHint(modelName, nativeProvider) {
33475
+ const hint = PROVIDER_HINT_MAP[nativeProvider];
33476
+ const lines = [
33477
+ `No credentials found for "${modelName}". Options:`
33478
+ ];
33479
+ let hasOption = false;
33480
+ if (hint?.loginFlag) {
33481
+ lines.push(` Run: claudish ${hint.loginFlag} (authenticate via OAuth)`);
33482
+ hasOption = true;
33483
+ }
33484
+ if (hint?.apiKeyEnvVar) {
33485
+ lines.push(` Set: export ${hint.apiKeyEnvVar}=your-key`);
33486
+ hasOption = true;
33487
+ }
33488
+ if (hint?.openRouterModel) {
33489
+ lines.push(` Use: claudish --model or@${hint.openRouterModel} (route via OpenRouter)`);
33490
+ hasOption = true;
33491
+ }
33492
+ if (!hasOption) {
33493
+ return null;
33494
+ }
33495
+ lines.push(` Or set OPENROUTER_API_KEY for automatic OpenRouter fallback`);
33496
+ return lines.join(`
33497
+ `);
33498
+ }
33499
+ function autoRoute(modelName, nativeProvider) {
33500
+ const litellmBaseUrl = process.env.LITELLM_BASE_URL;
33501
+ if (litellmBaseUrl) {
33502
+ const models = readLiteLLMCacheSync(litellmBaseUrl);
33503
+ if (models !== null) {
33504
+ const match = models.find((m) => m.name === modelName || m.id === `litellm@${modelName}`);
33505
+ if (match) {
33506
+ return {
33507
+ provider: "litellm",
33508
+ resolvedModelId: `litellm@${modelName}`,
33509
+ modelName,
33510
+ reason: "litellm-cache",
33511
+ displayMessage: `Auto-routed: ${modelName} -> litellm`
33512
+ };
33513
+ }
33514
+ }
33515
+ }
33516
+ if (nativeProvider !== "unknown") {
33517
+ const oauthResult = checkOAuthForProvider(nativeProvider, modelName);
33518
+ if (oauthResult)
33519
+ return oauthResult;
33520
+ }
33521
+ if (nativeProvider !== "unknown") {
33522
+ const apiKeyResult = checkApiKeyForProvider(nativeProvider, modelName);
33523
+ if (apiKeyResult)
33524
+ return apiKeyResult;
33525
+ }
33526
+ if (process.env.OPENROUTER_API_KEY) {
33527
+ const orModelId = formatForOpenRouter(modelName, nativeProvider);
33528
+ return {
33529
+ provider: "openrouter",
33530
+ resolvedModelId: orModelId,
33531
+ modelName,
33532
+ reason: "openrouter-fallback",
33533
+ displayMessage: `Auto-routed: ${modelName} -> openrouter`
33534
+ };
33535
+ }
33536
+ return null;
33537
+ }
33538
+ var API_KEY_ENV_VARS, OPENROUTER_VENDOR_MAP, PROVIDER_HINT_MAP;
33539
+ var init_auto_route = __esm(() => {
33540
+ init_oauth_registry();
33541
+ API_KEY_ENV_VARS = {
33542
+ google: { envVar: "GEMINI_API_KEY" },
33543
+ "gemini-codeassist": { envVar: "GEMINI_API_KEY" },
33544
+ openai: { envVar: "OPENAI_API_KEY" },
33545
+ minimax: { envVar: "MINIMAX_API_KEY" },
33546
+ "minimax-coding": { envVar: "MINIMAX_CODING_API_KEY" },
33547
+ kimi: { envVar: "MOONSHOT_API_KEY", aliases: ["KIMI_API_KEY"] },
33548
+ "kimi-coding": { envVar: "KIMI_CODING_API_KEY" },
33549
+ glm: { envVar: "ZHIPU_API_KEY", aliases: ["GLM_API_KEY"] },
33550
+ "glm-coding": { envVar: "GLM_CODING_API_KEY", aliases: ["ZAI_CODING_API_KEY"] },
33551
+ zai: { envVar: "ZAI_API_KEY" },
33552
+ ollamacloud: { envVar: "OLLAMA_API_KEY" },
33553
+ litellm: { envVar: "LITELLM_API_KEY" },
33554
+ openrouter: { envVar: "OPENROUTER_API_KEY" },
33555
+ vertex: { envVar: "VERTEX_API_KEY", aliases: ["VERTEX_PROJECT"] },
33556
+ poe: { envVar: "POE_API_KEY" }
33557
+ };
33558
+ OPENROUTER_VENDOR_MAP = {
33559
+ google: "google",
33560
+ openai: "openai",
33561
+ kimi: "moonshot",
33562
+ "kimi-coding": "moonshot",
33563
+ glm: "zhipuai",
33564
+ "glm-coding": "zhipuai",
33565
+ minimax: "minimax",
33566
+ ollamacloud: "meta-llama"
33567
+ };
33568
+ PROVIDER_HINT_MAP = {
33569
+ "kimi-coding": {
33570
+ loginFlag: "--kimi-login",
33571
+ apiKeyEnvVar: "KIMI_CODING_API_KEY",
33572
+ openRouterModel: "moonshot/kimi-k2"
33573
+ },
33574
+ kimi: {
33575
+ loginFlag: "--kimi-login",
33576
+ apiKeyEnvVar: "MOONSHOT_API_KEY",
33577
+ openRouterModel: "moonshot/moonshot-v1-8k"
33578
+ },
33579
+ google: {
33580
+ loginFlag: "--gemini-login",
33581
+ apiKeyEnvVar: "GEMINI_API_KEY",
33582
+ openRouterModel: "google/gemini-2.0-flash"
33583
+ },
33584
+ "gemini-codeassist": {
33585
+ loginFlag: "--gemini-login",
33586
+ apiKeyEnvVar: "GEMINI_API_KEY",
33587
+ openRouterModel: "google/gemini-2.0-flash"
33588
+ },
33589
+ openai: {
33590
+ apiKeyEnvVar: "OPENAI_API_KEY",
33591
+ openRouterModel: "openai/gpt-4o"
33592
+ },
33593
+ minimax: {
33594
+ apiKeyEnvVar: "MINIMAX_API_KEY",
33595
+ openRouterModel: "minimax/minimax-01"
33596
+ },
33597
+ "minimax-coding": {
33598
+ apiKeyEnvVar: "MINIMAX_CODING_API_KEY"
33599
+ },
33600
+ glm: {
33601
+ apiKeyEnvVar: "ZHIPU_API_KEY",
33602
+ openRouterModel: "zhipuai/glm-4"
33603
+ },
33604
+ "glm-coding": {
33605
+ apiKeyEnvVar: "GLM_CODING_API_KEY"
33606
+ },
33607
+ ollamacloud: {
33608
+ apiKeyEnvVar: "OLLAMA_API_KEY"
33609
+ }
33610
+ };
33611
+ });
33612
+
33323
33613
  // src/providers/provider-resolver.ts
33324
33614
  var exports_provider_resolver = {};
33325
33615
  __export(exports_provider_resolver, {
@@ -33331,9 +33621,9 @@ __export(exports_provider_resolver, {
33331
33621
  getMissingKeyResolutions: () => getMissingKeyResolutions,
33332
33622
  getMissingKeyError: () => getMissingKeyError
33333
33623
  });
33334
- import { existsSync as existsSync8 } from "node:fs";
33335
- import { join as join8 } from "node:path";
33336
- import { homedir as homedir7 } from "node:os";
33624
+ import { existsSync as existsSync10 } from "node:fs";
33625
+ import { join as join10 } from "node:path";
33626
+ import { homedir as homedir9 } from "node:os";
33337
33627
  function isApiKeyAvailable(info) {
33338
33628
  if (!info.envVar) {
33339
33629
  return true;
@@ -33350,8 +33640,8 @@ function isApiKeyAvailable(info) {
33350
33640
  }
33351
33641
  if (info.oauthFallback) {
33352
33642
  try {
33353
- const credPath = join8(homedir7(), ".claudish", info.oauthFallback);
33354
- if (existsSync8(credPath)) {
33643
+ const credPath = join10(homedir9(), ".claudish", info.oauthFallback);
33644
+ if (existsSync10(credPath)) {
33355
33645
  return true;
33356
33646
  }
33357
33647
  } catch {}
@@ -33442,6 +33732,43 @@ function resolveModelProvider(modelId) {
33442
33732
  apiKeyUrl: info.url
33443
33733
  });
33444
33734
  }
33735
+ let pendingAutoRouteMessage;
33736
+ if (!parsed.isExplicitProvider && parsed.provider !== "native-anthropic") {
33737
+ const autoResult = autoRoute(parsed.model, parsed.provider);
33738
+ if (autoResult) {
33739
+ if (autoResult.provider === "litellm") {
33740
+ const info = API_KEY_INFO.litellm;
33741
+ return addCommonFields({
33742
+ category: "direct-api",
33743
+ providerName: "LiteLLM",
33744
+ modelName: autoResult.modelName,
33745
+ fullModelId: autoResult.resolvedModelId,
33746
+ requiredApiKeyEnvVar: info.envVar || null,
33747
+ apiKeyAvailable: isApiKeyAvailable(info),
33748
+ apiKeyDescription: info.description,
33749
+ apiKeyUrl: info.url,
33750
+ wasAutoRouted: true,
33751
+ autoRouteMessage: autoResult.displayMessage
33752
+ });
33753
+ }
33754
+ if (autoResult.provider === "openrouter") {
33755
+ const info = API_KEY_INFO.openrouter;
33756
+ return addCommonFields({
33757
+ category: "openrouter",
33758
+ providerName: "OpenRouter",
33759
+ modelName: autoResult.modelName,
33760
+ fullModelId: autoResult.resolvedModelId,
33761
+ requiredApiKeyEnvVar: info.envVar,
33762
+ apiKeyAvailable: isApiKeyAvailable(info),
33763
+ apiKeyDescription: info.description,
33764
+ apiKeyUrl: info.url,
33765
+ wasAutoRouted: true,
33766
+ autoRouteMessage: autoResult.displayMessage
33767
+ });
33768
+ }
33769
+ pendingAutoRouteMessage = autoResult.displayMessage;
33770
+ }
33771
+ }
33445
33772
  const remoteResolved = resolveRemoteProvider(modelId);
33446
33773
  if (remoteResolved) {
33447
33774
  const provider = remoteResolved.provider;
@@ -33451,6 +33778,7 @@ function resolveModelProvider(modelId) {
33451
33778
  url: ""
33452
33779
  };
33453
33780
  const providerDisplayName = PROVIDER_DISPLAY_NAMES[provider.name] || provider.name.charAt(0).toUpperCase() + provider.name.slice(1);
33781
+ const wasAutoRouted = !parsed.isExplicitProvider;
33454
33782
  return addCommonFields({
33455
33783
  category: "direct-api",
33456
33784
  providerName: providerDisplayName,
@@ -33459,7 +33787,9 @@ function resolveModelProvider(modelId) {
33459
33787
  requiredApiKeyEnvVar: info.envVar || null,
33460
33788
  apiKeyAvailable: isApiKeyAvailable(info),
33461
33789
  apiKeyDescription: info.envVar ? info.description : null,
33462
- apiKeyUrl: info.envVar ? info.url : null
33790
+ apiKeyUrl: info.envVar ? info.url : null,
33791
+ wasAutoRouted,
33792
+ autoRouteMessage: wasAutoRouted ? pendingAutoRouteMessage ?? `Auto-routed: ${parsed.model} -> ${providerDisplayName}` : undefined
33463
33793
  });
33464
33794
  }
33465
33795
  if (parsed.provider === "unknown") {
@@ -33522,6 +33852,16 @@ function getMissingKeyError(resolution) {
33522
33852
  lines.push("");
33523
33853
  lines.push(`Get your API key from: ${resolution.apiKeyUrl}`);
33524
33854
  }
33855
+ {
33856
+ const parsed = resolution.parsed;
33857
+ if (parsed && !parsed.isExplicitProvider && parsed.provider !== "unknown" && parsed.provider !== "native-anthropic") {
33858
+ const hint = getAutoRouteHint(parsed.model, parsed.provider);
33859
+ if (hint) {
33860
+ lines.push("");
33861
+ lines.push(hint);
33862
+ }
33863
+ }
33864
+ }
33525
33865
  if (resolution.category === "openrouter") {
33526
33866
  const provider = resolution.fullModelId.split("/")[0];
33527
33867
  lines.push("");
@@ -33582,6 +33922,7 @@ var API_KEY_INFO, PROVIDER_DISPLAY_NAMES;
33582
33922
  var init_provider_resolver = __esm(() => {
33583
33923
  init_provider_registry();
33584
33924
  init_remote_provider_registry();
33925
+ init_auto_route();
33585
33926
  init_model_parser();
33586
33927
  API_KEY_INFO = {
33587
33928
  openrouter: {
@@ -33697,16 +34038,16 @@ __export(exports_cli, {
33697
34038
  getMissingKeyResolutions: () => getMissingKeyResolutions,
33698
34039
  getMissingKeyError: () => getMissingKeyError
33699
34040
  });
33700
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync6, copyFileSync, readdirSync, unlinkSync as unlinkSync3 } from "node:fs";
34041
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync6, copyFileSync, readdirSync, unlinkSync as unlinkSync3 } from "node:fs";
33701
34042
  import { fileURLToPath as fileURLToPath4 } from "node:url";
33702
- import { dirname as dirname4, join as join9 } from "node:path";
33703
- import { homedir as homedir8 } from "node:os";
34043
+ import { dirname as dirname4, join as join11 } from "node:path";
34044
+ import { homedir as homedir10 } from "node:os";
33704
34045
  function getVersion() {
33705
34046
  return VERSION;
33706
34047
  }
33707
34048
  function clearAllModelCaches() {
33708
- const cacheDir = join9(homedir8(), ".claudish");
33709
- if (!existsSync9(cacheDir))
34049
+ const cacheDir = join11(homedir10(), ".claudish");
34050
+ if (!existsSync11(cacheDir))
33710
34051
  return;
33711
34052
  const cachePatterns = ["all-models.json", "pricing-cache.json"];
33712
34053
  let cleared = 0;
@@ -33714,7 +34055,7 @@ function clearAllModelCaches() {
33714
34055
  const files = readdirSync(cacheDir);
33715
34056
  for (const file2 of files) {
33716
34057
  if (cachePatterns.includes(file2) || file2.startsWith("litellm-models-")) {
33717
- unlinkSync3(join9(cacheDir, file2));
34058
+ unlinkSync3(join11(cacheDir, file2));
33718
34059
  cleared++;
33719
34060
  }
33720
34061
  }
@@ -33889,9 +34230,16 @@ async function parseArgs(args) {
33889
34230
  process.exit(0);
33890
34231
  } else if (arg === "--summarize-tools") {
33891
34232
  config3.summarizeTools = true;
33892
- } else {
33893
- config3.claudeArgs = args.slice(i);
34233
+ } else if (arg === "--") {
34234
+ config3.claudeArgs.push(...args.slice(i + 1));
33894
34235
  break;
34236
+ } else if (arg.startsWith("-")) {
34237
+ config3.claudeArgs.push(arg);
34238
+ if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
34239
+ config3.claudeArgs.push(args[++i]);
34240
+ }
34241
+ } else {
34242
+ config3.claudeArgs.push(arg);
33895
34243
  }
33896
34244
  i++;
33897
34245
  }
@@ -33983,9 +34331,9 @@ async function fetchOllamaModels() {
33983
34331
  }
33984
34332
  async function searchAndPrintModels(query, forceUpdate) {
33985
34333
  let models = [];
33986
- if (!forceUpdate && existsSync9(ALL_MODELS_JSON_PATH2)) {
34334
+ if (!forceUpdate && existsSync11(ALL_MODELS_JSON_PATH2)) {
33987
34335
  try {
33988
- const cacheData = JSON.parse(readFileSync7(ALL_MODELS_JSON_PATH2, "utf-8"));
34336
+ const cacheData = JSON.parse(readFileSync9(ALL_MODELS_JSON_PATH2, "utf-8"));
33989
34337
  const lastUpdated = new Date(cacheData.lastUpdated);
33990
34338
  const now = new Date;
33991
34339
  const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
@@ -34153,9 +34501,9 @@ Found ${results.length} matching models:
34153
34501
  async function printAllModels(jsonOutput, forceUpdate) {
34154
34502
  let models = [];
34155
34503
  const [ollamaModels, zenModels] = await Promise.all([fetchOllamaModels(), fetchZenModels()]);
34156
- if (!forceUpdate && existsSync9(ALL_MODELS_JSON_PATH2)) {
34504
+ if (!forceUpdate && existsSync11(ALL_MODELS_JSON_PATH2)) {
34157
34505
  try {
34158
- const cacheData = JSON.parse(readFileSync7(ALL_MODELS_JSON_PATH2, "utf-8"));
34506
+ const cacheData = JSON.parse(readFileSync9(ALL_MODELS_JSON_PATH2, "utf-8"));
34159
34507
  const lastUpdated = new Date(cacheData.lastUpdated);
34160
34508
  const now = new Date;
34161
34509
  const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
@@ -34356,11 +34704,11 @@ async function printAllModels(jsonOutput, forceUpdate) {
34356
34704
  console.log("Top models: claudish --top-models");
34357
34705
  }
34358
34706
  function isCacheStale() {
34359
- if (!existsSync9(MODELS_JSON_PATH)) {
34707
+ if (!existsSync11(MODELS_JSON_PATH)) {
34360
34708
  return true;
34361
34709
  }
34362
34710
  try {
34363
- const jsonContent = readFileSync7(MODELS_JSON_PATH, "utf-8");
34711
+ const jsonContent = readFileSync9(MODELS_JSON_PATH, "utf-8");
34364
34712
  const data = JSON.parse(jsonContent);
34365
34713
  if (!data.lastUpdated) {
34366
34714
  return true;
@@ -34455,9 +34803,9 @@ async function updateModelsFromOpenRouter() {
34455
34803
  providers.add(provider);
34456
34804
  }
34457
34805
  let version2 = "1.1.5";
34458
- if (existsSync9(MODELS_JSON_PATH)) {
34806
+ if (existsSync11(MODELS_JSON_PATH)) {
34459
34807
  try {
34460
- const existing = JSON.parse(readFileSync7(MODELS_JSON_PATH, "utf-8"));
34808
+ const existing = JSON.parse(readFileSync9(MODELS_JSON_PATH, "utf-8"));
34461
34809
  version2 = existing.version || version2;
34462
34810
  } catch {}
34463
34811
  }
@@ -34485,7 +34833,7 @@ async function checkAndUpdateModelsCache(forceUpdate = false) {
34485
34833
  await updateModelsFromOpenRouter();
34486
34834
  } else {
34487
34835
  try {
34488
- const data = JSON.parse(readFileSync7(MODELS_JSON_PATH, "utf-8"));
34836
+ const data = JSON.parse(readFileSync9(MODELS_JSON_PATH, "utf-8"));
34489
34837
  console.error(`✓ Using cached models (last updated: ${data.lastUpdated})`);
34490
34838
  } catch {}
34491
34839
  }
@@ -34575,6 +34923,19 @@ OPTIONS:
34575
34923
  -h, --help Show this help message
34576
34924
  --help-ai Show AI agent usage guide (file-based patterns, sub-agents)
34577
34925
  --init Install Claudish skill in current project (.claude/skills/)
34926
+ -- Separator: everything after passes directly to Claude Code
34927
+
34928
+ CLAUDE CODE FLAG PASSTHROUGH:
34929
+ Any unrecognized flag is automatically forwarded to Claude Code.
34930
+ Claudish flags (--model, --stdin, --quiet, etc.) can appear in any order.
34931
+
34932
+ Examples:
34933
+ claudish --model grok --agent test "task" # --agent passes to Claude Code
34934
+ claudish --model grok --effort high --stdin "task" # --effort passes, --stdin stays
34935
+ claudish --model grok --permission-mode plan -i # Works in interactive mode too
34936
+
34937
+ Use -- when a Claude Code flag value starts with '-':
34938
+ claudish --model grok -- --system-prompt "-verbose mode" "task"
34578
34939
 
34579
34940
  PROFILE MANAGEMENT:
34580
34941
  claudish init [--local|--global] Setup wizard - create config and first profile
@@ -34789,8 +35150,8 @@ MORE INFO:
34789
35150
  }
34790
35151
  function printAIAgentGuide() {
34791
35152
  try {
34792
- const guidePath = join9(__dirname5, "../AI_AGENT_GUIDE.md");
34793
- const guideContent = readFileSync7(guidePath, "utf-8");
35153
+ const guidePath = join11(__dirname5, "../AI_AGENT_GUIDE.md");
35154
+ const guideContent = readFileSync9(guidePath, "utf-8");
34794
35155
  console.log(guideContent);
34795
35156
  } catch (error46) {
34796
35157
  console.error("Error reading AI Agent Guide:");
@@ -34806,19 +35167,19 @@ async function initializeClaudishSkill() {
34806
35167
  console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
34807
35168
  `);
34808
35169
  const cwd = process.cwd();
34809
- const claudeDir = join9(cwd, ".claude");
34810
- const skillsDir = join9(claudeDir, "skills");
34811
- const claudishSkillDir = join9(skillsDir, "claudish-usage");
34812
- const skillFile = join9(claudishSkillDir, "SKILL.md");
34813
- if (existsSync9(skillFile)) {
35170
+ const claudeDir = join11(cwd, ".claude");
35171
+ const skillsDir = join11(claudeDir, "skills");
35172
+ const claudishSkillDir = join11(skillsDir, "claudish-usage");
35173
+ const skillFile = join11(claudishSkillDir, "SKILL.md");
35174
+ if (existsSync11(skillFile)) {
34814
35175
  console.log("✅ Claudish skill already installed at:");
34815
35176
  console.log(` ${skillFile}
34816
35177
  `);
34817
35178
  console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
34818
35179
  return;
34819
35180
  }
34820
- const sourceSkillPath = join9(__dirname5, "../skills/claudish-usage/SKILL.md");
34821
- if (!existsSync9(sourceSkillPath)) {
35181
+ const sourceSkillPath = join11(__dirname5, "../skills/claudish-usage/SKILL.md");
35182
+ if (!existsSync11(sourceSkillPath)) {
34822
35183
  console.error("❌ Error: Claudish skill file not found in installation.");
34823
35184
  console.error(` Expected at: ${sourceSkillPath}`);
34824
35185
  console.error(`
@@ -34827,15 +35188,15 @@ async function initializeClaudishSkill() {
34827
35188
  process.exit(1);
34828
35189
  }
34829
35190
  try {
34830
- if (!existsSync9(claudeDir)) {
35191
+ if (!existsSync11(claudeDir)) {
34831
35192
  mkdirSync6(claudeDir, { recursive: true });
34832
35193
  console.log("\uD83D\uDCC1 Created .claude/ directory");
34833
35194
  }
34834
- if (!existsSync9(skillsDir)) {
35195
+ if (!existsSync11(skillsDir)) {
34835
35196
  mkdirSync6(skillsDir, { recursive: true });
34836
35197
  console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
34837
35198
  }
34838
- if (!existsSync9(claudishSkillDir)) {
35199
+ if (!existsSync11(claudishSkillDir)) {
34839
35200
  mkdirSync6(claudishSkillDir, { recursive: true });
34840
35201
  console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
34841
35202
  }
@@ -34878,8 +35239,8 @@ function printAvailableModels() {
34878
35239
  let lastUpdated = "unknown";
34879
35240
  let models = [];
34880
35241
  try {
34881
- if (existsSync9(MODELS_JSON_PATH)) {
34882
- const data = JSON.parse(readFileSync7(MODELS_JSON_PATH, "utf-8"));
35242
+ if (existsSync11(MODELS_JSON_PATH)) {
35243
+ const data = JSON.parse(readFileSync9(MODELS_JSON_PATH, "utf-8"));
34883
35244
  lastUpdated = data.lastUpdated || "unknown";
34884
35245
  models = data.models || [];
34885
35246
  }
@@ -34932,9 +35293,9 @@ Force update: claudish --list-models --force-update
34932
35293
  `);
34933
35294
  }
34934
35295
  function printAvailableModelsJSON() {
34935
- const jsonPath = join9(__dirname5, "../recommended-models.json");
35296
+ const jsonPath = join11(__dirname5, "../recommended-models.json");
34936
35297
  try {
34937
- const jsonContent = readFileSync7(jsonPath, "utf-8");
35298
+ const jsonContent = readFileSync9(jsonPath, "utf-8");
34938
35299
  const data = JSON.parse(jsonContent);
34939
35300
  const outputData = {
34940
35301
  ...data,
@@ -35026,7 +35387,7 @@ async function fetchGLMCodingModels2() {
35026
35387
  return [];
35027
35388
  }
35028
35389
  }
35029
- var __filename5, __dirname5, VERSION = "5.1.2", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
35390
+ var __filename5, __dirname5, VERSION = "5.3.0", CACHE_MAX_AGE_DAYS3 = 2, MODELS_JSON_PATH, CLAUDISH_CACHE_DIR3, ALL_MODELS_JSON_PATH2;
35030
35391
  var init_cli = __esm(() => {
35031
35392
  init_config();
35032
35393
  init_model_loader();
@@ -35035,12 +35396,12 @@ var init_cli = __esm(() => {
35035
35396
  __filename5 = fileURLToPath4(import.meta.url);
35036
35397
  __dirname5 = dirname4(__filename5);
35037
35398
  try {
35038
- const packageJson = JSON.parse(readFileSync7(join9(__dirname5, "../package.json"), "utf-8"));
35399
+ const packageJson = JSON.parse(readFileSync9(join11(__dirname5, "../package.json"), "utf-8"));
35039
35400
  VERSION = packageJson.version;
35040
35401
  } catch {}
35041
- MODELS_JSON_PATH = join9(__dirname5, "../recommended-models.json");
35042
- CLAUDISH_CACHE_DIR3 = join9(homedir8(), ".claudish");
35043
- ALL_MODELS_JSON_PATH2 = join9(CLAUDISH_CACHE_DIR3, "all-models.json");
35402
+ MODELS_JSON_PATH = join11(__dirname5, "../recommended-models.json");
35403
+ CLAUDISH_CACHE_DIR3 = join11(homedir10(), ".claudish");
35404
+ ALL_MODELS_JSON_PATH2 = join11(CLAUDISH_CACHE_DIR3, "all-models.json");
35044
35405
  });
35045
35406
 
35046
35407
  // src/claude-runner.ts
@@ -35050,17 +35411,17 @@ __export(exports_claude_runner, {
35050
35411
  checkClaudeInstalled: () => checkClaudeInstalled
35051
35412
  });
35052
35413
  import { spawn } from "node:child_process";
35053
- import { writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, mkdirSync as mkdirSync7, existsSync as existsSync10 } from "node:fs";
35054
- import { tmpdir, homedir as homedir9 } from "node:os";
35055
- import { join as join10 } from "node:path";
35414
+ import { writeFileSync as writeFileSync7, unlinkSync as unlinkSync4, mkdirSync as mkdirSync7, existsSync as existsSync12, readFileSync as readFileSync10 } from "node:fs";
35415
+ import { tmpdir, homedir as homedir11 } from "node:os";
35416
+ import { join as join12 } from "node:path";
35056
35417
  function isWindows() {
35057
35418
  return process.platform === "win32";
35058
35419
  }
35059
35420
  function createStatusLineScript(tokenFilePath) {
35060
35421
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir();
35061
- const claudishDir = join10(homeDir, ".claudish");
35422
+ const claudishDir = join12(homeDir, ".claudish");
35062
35423
  const timestamp = Date.now();
35063
- const scriptPath = join10(claudishDir, `status-${timestamp}.js`);
35424
+ const scriptPath = join12(claudishDir, `status-${timestamp}.js`);
35064
35425
  const escapedTokenPath = tokenFilePath.replace(/\\/g, "\\\\");
35065
35426
  const script = `
35066
35427
  const fs = require('fs');
@@ -35145,13 +35506,13 @@ process.stdin.on('end', () => {
35145
35506
  }
35146
35507
  function createTempSettingsFile(modelDisplay, port) {
35147
35508
  const homeDir = process.env.HOME || process.env.USERPROFILE || tmpdir();
35148
- const claudishDir = join10(homeDir, ".claudish");
35509
+ const claudishDir = join12(homeDir, ".claudish");
35149
35510
  try {
35150
35511
  mkdirSync7(claudishDir, { recursive: true });
35151
35512
  } catch {}
35152
35513
  const timestamp = Date.now();
35153
- const tempPath = join10(claudishDir, `settings-${timestamp}.json`);
35154
- const tokenFilePath = join10(claudishDir, `tokens-${port}.json`);
35514
+ const tempPath = join12(claudishDir, `settings-${timestamp}.json`);
35515
+ const tokenFilePath = join12(claudishDir, `tokens-${port}.json`);
35155
35516
  let statusCommand;
35156
35517
  if (isWindows()) {
35157
35518
  const scriptPath = createStatusLineScript(tokenFilePath);
@@ -35167,22 +35528,45 @@ function createTempSettingsFile(modelDisplay, port) {
35167
35528
  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; }`;
35168
35529
  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 "${CYAN2}${BOLD2}%s${RESET2} ${DIM2}•${RESET2} ${YELLOW2}%s${RESET2} ${DIM2}•${RESET2} ${GREEN2}%s${RESET2} ${DIM2}•${RESET2} ${MAGENTA2}%s${RESET2}\\n" "$DIR" "$MODEL_DISPLAY" "$COST_DISPLAY" "$CTX_DISPLAY"`;
35169
35530
  }
35170
- const settings = {
35171
- statusLine: {
35172
- type: "command",
35173
- command: statusCommand,
35174
- padding: 0
35175
- }
35531
+ const statusLine = {
35532
+ type: "command",
35533
+ command: statusCommand,
35534
+ padding: 0
35176
35535
  };
35536
+ const settings = { statusLine };
35177
35537
  writeFileSync7(tempPath, JSON.stringify(settings, null, 2), "utf-8");
35178
- return tempPath;
35538
+ return { path: tempPath, statusLine };
35539
+ }
35540
+ function mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine) {
35541
+ const idx = config3.claudeArgs.indexOf("--settings");
35542
+ if (idx === -1 || !config3.claudeArgs[idx + 1]) {
35543
+ return;
35544
+ }
35545
+ const userSettingsValue = config3.claudeArgs[idx + 1];
35546
+ try {
35547
+ let userSettings;
35548
+ if (userSettingsValue.trimStart().startsWith("{")) {
35549
+ userSettings = JSON.parse(userSettingsValue);
35550
+ } else {
35551
+ const rawUserSettings = readFileSync10(userSettingsValue, "utf-8");
35552
+ userSettings = JSON.parse(rawUserSettings);
35553
+ }
35554
+ userSettings.statusLine = statusLine;
35555
+ writeFileSync7(tempSettingsPath, JSON.stringify(userSettings, null, 2), "utf-8");
35556
+ } catch {
35557
+ if (!config3.quiet) {
35558
+ console.warn(`[claudish] Warning: could not merge user settings: ${userSettingsValue}`);
35559
+ }
35560
+ }
35561
+ config3.claudeArgs.splice(idx, 2);
35179
35562
  }
35180
35563
  async function runClaudeWithProxy(config3, proxyUrl) {
35181
35564
  const hasProfileMappings = config3.modelOpus || config3.modelSonnet || config3.modelHaiku || config3.modelSubagent;
35182
35565
  const modelId = config3.model || (hasProfileMappings ? undefined : "unknown");
35183
35566
  const portMatch = proxyUrl.match(/:(\d+)/);
35184
35567
  const port = portMatch ? portMatch[1] : "unknown";
35185
- const tempSettingsPath = createTempSettingsFile(modelId, port);
35568
+ const { path: tempSettingsPath, statusLine } = createTempSettingsFile(modelId, port);
35569
+ mergeUserSettingsIfPresent(config3, tempSettingsPath, statusLine);
35186
35570
  const claudeArgs = [];
35187
35571
  claudeArgs.push("--settings", tempSettingsPath);
35188
35572
  if (config3.interactive) {
@@ -35192,6 +35576,7 @@ async function runClaudeWithProxy(config3, proxyUrl) {
35192
35576
  if (config3.dangerous) {
35193
35577
  claudeArgs.push("--dangerouslyDisableSandbox");
35194
35578
  }
35579
+ claudeArgs.push(...config3.claudeArgs);
35195
35580
  } else {
35196
35581
  claudeArgs.push("-p");
35197
35582
  if (config3.autoApprove) {
@@ -35203,14 +35588,7 @@ async function runClaudeWithProxy(config3, proxyUrl) {
35203
35588
  if (config3.jsonOutput) {
35204
35589
  claudeArgs.push("--output-format", "json");
35205
35590
  }
35206
- if (config3.agent && config3.claudeArgs.length > 0) {
35207
- const modifiedArgs = [...config3.claudeArgs];
35208
- const agentId = config3.agent.startsWith("@agent-") ? config3.agent : `@agent-${config3.agent}`;
35209
- modifiedArgs[0] = `Use the ${agentId} agent to: ${modifiedArgs[0]}`;
35210
- claudeArgs.push(...modifiedArgs);
35211
- } else {
35212
- claudeArgs.push(...config3.claudeArgs);
35213
- }
35591
+ claudeArgs.push(...config3.claudeArgs);
35214
35592
  }
35215
35593
  const isLocalModel2 = modelId ? modelId.startsWith("ollama/") || modelId.startsWith("ollama:") || modelId.startsWith("lmstudio/") || modelId.startsWith("lmstudio:") || modelId.startsWith("vllm/") || modelId.startsWith("vllm:") || modelId.startsWith("mlx/") || modelId.startsWith("mlx:") || modelId.startsWith("http://") || modelId.startsWith("https://") : false;
35216
35594
  const modelDisplayName = modelId || config3.profile || "default";
@@ -35257,8 +35635,8 @@ async function runClaudeWithProxy(config3, proxyUrl) {
35257
35635
  console.error("Install it from: https://claude.com/claude-code");
35258
35636
  console.error(`
35259
35637
  Or set CLAUDE_PATH to your custom installation:`);
35260
- const home = homedir9();
35261
- const localPath = isWindows() ? join10(home, ".claude", "local", "claude.exe") : join10(home, ".claude", "local", "claude");
35638
+ const home = homedir11();
35639
+ const localPath = isWindows() ? join12(home, ".claude", "local", "claude.exe") : join12(home, ".claude", "local", "claude");
35262
35640
  console.error(` export CLAUDE_PATH=${localPath}`);
35263
35641
  process.exit(1);
35264
35642
  }
@@ -35297,23 +35675,23 @@ function setupSignalHandlers(proc, tempSettingsPath, quiet) {
35297
35675
  async function findClaudeBinary() {
35298
35676
  const isWindows2 = process.platform === "win32";
35299
35677
  if (process.env.CLAUDE_PATH) {
35300
- if (existsSync10(process.env.CLAUDE_PATH)) {
35678
+ if (existsSync12(process.env.CLAUDE_PATH)) {
35301
35679
  return process.env.CLAUDE_PATH;
35302
35680
  }
35303
35681
  }
35304
- const home = homedir9();
35305
- const localPath = isWindows2 ? join10(home, ".claude", "local", "claude.exe") : join10(home, ".claude", "local", "claude");
35306
- if (existsSync10(localPath)) {
35682
+ const home = homedir11();
35683
+ const localPath = isWindows2 ? join12(home, ".claude", "local", "claude.exe") : join12(home, ".claude", "local", "claude");
35684
+ if (existsSync12(localPath)) {
35307
35685
  return localPath;
35308
35686
  }
35309
35687
  if (isWindows2) {
35310
35688
  const windowsPaths = [
35311
- join10(home, "AppData", "Roaming", "npm", "claude.cmd"),
35312
- join10(home, ".npm-global", "claude.cmd"),
35313
- join10(home, "node_modules", ".bin", "claude.cmd")
35689
+ join12(home, "AppData", "Roaming", "npm", "claude.cmd"),
35690
+ join12(home, ".npm-global", "claude.cmd"),
35691
+ join12(home, "node_modules", ".bin", "claude.cmd")
35314
35692
  ];
35315
35693
  for (const path of windowsPaths) {
35316
- if (existsSync10(path)) {
35694
+ if (existsSync12(path)) {
35317
35695
  return path;
35318
35696
  }
35319
35697
  }
@@ -35321,14 +35699,14 @@ async function findClaudeBinary() {
35321
35699
  const commonPaths = [
35322
35700
  "/usr/local/bin/claude",
35323
35701
  "/opt/homebrew/bin/claude",
35324
- join10(home, ".npm-global/bin/claude"),
35325
- join10(home, ".local/bin/claude"),
35326
- join10(home, "node_modules/.bin/claude"),
35702
+ join12(home, ".npm-global/bin/claude"),
35703
+ join12(home, ".local/bin/claude"),
35704
+ join12(home, "node_modules/.bin/claude"),
35327
35705
  "/data/data/com.termux/files/usr/bin/claude",
35328
- join10(home, "../usr/bin/claude")
35706
+ join12(home, "../usr/bin/claude")
35329
35707
  ];
35330
35708
  for (const path of commonPaths) {
35331
- if (existsSync10(path)) {
35709
+ if (existsSync12(path)) {
35332
35710
  return path;
35333
35711
  }
35334
35712
  }
@@ -61219,9 +61597,9 @@ var init_gemini_codeassist = __esm(() => {
61219
61597
  // src/auth/vertex-auth.ts
61220
61598
  import { exec as exec4 } from "node:child_process";
61221
61599
  import { promisify as promisify3 } from "node:util";
61222
- import { existsSync as existsSync11 } from "node:fs";
61223
- import { homedir as homedir10 } from "node:os";
61224
- import { join as join11 } from "node:path";
61600
+ import { existsSync as existsSync13 } from "node:fs";
61601
+ import { homedir as homedir12 } from "node:os";
61602
+ import { join as join13 } from "node:path";
61225
61603
 
61226
61604
  class VertexAuthManager {
61227
61605
  cachedToken = null;
@@ -61275,8 +61653,8 @@ class VertexAuthManager {
61275
61653
  }
61276
61654
  async tryADC() {
61277
61655
  try {
61278
- const adcPath = join11(homedir10(), ".config/gcloud/application_default_credentials.json");
61279
- if (!existsSync11(adcPath)) {
61656
+ const adcPath = join13(homedir12(), ".config/gcloud/application_default_credentials.json");
61657
+ if (!existsSync13(adcPath)) {
61280
61658
  log("[VertexAuth] ADC credentials file not found");
61281
61659
  return null;
61282
61660
  }
@@ -61300,7 +61678,7 @@ class VertexAuthManager {
61300
61678
  if (!credPath) {
61301
61679
  return null;
61302
61680
  }
61303
- if (!existsSync11(credPath)) {
61681
+ if (!existsSync13(credPath)) {
61304
61682
  throw new Error(`Service account file not found: ${credPath}
61305
61683
 
61306
61684
  Check GOOGLE_APPLICATION_CREDENTIALS path.`);
@@ -61339,8 +61717,8 @@ function validateVertexOAuthConfig() {
61339
61717
  ` + ` export VERTEX_PROJECT='your-gcp-project-id'
61340
61718
  ` + " export VERTEX_LOCATION='us-central1' # optional";
61341
61719
  }
61342
- const adcPath = join11(homedir10(), ".config/gcloud/application_default_credentials.json");
61343
- const hasADC = existsSync11(adcPath);
61720
+ const adcPath = join13(homedir12(), ".config/gcloud/application_default_credentials.json");
61721
+ const hasADC = existsSync13(adcPath);
61344
61722
  const hasServiceAccount = !!process.env.GOOGLE_APPLICATION_CREDENTIALS;
61345
61723
  if (!hasADC && !hasServiceAccount) {
61346
61724
  return `No Vertex AI credentials found.
@@ -61736,8 +62114,8 @@ var init_middleware = __esm(() => {
61736
62114
 
61737
62115
  // src/handlers/shared/token-tracker.ts
61738
62116
  import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
61739
- import { homedir as homedir11 } from "node:os";
61740
- import { join as join12 } from "node:path";
62117
+ import { homedir as homedir13 } from "node:os";
62118
+ import { join as join14 } from "node:path";
61741
62119
 
61742
62120
  class TokenTracker {
61743
62121
  port;
@@ -61851,9 +62229,9 @@ class TokenTracker {
61851
62229
  is_free: isFreeModel,
61852
62230
  is_estimated: isEstimate || false
61853
62231
  };
61854
- const claudishDir = join12(homedir11(), ".claudish");
62232
+ const claudishDir = join14(homedir13(), ".claudish");
61855
62233
  mkdirSync8(claudishDir, { recursive: true });
61856
- writeFileSync8(join12(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
62234
+ writeFileSync8(join14(claudishDir, `tokens-${this.port}.json`), JSON.stringify(data), "utf-8");
61857
62235
  } catch (e) {
61858
62236
  log(`[TokenTracker] Error writing token file: ${e}`);
61859
62237
  }
@@ -63048,10 +63426,10 @@ var init_litellm = __esm(() => {
63048
63426
  });
63049
63427
 
63050
63428
  // src/adapters/litellm-adapter.ts
63051
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
63052
- import { createHash as createHash3 } from "node:crypto";
63053
- import { homedir as homedir12 } from "node:os";
63054
- import { join as join13 } from "node:path";
63429
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "node:fs";
63430
+ import { createHash as createHash4 } from "node:crypto";
63431
+ import { homedir as homedir14 } from "node:os";
63432
+ import { join as join15 } from "node:path";
63055
63433
  var INLINE_IMAGE_MODEL_PATTERNS, LiteLLMAdapter;
63056
63434
  var init_litellm_adapter = __esm(() => {
63057
63435
  init_base_adapter();
@@ -63146,11 +63524,11 @@ var init_litellm_adapter = __esm(() => {
63146
63524
  }
63147
63525
  checkVisionSupport() {
63148
63526
  try {
63149
- const hash2 = createHash3("sha256").update(this.baseUrl).digest("hex").substring(0, 16);
63150
- const cachePath = join13(homedir12(), ".claudish", `litellm-models-${hash2}.json`);
63151
- if (!existsSync12(cachePath))
63527
+ const hash2 = createHash4("sha256").update(this.baseUrl).digest("hex").substring(0, 16);
63528
+ const cachePath = join15(homedir14(), ".claudish", `litellm-models-${hash2}.json`);
63529
+ if (!existsSync14(cachePath))
63152
63530
  return true;
63153
- const cacheData = JSON.parse(readFileSync9(cachePath, "utf-8"));
63531
+ const cacheData = JSON.parse(readFileSync12(cachePath, "utf-8"));
63154
63532
  const model = cacheData.models?.find((m) => m.name === this.modelId);
63155
63533
  if (model && model.supportsVision === false) {
63156
63534
  log(`[LiteLLMAdapter] Model ${this.modelId} does not support vision`);
@@ -63268,12 +63646,12 @@ class AnthropicCompatProvider {
63268
63646
  }
63269
63647
  if (this.provider.name === "kimi-coding" && !this.apiKey) {
63270
63648
  try {
63271
- const { existsSync: existsSync13, readFileSync: readFileSync10 } = await import("node:fs");
63272
- const { join: join14 } = await import("node:path");
63273
- const { homedir: homedir13 } = await import("node:os");
63274
- const credPath = join14(homedir13(), ".claudish", "kimi-oauth.json");
63275
- if (existsSync13(credPath)) {
63276
- const data = JSON.parse(readFileSync10(credPath, "utf-8"));
63649
+ const { existsSync: existsSync15, readFileSync: readFileSync13 } = await import("node:fs");
63650
+ const { join: join16 } = await import("node:path");
63651
+ const { homedir: homedir15 } = await import("node:os");
63652
+ const credPath = join16(homedir15(), ".claudish", "kimi-oauth.json");
63653
+ if (existsSync15(credPath)) {
63654
+ const data = JSON.parse(readFileSync13(credPath, "utf-8"));
63277
63655
  if (data.access_token && data.refresh_token) {
63278
63656
  const { KimiOAuth: KimiOAuth2 } = await Promise.resolve().then(() => (init_kimi_oauth(), exports_kimi_oauth));
63279
63657
  const oauth = KimiOAuth2.getInstance();
@@ -63495,9 +63873,9 @@ var init_ollamacloud_adapter = __esm(() => {
63495
63873
  });
63496
63874
 
63497
63875
  // src/services/pricing-cache.ts
63498
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync13, mkdirSync as mkdirSync9, statSync } from "node:fs";
63499
- import { homedir as homedir13 } from "node:os";
63500
- import { join as join14 } from "node:path";
63876
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync15, mkdirSync as mkdirSync9, statSync } from "node:fs";
63877
+ import { homedir as homedir15 } from "node:os";
63878
+ import { join as join16 } from "node:path";
63501
63879
  function getDynamicPricingSync(provider, modelName) {
63502
63880
  if (provider === "openrouter") {
63503
63881
  const direct = pricingMap.get(modelName);
@@ -63562,12 +63940,12 @@ async function warmPricingCache() {
63562
63940
  }
63563
63941
  function loadDiskCache() {
63564
63942
  try {
63565
- if (!existsSync13(CACHE_FILE))
63943
+ if (!existsSync15(CACHE_FILE))
63566
63944
  return false;
63567
63945
  const stat = statSync(CACHE_FILE);
63568
63946
  const age = Date.now() - stat.mtimeMs;
63569
63947
  const isFresh = age < CACHE_TTL_MS;
63570
- const raw2 = readFileSync10(CACHE_FILE, "utf-8");
63948
+ const raw2 = readFileSync13(CACHE_FILE, "utf-8");
63571
63949
  const data = JSON.parse(raw2);
63572
63950
  for (const [key, pricing] of Object.entries(data)) {
63573
63951
  pricingMap.set(key, pricing);
@@ -63614,8 +63992,8 @@ var init_pricing_cache = __esm(() => {
63614
63992
  init_model_loader();
63615
63993
  init_remote_provider_types();
63616
63994
  pricingMap = new Map;
63617
- CACHE_DIR = join14(homedir13(), ".claudish");
63618
- CACHE_FILE = join14(CACHE_DIR, "pricing-cache.json");
63995
+ CACHE_DIR = join16(homedir15(), ".claudish");
63996
+ CACHE_FILE = join16(CACHE_DIR, "pricing-cache.json");
63619
63997
  CACHE_TTL_MS = 24 * 60 * 60 * 1000;
63620
63998
  PROVIDER_TO_OR_PREFIX = {
63621
63999
  openai: ["openai/"],
@@ -63710,11 +64088,18 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
63710
64088
  return remoteProviderHandlers.get(targetModel);
63711
64089
  }
63712
64090
  const resolution = resolveModelProvider(targetModel);
64091
+ if (resolution.wasAutoRouted && resolution.autoRouteMessage) {
64092
+ console.error(`[Auto-route] ${resolution.autoRouteMessage}`);
64093
+ }
63713
64094
  if (resolution.category === "openrouter") {
64095
+ if (resolution.wasAutoRouted && resolution.fullModelId) {
64096
+ return getOpenRouterHandler(resolution.fullModelId);
64097
+ }
63714
64098
  return null;
63715
64099
  }
64100
+ const resolveTarget = resolution.wasAutoRouted && resolution.fullModelId ? resolution.fullModelId : targetModel;
63716
64101
  if (resolution.category === "direct-api" && resolution.apiKeyAvailable) {
63717
- const resolved = resolveRemoteProvider(targetModel);
64102
+ const resolved = resolveRemoteProvider(resolveTarget);
63718
64103
  if (!resolved)
63719
64104
  return null;
63720
64105
  if (resolved.provider.name === "openrouter") {
@@ -63838,11 +64223,19 @@ async function createProxyServer(port, openrouterApiKey, model, monitorMode = fa
63838
64223
  } else {
63839
64224
  return null;
63840
64225
  }
63841
- remoteProviderHandlers.set(targetModel, handler);
64226
+ remoteProviderHandlers.set(resolveTarget, handler);
64227
+ if (resolveTarget !== targetModel) {
64228
+ remoteProviderHandlers.set(targetModel, handler);
64229
+ }
63842
64230
  return handler;
63843
64231
  }
63844
64232
  return null;
63845
64233
  };
64234
+ if (process.env.LITELLM_BASE_URL && process.env.LITELLM_API_KEY) {
64235
+ fetchLiteLLMModels(process.env.LITELLM_BASE_URL, process.env.LITELLM_API_KEY).then(() => {
64236
+ log("[Proxy] LiteLLM model cache pre-warmed for auto-routing");
64237
+ }).catch(() => {});
64238
+ }
63846
64239
  const getHandlerForRequest = (requestedModel) => {
63847
64240
  if (monitorMode)
63848
64241
  return nativeHandler;
@@ -63965,6 +64358,7 @@ var init_proxy_server = __esm(() => {
63965
64358
  init_vertex_auth();
63966
64359
  init_provider_resolver();
63967
64360
  init_pricing_cache();
64361
+ init_model_loader();
63968
64362
  });
63969
64363
 
63970
64364
  // src/update-checker.ts
@@ -63976,9 +64370,9 @@ __export(exports_update_checker, {
63976
64370
  checkForUpdates: () => checkForUpdates
63977
64371
  });
63978
64372
  import { execSync } from "node:child_process";
63979
- import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync11, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "node:fs";
63980
- import { homedir as homedir14, platform as platform2, tmpdir as tmpdir2 } from "node:os";
63981
- import { join as join15 } from "node:path";
64373
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "node:fs";
64374
+ import { homedir as homedir16, platform as platform2, tmpdir as tmpdir2 } from "node:os";
64375
+ import { join as join17 } from "node:path";
63982
64376
  import { createInterface as createInterface2 } from "node:readline";
63983
64377
  function getUpdateCommand() {
63984
64378
  const scriptPath = process.argv[1] || "";
@@ -63990,27 +64384,27 @@ function getUpdateCommand() {
63990
64384
  function getCacheFilePath() {
63991
64385
  let cacheDir;
63992
64386
  if (isWindows2) {
63993
- const localAppData = process.env.LOCALAPPDATA || join15(homedir14(), "AppData", "Local");
63994
- cacheDir = join15(localAppData, "claudish");
64387
+ const localAppData = process.env.LOCALAPPDATA || join17(homedir16(), "AppData", "Local");
64388
+ cacheDir = join17(localAppData, "claudish");
63995
64389
  } else {
63996
- cacheDir = join15(homedir14(), ".cache", "claudish");
64390
+ cacheDir = join17(homedir16(), ".cache", "claudish");
63997
64391
  }
63998
64392
  try {
63999
- if (!existsSync14(cacheDir)) {
64393
+ if (!existsSync16(cacheDir)) {
64000
64394
  mkdirSync10(cacheDir, { recursive: true });
64001
64395
  }
64002
- return join15(cacheDir, "update-check.json");
64396
+ return join17(cacheDir, "update-check.json");
64003
64397
  } catch {
64004
- return join15(tmpdir2(), "claudish-update-check.json");
64398
+ return join17(tmpdir2(), "claudish-update-check.json");
64005
64399
  }
64006
64400
  }
64007
64401
  function readCache() {
64008
64402
  try {
64009
64403
  const cachePath = getCacheFilePath();
64010
- if (!existsSync14(cachePath)) {
64404
+ if (!existsSync16(cachePath)) {
64011
64405
  return null;
64012
64406
  }
64013
- const data = JSON.parse(readFileSync11(cachePath, "utf-8"));
64407
+ const data = JSON.parse(readFileSync14(cachePath, "utf-8"));
64014
64408
  return data;
64015
64409
  } catch {
64016
64410
  return null;
@@ -64033,7 +64427,7 @@ function isCacheValid(cache) {
64033
64427
  function clearCache() {
64034
64428
  try {
64035
64429
  const cachePath = getCacheFilePath();
64036
- if (existsSync14(cachePath)) {
64430
+ if (existsSync16(cachePath)) {
64037
64431
  unlinkSync5(cachePath);
64038
64432
  }
64039
64433
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "5.1.2",
3
+ "version": "5.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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.2.0",
3
- "lastUpdated": "2026-02-25",
3
+ "lastUpdated": "2026-03-02",
4
4
  "source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
5
5
  "models": [
6
6
  {