claudish 1.4.1 → 1.7.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,135 @@
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
+ "google/gemini-2.5-flash": {
58
+ name: "Advanced reasoning + vision",
59
+ description: "Advanced reasoning + vision",
60
+ priority: 6,
61
+ provider: "Google"
62
+ },
63
+ "openai/gpt-5": {
64
+ name: "Most advanced reasoning",
65
+ description: "Most advanced reasoning",
66
+ priority: 4,
67
+ provider: "OpenAI"
68
+ },
69
+ "openai/gpt-5.1-codex": {
70
+ name: "Specialized for software engineering",
71
+ description: "Specialized for software engineering",
72
+ priority: 5,
73
+ provider: "OpenAI"
74
+ },
75
+ "qwen/qwen3-vl-235b-a22b-instruct": {
76
+ name: "Multimodal with OCR",
77
+ description: "Multimodal with OCR",
78
+ priority: 7,
79
+ provider: "Alibaba"
80
+ },
81
+ "openrouter/polaris-alpha": {
82
+ name: "FREE experimental (logs usage)",
83
+ description: "FREE experimental (logs usage)",
84
+ priority: 8,
85
+ provider: "OpenRouter"
86
+ },
87
+ custom: {
88
+ name: "Custom Model",
89
+ description: "Enter any OpenRouter model ID manually",
90
+ priority: 999,
91
+ provider: "Custom"
92
+ }
93
+ };
94
+ ENV = {
95
+ OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
96
+ CLAUDISH_MODEL: "CLAUDISH_MODEL",
97
+ CLAUDISH_PORT: "CLAUDISH_PORT",
98
+ CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME",
99
+ ANTHROPIC_MODEL: "ANTHROPIC_MODEL",
100
+ ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL"
101
+ };
102
+ OPENROUTER_HEADERS = {
103
+ "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
104
+ "X-Title": "Claudish - OpenRouter Proxy"
105
+ };
106
+ });
107
+
108
+ // src/types.ts
109
+ var exports_types = {};
110
+ __export(exports_types, {
111
+ OPENROUTER_MODELS: () => OPENROUTER_MODELS
112
+ });
113
+ var OPENROUTER_MODELS;
114
+ var init_types = __esm(() => {
115
+ OPENROUTER_MODELS = [
116
+ "x-ai/grok-code-fast-1",
117
+ "minimax/minimax-m2",
118
+ "google/gemini-2.5-flash",
119
+ "openai/gpt-5",
120
+ "openai/gpt-5.1-codex",
121
+ "qwen/qwen3-vl-235b-a22b-instruct",
122
+ "openrouter/polaris-alpha",
123
+ "custom"
124
+ ];
125
+ });
2
126
 
3
127
  // src/claude-runner.ts
128
+ init_config();
4
129
  import { spawn } from "node:child_process";
5
130
  import { writeFileSync, unlinkSync } from "node:fs";
6
131
  import { tmpdir } from "node:os";
7
132
  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
133
  function createTempSettingsFile(modelDisplay, port) {
66
134
  const tempDir = tmpdir();
67
135
  const timestamp = Date.now();
@@ -194,16 +262,73 @@ async function checkClaudeInstalled() {
194
262
  }
195
263
  }
