claudish 1.4.1 → 1.6.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/dist/index.js CHANGED
@@ -1,67 +1,163 @@
1
1
  #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
7
+ var __toCommonJS = (from) => {
8
+ var entry = __moduleCache.get(from), desc;
9
+ if (entry)
10
+ return entry;
11
+ entry = __defProp({}, "__esModule", { value: true });
12
+ if (from && typeof from === "object" || typeof from === "function")
13
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
14
+ get: () => from[key],
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ }));
17
+ __moduleCache.set(from, entry);
18
+ return entry;
19
+ };
20
+ var __export = (target, all) => {
21
+ for (var name in all)
22
+ __defProp(target, name, {
23
+ get: all[name],
24
+ enumerable: true,
25
+ configurable: true,
26
+ set: (newValue) => all[name] = () => newValue
27
+ });
28
+ };
29
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
30
+
31
+ // src/config.ts
32
+ var exports_config = {};
33
+ __export(exports_config, {
34
+ OPENROUTER_HEADERS: () => OPENROUTER_HEADERS,
35
+ OPENROUTER_API_URL: () => OPENROUTER_API_URL,
36
+ MODEL_INFO: () => MODEL_INFO,
37
+ ENV: () => ENV,
38
+ DEFAULT_PORT_RANGE: () => DEFAULT_PORT_RANGE,
39
+ DEFAULT_MODEL: () => DEFAULT_MODEL
40
+ });
41
+ var DEFAULT_MODEL = "x-ai/grok-code-fast-1", DEFAULT_PORT_RANGE, MODEL_INFO, ENV, OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions", OPENROUTER_HEADERS;
42
+ var init_config = __esm(() => {
43
+ DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
44
+ MODEL_INFO = {
45
+ "x-ai/grok-code-fast-1": {
46
+ name: "Ultra-fast coding",
47
+ description: "Ultra-fast coding",
48
+ priority: 1,
49
+ provider: "xAI"
50
+ },
51
+ "minimax/minimax-m2": {
52
+ name: "Compact high-efficiency",
53
+ description: "Compact high-efficiency",
54
+ priority: 2,
55
+ provider: "MiniMax"
56
+ },
57
+ "z-ai/glm-4.6": {
58
+ name: "Enhanced coding capabilities",
59
+ description: "Enhanced coding capabilities",
60
+ priority: 3,
61
+ provider: "Zhipu AI"
62
+ },
63
+ "openai/gpt-5.1-codex": {
64
+ name: "Specialized software engineering",
65
+ description: "Specialized software engineering",
66
+ priority: 4,
67
+ provider: "OpenAI"
68
+ },
69
+ "google/gemini-2.5-flash": {
70
+ name: "Advanced reasoning with built-in thinking",
71
+ description: "Advanced reasoning with built-in thinking",
72
+ priority: 5,
73
+ provider: "Google"
74
+ },
75
+ "google/gemini-2.5-pro": {
76
+ name: "State-of-the-art reasoning",
77
+ description: "State-of-the-art reasoning",
78
+ priority: 6,
79
+ provider: "Google"
80
+ },
81
+ "qwen/qwen3-vl-235b-a22b-instruct": {
82
+ name: "Multimodal vision-language",
83
+ description: "Multimodal vision-language",
84
+ priority: 7,
85
+ provider: "Alibaba"
86
+ },
87
+ "google/gemini-2.0-flash-001": {
88
+ name: "Faster TTFT, multimodal",
89
+ description: "Faster TTFT, multimodal",
90
+ priority: 8,
91
+ provider: "Google"
92
+ },
93
+ "google/gemini-2.5-flash-lite": {
94
+ name: "Ultra-low latency",
95
+ description: "Ultra-low latency",
96
+ priority: 9,
97
+ provider: "Google"
98
+ },
99
+ "deepseek/deepseek-chat-v3-0324": {
100
+ name: "685B parameter MoE",
101
+ description: "685B parameter MoE",
102
+ priority: 10,
103
+ provider: "DeepSeek"
104
+ },
105
+ "openai/gpt-4o-mini": {
106
+ name: "Compact multimodal",
107
+ description: "Compact multimodal",
108
+ priority: 11,
109
+ provider: "OpenAI"
110
+ },
111
+ custom: {
112
+ name: "Custom Model",
113
+ description: "Enter any OpenRouter model ID manually",
114
+ priority: 999,
115
+ provider: "Custom"
116
+ }
117
+ };
118
+ ENV = {
119
+ OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
120
+ CLAUDISH_MODEL: "CLAUDISH_MODEL",
121
+ CLAUDISH_PORT: "CLAUDISH_PORT",
122
+ CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME",
123
+ ANTHROPIC_MODEL: "ANTHROPIC_MODEL",
124
+ ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL"
125
+ };
126
+ OPENROUTER_HEADERS = {
127
+ "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
128
+ "X-Title": "Claudish - OpenRouter Proxy"
129
+ };
130
+ });
131
+
132
+ // src/types.ts
133
+ var exports_types = {};
134
+ __export(exports_types, {
135
+ OPENROUTER_MODELS: () => OPENROUTER_MODELS
136
+ });
137
+ var OPENROUTER_MODELS;
138
+ var init_types = __esm(() => {
139
+ OPENROUTER_MODELS = [
140
+ "x-ai/grok-code-fast-1",
141
+ "minimax/minimax-m2",
142
+ "z-ai/glm-4.6",
143
+ "openai/gpt-5.1-codex",
144
+ "google/gemini-2.5-flash",
145
+ "google/gemini-2.5-pro",
146
+ "qwen/qwen3-vl-235b-a22b-instruct",
147
+ "google/gemini-2.0-flash-001",
148
+ "google/gemini-2.5-flash-lite",
149
+ "deepseek/deepseek-chat-v3-0324",
150
+ "openai/gpt-4o-mini",
151
+ "custom"
152
+ ];
153
+ });
2
154
 
