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 +242 -107
- package/package.json +3 -2
- package/scripts/extract-models.ts +209 -0
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/
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
451
|
-
|
|
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
|
-
|
|
519
|
-
const info =
|
|
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-${
|
|
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 >
|
|
546
|
-
console.log(`\x1B[31mInvalid selection. Please enter 1-${
|
|
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 =
|
|
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
|
|
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 =
|
|
653
|
-
if (!
|
|
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 =
|
|
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(
|
|
1127
|
+
let keyIndex2 = url.indexOf("?", 8);
|
|
996
1128
|
if (keyIndex2 === -1) {
|
|
997
|
-
|
|
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
|
|
3085
|
-
const
|
|
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
|
-
...
|
|
3596
|
+
...OPENROUTER_HEADERS2
|
|
3462
3597
|
};
|
|
3463
|
-
const openrouterResponse = await fetch(
|
|
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.
|
|
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
|
-
"
|
|
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
|
+
}
|