tmpa-cli 1.0.22 → 1.0.23

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.
Files changed (2) hide show
  1. package/bin/index.js +74 -41
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -39,15 +39,13 @@ const PROVIDERS = {
39
39
  '3': { name: 'NVIDIA NIM', endpoint: 'https://integrate.api.nvidia.com/v1', defaultModel: 'meta/llama-3.1-70b-instruct' },
40
40
  '4': { name: 'OpenAI', endpoint: 'https://api.openai.com/v1', defaultModel: 'gpt-4o-mini' },
41
41
  '5': { name: 'Anthropic', endpoint: 'https://api.anthropic.com/v1', defaultModel: 'claude-3-5-haiku-20241022' },
42
- '6': { name: 'Google Gemini', endpoint: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent', defaultModel: 'gemini-2.5-flash' },
42
+ '6': { name: 'Google Gemini', endpoint: 'https://generativelanguage.googleapis.com/v1beta', defaultModel: 'gemini-2.5-flash' },
43
43
  '7': { name: 'Custom / Auto-Detect', endpoint: '', defaultModel: '' }
44
44
  };
45
45
 
46
46
  // 100+ POPULAR MCP PRESETS LIST
47
47
  const MCP_PRESETS = [
48
48
  { id: 'custom', name: '🛠️ Custom / Lainnya', category: 'General', type: 'custom', desc: 'Input Manual Name, Target, & Key' },
49
-
50
- // Cloud, AI & UI
51
49
  { id: 'google-stitch', name: '⚡ Google Stitch', category: 'Cloud & AI', type: 'direct-api', endpoint: 'https://stitch.googleapis.com/v1', reqAuth: 'GOOGLE_STITCH_API_KEY', desc: 'UI & App Prototyping MCP by Google' },
52
50
  { id: 'supabase', name: '⚡ Supabase MCP', category: 'Cloud & AI', type: 'direct-api', endpoint: 'https://api.supabase.com/mcp', reqAuth: 'SUPABASE_ACCESS_TOKEN', desc: 'Database, Auth & Storage Management' },
53
51
  { id: 'cloudflare-workers', name: '☁️ Cloudflare Workers', category: 'Cloud & AI', type: 'stdio', command: 'npx -y @cloudflare/mcp-server-cloudflare', reqAuth: 'CLOUDFLARE_API_TOKEN', desc: 'Deploy & manage edge functions' },
@@ -56,30 +54,22 @@ const MCP_PRESETS = [
56
54
  { id: 'firebase', name: '🔥 Firebase MCP', category: 'Cloud & AI', type: 'stdio', command: 'npx -y firebase-mcp-server', reqAuth: 'FIREBASE_TOKEN', desc: 'Firestore, Auth & Realtime DB' },
57
55
  { id: 'huggingface', name: '🤗 HuggingFace Spaces', category: 'Cloud & AI', type: 'direct-api', endpoint: 'https://huggingface.co/api/mcp', reqAuth: 'HF_TOKEN', desc: 'Run open-source AI models & spaces' },
58
56
  { id: 'replicate', name: '🌀 Replicate MCP', category: 'Cloud & AI', type: 'stdio', command: 'npx -y @replicate/mcp-server', reqAuth: 'REPLICATE_API_TOKEN', desc: 'Run image/video AI generation models' },
59
-
60
- // Developer Tools & VCS
61
57
  { id: 'github', name: '🐙 GitHub Official', category: 'Developer Tools', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-github', reqAuth: 'GITHUB_PERSONAL_ACCESS_TOKEN', desc: 'Repository, Issues, PRs & Gists' },
62
58
  { id: 'gitlab', name: '🦊 GitLab MCP', category: 'Developer Tools', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-gitlab', reqAuth: 'GITLAB_PERSONAL_ACCESS_TOKEN', desc: 'GitLab projects & CI/CD pipelines' },
63
59
  { id: 'postman', name: '🚀 Postman MCP', category: 'Developer Tools', type: 'stdio', command: 'npx -y @postman/mcp-server', reqAuth: 'POSTMAN_API_KEY', desc: 'API Collection testing & documentation' },
64
60
  { id: 'sentry', name: '🛡️ Sentry Error Tracker', category: 'Developer Tools', type: 'stdio', command: 'npx -y @sentry/mcp-server', reqAuth: 'SENTRY_AUTH_TOKEN', desc: 'Inspect application bugs & stacktraces' },
65
61
  { id: 'docker', name: '🐳 Docker Local MCP', category: 'Developer Tools', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-docker', desc: 'Manage local containers & images' },
66
-
67
- // Databases & Storage
68
62
  { id: 'postgresql', name: '🗄️ PostgreSQL', category: 'Databases', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-postgres', reqAuth: 'DATABASE_URL', desc: 'Direct SQL query execution' },
69
63
  { id: 'mysql', name: '🐬 MySQL MCP', category: 'Databases', type: 'stdio', command: 'npx -y mysql-mcp-server', reqAuth: 'MYSQL_CONNECTION_STRING', desc: 'MySQL relational database runner' },
70
64
  { id: 'sqlite', name: '📦 SQLite Local', category: 'Databases', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-sqlite', desc: 'Lightweight local database query tool' },
71
65
  { id: 'mongodb', name: '🍃 MongoDB MCP', category: 'Databases', type: 'stdio', command: 'npx -y mongodb-mcp-server', reqAuth: 'MONGODB_URI', desc: 'NoSQL collection queries & aggregation' },
72
66
  { id: 'redis', name: '🔴 Redis Cache', category: 'Databases', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-redis', reqAuth: 'REDIS_URL', desc: 'Key-value data structure store' },
73
67
  { id: 'pinecone', name: '🌲 Pinecone Vector DB', category: 'Databases', type: 'direct-api', endpoint: 'https://api.pinecone.io/mcp', reqAuth: 'PINECONE_API_KEY', desc: 'Vector database for AI embeddings' },
74
-
75
- // Search & Web Scraping
76
68
  { id: 'brave-search', name: '🦁 Brave Search', category: 'Search & Scraping', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-brave-search', reqAuth: 'BRAVE_API_KEY', desc: 'Real-time global web search engine' },
77
69
  { id: 'tavily', name: '🔍 Tavily AI Search', category: 'Search & Scraping', type: 'stdio', command: 'npx -y tavily-mcp', reqAuth: 'TAVILY_API_KEY', desc: 'Optimized search engine for LLMs' },
78
70
  { id: 'puppeteer', name: '🌐 Puppeteer Scraper', category: 'Search & Scraping', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-puppeteer', desc: 'Headless browser web automation & screenshot' },
79
71
  { id: 'firecrawl', name: '🔥 Firecrawl Scraper', category: 'Search & Scraping', type: 'direct-api', endpoint: 'https://api.firecrawl.dev/v1/mcp', reqAuth: 'FIRECRAWL_API_KEY', desc: 'Convert entire websites to clean Markdown' },
80
72
  { id: 'fetch', name: '📡 Fetch HTTP Utility', category: 'Search & Scraping', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-fetch', desc: 'HTTP request & web page parser' },
81
-
82
- // Productivity & Communication
83
73
  { id: 'notion', name: '📄 Notion Workspace', category: 'Productivity', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-notion', reqAuth: 'NOTION_API_TOKEN', desc: 'Read & edit Notion pages and databases' },
84
74
  { id: 'slack', name: '💬 Slack Channel', category: 'Productivity', type: 'stdio', command: 'npx -y @modelcontextprotocol/server-slack', reqAuth: 'SLACK_BOT_TOKEN', desc: 'Send messages & read channels' },
85
75
  { id: 'discord', name: '🎮 Discord Bot MCP', category: 'Productivity', type: 'stdio', command: 'npx -y discord-mcp-server', reqAuth: 'DISCORD_BOT_TOKEN', desc: 'Interact with Discord servers & channels' },
@@ -135,7 +125,7 @@ ${C.c4} ██║ ██║ ╚═╝ ██║██║ ██║ █
135
125
  ${C.c4} ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${C.reset}
136
126
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
137
127
  ${C.reset}The Multi Platform AI ${C.green}[MCP Hub & Interactive Provider Engine]${C.reset}
138
- ${C.gray}/config | /models | /skill | /mcp | /new-mcp | /scan | /uninstall | /exit${C.reset}
128
+ ${C.gray}/config | /models | /custom-models | /skill | /mcp | /new-mcp | /scan | /uninstall${C.reset}
139
129
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
140
130
  `);
141
131
  }
@@ -369,9 +359,10 @@ function interactiveProviderSelector(allItems, onSelect, onCancel) {
369
359
  renderMenu();
370
360
  }
371
361
 
372
- // INTERACTIVE ARROW-KEY SELECTOR UNTUK MODEL AI (/models)
362
+ // INTERACTIVE ARROW-KEY SELECTOR UNTUK MODEL AI (/models) - CAPACITY HINGGA 600 MODEL
373
363
  function interactiveModelSelector(allModels, onSelect, onCancel) {
374
- let filteredModels = [...allModels];
364
+ // Cap pada 600 model untuk mencegah lag ekstrem di memori Termux
365
+ let filteredModels = allModels.slice(0, 600);
375
366
  let selectedIndex = 0;
376
367
  let currentPage = 0;
377
368
  const pageSize = 10;
@@ -417,9 +408,9 @@ function interactiveModelSelector(allModels, onSelect, onCancel) {
417
408
  }
418
409
 
419
410
  console.log(`\n${C.darkGray}────────────────────────────────────────────────────────────${C.reset}`);
420
- console.log(`${C.cyan}Halaman ${currentPage + 1}/${totalPages}${C.reset} | Total: ${filteredModels.length} Model AI`);
421
- console.log(`${C.gray}🎮 Navigasi: [▲/▼] Panah Termux/Keyboard | [Enter] Pilih${C.reset}`);
422
- console.log(`${C.gray}⌨️ Atau: [f] Cari Nama Model | [n] Next | [p] Prev | [q] Batal${C.reset}`);
411
+ console.log(`${C.cyan}Halaman ${currentPage + 1}/${totalPages}${C.reset} | Total Model Loaded: ${filteredModels.length}`);
412
+ console.log(`${C.gray}🎮 Navigasi: [▲/▼] Panah Termux | [Enter] Pilih${C.reset}`);
413
+ console.log(`${C.gray}⌨️ [f] Cari Nama Model | [n] Next | [p] Prev | [q] Batal${C.reset}`);
423
414
  console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}\n`);
424
415
  }
425
416
 
@@ -464,9 +455,9 @@ function interactiveModelSelector(allModels, onSelect, onCancel) {
464
455
  renderMenu();
465
456
  } else if (str === 'f' || str === 'F') {
466
457
  cleanup();
467
- rl.question(`\n${C.yellow}[>] Ketik kata kunci nama model (misal: llama, gemini, claude):${C.reset} `, (query) => {
458
+ rl.question(`\n${C.yellow}[>] Ketik nama/filter model (misal: llama, gemini, claude, qwen):${C.reset} `, (query) => {
468
459
  const q = query.trim().toLowerCase();
469
- filteredModels = allModels.filter(m => m.id.toLowerCase().includes(q));
460
+ filteredModels = allModels.filter(m => m.id.toLowerCase().includes(q)).slice(0, 600);
470
461
  currentPage = 0;
471
462
  selectedIndex = 0;
472
463
  interactiveModelSelector(filteredModels, onSelect, onCancel);
@@ -485,7 +476,6 @@ function createNewMCPWizard(callback) {
485
476
  (selectedProvider) => {
486
477
  console.clear();
487
478
 
488
- // CASE 1: CUSTOM MCP INPUT MANUAL
489
479
  if (selectedProvider.id === 'custom') {
490
480
  console.log(`\n${C.cyan}=== 🛠️ SETUP MCP MANUAL (CUSTOM) ===${C.reset}\n`);
491
481
  rl.question(`${C.yellow}[1/4] Masukkan Nama MCP Server (misal: my-mcp):${C.reset} `, (nameInput) => {
@@ -530,9 +520,7 @@ function createNewMCPWizard(callback) {
530
520
  });
531
521
  });
532
522
  });
533
- }
534
- // CASE 2: PRESET PROVIDER POPULER
535
- else {
523
+ } else {
536
524
  console.log(`\n${C.cyan}=== ⚡ SETUP PROVIDER: ${selectedProvider.name} ===${C.reset}`);
537
525
  console.log(`${C.gray}${selectedProvider.desc}${C.reset}\n`);
538
526
 
@@ -719,7 +707,7 @@ function askConfig(callback) {
719
707
  console.log(` ${C.yellow}3.${C.reset} NVIDIA NIM`);
720
708
  console.log(` ${C.yellow}4.${C.reset} OpenAI`);
721
709
  console.log(` ${C.yellow}5.${C.reset} Anthropic`);
722
- console.log(` ${C.yellow}6.${C.reset} Google Gemini (Default)`);
710
+ console.log(` ${C.yellow}6.${C.reset} Google Gemini`);
723
711
  console.log(` ${C.yellow}7.${C.reset} Custom / Auto-Detect Endpoint\n`);
724
712
 
725
713
  rl.question(`${C.yellow}[>] Select Provider (1-7):${C.reset} `, (choice) => {
@@ -751,6 +739,7 @@ function askConfig(callback) {
751
739
  });
752
740
  }
753
741
 
742
+ // PERBAIKAN FETCH ALL MODELS UNIVERSAL UNTUK SEMUA PROVIDER
754
743
  async function fetchAvailableModels() {
755
744
  if (!config.apiKey) {
756
745
  console.log(`${C.red}[x] API Key is not set. Use /config first.${C.reset}\n`);
@@ -761,26 +750,46 @@ async function fetchAvailableModels() {
761
750
 
762
751
  try {
763
752
  let url = config.endpoint;
764
- if (url.includes('googleapis.com')) {
765
- console.log(`${C.yellow}[!] Gemini Default REST API uses fixed model: ${config.model}${C.reset}\n`);
766
- return startPrompt();
767
- }
768
-
769
- let modelsUrl = url.endsWith('/models') ? url : `${url.replace(/\/chat\/completions$/, '')}/models`;
753
+ let fetchUrl = '';
754
+ let headers = {};
770
755
 
771
- const response = await fetch(modelsUrl, {
772
- method: 'GET',
773
- headers: {
756
+ // 1. Google Gemini Native Models Fetch
757
+ if (url.includes('googleapis.com')) {
758
+ fetchUrl = `https://generativelanguage.googleapis.com/v1beta/models?key=${config.apiKey}`;
759
+ }
760
+ // 2. Anthropic Direct Fetch (jika endpoint anthropic)
761
+ else if (url.includes('anthropic.com')) {
762
+ fetchUrl = 'https://api.anthropic.com/v1/models';
763
+ headers = {
764
+ 'x-api-key': config.apiKey,
765
+ 'anthropic-version': '2023-06-01'
766
+ };
767
+ }
768
+ // 3. OpenRouter, Groq, NVIDIA, OpenAI & Custom Universal OpenAI Standard
769
+ else {
770
+ let baseUrl = url.replace(/\/chat\/completions$/, '').replace(/\/$/, '');
771
+ fetchUrl = baseUrl.endsWith('/models') ? baseUrl : `${baseUrl}/models`;
772
+ headers = {
774
773
  'Authorization': `Bearer ${config.apiKey}`,
775
774
  'Content-Type': 'application/json'
776
- }
777
- });
775
+ };
776
+ }
778
777
 
778
+ const response = await fetch(fetchUrl, { method: 'GET', headers: headers });
779
779
  const data = await response.json();
780
780
 
781
- if (data.data && Array.isArray(data.data) && data.data.length > 0) {
781
+ let extractedModels = [];
782
+
783
+ // Parsing fleksibel dari berbagai bentuk JSON provider
784
+ if (data.data && Array.isArray(data.data)) {
785
+ extractedModels = data.data.map(m => ({ id: typeof m === 'string' ? m : (m.id || m.name) }));
786
+ } else if (data.models && Array.isArray(data.models)) {
787
+ extractedModels = data.models.map(m => ({ id: typeof m === 'string' ? m : (m.name?.replace('models/', '') || m.id) }));
788
+ }
789
+
790
+ if (extractedModels.length > 0) {
782
791
  interactiveModelSelector(
783
- data.data,
792
+ extractedModels,
784
793
  (selectedModelId) => {
785
794
  config.model = selectedModelId;
786
795
  saveConfig(config);
@@ -795,15 +804,37 @@ async function fetchAvailableModels() {
795
804
  }
796
805
  );
797
806
  } else {
798
- console.log(`${C.red}[x] Could not retrieve models list automatically from ${config.provider}.${C.reset}`);
807
+ console.log(`${C.red}[x] Gagal mengambil daftar model secara otomatis dari ${config.provider}.${C.reset}`);
808
+ console.log(`${C.yellow}💡 Tips: Gunakan perintah ${C.bold}/custom-models${C.reset}${C.yellow} untuk menginput nama model secara manual dengan presisi.${C.reset}\n`);
799
809
  startPrompt();
800
810
  }
801
811
  } catch (err) {
802
- console.log(`${C.red}[x] Error fetching models: ${err.message}${C.reset}\n`);
812
+ console.log(`${C.red}[x] Error fetching models: ${err.message}${C.reset}`);
813
+ console.log(`${C.yellow}💡 Kamu bisa menggunakan perintah ${C.bold}/custom-models${C.reset}${C.yellow} untuk memasukkan nama model manual.${C.reset}\n`);
803
814
  startPrompt();
804
815
  }
805
816
  }
806
817
 
818
+ // PERINTAH BARU: /custom-models UNTUK PRESISI NAMA MODEL
819
+ function handleCustomModels() {
820
+ console.log(`\n${C.cyan}=== 🎯 SET CUSTOM MODEL (PRESISI HIGH-PRECISION) ===${C.reset}`);
821
+ console.log(`${C.gray}Provider Aktif : ${C.yellow}${config.provider || 'Belum diatur'}${C.reset}`);
822
+ console.log(`${C.gray}Model Saat Ini : ${C.green}${config.model || 'Belum diatur'}${C.reset}\n`);
823
+
824
+ rl.question(`${C.yellow}[>] Masukkan ID / Nama Model secara presisi sesuai provider:${C.reset} `, (inputModel) => {
825
+ const cleanModel = inputModel.trim();
826
+ if (!cleanModel) {
827
+ console.log(`${C.red}[x] Nama model tidak boleh kosong.${C.reset}\n`);
828
+ return startPrompt();
829
+ }
830
+
831
+ config.model = cleanModel;
832
+ saveConfig(config);
833
+ console.log(`\n${C.green}[✔] Model berhasil diperbarui secara presisi ke: ${C.bold}${config.model}${C.reset}\n`);
834
+ startPrompt();
835
+ });
836
+ }
837
+
807
838
  async function handleChat(prompt, forcedTool = null) {
808
839
  if (!config.apiKey) {
809
840
  console.log(`${C.yellow}[!] API Key is not set.${C.reset}`);
@@ -825,7 +856,8 @@ async function handleChat(prompt, forcedTool = null) {
825
856
  const fullPrompt = (prompt || "Jalankan instruksi tool ini.") + toolsContext;
826
857
 
827
858
  if (url.includes('googleapis.com')) {
828
- url = `${url}?key=${config.apiKey}`;
859
+ const activeModel = config.model || 'gemini-2.5-flash';
860
+ url = `https://generativelanguage.googleapis.com/v1beta/models/${activeModel}:generateContent?key=${config.apiKey}`;
829
861
  bodyData = { contents: [{ parts: [{ text: fullPrompt }] }] };
830
862
  } else {
831
863
  if (!url.endsWith('/chat/completions')) {
@@ -848,7 +880,6 @@ async function handleChat(prompt, forcedTool = null) {
848
880
 
849
881
  let aiResponse = "";
850
882
 
851
- // DUKUNGAN UNTUK REASONING MODELS & STANDAR OPENAI/GEMINI
852
883
  if (data.choices && data.choices[0] && data.choices[0].message) {
853
884
  const msg = data.choices[0].message;
854
885
  aiResponse = msg.content || msg.reasoning || msg.reasoning_content || "";
@@ -908,6 +939,8 @@ function startPrompt() {
908
939
  askConfig(() => startPrompt());
909
940
  } else if (cmd === '/models') {
910
941
  fetchAvailableModels();
942
+ } else if (cmd === '/custom-models') {
943
+ handleCustomModels();
911
944
  } else if (cmd === '/skill' || cmd === '/skills') {
912
945
  listSkills();
913
946
  startPrompt();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmpa-cli",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "bin": {