3
155
  // src/claude-runner.ts
156
+ init_config();
4
157
  import { spawn } from "node:child_process";
5
158
  import { writeFileSync, unlinkSync } from "node:fs";
6
159
  import { tmpdir } from "node:os";
7
160
  import { join } from "node:path";
8
-
9
- // src/config.ts
10
- var DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
11
- var MODEL_INFO = {
12
- "x-ai/grok-code-fast-1": {
13
- name: "Grok Code Fast",
14
- description: "xAI's fast coding model",
15
- priority: 1,
16
- provider: "xAI"
17
- },
18
- "openai/gpt-5-codex": {
19
- name: "GPT-5 Codex",
20
- description: "OpenAI's advanced coding model",
21
- priority: 2,
22
- provider: "OpenAI"
23
- },
24
- "minimax/minimax-m2": {
25
- name: "MiniMax M2",
26
- description: "MiniMax's high-performance model",
27
- priority: 3,
28
- provider: "MiniMax"
29
- },
30
- "z-ai/glm-4.6": {
31
- name: "GLM-4.6",
32
- description: "Advanced language model",
33
- priority: 4,
34
- provider: "Zhipu AI"
35
- },
36
- "qwen/qwen3-vl-235b-a22b-instruct": {
37
- name: "Qwen3 VL 235B",
38
- description: "Alibaba's vision-language model",
39
- priority: 5,
40
- provider: "Alibaba"
41
- },
42
- "anthropic/claude-sonnet-4.5": {
43
- name: "Claude Sonnet 4.5",
44
- description: "Anthropic's Claude (for comparison)",
45
- priority: 6,
46
- provider: "Anthropic"
47
- },
48
- custom: {
49
- name: "Custom Model",
50
- description: "Enter any OpenRouter model ID manually",
51
- priority: 999,
52
- provider: "Custom"
53
- }
54
- };
55
- var ENV = {
56
- OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
57
- CLAUDISH_MODEL: "CLAUDISH_MODEL",
58
- CLAUDISH_PORT: "CLAUDISH_PORT",
59
- CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME",
60
- ANTHROPIC_MODEL: "ANTHROPIC_MODEL",
61
- ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL"
62
- };
63
-
64
- // src/claude-runner.ts
65
161
  function createTempSettingsFile(modelDisplay, port) {
66
162
  const tempDir = tmpdir();
67
163
  const timestamp = Date.now();
@@ -194,16 +290,73 @@ async function checkClaudeInstalled() {
194
290
  }
195
291
  }
196
292
 