196
264
 
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
- ];
265
+ // src/cli.ts
266
+ init_config();
267
+
268
+ // src/model-loader.ts
269
+ import { readFileSync, existsSync } from "node:fs";
270
+ import { join as join2, dirname } from "node:path";
271
+ import { fileURLToPath } from "node:url";
272
+ var __filename2 = fileURLToPath(import.meta.url);
273
+ var __dirname2 = dirname(__filename2);
274
+ var _cachedModelInfo = null;
275
+ var _cachedModelIds = null;
276
+ function loadModelInfo() {
277
+ if (_cachedModelInfo) {
278
+ return _cachedModelInfo;
279
+ }
280
+ const jsonPath = join2(__dirname2, "../recommended-models.json");
281
+ if (existsSync(jsonPath)) {
282
+ try {
283
+ const jsonContent = readFileSync(jsonPath, "utf-8");
284
+ const data = JSON.parse(jsonContent);
285
+ const modelInfo = {};
286
+ for (const model of data.models) {
287
+ modelInfo[model.id] = {
288
+ name: model.name,
289
+ description: model.description,
290
+ priority: model.priority,
291
+ provider: model.provider
292
+ };
293
+ }
294
+ modelInfo.custom = {
295
+ name: "Custom Model",
296
+ description: "Enter any OpenRouter model ID manually",
297
+ priority: 999,
298
+ provider: "Custom"
299
+ };
300
+ _cachedModelInfo = modelInfo;
301
+ return modelInfo;
302
+ } catch (error) {
303
+ console.warn("⚠️ Failed to load recommended-models.json, falling back to build-time config");
304
+ console.warn(` Error: ${error}`);
305
+ }
306
+ }
307
+ const { MODEL_INFO: MODEL_INFO2 } = (init_config(), __toCommonJS(exports_config));
308
+ _cachedModelInfo = MODEL_INFO2;
309
+ return MODEL_INFO2;
310
+ }
311
+ function getAvailableModels() {
312
+ if (_cachedModelIds) {
313
+ return _cachedModelIds;
314
+ }
315
+ const jsonPath = join2(__dirname2, "../recommended-models.json");
316
+ if (existsSync(jsonPath)) {
317
+ try {
318
+ const jsonContent = readFileSync(jsonPath, "utf-8");
319
+ const data = JSON.parse(jsonContent);
320
+ const modelIds = data.models.sort((a, b) => a.priority - b.priority).map((m) => m.id);
321
+ const result = [...modelIds, "custom"];
322
+ _cachedModelIds = result;
323
+ return result;
324
+ } catch (error) {
325
+ console.warn("⚠️ Failed to load model list from JSON, falling back to build-time config");
326
+ }
327
+ }
328
+ const { OPENROUTER_MODELS: OPENROUTER_MODELS2 } = (init_types(), __toCommonJS(exports_types));
329
+ _cachedModelIds = [...OPENROUTER_MODELS2];
330
+ return [...OPENROUTER_MODELS2];
331
+ }
207
332
 
208
333
  // src/cli.ts
