claudish 1.8.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_AGENT_GUIDE.md +534 -0
- package/README.md +102 -0
- package/dist/index.js +317 -21
- package/package.json +24 -21
- package/recommended-models.json +154 -0
- package/scripts/postinstall.cjs +0 -0
- package/skills/claudish-usage/SKILL.md +1127 -0
package/dist/index.js
CHANGED
|
@@ -331,14 +331,14 @@ function getAvailableModels() {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
// src/cli.ts
|
|
334
|
-
import { readFileSync as readFileSync2 } from "node:fs";
|
|
334
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync, copyFileSync } from "node:fs";
|
|
335
335
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
336
336
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
337
337
|
var __filename3 = fileURLToPath2(import.meta.url);
|
|
338
338
|
var __dirname3 = dirname2(__filename3);
|
|
339
339
|
var packageJson = JSON.parse(readFileSync2(join3(__dirname3, "../package.json"), "utf-8"));
|
|
340
340
|
var VERSION = packageJson.version;
|
|
341
|
-
function parseArgs(args) {
|
|
341
|
+
async function parseArgs(args) {
|
|
342
342
|
const config = {
|
|
343
343
|
model: undefined,
|
|
344
344
|
autoApprove: true,
|
|
@@ -429,8 +429,16 @@ function parseArgs(args) {
|
|
|
429
429
|
} else if (arg === "--help" || arg === "-h") {
|
|
430
430
|
printHelp();
|
|
431
431
|
process.exit(0);
|
|
432
|
+
} else if (arg === "--help-ai") {
|
|
433
|
+
printAIAgentGuide();
|
|
434
|
+
process.exit(0);
|
|
435
|
+
} else if (arg === "--init") {
|
|
436
|
+
await initializeClaudishSkill();
|
|
437
|
+
process.exit(0);
|
|
432
438
|
} else if (arg === "--list-models") {
|
|
433
439
|
const hasJsonFlag = args.includes("--json");
|
|
440
|
+
const forceUpdate = args.includes("--force-update");
|
|
441
|
+
await checkAndUpdateModelsCache(forceUpdate);
|
|
434
442
|
if (hasJsonFlag) {
|
|
435
443
|
printAvailableModelsJSON();
|
|
436
444
|
} else {
|
|
@@ -483,6 +491,164 @@ function parseArgs(args) {
|
|
|
483
491
|
}
|
|
484
492
|
return config;
|
|
485
493
|
}
|
|
494
|
+
var CACHE_MAX_AGE_DAYS = 2;
|
|
495
|
+
var MODELS_JSON_PATH = join3(__dirname3, "../recommended-models.json");
|
|
496
|
+
function isCacheStale() {
|
|
497
|
+
if (!existsSync2(MODELS_JSON_PATH)) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
const jsonContent = readFileSync2(MODELS_JSON_PATH, "utf-8");
|
|
502
|
+
const data = JSON.parse(jsonContent);
|
|
503
|
+
if (!data.lastUpdated) {
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
const lastUpdated = new Date(data.lastUpdated);
|
|
507
|
+
const now = new Date;
|
|
508
|
+
const ageInDays = (now.getTime() - lastUpdated.getTime()) / (1000 * 60 * 60 * 24);
|
|
509
|
+
return ageInDays > CACHE_MAX_AGE_DAYS;
|
|
510
|
+
} catch (error) {
|
|
511
|
+
return true;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
async function updateModelsFromOpenRouter() {
|
|
515
|
+
console.error("\uD83D\uDD04 Updating model recommendations from OpenRouter...");
|
|
516
|
+
try {
|
|
517
|
+
const topWeeklyProgrammingModels = [
|
|
518
|
+
"x-ai/grok-code-fast-1",
|
|
519
|
+
"anthropic/claude-sonnet-4.5",
|
|
520
|
+
"google/gemini-2.5-flash",
|
|
521
|
+
"minimax/minimax-m2",
|
|
522
|
+
"anthropic/claude-sonnet-4",
|
|
523
|
+
"z-ai/glm-4.6",
|
|
524
|
+
"anthropic/claude-haiku-4.5",
|
|
525
|
+
"openai/gpt-5",
|
|
526
|
+
"qwen/qwen3-vl-235b-a22b-instruct",
|
|
527
|
+
"openrouter/polaris-alpha"
|
|
528
|
+
];
|
|
529
|
+
const apiResponse = await fetch("https://openrouter.ai/api/v1/models");
|
|
530
|
+
if (!apiResponse.ok) {
|
|
531
|
+
throw new Error(`OpenRouter API returned ${apiResponse.status}`);
|
|
532
|
+
}
|
|
533
|
+
const openrouterData = await apiResponse.json();
|
|
534
|
+
const allModels = openrouterData.data;
|
|
535
|
+
const modelMap = new Map;
|
|
536
|
+
for (const model of allModels) {
|
|
537
|
+
modelMap.set(model.id, model);
|
|
538
|
+
}
|
|
539
|
+
const recommendations = [];
|
|
540
|
+
const providers = new Set;
|
|
541
|
+
for (const modelId of topWeeklyProgrammingModels) {
|
|
542
|
+
const provider = modelId.split("/")[0];
|
|
543
|
+
if (provider === "anthropic") {
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (providers.has(provider)) {
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const model = modelMap.get(modelId);
|
|
550
|
+
if (!model) {
|
|
551
|
+
console.error(`⚠️ Model ${modelId} not found in OpenRouter API (including with limited metadata)`);
|
|
552
|
+
recommendations.push({
|
|
553
|
+
id: modelId,
|
|
554
|
+
name: modelId.split("/")[1].replace(/-/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()),
|
|
555
|
+
description: `${modelId} (metadata pending - not yet available in API)`,
|
|
556
|
+
provider: provider.charAt(0).toUpperCase() + provider.slice(1),
|
|
557
|
+
category: "programming",
|
|
558
|
+
priority: recommendations.length + 1,
|
|
559
|
+
pricing: {
|
|
560
|
+
input: "N/A",
|
|
561
|
+
output: "N/A",
|
|
562
|
+
average: "N/A"
|
|
563
|
+
},
|
|
564
|
+
context: "N/A",
|
|
565
|
+
maxOutputTokens: null,
|
|
566
|
+
modality: "text->text",
|
|
567
|
+
supportsTools: false,
|
|
568
|
+
supportsReasoning: false,
|
|
569
|
+
supportsVision: false,
|
|
570
|
+
isModerated: false,
|
|
571
|
+
recommended: true
|
|
572
|
+
});
|
|
573
|
+
providers.add(provider);
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
const name = model.name || modelId;
|
|
577
|
+
const description = model.description || `${name} model`;
|
|
578
|
+
const architecture = model.architecture || {};
|
|
579
|
+
const topProvider = model.top_provider || {};
|
|
580
|
+
const supportedParams = model.supported_parameters || [];
|
|
581
|
+
const promptPrice = parseFloat(model.pricing?.prompt || "0");
|
|
582
|
+
const completionPrice = parseFloat(model.pricing?.completion || "0");
|
|
583
|
+
const inputPrice = promptPrice > 0 ? `$${(promptPrice * 1e6).toFixed(2)}/1M` : "FREE";
|
|
584
|
+
const outputPrice = completionPrice > 0 ? `$${(completionPrice * 1e6).toFixed(2)}/1M` : "FREE";
|
|
585
|
+
const avgPrice = promptPrice > 0 || completionPrice > 0 ? `$${((promptPrice + completionPrice) / 2 * 1e6).toFixed(2)}/1M` : "FREE";
|
|
586
|
+
let category = "programming";
|
|
587
|
+
const lowerDesc = description.toLowerCase() + " " + name.toLowerCase();
|
|
588
|
+
if (lowerDesc.includes("vision") || lowerDesc.includes("vl-") || lowerDesc.includes("multimodal")) {
|
|
589
|
+
category = "vision";
|
|
590
|
+
} else if (lowerDesc.includes("reason")) {
|
|
591
|
+
category = "reasoning";
|
|
592
|
+
}
|
|
593
|
+
recommendations.push({
|
|
594
|
+
id: modelId,
|
|
595
|
+
name,
|
|
596
|
+
description,
|
|
597
|
+
provider: provider.charAt(0).toUpperCase() + provider.slice(1),
|
|
598
|
+
category,
|
|
599
|
+
priority: recommendations.length + 1,
|
|
600
|
+
pricing: {
|
|
601
|
+
input: inputPrice,
|
|
602
|
+
output: outputPrice,
|
|
603
|
+
average: avgPrice
|
|
604
|
+
},
|
|
605
|
+
context: topProvider.context_length ? `${Math.floor(topProvider.context_length / 1000)}K` : "N/A",
|
|
606
|
+
maxOutputTokens: topProvider.max_completion_tokens || null,
|
|
607
|
+
modality: architecture.modality || "text->text",
|
|
608
|
+
supportsTools: supportedParams.includes("tools") || supportedParams.includes("tool_choice"),
|
|
609
|
+
supportsReasoning: supportedParams.includes("reasoning") || supportedParams.includes("include_reasoning"),
|
|
610
|
+
supportsVision: (architecture.input_modalities || []).includes("image") || (architecture.input_modalities || []).includes("video"),
|
|
611
|
+
isModerated: topProvider.is_moderated || false,
|
|
612
|
+
recommended: true
|
|
613
|
+
});
|
|
614
|
+
providers.add(provider);
|
|
615
|
+
}
|
|
616
|
+
let version = "1.1.5";
|
|
617
|
+
if (existsSync2(MODELS_JSON_PATH)) {
|
|
618
|
+
try {
|
|
619
|
+
const existing = JSON.parse(readFileSync2(MODELS_JSON_PATH, "utf-8"));
|
|
620
|
+
version = existing.version || version;
|
|
621
|
+
} catch {}
|
|
622
|
+
}
|
|
623
|
+
const updatedData = {
|
|
624
|
+
version,
|
|
625
|
+
lastUpdated: new Date().toISOString().split("T")[0],
|
|
626
|
+
source: "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
|
|
627
|
+
models: recommendations
|
|
628
|
+
};
|
|
629
|
+
writeFileSync2(MODELS_JSON_PATH, JSON.stringify(updatedData, null, 2), "utf-8");
|
|
630
|
+
console.error(`✅ Updated ${recommendations.length} models (last updated: ${updatedData.lastUpdated})`);
|
|
631
|
+
} catch (error) {
|
|
632
|
+
console.error(`❌ Failed to update models: ${error instanceof Error ? error.message : String(error)}`);
|
|
633
|
+
console.error(" Using cached models (if available)");
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async function checkAndUpdateModelsCache(forceUpdate = false) {
|
|
637
|
+
if (forceUpdate) {
|
|
638
|
+
console.error("\uD83D\uDD04 Force update requested...");
|
|
639
|
+
await updateModelsFromOpenRouter();
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
if (isCacheStale()) {
|
|
643
|
+
console.error("⚠️ Model cache is stale (>2 days old), updating...");
|
|
644
|
+
await updateModelsFromOpenRouter();
|
|
645
|
+
} else {
|
|
646
|
+
try {
|
|
647
|
+
const data = JSON.parse(readFileSync2(MODELS_JSON_PATH, "utf-8"));
|
|
648
|
+
console.error(`✓ Using cached models (last updated: ${data.lastUpdated})`);
|
|
649
|
+
} catch {}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
486
652
|
function printVersion() {
|
|
487
653
|
console.log(`claudish version ${VERSION}`);
|
|
488
654
|
}
|
|
@@ -510,10 +676,13 @@ OPTIONS:
|
|
|
510
676
|
--cost-tracker Enable cost tracking for API usage (NB!)
|
|
511
677
|
--audit-costs Show cost analysis report
|
|
512
678
|
--reset-costs Reset accumulated cost statistics
|
|
513
|
-
--list-models List available OpenRouter models
|
|
679
|
+
--list-models List available OpenRouter models (auto-updates if stale >2 days)
|
|
514
680
|
--list-models --json Output model list in JSON format
|
|
681
|
+
--force-update Force refresh model cache from OpenRouter API
|
|
515
682
|
--version Show version information
|
|
516
683
|
-h, --help Show this help message
|
|
684
|
+
--help-ai Show AI agent usage guide (file-based patterns, sub-agents)
|
|
685
|
+
--init Install Claudish skill in current project (.claude/skills/)
|
|
517
686
|
|
|
518
687
|
MODES:
|
|
519
688
|
• Interactive mode (default): Shows model selector, starts persistent session
|
|
@@ -574,29 +743,156 @@ EXAMPLES:
|
|
|
574
743
|
claudish --verbose "analyze code structure"
|
|
575
744
|
|
|
576
745
|
AVAILABLE MODELS:
|
|
577
|
-
|
|
746
|
+
List models: claudish --list-models
|
|
578
747
|
JSON output: claudish --list-models --json
|
|
748
|
+
Force update: claudish --list-models --force-update
|
|
749
|
+
(Cache auto-updates every 2 days)
|
|
579
750
|
|
|
580
751
|
MORE INFO:
|
|
581
752
|
GitHub: https://github.com/MadAppGang/claude-code
|
|
582
753
|
OpenRouter: https://openrouter.ai
|
|
583
754
|
`);
|
|
584
755
|
}
|
|
756
|
+
function printAIAgentGuide() {
|
|
757
|
+
try {
|
|
758
|
+
const guidePath = join3(__dirname3, "../AI_AGENT_GUIDE.md");
|
|
759
|
+
const guideContent = readFileSync2(guidePath, "utf-8");
|
|
760
|
+
console.log(guideContent);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error("Error reading AI Agent Guide:");
|
|
763
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
764
|
+
console.error(`
|
|
765
|
+
The guide should be located at: AI_AGENT_GUIDE.md`);
|
|
766
|
+
console.error("You can also view it online at:");
|
|
767
|
+
console.error("https://github.com/MadAppGang/claude-code/blob/main/mcp/claudish/AI_AGENT_GUIDE.md");
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
async function initializeClaudishSkill() {
|
|
772
|
+
console.log(`\uD83D\uDD27 Initializing Claudish skill in current project...
|
|
773
|
+
`);
|
|
774
|
+
const cwd = process.cwd();
|
|
775
|
+
const claudeDir = join3(cwd, ".claude");
|
|
776
|
+
const skillsDir = join3(claudeDir, "skills");
|
|
777
|
+
const claudishSkillDir = join3(skillsDir, "claudish-usage");
|
|
778
|
+
const skillFile = join3(claudishSkillDir, "SKILL.md");
|
|
779
|
+
if (existsSync2(skillFile)) {
|
|
780
|
+
console.log("✅ Claudish skill already installed at:");
|
|
781
|
+
console.log(` ${skillFile}
|
|
782
|
+
`);
|
|
783
|
+
console.log("\uD83D\uDCA1 To reinstall, delete the file and run 'claudish --init' again.");
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
const sourceSkillPath = join3(__dirname3, "../skills/claudish-usage/SKILL.md");
|
|
787
|
+
if (!existsSync2(sourceSkillPath)) {
|
|
788
|
+
console.error("❌ Error: Claudish skill file not found in installation.");
|
|
789
|
+
console.error(` Expected at: ${sourceSkillPath}`);
|
|
790
|
+
console.error(`
|
|
791
|
+
\uD83D\uDCA1 Try reinstalling Claudish:`);
|
|
792
|
+
console.error(" npm install -g claudish@latest");
|
|
793
|
+
process.exit(1);
|
|
794
|
+
}
|
|
795
|
+
try {
|
|
796
|
+
if (!existsSync2(claudeDir)) {
|
|
797
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
798
|
+
console.log("\uD83D\uDCC1 Created .claude/ directory");
|
|
799
|
+
}
|
|
800
|
+
if (!existsSync2(skillsDir)) {
|
|
801
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
802
|
+
console.log("\uD83D\uDCC1 Created .claude/skills/ directory");
|
|
803
|
+
}
|
|
804
|
+
if (!existsSync2(claudishSkillDir)) {
|
|
805
|
+
mkdirSync(claudishSkillDir, { recursive: true });
|
|
806
|
+
console.log("\uD83D\uDCC1 Created .claude/skills/claudish-usage/ directory");
|
|
807
|
+
}
|
|
808
|
+
copyFileSync(sourceSkillPath, skillFile);
|
|
809
|
+
console.log("✅ Installed Claudish skill at:");
|
|
810
|
+
console.log(` ${skillFile}
|
|
811
|
+
`);
|
|
812
|
+
console.log("━".repeat(60));
|
|
813
|
+
console.log(`
|
|
814
|
+
\uD83C\uDF89 Claudish skill installed successfully!
|
|
815
|
+
`);
|
|
816
|
+
console.log(`\uD83D\uDCCB Next steps:
|
|
817
|
+
`);
|
|
818
|
+
console.log("1. Reload Claude Code to discover the skill");
|
|
819
|
+
console.log(" - Restart Claude Code, or");
|
|
820
|
+
console.log(` - Re-open your project
|
|
821
|
+
`);
|
|
822
|
+
console.log("2. Use Claudish with external models:");
|
|
823
|
+
console.log(' - User: "use Grok to implement feature X"');
|
|
824
|
+
console.log(` - Claude will automatically use the skill
|
|
825
|
+
`);
|
|
826
|
+
console.log("\uD83D\uDCA1 The skill enforces best practices:");
|
|
827
|
+
console.log(" ✅ Mandatory sub-agent delegation");
|
|
828
|
+
console.log(" ✅ File-based instruction patterns");
|
|
829
|
+
console.log(` ✅ Context window protection
|
|
830
|
+
`);
|
|
831
|
+
console.log(`\uD83D\uDCD6 For more info: claudish --help-ai
|
|
832
|
+
`);
|
|
833
|
+
console.log("━".repeat(60));
|
|
834
|
+
} catch (error) {
|
|
835
|
+
console.error(`
|
|
836
|
+
❌ Error installing Claudish skill:`);
|
|
837
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
838
|
+
console.error(`
|
|
839
|
+
\uD83D\uDCA1 Make sure you have write permissions in the current directory.`);
|
|
840
|
+
process.exit(1);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
585
843
|
function printAvailableModels() {
|
|
844
|
+
let lastUpdated = "unknown";
|
|
845
|
+
let models = [];
|
|
846
|
+
try {
|
|
847
|
+
if (existsSync2(MODELS_JSON_PATH)) {
|
|
848
|
+
const data = JSON.parse(readFileSync2(MODELS_JSON_PATH, "utf-8"));
|
|
849
|
+
lastUpdated = data.lastUpdated || "unknown";
|
|
850
|
+
models = data.models || [];
|
|
851
|
+
}
|
|
852
|
+
} catch {
|
|
853
|
+
const basicModels = getAvailableModels();
|
|
854
|
+
const modelInfo = loadModelInfo();
|
|
855
|
+
for (const model of basicModels) {
|
|
856
|
+
const info = modelInfo[model];
|
|
857
|
+
console.log(` ${model}`);
|
|
858
|
+
console.log(` ${info.name} - ${info.description}`);
|
|
859
|
+
console.log("");
|
|
860
|
+
}
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
586
863
|
console.log(`
|
|
587
|
-
Available OpenRouter Models (
|
|
864
|
+
Available OpenRouter Models (last updated: ${lastUpdated}):
|
|
588
865
|
`);
|
|
589
|
-
|
|
590
|
-
|
|
866
|
+
console.log(" Model Provider Pricing Context Capabilities");
|
|
867
|
+
console.log(" " + "─".repeat(86));
|
|
591
868
|
for (const model of models) {
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
869
|
+
const modelId = model.id.length > 30 ? model.id.substring(0, 27) + "..." : model.id;
|
|
870
|
+
const modelIdPadded = modelId.padEnd(30);
|
|
871
|
+
const provider = model.provider.length > 10 ? model.provider.substring(0, 7) + "..." : model.provider;
|
|
872
|
+
const providerPadded = provider.padEnd(10);
|
|
873
|
+
let pricing = model.pricing?.average || "N/A";
|
|
874
|
+
if (pricing.includes("-1000000")) {
|
|
875
|
+
pricing = "varies";
|
|
876
|
+
} else if (pricing === "$0.00/1M" || pricing === "FREE") {
|
|
877
|
+
pricing = "FREE";
|
|
878
|
+
}
|
|
879
|
+
const pricingPadded = pricing.padEnd(10);
|
|
880
|
+
const context = model.context || "N/A";
|
|
881
|
+
const contextPadded = context.padEnd(7);
|
|
882
|
+
const tools = model.supportsTools ? "\uD83D\uDD27" : " ";
|
|
883
|
+
const reasoning = model.supportsReasoning ? "\uD83E\uDDE0" : " ";
|
|
884
|
+
const vision = model.supportsVision ? "\uD83D\uDC41️ " : " ";
|
|
885
|
+
const capabilities = `${tools} ${reasoning} ${vision}`;
|
|
886
|
+
console.log(` ${modelIdPadded} ${providerPadded} ${pricingPadded} ${contextPadded} ${capabilities}`);
|
|
887
|
+
}
|
|
888
|
+
console.log("");
|
|
889
|
+
console.log(" Capabilities: \uD83D\uDD27 Tools \uD83E\uDDE0 Reasoning \uD83D\uDC41️ Vision");
|
|
890
|
+
console.log("");
|
|
597
891
|
console.log("Set default with: export CLAUDISH_MODEL=<model>");
|
|
598
892
|
console.log(" or: export ANTHROPIC_MODEL=<model>");
|
|
599
|
-
console.log(
|
|
893
|
+
console.log("Or use: claudish --model <model> ...");
|
|
894
|
+
console.log(`
|
|
895
|
+
Force update: claudish --list-models --force-update
|
|
600
896
|
`);
|
|
601
897
|
}
|
|
602
898
|
function printAvailableModelsJSON() {
|
|
@@ -776,7 +1072,7 @@ async function selectModelInteractively() {
|
|
|
776
1072
|
}
|
|
777
1073
|
|
|
778
1074
|
// src/logger.ts
|
|
779
|
-
import { writeFileSync as
|
|
1075
|
+
import { writeFileSync as writeFileSync3, appendFile, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
780
1076
|
import { join as join4 } from "path";
|
|
781
1077
|
var logFilePath = null;
|
|
782
1078
|
var logLevel = "info";
|
|
@@ -807,7 +1103,7 @@ function scheduleFlush() {
|
|
|
807
1103
|
flushTimer = null;
|
|
808
1104
|
}
|
|
809
1105
|
if (logFilePath && logBuffer.length > 0) {
|
|
810
|
-
|
|
1106
|
+
writeFileSync3(logFilePath, logBuffer.join(""), { flag: "a" });
|
|
811
1107
|
logBuffer = [];
|
|
812
1108
|
}
|
|
813
1109
|
});
|
|
@@ -823,12 +1119,12 @@ function initLogger(debugMode, level = "info") {
|
|
|
823
1119
|
}
|
|
824
1120
|
logLevel = level;
|
|
825
1121
|
const logsDir = join4(process.cwd(), "logs");
|
|
826
|
-
if (!
|
|
827
|
-
|
|
1122
|
+
if (!existsSync3(logsDir)) {
|
|
1123
|
+
mkdirSync2(logsDir, { recursive: true });
|
|
828
1124
|
}
|
|
829
1125
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").split("T").join("_").slice(0, -5);
|
|
830
1126
|
logFilePath = join4(logsDir, `claudish_${timestamp}.log`);
|
|
831
|
-
|
|
1127
|
+
writeFileSync3(logFilePath, `Claudish Debug Log - ${new Date().toISOString()}
|
|
832
1128
|
Log Level: ${level}
|
|
833
1129
|
${"=".repeat(80)}
|
|
834
1130
|
|
|
@@ -3063,7 +3359,7 @@ var serve = (options, listeningListener) => {
|
|
|
3063
3359
|
};
|
|
3064
3360
|
|
|
3065
3361
|
// src/proxy-server.ts
|
|
3066
|
-
import { writeFileSync as
|
|
3362
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
3067
3363
|
|
|
3068
3364
|
// src/transform.ts
|
|
3069
3365
|
function removeUriFormat(schema) {
|
|
@@ -3851,7 +4147,7 @@ data: ${JSON.stringify(data)}
|
|
|
3851
4147
|
total_tokens: cumulativeInputTokens + cumulativeOutputTokens,
|
|
3852
4148
|
updated_at: Date.now()
|
|
3853
4149
|
};
|
|
3854
|
-
|
|
4150
|
+
writeFileSync4(tokenFilePath, JSON.stringify(tokenData), "utf-8");
|
|
3855
4151
|
} catch (error) {
|
|
3856
4152
|
if (isLoggingEnabled()) {
|
|
3857
4153
|
log(`[Proxy] Failed to write token file: ${error}`);
|
|
@@ -4330,7 +4626,7 @@ async function readStdin() {
|
|
|
4330
4626
|
}
|
|
4331
4627
|
async function main() {
|
|
4332
4628
|
try {
|
|
4333
|
-
const config = parseArgs(process.argv.slice(2));
|
|
4629
|
+
const config = await parseArgs(process.argv.slice(2));
|
|
4334
4630
|
initLogger(config.debug, config.logLevel);
|
|
4335
4631
|
if (config.debug && !config.quiet) {
|
|
4336
4632
|
const logFile = getLogFilePath();
|
package/package.json
CHANGED
|
@@ -1,29 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudish",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.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",
|
|
7
7
|
"bin": {
|
|
8
8
|
"claudish": "dist/index.js"
|
|
9
9
|
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"dev": "bun run src/index.ts",
|
|
12
|
-
"dev:grok": "bun run src/index.ts --interactive --model x-ai/grok-code-fast-1",
|
|
13
|
-
"dev:grok:debug": "bun run src/index.ts --interactive --debug --log-level info --model x-ai/grok-code-fast-1",
|
|
14
|
-
"dev:info": "bun run src/index.ts --interactive --monitor",
|
|
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",
|
|
17
|
-
"link": "npm link",
|
|
18
|
-
"unlink": "npm unlink -g claudish",
|
|
19
|
-
"install-global": "bun run build && npm link",
|
|
20
|
-
"kill-all": "pkill -f 'bun.*claudish' || pkill -f 'claude.*claudish-settings' || echo 'No claudish processes found'",
|
|
21
|
-
"test": "bun test ./tests/comprehensive-model-test.ts",
|
|
22
|
-
"typecheck": "tsc --noEmit",
|
|
23
|
-
"lint": "biome check .",
|
|
24
|
-
"format": "biome format --write .",
|
|
25
|
-
"postinstall": "node scripts/postinstall.cjs"
|
|
26
|
-
},
|
|
27
10
|
"dependencies": {
|
|
28
11
|
"@hono/node-server": "^1.19.6",
|
|
29
12
|
"hono": "^4.10.6"
|
|
@@ -35,7 +18,10 @@
|
|
|
35
18
|
},
|
|
36
19
|
"files": [
|
|
37
20
|
"dist/",
|
|
38
|
-
"scripts/"
|
|
21
|
+
"scripts/",
|
|
22
|
+
"skills/",
|
|
23
|
+
"AI_AGENT_GUIDE.md",
|
|
24
|
+
"recommended-models.json"
|
|
39
25
|
],
|
|
40
26
|
"engines": {
|
|
41
27
|
"node": ">=18.0.0",
|
|
@@ -51,5 +37,22 @@
|
|
|
51
37
|
"ai"
|
|
52
38
|
],
|
|
53
39
|
"author": "Jack Rudenko <i@madappgang.com>",
|
|
54
|
-
"license": "MIT"
|
|
55
|
-
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"scripts": {
|
|
42
|
+
"dev": "bun run src/index.ts",
|
|
43
|
+
"dev:grok": "bun run src/index.ts --interactive --model x-ai/grok-code-fast-1",
|
|
44
|
+
"dev:grok:debug": "bun run src/index.ts --interactive --debug --log-level info --model x-ai/grok-code-fast-1",
|
|
45
|
+
"dev:info": "bun run src/index.ts --interactive --monitor",
|
|
46
|
+
"extract-models": "bun run scripts/extract-models.ts",
|
|
47
|
+
"build": "bun run extract-models && bun build src/index.ts --outdir dist --target node && chmod +x dist/index.js",
|
|
48
|
+
"link": "npm link",
|
|
49
|
+
"unlink": "npm unlink -g claudish",
|
|
50
|
+
"install-global": "bun run build && npm link",
|
|
51
|
+
"kill-all": "pkill -f 'bun.*claudish' || pkill -f 'claude.*claudish-settings' || echo 'No claudish processes found'",
|
|
52
|
+
"test": "bun test ./tests/comprehensive-model-test.ts",
|
|
53
|
+
"typecheck": "tsc --noEmit",
|
|
54
|
+
"lint": "biome check .",
|
|
55
|
+
"format": "biome format --write .",
|
|
56
|
+
"postinstall": "node scripts/postinstall.cjs"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.1.5",
|
|
3
|
+
"lastUpdated": "2025-11-19",
|
|
4
|
+
"source": "https://openrouter.ai/models?categories=programming&fmt=cards&order=top-weekly",
|
|
5
|
+
"models": [
|
|
6
|
+
{
|
|
7
|
+
"id": "x-ai/grok-code-fast-1",
|
|
8
|
+
"name": "xAI: Grok Code Fast 1",
|
|
9
|
+
"description": "Grok Code Fast 1 is a speedy and economical reasoning model that excels at agentic coding. With reasoning traces visible in the response, developers can steer Grok Code for high-quality work flows.",
|
|
10
|
+
"provider": "X-ai",
|
|
11
|
+
"category": "reasoning",
|
|
12
|
+
"priority": 1,
|
|
13
|
+
"pricing": {
|
|
14
|
+
"input": "$0.20/1M",
|
|
15
|
+
"output": "$1.50/1M",
|
|
16
|
+
"average": "$0.85/1M"
|
|
17
|
+
},
|
|
18
|
+
"context": "256K",
|
|
19
|
+
"maxOutputTokens": 10000,
|
|
20
|
+
"modality": "text->text",
|
|
21
|
+
"supportsTools": true,
|
|
22
|
+
"supportsReasoning": true,
|
|
23
|
+
"supportsVision": false,
|
|
24
|
+
"isModerated": false,
|
|
25
|
+
"recommended": true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "google/gemini-2.5-flash",
|
|
29
|
+
"name": "Google: Gemini 2.5 Flash",
|
|
30
|
+
"description": "Gemini 2.5 Flash is Google's state-of-the-art workhorse model, specifically designed for advanced reasoning, coding, mathematics, and scientific tasks. It includes built-in \"thinking\" capabilities, enabling it to provide responses with greater accuracy and nuanced context handling. \n\nAdditionally, Gemini 2.5 Flash is configurable through the \"max tokens for reasoning\" parameter, as described in the documentation (https://openrouter.ai/docs/use-cases/reasoning-tokens#max-tokens-for-reasoning).",
|
|
31
|
+
"provider": "Google",
|
|
32
|
+
"category": "reasoning",
|
|
33
|
+
"priority": 2,
|
|
34
|
+
"pricing": {
|
|
35
|
+
"input": "$0.30/1M",
|
|
36
|
+
"output": "$2.50/1M",
|
|
37
|
+
"average": "$1.40/1M"
|
|
38
|
+
},
|
|
39
|
+
"context": "1048K",
|
|
40
|
+
"maxOutputTokens": 65535,
|
|
41
|
+
"modality": "text+image->text",
|
|
42
|
+
"supportsTools": true,
|
|
43
|
+
"supportsReasoning": true,
|
|
44
|
+
"supportsVision": true,
|
|
45
|
+
"isModerated": false,
|
|
46
|
+
"recommended": true
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "minimax/minimax-m2",
|
|
50
|
+
"name": "MiniMax: MiniMax M2",
|
|
51
|
+
"description": "MiniMax-M2 is a compact, high-efficiency large language model optimized for end-to-end coding and agentic workflows. With 10 billion activated parameters (230 billion total), it delivers near-frontier intelligence across general reasoning, tool use, and multi-step task execution while maintaining low latency and deployment efficiency.\n\nThe model excels in code generation, multi-file editing, compile-run-fix loops, and test-validated repair, showing strong results on SWE-Bench Verified, Multi-SWE-Bench, and Terminal-Bench. It also performs competitively in agentic evaluations such as BrowseComp and GAIA, effectively handling long-horizon planning, retrieval, and recovery from execution errors.\n\nBenchmarked by [Artificial Analysis](https://artificialanalysis.ai/models/minimax-m2), MiniMax-M2 ranks among the top open-source models for composite intelligence, spanning mathematics, science, and instruction-following. Its small activation footprint enables fast inference, high concurrency, and improved unit economics, making it well-suited for large-scale agents, developer assistants, and reasoning-driven applications that require responsiveness and cost efficiency.\n\nTo avoid degrading this model's performance, MiniMax highly recommends preserving reasoning between turns. Learn more about using reasoning_details to pass back reasoning in our [docs](https://openrouter.ai/docs/use-cases/reasoning-tokens#preserving-reasoning-blocks).",
|
|
52
|
+
"provider": "Minimax",
|
|
53
|
+
"category": "reasoning",
|
|
54
|
+
"priority": 3,
|
|
55
|
+
"pricing": {
|
|
56
|
+
"input": "$0.26/1M",
|
|
57
|
+
"output": "$1.02/1M",
|
|
58
|
+
"average": "$0.64/1M"
|
|
59
|
+
},
|
|
60
|
+
"context": "204K",
|
|
61
|
+
"maxOutputTokens": 131072,
|
|
62
|
+
"modality": "text->text",
|
|
63
|
+
"supportsTools": true,
|
|
64
|
+
"supportsReasoning": true,
|
|
65
|
+
"supportsVision": false,
|
|
66
|
+
"isModerated": false,
|
|
67
|
+
"recommended": true
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "z-ai/glm-4.6",
|
|
71
|
+
"name": "Z.AI: GLM 4.6",
|
|
72
|
+
"description": "Compared with GLM-4.5, this generation brings several key improvements:\n\nLonger context window: The context window has been expanded from 128K to 200K tokens, enabling the model to handle more complex agentic tasks.\nSuperior coding performance: The model achieves higher scores on code benchmarks and demonstrates better real-world performance in applications such as Claude Code、Cline、Roo Code and Kilo Code, including improvements in generating visually polished front-end pages.\nAdvanced reasoning: GLM-4.6 shows a clear improvement in reasoning performance and supports tool use during inference, leading to stronger overall capability.\nMore capable agents: GLM-4.6 exhibits stronger performance in tool using and search-based agents, and integrates more effectively within agent frameworks.\nRefined writing: Better aligns with human preferences in style and readability, and performs more naturally in role-playing scenarios.",
|
|
73
|
+
"provider": "Z-ai",
|
|
74
|
+
"category": "reasoning",
|
|
75
|
+
"priority": 4,
|
|
76
|
+
"pricing": {
|
|
77
|
+
"input": "$0.40/1M",
|
|
78
|
+
"output": "$1.75/1M",
|
|
79
|
+
"average": "$1.07/1M"
|
|
80
|
+
},
|
|
81
|
+
"context": "202K",
|
|
82
|
+
"maxOutputTokens": 202752,
|
|
83
|
+
"modality": "text->text",
|
|
84
|
+
"supportsTools": true,
|
|
85
|
+
"supportsReasoning": true,
|
|
86
|
+
"supportsVision": false,
|
|
87
|
+
"isModerated": false,
|
|
88
|
+
"recommended": true
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "openai/gpt-5",
|
|
92
|
+
"name": "OpenAI: GPT-5",
|
|
93
|
+
"description": "GPT-5 is OpenAI’s most advanced model, offering major improvements in reasoning, code quality, and user experience. It is optimized for complex tasks that require step-by-step reasoning, instruction following, and accuracy in high-stakes use cases. It supports test-time routing features and advanced prompt understanding, including user-specified intent like \"think hard about this.\" Improvements include reductions in hallucination, sycophancy, and better performance in coding, writing, and health-related tasks.",
|
|
94
|
+
"provider": "Openai",
|
|
95
|
+
"category": "reasoning",
|
|
96
|
+
"priority": 5,
|
|
97
|
+
"pricing": {
|
|
98
|
+
"input": "$1.25/1M",
|
|
99
|
+
"output": "$10.00/1M",
|
|
100
|
+
"average": "$5.63/1M"
|
|
101
|
+
},
|
|
102
|
+
"context": "400K",
|
|
103
|
+
"maxOutputTokens": 128000,
|
|
104
|
+
"modality": "text+image->text",
|
|
105
|
+
"supportsTools": true,
|
|
106
|
+
"supportsReasoning": true,
|
|
107
|
+
"supportsVision": true,
|
|
108
|
+
"isModerated": true,
|
|
109
|
+
"recommended": true
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"id": "qwen/qwen3-vl-235b-a22b-instruct",
|
|
113
|
+
"name": "Qwen: Qwen3 VL 235B A22B Instruct",
|
|
114
|
+
"description": "Qwen3-VL-235B-A22B Instruct is an open-weight multimodal model that unifies strong text generation with visual understanding across images and video. The Instruct model targets general vision-language use (VQA, document parsing, chart/table extraction, multilingual OCR). The series emphasizes robust perception (recognition of diverse real-world and synthetic categories), spatial understanding (2D/3D grounding), and long-form visual comprehension, with competitive results on public multimodal benchmarks for both perception and reasoning.\n\nBeyond analysis, Qwen3-VL supports agentic interaction and tool use: it can follow complex instructions over multi-image, multi-turn dialogues; align text to video timelines for precise temporal queries; and operate GUI elements for automation tasks. The models also enable visual coding workflows—turning sketches or mockups into code and assisting with UI debugging—while maintaining strong text-only performance comparable to the flagship Qwen3 language models. This makes Qwen3-VL suitable for production scenarios spanning document AI, multilingual OCR, software/UI assistance, spatial/embodied tasks, and research on vision-language agents.",
|
|
115
|
+
"provider": "Qwen",
|
|
116
|
+
"category": "vision",
|
|
117
|
+
"priority": 6,
|
|
118
|
+
"pricing": {
|
|
119
|
+
"input": "$0.21/1M",
|
|
120
|
+
"output": "$1.90/1M",
|
|
121
|
+
"average": "$1.06/1M"
|
|
122
|
+
},
|
|
123
|
+
"context": "131K",
|
|
124
|
+
"maxOutputTokens": 32768,
|
|
125
|
+
"modality": "text+image->text",
|
|
126
|
+
"supportsTools": true,
|
|
127
|
+
"supportsReasoning": false,
|
|
128
|
+
"supportsVision": true,
|
|
129
|
+
"isModerated": false,
|
|
130
|
+
"recommended": true
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"id": "openrouter/polaris-alpha",
|
|
134
|
+
"name": "Polaris Alpha",
|
|
135
|
+
"description": "openrouter/polaris-alpha (metadata pending - not yet available in API)",
|
|
136
|
+
"provider": "Openrouter",
|
|
137
|
+
"category": "programming",
|
|
138
|
+
"priority": 7,
|
|
139
|
+
"pricing": {
|
|
140
|
+
"input": "N/A",
|
|
141
|
+
"output": "N/A",
|
|
142
|
+
"average": "N/A"
|
|
143
|
+
},
|
|
144
|
+
"context": "N/A",
|
|
145
|
+
"maxOutputTokens": null,
|
|
146
|
+
"modality": "text->text",
|
|
147
|
+
"supportsTools": false,
|
|
148
|
+
"supportsReasoning": false,
|
|
149
|
+
"supportsVision": false,
|
|
150
|
+
"isModerated": false,
|
|
151
|
+
"recommended": true
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
package/scripts/postinstall.cjs
CHANGED
|
File without changes
|