197
- // src/types.ts
198
- var OPENROUTER_MODELS = [
199
- "x-ai/grok-code-fast-1",
200
- "openai/gpt-5-codex",
201
- "minimax/minimax-m2",
202
- "z-ai/glm-4.6",
203
- "qwen/qwen3-vl-235b-a22b-instruct",
204
- "anthropic/claude-sonnet-4.5",
205
- "custom"
206
- ];
293
+ // src/cli.ts
294
+ init_config();
295
+
296
+ // src/model-loader.ts
297
+ import { readFileSync, existsSync } from "node:fs";
298
+ import { join as join2, dirname } from "node:path";
299
+ import { fileURLToPath } from "node:url";
300
+ var __filename2 = fileURLToPath(import.meta.url);
301
+ var __dirname2 = dirname(__filename2);
302
+ var _cachedModelInfo = null;
303
+ var _cachedModelIds = null;
304
+ function loadModelInfo() {
305
+ if (_cachedModelInfo) {
306
+ return _cachedModelInfo;
307
+ }
308
+ const jsonPath = join2(__dirname2, "../recommended-models.json");
309
+ if (existsSync(jsonPath)) {
310
+ try {
311
+ const jsonContent = readFileSync(jsonPath, "utf-8");
312
+ const data = JSON.parse(jsonContent);
313
+ const modelInfo = {};
314
+ for (const model of data.models) {
315
+ modelInfo[model.id] = {
316
+ name: model.name,
317
+ description: model.description,
318
+ priority: model.priority,
319
+ provider: model.provider
320
+ };
321
+ }
322
+ modelInfo.custom = {
323
+ name: "Custom Model",
324
+ description: "Enter any OpenRouter model ID manually",
325
+ priority: 999,
326
+ provider: "Custom"
327
+ };
328
+ _cachedModelInfo = modelInfo;
329
+ return modelInfo;
330
+ } catch (error) {
331
+ console.warn("⚠️ Failed to load recommended-models.json, falling back to build-time config");
332
+ console.warn(` Error: ${error}`);
333
+ }
334
+ }
335
+ const { MODEL_INFO: MODEL_INFO2 } = (init_config(), __toCommonJS(exports_config));
336
+ _cachedModelInfo = MODEL_INFO2;
337
+ return MODEL_INFO2;
338
+ }
339
+ function getAvailableModels() {
340
+ if (_cachedModelIds) {
341
+ return _cachedModelIds;
342
+ }
343
+ const jsonPath = join2(__dirname2, "../recommended-models.json");
344
+ if (existsSync(jsonPath)) {
345
+ try {
346
+ const jsonContent = readFileSync(jsonPath, "utf-8");
347
+ const data = JSON.parse(jsonContent);
348
+ const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
349
+ const result = [...modelIds, "custom"];
350
+ _cachedModelIds = result;
351
+ return result;
352
+ } catch (error) {
353
+ console.warn("⚠️ Failed to load model list from JSON, falling back to build-time config");
354
+ }
355
+ }
356
+ const { OPENROUTER_MODELS: OPENROUTER_MODELS2 } = (init_types(), __toCommonJS(exports_types));
357
+ _cachedModelIds = [...OPENROUTER_MODELS2];
358
+ return [...OPENROUTER_MODELS2];
359
+ }
207
360
 
208
361
  // src/cli.ts