209
334
  function parseArgs(args) {
@@ -447,8 +572,10 @@ function printAvailableModels() {
447
572
  console.log(`
448
573
  Available OpenRouter Models (in priority order):
449
574
  `);
450
- for (const model of OPENROUTER_MODELS) {
451
- const info = MODEL_INFO[model];
575
+ const models = getAvailableModels();
576
+ const modelInfo = loadModelInfo();
577
+ for (const model of models) {
578
+ const info = modelInfo[model];
452
579
  console.log(` ${model}`);
453
580
  console.log(` ${info.name} - ${info.description}`);
454
581
  console.log("");
@@ -459,6 +586,9 @@ Available OpenRouter Models (in priority order):
459
586
  `);
460
587
  }
461
588
 
589
+ // src/index.ts
590
+ init_config();
591
+
462
592
  // src/simple-selector.ts
463
593
  import { createInterface } from "readline";
464
594
  async function promptForApiKey() {
@@ -511,12 +641,14 @@ async function promptForApiKey() {
511
641
  });
512
642
  }
513
643
  async function selectModelInteractively() {
644
+ const models = getAvailableModels();
645
+ const modelInfo = loadModelInfo();
514
646
  return new Promise((resolve) => {
515
647
  console.log(`
516
648
  \x1B[1m\x1B[36mSelect an OpenRouter model:\x1B[0m
517
649
  `);
518
- OPENROUTER_MODELS.forEach((model, index) => {
519
- const info = MODEL_INFO[model];
650
+ models.forEach((model, index) => {
651
+ const info = modelInfo[model];
520
652
  const displayName = info ? info.name : model;
521
653
  const description = info ? info.description : "Custom model entry";
522
654
  const provider = info ? info.provider : "";
@@ -528,7 +660,7 @@ async function selectModelInteractively() {
528
660
  }
529
661
  console.log("");
530
662
  });
531
- console.log(`\x1B[2mEnter number (1-${OPENROUTER_MODELS.length}) or 'q' to quit:\x1B[0m`);
663
+ console.log(`\x1B[2mEnter number (1-${models.length}) or 'q' to quit:\x1B[0m`);
532
664
  const rl = createInterface({
533
665
  input: process.stdin,
534
666
  output: process.stdout,
@@ -542,11 +674,11 @@ async function selectModelInteractively() {
542
674
  process.exit(0);
543
675
  }
544
676
  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`);
677
+ if (isNaN(selection) || selection < 1 || selection > models.length) {
678
+ console.log(`\x1B[31mInvalid selection. Please enter 1-${models.length}\x1B[0m`);
547
679
  return;
548
680
  }
549
- const model = OPENROUTER_MODELS[selection - 1];
681
+ const model = models[selection - 1];
550
682
  if (model === "custom") {
551
683
  rl.close();
552
684
  console.log(`
@@ -603,8 +735,8 @@ async function selectModelInteractively() {
603
735
  }
604
736
 
605
737
  // src/logger.ts
606
- import { writeFileSync as writeFileSync2, appendFile, existsSync, mkdirSync } from "fs";
607
- import { join as join2 } from "path";
738
+ import { writeFileSync as writeFileSync2, appendFile, existsSync as existsSync2, mkdirSync } from "fs";
739
+ import { join as join3 } from "path";
608
740
  var logFilePath = null;
609
741
  var logLevel = "info";
610
742
  var logBuffer = [];
@@ -649,12 +781,12 @@ function initLogger(debugMode, level = "info") {
649
781
  return;
650
782
  }
651
783
  logLevel = level;
652
- const logsDir = join2(process.cwd(), "logs");
653
- if (!existsSync(logsDir)) {
784
+ const logsDir = join3(process.cwd(), "logs");
785
+ if (!existsSync2(logsDir)) {
654
786
  mkdirSync(logsDir, { recursive: true });
655
787
  }
656
788
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").split("T").join("_").slice(0, -5);
657
- logFilePath = join2(logsDir, `claudish_${timestamp}.log`);
789
+ logFilePath = join3(logsDir, `claudish_${timestamp}.log`);
658
790
  writeFileSync2(logFilePath, `Claudish Debug Log - ${new Date().toISOString()}
659
791
  Log Level: ${level}
660
792
  ${"=".repeat(80)}
@@ -745,7 +877,7 @@ async function isPortAvailable(port) {
745
877
  });
746
878
  }
747
879
 
748
- // node_modules/hono/dist/compose.js
880
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/compose.js
749
881
  var compose = (middleware, onError, onNotFound) => {
750
882
  return (context, next) => {
751
883
  let index = -1;
@@ -789,10 +921,10 @@ var compose = (middleware, onError, onNotFound) => {
789
921
  };
790
922
  };
791
923
 
792
- // node_modules/hono/dist/request/constants.js
924
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/request/constants.js
793
925
  var GET_MATCH_RESULT = Symbol();
794
926
 
795
- // node_modules/hono/dist/utils/body.js
927
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/body.js
796
928
  var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
797
929
  const { all = false, dot = false } = options;
798
930
  const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
@@ -860,7 +992,7 @@ var handleParsingNestedValues = (form, key, value) => {
860
992
  });
861
993
  };
862
994
 
863
- // node_modules/hono/dist/utils/url.js
995
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/url.js
864
996
  var splitPath = (path) => {
865
997
  const paths = path.split("/");
866
998
  if (paths[0] === "") {
@@ -992,9 +1124,12 @@ var _decodeURI = (value) => {
992
1124
  var _getQueryParam = (url, key, multiple) => {
993
1125
  let encoded;
994
1126
  if (!multiple && key && !/[%+]/.test(key)) {
995
- let keyIndex2 = url.indexOf(`?${key}`, 8);
1127
+ let keyIndex2 = url.indexOf("?", 8);
996
1128
  if (keyIndex2 === -1) {
997
- keyIndex2 = url.indexOf(`&${key}`, 8);
1129
+ return;
1130
+ }
1131
+ if (!url.startsWith(key, keyIndex2 + 1)) {
1132
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
998
1133
  }
999
1134
  while (keyIndex2 !== -1) {
1000
1135
  const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
@@ -1055,7 +1190,7 @@ var getQueryParams = (url, key) => {
1055
1190
  };
1056
1191
  var decodeURIComponent_ = decodeURIComponent;
1057
1192
 
1058
- // node_modules/hono/dist/request.js
1193
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/request.js
1059
1194
  var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
1060
1195
  var HonoRequest = class {
1061
1196
  raw;
@@ -1166,7 +1301,7 @@ var HonoRequest = class {
1166
1301
  }
1167
1302
  };
1168
1303
 
1169
- // node_modules/hono/dist/utils/html.js
1304
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/html.js
1170
1305
  var HtmlEscapedCallbackPhase = {
1171
1306
  Stringify: 1,
1172
1307
  BeforeStream: 2,
@@ -1204,7 +1339,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
1204
1339
  }
1205
1340
  };
1206
1341
 
1207
- // node_modules/hono/dist/context.js
1342
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/context.js
1208
1343
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
1209
1344
  var setDefaultContentType = (contentType, headers) => {
1210
1345
  return {
@@ -1370,7 +1505,7 @@ var Context = class {
1370
1505
  };
1371
1506
  };
1372
1507
 
1373
- // node_modules/hono/dist/router.js
1508
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router.js
1374
1509
  var METHOD_NAME_ALL = "ALL";
1375
1510
  var METHOD_NAME_ALL_LOWERCASE = "all";
1376
1511
  var METHODS = ["get", "post", "put", "delete", "options", "patch"];
@@ -1378,10 +1513,10 @@ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is
1378
1513
  var UnsupportedPathError = class extends Error {
1379
1514
  };
1380
1515
 
1381
- // node_modules/hono/dist/utils/constants.js
1516
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/utils/constants.js
1382
1517
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
1383
1518
 
1384
- // node_modules/hono/dist/hono-base.js
1519
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/hono-base.js
1385
1520
  var notFoundHandler = (c) => {
1386
1521
  return c.text("404 Not Found", 404);
1387
1522
  };
@@ -1600,7 +1735,7 @@ var Hono = class {
1600
1735
  };
1601
1736
  };
1602
1737
 
1603
- // node_modules/hono/dist/router/reg-exp-router/matcher.js
1738
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/matcher.js
1604
1739
  var emptyParam = [];
1605
1740
  function match(method, path) {
1606
1741
  const matchers = this.buildAllMatchers();
@@ -1621,7 +1756,7 @@ function match(method, path) {
1621
1756
  return match2(method, path);
1622
1757
  }
1623
1758
 
1624
- // node_modules/hono/dist/router/reg-exp-router/node.js
1759
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/node.js
1625
1760
  var LABEL_REG_EXP_STR = "[^/]+";
1626
1761
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
1627
1762
  var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
@@ -1725,7 +1860,7 @@ var Node = class {
1725
1860
  }
1726
1861
  };
1727
1862
 
1728
- // node_modules/hono/dist/router/reg-exp-router/trie.js
1863
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/trie.js
1729
1864
  var Trie = class {
1730
1865
  #context = { varIndex: 0 };
1731
1866
  #root = new Node;
@@ -1781,7 +1916,7 @@ var Trie = class {
1781
1916
  }
1782
1917
  };
1783
1918
 
1784
- // node_modules/hono/dist/router/reg-exp-router/router.js
1919
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/router.js
1785
1920
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
1786
1921
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
1787
1922
  function buildWildcardRegExp(path) {
@@ -1946,7 +2081,7 @@ var RegExpRouter = class {
1946
2081
  }
1947
2082
  };
1948
2083
 
1949
- // node_modules/hono/dist/router/reg-exp-router/prepared-router.js
2084
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
1950
2085
  var PreparedRegExpRouter = class {
1951
2086
  name = "PreparedRegExpRouter";
1952
2087
  #matchers;
@@ -2018,7 +2153,7 @@ var PreparedRegExpRouter = class {
2018
2153
  match = match;
2019
2154
  };
2020
2155
 
2021
- // node_modules/hono/dist/router/smart-router/router.js
2156
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/smart-router/router.js
2022
2157
  var SmartRouter = class {
2023
2158
  name = "SmartRouter";
2024
2159
  #routers = [];
@@ -2073,7 +2208,7 @@ var SmartRouter = class {
2073
2208
  }
2074
2209
  };
2075
2210
 
2076
- // node_modules/hono/dist/router/trie-router/node.js
2211
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/trie-router/node.js
2077
2212
  var emptyParams = /* @__PURE__ */ Object.create(null);
2078
2213
  var Node2 = class {
2079
2214
  #methods;
@@ -2227,7 +2362,7 @@ var Node2 = class {
2227
2362
  }
2228
2363
  };
2229
2364
 
2230
- // node_modules/hono/dist/router/trie-router/router.js
2365
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/router/trie-router/router.js
2231
2366
  var TrieRouter = class {
2232
2367
  name = "TrieRouter";
2233
2368
  #node;
@@ -2249,7 +2384,7 @@ var TrieRouter = class {
2249
2384
  }
2250
2385
  };
2251
2386
 
2252
- // node_modules/hono/dist/hono.js
2387
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/hono.js
2253
2388
  var Hono2 = class extends Hono {
2254
2389
  constructor(options = {}) {
2255
2390
  super(options);
@@ -2259,7 +2394,7 @@ var Hono2 = class extends Hono {
2259
2394
  }
2260
2395
  };
2261
2396
 
2262
- // node_modules/hono/dist/middleware/cors/index.js
2397
+ // node_modules/.pnpm/hono@4.10.6/node_modules/hono/dist/middleware/cors/index.js
2263
2398
  var cors = (options) => {
2264
2399
  const defaults = {
2265
2400
  origin: "*",
@@ -2344,7 +2479,7 @@ var cors = (options) => {
2344
2479
  };
2345
2480
  };
2346
2481
 
2347
- // node_modules/@hono/node-server/dist/index.mjs
2482
+ // node_modules/.pnpm/@hono+node-server@1.19.6_hono@4.10.6/node_modules/@hono/node-server/dist/index.mjs
2348
2483
  import { createServer as createServerHTTP } from "http";
2349
2484
  import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
2350
2485
  import { Http2ServerRequest } from "http2";
@@ -3081,8 +3216,8 @@ class AdapterManager {
3081
3216
 
3082
3217
  // src/proxy-server.ts
3083
3218
  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 = {
3219
+ const OPENROUTER_API_URL2 = "https://openrouter.ai/api/v1/chat/completions";
3220
+ const OPENROUTER_HEADERS2 = {
3086
3221
  "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
3087
3222
  "X-Title": "Claudish - OpenRouter Proxy"
3088
3223
  };
@@ -3458,9 +3593,9 @@ IMPORTANT: When calling tools, you MUST use the OpenAI tool_calls format with JS
3458
3593
  const headers = {
3459
3594
  "Content-Type": "application/json",
3460
3595
  Authorization: `Bearer ${openrouterApiKey}`,
3461
- ...OPENROUTER_HEADERS
3596
+ ...OPENROUTER_HEADERS2
3462
3597
  };
3463
- const openrouterResponse = await fetch(OPENROUTER_API_URL, {
3598
+ const openrouterResponse = await fetch(OPENROUTER_API_URL2, {
3464
3599
  method: "POST",
3465
3600
  headers,
3466
3601
  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.7.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,209 @@
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 or FREE, contextK/M [⭐]
39
+ // Use non-greedy match and look for $ or FREE to find the price section
40
+ const match = line.match(
41
+ /^- `([^`]+)` - (.+?), (?:\$[\d.]+\/1M|FREE), ([\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("tngtech/")) provider = "TNG Tech";
56
+ else if (modelId.startsWith("openrouter/")) provider = "OpenRouter";
57
+ else if (modelId.startsWith("anthropic/")) provider = "Anthropic";
58
+
59
+ // Extract short name from description
60
+ const name = description.trim();
61
+
62
+ models[modelId] = {
63
+ name,
64
+ description: description.trim(),
65
+ priority: priority++,
66
+ provider,
67
+ };
68
+ }
69
+ }
70
+
71
+ // Add custom option
72
+ models.custom = {
73
+ name: "Custom Model",
74
+ description: "Enter any OpenRouter model ID manually",
75
+ priority: 999,
76
+ provider: "Custom",
77
+ };
78
+
79
+ return models;
80
+ }
81
+
82
+ function generateTypeScript(models: ExtractedModels): string {
83
+ const modelIds = Object.keys(models)
84
+ .filter((id) => id !== "custom")
85
+ .map((id) => ` | "${id}"`)
86
+ .join("\n");
87
+
88
+ const modelInfo = Object.entries(models)
89
+ .map(([id, info]) => {
90
+ return ` "${id}": {
91
+ name: "${info.name}",
92
+ description: "${info.description}",
93
+ priority: ${info.priority},
94
+ provider: "${info.provider}",
95
+ }`;
96
+ })
97
+ .join(",\n");
98
+
99
+ return `// AUTO-GENERATED from shared/recommended-models.md
100
+ // DO NOT EDIT MANUALLY - Run 'bun run extract-models' to regenerate
101
+
102
+ import type { OpenRouterModel } from "./types.js";
103
+
104
+ export const DEFAULT_MODEL: OpenRouterModel = "x-ai/grok-code-fast-1";
105
+ export const DEFAULT_PORT_RANGE = { start: 3000, end: 9000 };
106
+
107
+ // Model metadata for validation and display
108
+ export const MODEL_INFO: Record<
109
+ OpenRouterModel,
110
+ { name: string; description: string; priority: number; provider: string }
111
+ > = {
112
+ ${modelInfo},
113
+ };
114
+
115
+ // Environment variable names
116
+ export const ENV = {
117
+ OPENROUTER_API_KEY: "OPENROUTER_API_KEY",
118
+ CLAUDISH_MODEL: "CLAUDISH_MODEL",
119
+ CLAUDISH_PORT: "CLAUDISH_PORT",
120
+ CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME", // Set by claudish to show active model in status line
121
+ ANTHROPIC_MODEL: "ANTHROPIC_MODEL", // Claude Code standard env var for model selection
122
+ ANTHROPIC_SMALL_FAST_MODEL: "ANTHROPIC_SMALL_FAST_MODEL", // Claude Code standard env var for fast model
123
+ } as const;
124
+
125
+ // OpenRouter API Configuration
126
+ export const OPENROUTER_API_URL = "https://openrouter.ai/api/v1/chat/completions";
127
+ export const OPENROUTER_HEADERS = {
128
+ "HTTP-Referer": "https://github.com/MadAppGang/claude-code",
129
+ "X-Title": "Claudish - OpenRouter Proxy",
130
+ } as const;
131
+ `;
132
+ }
133
+
134
+ function generateTypes(models: ExtractedModels): string {
135
+ const modelIds = Object.keys(models)
136
+ .filter((id) => id !== "custom")
137
+ .map((id) => ` "${id}"`)
138
+ .join(",\n");
139
+
140
+ return `// AUTO-GENERATED from shared/recommended-models.md
141
+ // DO NOT EDIT MANUALLY - Run 'bun run extract-models' to regenerate
142
+
143
+ // OpenRouter Models - Top Recommended for Development (Priority Order)
144
+ export const OPENROUTER_MODELS = [
145
+ ${modelIds},
146
+ "custom",
147
+ ] as const;
148
+
149
+ export type OpenRouterModel = (typeof OPENROUTER_MODELS)[number];
150
+ `;
151
+ }
152
+
153
+ // Main execution
154
+ try {
155
+ const sharedModelsPath = join(
156
+ import.meta.dir,
157
+ "../../../shared/recommended-models.md",
158
+ );
159
+ const configPath = join(import.meta.dir, "../src/config.ts");
160
+ const typesPath = join(import.meta.dir, "../src/types.ts");
161
+
162
+ console.log("📖 Reading shared/recommended-models.md...");
163
+ const markdownContent = readFileSync(sharedModelsPath, "utf-8");
164
+
165
+ console.log("🔍 Extracting model information...");
166
+ const models = extractModels(markdownContent);
167
+
168
+ console.log(`✅ Found ${Object.keys(models).length - 1} models + custom option`);
169
+
170
+ console.log("📝 Generating config.ts...");
171
+ const configCode = generateTypeScript(models);
172
+ writeFileSync(configPath, configCode);
173
+
174
+ console.log("📝 Generating types.ts...");
175
+ const typesCode = generateTypes(models);
176
+ const existingTypes = readFileSync(typesPath, "utf-8");
177
+
178
+ // Replace OPENROUTER_MODELS array and OpenRouterModel type, keep other types
179
+ // Handle both auto-generated and manual versions
180
+ let updatedTypes = existingTypes;
181
+
182
+ // Try to replace auto-generated section first
183
+ if (existingTypes.includes("// AUTO-GENERATED")) {
184
+ updatedTypes = existingTypes.replace(
185
+ /\/\/ AUTO-GENERATED[\s\S]*?export type OpenRouterModel = \(typeof OPENROUTER_MODELS\)\[number\];/,
186
+ typesCode.trim(),
187
+ );
188
+ } else {
189
+ // First time - replace manual OPENROUTER_MODELS section
190
+ updatedTypes = existingTypes.replace(
191
+ /\/\/ OpenRouter Models[\s\S]*?export type OpenRouterModel = \(typeof OPENROUTER_MODELS\)\[number\];/,
192
+ typesCode.trim(),
193
+ );
194
+ }
195
+
196
+ writeFileSync(typesPath, updatedTypes);
197
+
198
+ console.log("✅ Successfully generated TypeScript files");
199
+ console.log("");
200
+ console.log("Models:");
201
+ for (const [id, info] of Object.entries(models)) {
202
+ if (id !== "custom") {
203
+ console.log(` • ${id} - ${info.name} (${info.provider})`);
204
+ }
205
+ }
206
+ } catch (error) {
207
+ console.error("❌ Error:", error);
208
+ process.exit(1);
209
+ }