209
362
  function parseArgs(args) {
@@ -447,8 +600,10 @@ function printAvailableModels() {
447
600
  console.log(`
448
601
  Available OpenRouter Models (in priority order):
449
602
  `);
450
- for (const model of OPENROUTER_MODELS) {
451
- const info = MODEL_INFO[model];
603
+ const models = getAvailableModels();
604
+ const modelInfo = loadModelInfo();
605
+ for (const model of models) {
606
+ const info = modelInfo[model];
452
607
  console.log(` ${model}`);
453
608
  console.log(` ${info.name} - ${info.description}`);
454
609
  console.log("");
@@ -459,6 +614,9 @@ Available OpenRouter Models (in priority order):
459
614
  `);
460
615
  }
461
616
 
617
+ // src/index.ts
618
+ init_config();
619
+
462
620
  // src/simple-selector.ts
463
621
  import { createInterface } from "readline";
464
622
  async function promptForApiKey() {
@@ -511,12 +669,14 @@ async function promptForApiKey() {
511
669
  });
512
670
  }
513
671
  async function selectModelInteractively() {
672
+ const models = getAvailableModels();
673
+ const modelInfo = loadModelInfo();
514
674
  return new Promise((resolve) => {
515
675
  console.log(`
516
676
  \x1B[1m\x1B[36mSelect an OpenRouter model:\x1B[0m
517
677
  `);
518
- OPENROUTER_MODELS.forEach((model, index) => {
519
- const info = MODEL_INFO[model];
678
+ models.forEach((model, index) => {
679
+ const info = modelInfo[model];
520
680
  const displayName = info ? info.name : model;
521
681
  const description = info ? info.description : "Custom model entry";
522
682
  const provider = info ? info.provider : "";
@@ -528,7 +688,7 @@ async function selectModelInteractively() {
528
688
  }
529
689
  console.log("");
530
690
  });
531
- console.log(`\x1B[2mEnter number (1-${OPENROUTER_MODELS.length}) or 'q' to quit:\x1B[0m`);
691
+ console.log(`\x1B[2mEnter number (1-${models.length}) or 'q' to quit:\x1B[0m`);
532
692
  const rl = createInterface({
533
693
  input: process.stdin,
534
694
  output: process.stdout,
@@ -542,11 +702,11 @@ async function selectModelInteractively() {
542
702
  process.exit(0);
543
703
  }
544
704
  const selection = parseInt(trimmed, 10);
545
- if (isNaN(selection) || selection < 1 || selection > OPENROUTER_MODELS.length) {
546
- console.log(`\x1B[31mInvalid selection. Please enter 1-${OPENROUTER_MODELS.length}\x1B[0m`);
705
+ if (isNaN(selection) || selection < 1 || selection > models.length) {
706
+ console.log(`\x1B[31mInvalid selection. Please enter 1-${models.length}\x1B[0m`);
547
707
  return;
548
708
  }
549
- const model = OPENROUTER_MODELS[selection - 1];
709
+ const model = models[selection - 1];
550
710
  if (model === "custom") {
551
711
  rl.close();
552
712
  console.log(`
@@ -603,8 +763,8 @@ async function selectModelInteractively() {
603
763
  }
604
764
 
605
765
  // src/logger.ts
606
- import { writeFileSync as writeFileSync2, appendFile, existsSync, mkdirSync } from "fs";
607
- import { join as join2 } from "path";
766
+ import { writeFileSync as writeFileSync2, appendFile, existsSync as existsSync2, mkdirSync } from "fs";
767
+ import { join as join3 } from "path";
608
768
  var logFilePath = null;
609
769
  var logLevel = "info";
610
770
  var logBuffer = [];
@@ -649,12 +809,12 @@ function initLogger(debugMode, level = "info") {
649
809
  return;
650
810
  }
651
811
  logLevel = level;
652
- const logsDir = join2(process.cwd(), "logs");
653
- if (!existsSync(logsDir)) {
812
+ const logsDir = join3(process.cwd(), "logs");
813
+ if (!existsSync2(logsDir)) {
654
814
  mkdirSync(logsDir, { recursive: true });
655
815
  }
656
816
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").split("T").join("_").slice(0, -5);
657
- logFilePath = join2(logsDir, `claudish_${timestamp}.log`);
817
+ logFilePath = join3(logsDir, `claudish_${timestamp}.log`);
658
818
  writeFileSync2(logFilePath, `Claudish Debug Log - ${new Date().toISOString()}
659
819
  Log Level: ${level}
660
820
  ${"=".repeat(80)}
@@ -745,7 +905,7 @@ async function isPortAvailable(port) {
745
905
  });
746
906
  }
747
907
 
748
- // node_modules/hono/dist/compose.js
908
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/compose.js
749
909
  var compose = (middleware, onError, onNotFound) => {
750
910
  return (context, next) => {
751
911
  let index = -1;
@@ -789,10 +949,10 @@ var compose = (middleware, onError, onNotFound) => {
789
949
  };
790
950
  };
791
951
 
792
- // node_modules/hono/dist/request/constants.js
952
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/request/constants.js
793
953
  var GET_MATCH_RESULT = Symbol();
794
954
 
795
- // node_modules/hono/dist/utils/body.js
955
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/body.js
796
956
  var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
797
957
  const { all = false, dot = false } = options;
798
958
  const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
@@ -860,7 +1020,7 @@ var handleParsingNestedValues = (form, key, value) => {
860
1020
  });
861
1021
  };
862
1022
 
863
- // node_modules/hono/dist/utils/url.js
1023
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/url.js
864
1024
  var splitPath = (path) => {
865
1025
  const paths = path.split("/");
866
1026
  if (paths[0] === "") {
@@ -992,9 +1152,12 @@ var _decodeURI = (value) => {
992
1152
  var _getQueryParam = (url, key, multiple) => {
993
1153
  let encoded;
994
1154
  if (!multiple && key && !/[%+]/.test(key)) {
995
- let keyIndex2 = url.indexOf(`?${key}`, 8);
1155
+ let keyIndex2 = url.indexOf("?", 8);
996
1156
  if (keyIndex2 === -1) {
997
- keyIndex2 = url.indexOf(`&${key}`, 8);
1157
+ return;
1158
+ }
1159
+ if (!url.startsWith(key, keyIndex2 + 1)) {
1160
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
998
1161
  }
999
1162
  while (keyIndex2 !== -1) {
1000
1163
  const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
@@ -1055,7 +1218,7 @@ var getQueryParams = (url, key) => {
1055
1218
  };
1056
1219
  var decodeURIComponent_ = decodeURIComponent;
1057
1220
 
1058
- // node_modules/hono/dist/request.js
1221
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/request.js
1059
1222
  var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
1060
1223
  var HonoRequest = class {
1061
1224
  raw;
@@ -1166,7 +1329,7 @@ var HonoRequest = class {
1166
1329
  }
1167
1330
  };
1168
1331
 
1169
- // node_modules/hono/dist/utils/html.js
1332
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/html.js
1170
1333
  var HtmlEscapedCallbackPhase = {
1171
1334
  Stringify: 1,
1172
1335
  BeforeStream: 2,
@@ -1204,7 +1367,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
1204
1367
  }
1205
1368
  };
1206
1369
 
1207
- // node_modules/hono/dist/context.js
1370
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/context.js
1208
1371
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
1209
1372
  var setDefaultContentType = (contentType, headers) => {
1210
1373
  return {
@@ -1370,7 +1533,7 @@ var Context = class {
1370
1533
  };
1371
1534
  };
1372
1535
 
1373
- // node_modules/hono/dist/router.js
1536
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router.js
1374
1537
  var METHOD_NAME_ALL = "ALL";
1375
1538
  var METHOD_NAME_ALL_LOWERCASE = "all";
1376
1539
  var METHODS = ["get", "post", "put", "delete", "options", "patch"];
@@ -1378,10 +1541,10 @@ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is
1378
1541
  var UnsupportedPathError = class extends Error {
1379
1542
  };
1380
1543
 
1381
- // node_modules/hono/dist/utils/constants.js
1544
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/constants.js
1382
1545
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
1383
1546
 
1384
- // node_modules/hono/dist/hono-base.js
1547
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/hono-base.js
1385
1548
  var notFoundHandler = (c) => {
1386
1549
  return c.text("404 Not Found", 404);
1387
1550
  };
@@ -1600,7 +1763,7 @@ var Hono = class {
1600
1763
  };
1601
1764
  };
1602
1765
 
1603
- // node_modules/hono/dist/router/reg-exp-router/matcher.js
1766
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/matcher.js
1604
1767
  var emptyParam = [];
1605
1768
  function match(method, path) {
1606
1769
  const matchers = this.buildAllMatchers();
@@ -1621,7 +1784,7 @@ function match(method, path) {
1621
1784
  return match2(method, path);
1622
1785
  }
1623
1786
 
1624
- // node_modules/hono/dist/router/reg-exp-router/node.js
1787
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/node.js
1625
1788
  var LABEL_REG_EXP_STR = "[^/]+";
1626
1789
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
1627
1790
  var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
@@ -1725,7 +1888,7 @@ var Node = class {
1725
1888
  }
1726
1889
  };
1727
1890
 
1728
- // node_modules/hono/dist/router/reg-exp-router/trie.js
1891
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/trie.js
1729
1892
  var Trie = class {
1730
1893
  #context = { varIndex: 0 };
1731
1894
  #root = new Node;
@@ -1781,7 +1944,7 @@ var Trie = class {
1781
1944
  }
1782
1945
  };
1783
1946
 
1784
- // node_modules/hono/dist/router/reg-exp-router/router.js
1947
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/router.js
1785
1948
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
1786
1949
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
1787
1950
  function buildWildcardRegExp(path) {
@@ -1946,7 +2109,7 @@ var RegExpRouter = class {
1946
2109
  }
1947
2110
  };
1948
2111
 
1949
- // node_modules/hono/dist/router/reg-exp-router/prepared-router.js
2112
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
1950
2113
  var PreparedRegExpRouter = class {
1951
2114
  name = "PreparedRegExpRouter";
1952
2115
  #matchers;
@@ -2018,7 +2181,7 @@ var PreparedRegExpRouter = class {
2018
2181
  match = match;
2019
2182
  };
2020
2183
 
2021
- // node_modules/hono/dist/router/smart-router/router.js
2184
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/smart-router/router.js
2022
2185
  var SmartRouter = class {
2023
2186
  name = "SmartRouter";
2024
2187
  #routers = [];
@@ -2073,7 +2236,7 @@ var SmartRouter = class {
2073
2236
  }
2074
2237
  };
2075
2238
 
2076
- // node_modules/hono/dist/router/trie-router/node.js
2239
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/trie-router/node.js
2077
2240
  var emptyParams = /* @__PURE__ */ Object.create(null);
2078
2241
  var Node2 = class {
2079
2242
  #methods;
@@ -2227,7 +2390,7 @@ var Node2 = class {
2227
2390
  }
2228
2391
  };
2229
2392
 
2230
- // node_modules/hono/dist/router/trie-router/router.js
2393
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/trie-router/router.js
2231
2394
  var TrieRouter = class {
2232
2395
  name = "TrieRouter";
2233
2396
  #node;
@@ -2249,7 +2412,7 @@ var TrieRouter = class {
2249
2412
  }
2250
2413
  };
2251
2414
 
2252
- // node_modules/hono/dist/hono.js
2415
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/hono.js
2253
2416
  var Hono2 = class extends Hono {
2254
2417
  constructor(options = {}) {
2255
2418
  super(options);
@@ -2259,7 +2422,7 @@ var Hono2 = class extends Hono {
2259
2422
  }
2260
2423
  };
2261
2424
 
2262
- // node_modules/hono/dist/middleware/cors/index.js
2425
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/middleware/cors/index.js
2263
2426
  var cors = (options) => {
2264
2427
  const defaults = {
2265
2428
  origin: "*",
@@ -2344,7 +2507,7 @@ var cors = (options) => {
2344
2507
  };
2345
2508
  };
2346
2509
 
2347
- // node_modules/@hono/node-server/dist/index.mjs
2510
+ // node_modules/.pnpm/@hono+node-server@1.19.6_hono@4.10.6/node_modules/@hono/node-server/dist/index.mjs
2348
2511
  import { createServer as createServerHTTP } from "http";
2349
2512
  import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
2350
2513
  import { Http2ServerRequest } from "http2";
@@ -3081,8 +3244,8 @@ class AdapterManager {
3081
3244
 
3082
3245
  // src/proxy-server.ts
3083
3246
  async function createProxyServer(port, openrouterApiKey, model, monitorMode = false, anthropicApiKey) {
3084
- const OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions";
3085
- const OPENROUTER_HEADERS = {
3247
+ const OPENROUTER_API_URL2 = "https://openrouter.ai/api/v1/chat/completions";
3248
+ const OPENROUTER_HEADERS2 = {
3086
3249
  "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
3087
3250
  "X-Title": "Claudish - OpenRouter Proxy"
3088
3251
  };
@@ -3458,9 +3621,9 @@ IMPORTANT: When calling tools, you MUST use the OpenAI tool_calls format with JS
3458
3621
  const headers = {
3459
3622
  "Content-Type": "application/json",
3460
3623
  Authorization: `Bearer ${openrouterApiKey}`,
3461
- ...OPENROUTER_HEADERS
3624
+ ...OPENROUTER_HEADERS2
3462
3625
  };
3463
- const openrouterResponse = await fetch(OPENROUTER_API_URL, {
3626
+ const openrouterResponse = await fetch(OPENROUTER_API_URL2, {
3464
3627
  method: "POST",
3465
3628
  headers,
3466
3629
  body: JSON.stringify(openrouterPayload)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudish",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "CLI tool to run Claude Code with any OpenRouter model (Grok, GPT-5, MiniMax, etc.) via local Anthropic API-compatible proxy",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -12,7 +12,8 @@
12
12
  "dev:grok": "bun run src/index.ts --interactive --model x-ai/grok-code-fast-1",
13
13
  "dev:grok:debug": "bun run src/index.ts --interactive --debug --log-level info --model x-ai/grok-code-fast-1",
14
14
  "dev:info": "bun run src/index.ts --interactive --monitor",
15
- "build": "bun build src/index.ts --outdir dist --target node && chmod +x dist/index.js",
15
+ "extract-models": "bun run scripts/extract-models.ts",
16
+ "build": "bun run extract-models && bun build src/index.ts --outdir dist --target node && chmod +x dist/index.js",
16
17
  "link": "npm link",
17
18
  "unlink": "npm unlink -g claudish",
18
19
  "install-global": "bun run build && npm link",
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Extract model information from shared/recommended-models.md
5
+ * and generate TypeScript types for use in Claudish
6
+ */
7
+
8
+ import { readFileSync, writeFileSync } from "node:fs";
9
+ import { join } from "node:path";
10
+
11
+ interface ModelInfo {
12
+ name: string;
13
+ description: string;
14
+ priority: number;
15
+ provider: string;
16
+ }
17
+
18
+ interface ExtractedModels {
19
+ [key: string]: ModelInfo;
20
+ }
21
+
22
+ function extractModels(markdownContent: string): ExtractedModels {
23
+ const models: ExtractedModels = {};
24
+ let priority = 1;
25
+
26
+ // Extract from Quick Reference section (lines 11-30)
27
+ const quickRefMatch = markdownContent.match(
28
+ /## Quick Reference - Model IDs Only\n\n([\s\S]*?)\n---/,
29
+ );
30
+ if (!quickRefMatch) {
31
+ throw new Error("Could not find Quick Reference section");
32
+ }
33
+
34
+ const quickRef = quickRefMatch[1];
35
+ const lines = quickRef.split("\n");
36
+
37
+ for (const line of lines) {
38
+ // Match pattern: - `model-id` - Description (may contain commas), $price/1M, contextK/M [⭐]
39
+ // Use non-greedy match and look for $ to find the price section
40
+ const match = line.match(
41
+ /^- `([^`]+)` - (.+?), (\$[\d.]+\/1M), ([\dKM]+)(?: ⭐)?$/,
42
+ );
43
+ if (match) {
44
+ const [, modelId, description] = match;
45
+
46
+ // Determine provider from model ID
47
+ let provider = "Unknown";
48
+ if (modelId.startsWith("x-ai/")) provider = "xAI";
49
+ else if (modelId.startsWith("minimax/")) provider = "MiniMax";
50
+ else if (modelId.startsWith("z-ai/")) provider = "Zhipu AI";
51
+ else if (modelId.startsWith("openai/")) provider = "OpenAI";
52
+ else if (modelId.startsWith("google/")) provider = "Google";
53
+ else if (modelId.startsWith("qwen/")) provider = "Alibaba";
54
+ else if (modelId.startsWith("deepseek/")) provider = "DeepSeek";
55
+ else if (modelId.startsWith("anthropic/")) provider = "Anthropic";
56
+
57
+ // Extract short name from description
58
+ const name = description.trim();
59
+
60
+ models[modelId] = {
61
+ name,
62
+ description: description.trim(),
63
+ priority: priority++,
64
+ provider,
65
+ };
66
+ }
67
+ }
68
+
69
+ // Add custom option
70
+ models.custom = {
71
+ name: "Custom Model",
72
+ description: "Enter any OpenRouter model ID manually",
73
+ priority: 999,
74
+ provider: "Custom",
75
+ };
76
+
77
+ return models;
78
+ }
79
+
80
+ function generateTypeScript(models: ExtractedModels): string {
81
+ const modelIds = Object.keys(models)
82
+ .filter((id) => id !== "custom")
83
+ .map((id) => ` | "${id}"`)
84
+ .join("\n");
85
+
86
+ const modelInfo = Object.entries(models)
87
+ .map(([id, info]) => {
88
+ return ` "${id}": {
89
+ name: "${info.name}",
90
+ description: "${info.description}",
91
+ priority: ${info.priority},
92
+ provider: "${info.provider}",
93
+ }`;
94
+ })
95
+ .join(",\n");
96
+
97
+ return `// AUTO-GENERATED from shared/recommended-models.md
98
+ // DO NOT EDIT MANUALLY - Run 'bun run extract-models' to regenerate
99
+
100
+ import type { OpenRouterModel } from "./types.js";
101
+
102
+ export const DEFAULT_MODEL: OpenRouterModel = "x-ai/grok-code-fast-1";
103
+ export const DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
104
+
105
+ // Model metadata for validation and display
106
+ export const MODEL_INFO: Record<
107
+ OpenRouterModel,
108
+ { name: string; description: string; priority: number; provider: string }
109
+ > = {
110
+ ${modelInfo},
111
+ };
112
+
113
+ // Environment variable names
114
+ export const ENV = {
115
+ OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
116
+ CLAUDISH_MODEL: "CLAUDISH_MODEL",
117
+ CLAUDISH_PORT: "CLAUDISH_PORT",
118
+ CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME", // Set by claudish to show active model in status line
119
+ ANTHROPIC_MODEL: "ANTHROPIC_MODEL", // Claude Code standard env var for model selection
120
+ ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL", // Claude Code standard env var for fast model
121
+ } as const;
122
+
123
+ // OpenRouter API Configuration
124
+ export const OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions";
125
+ export const OPENROUTER_HEADERS = {
126
+ "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
127
+ "X-Title": "Claudish - OpenRouter Proxy",
128
+ } as const;
129
+ `;
130
+ }
131
+
132
+ function generateTypes(models: ExtractedModels): string {
133
+ const modelIds = Object.keys(models)
134
+ .filter((id) => id !== "custom")
135
+ .map((id) => ` "${id}"`)
136
+ .join(",\n");
137
+
138
+ return `// AUTO-GENERATED from shared/recommended-models.md
139
+ // DO NOT EDIT MANUALLY - Run 'bun run extract-models' to regenerate
140
+
141
+ // OpenRouter Models - Top Recommended for Development (Priority Order)
142
+ export const OPENROUTER_MODELS = [
143
+ ${modelIds},
144
+ "custom",
145
+ ] as const;
146
+
147
+ export type OpenRouterModel = (typeof OPENROUTER_MODELS)[number];
148
+ `;
149
+ }
150
+
151
+ // Main execution
152
+ try {
153
+ const sharedModelsPath = join(
154
+ import.meta.dir,
155
+ "../../../shared/recommended-models.md",
156
+ );
157
+ const configPath = join(import.meta.dir, "../src/config.ts");
158
+ const typesPath = join(import.meta.dir, "../src/types.ts");
159
+
160
+ console.log("📖 Reading shared/recommended-models.md...");
161
+ const markdownContent = readFileSync(sharedModelsPath, "utf-8");
162
+
163
+ console.log("🔍 Extracting model information...");
164
+ const models = extractModels(markdownContent);
165
+
166
+ console.log(`✅ Found ${Object.keys(models).length - 1} models + custom option`);
167
+
168
+ console.log("📝 Generating config.ts...");
169
+ const configCode = generateTypeScript(models);
170
+ writeFileSync(configPath, configCode);
171
+
172
+ console.log("📝 Generating types.ts...");
173
+ const typesCode = generateTypes(models);
174
+ const existingTypes = readFileSync(typesPath, "utf-8");
175
+
176
+ // Replace OPENROUTER_MODELS array and OpenRouterModel type, keep other types
177
+ // Handle both auto-generated and manual versions
178
+ let updatedTypes = existingTypes;
179
+
180
+ // Try to replace auto-generated section first
181
+ if (existingTypes.includes("// AUTO-GENERATED")) {
182
+ updatedTypes = existingTypes.replace(
183
+ /\/\/ AUTO-GENERATED[\s\S]*?export type OpenRouterModel = \(typeof OPENROUTER_MODELS\)\[number\];/,
184
+ typesCode.trim(),
185
+ );
186
+ } else {
187
+ // First time - replace manual OPENROUTER_MODELS section
188
+ updatedTypes = existingTypes.replace(
189
+ /\/\/ OpenRouter Models[\s\S]*?export type OpenRouterModel = \(typeof OPENROUTER_MODELS\)\[number\];/,
190
+ typesCode.trim(),
191
+ );
192
+ }
193
+
194
+ writeFileSync(typesPath, updatedTypes);
195
+
196
+ console.log("✅ Successfully generated TypeScript files");
197
+ console.log("");
198
+ console.log("Models:");
199
+ for (const [id, info] of Object.entries(models)) {
200
+ if (id !== "custom") {
201
+ console.log(` • ${id} - ${info.name} (${info.provider})`);
202
+ }
203
+ }
204
+ } catch (error) {
205
+ console.error("❌ Error:", error);
206
+ process.exit(1);
207
+ }