tmpa-cli 1.0.21 → 1.0.22
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/bin/index.js +132 -84
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -135,7 +135,7 @@ ${C.c4} ██║ ██║ ╚═╝ ██║██║ ██║ █
|
|
|
135
135
|
${C.c4} ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${C.reset}
|
|
136
136
|
${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
|
|
137
137
|
${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 | /exit${C.reset}
|
|
138
|
+
${C.gray}/config | /models | /skill | /mcp | /new-mcp | /scan | /uninstall | /exit${C.reset}
|
|
139
139
|
${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
|
|
140
140
|
`);
|
|
141
141
|
}
|
|
@@ -253,7 +253,7 @@ function showMCPHub() {
|
|
|
253
253
|
console.log('');
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
// INTERACTIVE ARROW-KEY SELECTOR
|
|
256
|
+
// INTERACTIVE ARROW-KEY SELECTOR UNTUK MCP PROVIDERS
|
|
257
257
|
function interactiveProviderSelector(allItems, onSelect, onCancel) {
|
|
258
258
|
let filteredItems = [...allItems];
|
|
259
259
|
let selectedIndex = 0;
|
|
@@ -369,6 +369,115 @@ function interactiveProviderSelector(allItems, onSelect, onCancel) {
|
|
|
369
369
|
renderMenu();
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
// INTERACTIVE ARROW-KEY SELECTOR UNTUK MODEL AI (/models)
|
|
373
|
+
function interactiveModelSelector(allModels, onSelect, onCancel) {
|
|
374
|
+
let filteredModels = [...allModels];
|
|
375
|
+
let selectedIndex = 0;
|
|
376
|
+
let currentPage = 0;
|
|
377
|
+
const pageSize = 10;
|
|
378
|
+
|
|
379
|
+
const wasRaw = process.stdin.isRaw;
|
|
380
|
+
|
|
381
|
+
function cleanup() {
|
|
382
|
+
process.stdin.removeListener('keypress', handleKeypress);
|
|
383
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(wasRaw || false);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function renderMenu() {
|
|
387
|
+
console.clear();
|
|
388
|
+
const totalPages = Math.ceil(filteredModels.length / pageSize) || 1;
|
|
389
|
+
if (currentPage >= totalPages) currentPage = totalPages - 1;
|
|
390
|
+
if (currentPage < 0) currentPage = 0;
|
|
391
|
+
|
|
392
|
+
const startIdx = currentPage * pageSize;
|
|
393
|
+
const pageItems = filteredModels.slice(startIdx, startIdx + pageSize);
|
|
394
|
+
|
|
395
|
+
if (selectedIndex >= pageItems.length) selectedIndex = Math.max(0, pageItems.length - 1);
|
|
396
|
+
|
|
397
|
+
console.log(`${C.c1}============================================================${C.reset}`);
|
|
398
|
+
console.log(`${C.c1} 🤖 PILIH MODEL AI (${config.provider || 'Provider'}) ${C.reset}`);
|
|
399
|
+
console.log(`${C.c1}============================================================${C.reset}`);
|
|
400
|
+
console.log(`${C.gray}Model Aktif Saat Ini: ${C.green}${config.model || 'Belum Diatur'}${C.reset}\n`);
|
|
401
|
+
|
|
402
|
+
if (pageItems.length === 0) {
|
|
403
|
+
console.log(`${C.red} Tidak ada model yang cocok dengan pencarian.${C.reset}\n`);
|
|
404
|
+
} else {
|
|
405
|
+
pageItems.forEach((m, idx) => {
|
|
406
|
+
const globalNum = startIdx + idx;
|
|
407
|
+
const isFocused = idx === selectedIndex;
|
|
408
|
+
const isCurrentActive = m.id === config.model;
|
|
409
|
+
|
|
410
|
+
const pointer = isFocused ? `${C.cyan}❯${C.reset}` : ' ';
|
|
411
|
+
const activeBadge = isCurrentActive ? `${C.green}(Aktif)${C.reset}` : '';
|
|
412
|
+
const numStr = globalNum.toString().padStart(3, ' ');
|
|
413
|
+
const modelNameStyled = isFocused ? `${C.bold}${C.yellow}${m.id}${C.reset}` : m.id;
|
|
414
|
+
|
|
415
|
+
console.log(`${pointer} ${C.gray}${numStr}.${C.reset} • ${modelNameStyled} ${activeBadge}`);
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
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}`);
|
|
423
|
+
console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}\n`);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
readline.emitKeypressEvents(process.stdin);
|
|
427
|
+
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
428
|
+
|
|
429
|
+
function handleKeypress(str, key) {
|
|
430
|
+
const totalPages = Math.ceil(filteredModels.length / pageSize) || 1;
|
|
431
|
+
const startIdx = currentPage * pageSize;
|
|
432
|
+
const pageItems = filteredModels.slice(startIdx, startIdx + pageSize);
|
|
433
|
+
|
|
434
|
+
if (key.name === 'up') {
|
|
435
|
+
if (selectedIndex > 0) {
|
|
436
|
+
selectedIndex--;
|
|
437
|
+
} else if (currentPage > 0) {
|
|
438
|
+
currentPage--;
|
|
439
|
+
selectedIndex = pageSize - 1;
|
|
440
|
+
}
|
|
441
|
+
renderMenu();
|
|
442
|
+
} else if (key.name === 'down') {
|
|
443
|
+
if (selectedIndex < pageItems.length - 1) {
|
|
444
|
+
selectedIndex++;
|
|
445
|
+
} else if (currentPage < totalPages - 1) {
|
|
446
|
+
currentPage++;
|
|
447
|
+
selectedIndex = 0;
|
|
448
|
+
}
|
|
449
|
+
renderMenu();
|
|
450
|
+
} else if (key.name === 'return') {
|
|
451
|
+
cleanup();
|
|
452
|
+
const selectedModelObj = pageItems[selectedIndex];
|
|
453
|
+
if (selectedModelObj) onSelect(selectedModelObj.id);
|
|
454
|
+
} else if (str === 'q' || str === 'Q' || (key.ctrl && key.name === 'c')) {
|
|
455
|
+
cleanup();
|
|
456
|
+
onCancel();
|
|
457
|
+
} else if (str === 'n' || str === 'N') {
|
|
458
|
+
if (currentPage < totalPages - 1) currentPage++;
|
|
459
|
+
selectedIndex = 0;
|
|
460
|
+
renderMenu();
|
|
461
|
+
} else if (str === 'p' || str === 'P') {
|
|
462
|
+
if (currentPage > 0) currentPage--;
|
|
463
|
+
selectedIndex = 0;
|
|
464
|
+
renderMenu();
|
|
465
|
+
} else if (str === 'f' || str === 'F') {
|
|
466
|
+
cleanup();
|
|
467
|
+
rl.question(`\n${C.yellow}[>] Ketik kata kunci nama model (misal: llama, gemini, claude):${C.reset} `, (query) => {
|
|
468
|
+
const q = query.trim().toLowerCase();
|
|
469
|
+
filteredModels = allModels.filter(m => m.id.toLowerCase().includes(q));
|
|
470
|
+
currentPage = 0;
|
|
471
|
+
selectedIndex = 0;
|
|
472
|
+
interactiveModelSelector(filteredModels, onSelect, onCancel);
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
process.stdin.on('keypress', handleKeypress);
|
|
478
|
+
renderMenu();
|
|
479
|
+
}
|
|
480
|
+
|
|
372
481
|
// WIZARD KONFIGURASI MCP BARU (/new-mcp)
|
|
373
482
|
function createNewMCPWizard(callback) {
|
|
374
483
|
interactiveProviderSelector(
|
|
@@ -642,81 +751,6 @@ function askConfig(callback) {
|
|
|
642
751
|
});
|
|
643
752
|
}
|
|
644
753
|
|
|
645
|
-
function selectModelCLI(allModels) {
|
|
646
|
-
let filteredModels = [...allModels];
|
|
647
|
-
let currentPage = 0;
|
|
648
|
-
const pageSize = 12;
|
|
649
|
-
|
|
650
|
-
function displayList() {
|
|
651
|
-
console.clear();
|
|
652
|
-
const totalPages = Math.ceil(filteredModels.length / pageSize) || 1;
|
|
653
|
-
if (currentPage >= totalPages) currentPage = totalPages - 1;
|
|
654
|
-
if (currentPage < 0) currentPage = 0;
|
|
655
|
-
|
|
656
|
-
const startIdx = currentPage * pageSize;
|
|
657
|
-
const pageItems = filteredModels.slice(startIdx, startIdx + pageSize);
|
|
658
|
-
|
|
659
|
-
console.log(`${C.cyan}=== Models Selector for ${config.provider} (${filteredModels.length} models) ===${C.reset}`);
|
|
660
|
-
console.log(`${C.gray}Current Active: ${C.green}${config.model || 'None'}${C.reset}`);
|
|
661
|
-
console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}`);
|
|
662
|
-
|
|
663
|
-
if (pageItems.length === 0) {
|
|
664
|
-
console.log(`${C.red} No models found matching filter.${C.reset}`);
|
|
665
|
-
} else {
|
|
666
|
-
pageItems.forEach((m, idx) => {
|
|
667
|
-
const itemNum = startIdx + idx + 1;
|
|
668
|
-
const isCurrent = m.id === config.model;
|
|
669
|
-
const bullet = isCurrent ? `${C.green}●${C.reset}` : `${C.gray}○${C.reset}`;
|
|
670
|
-
console.log(` ${bullet} ${C.yellow}${itemNum.toString().padStart(3, ' ')}.${C.reset} ${m.id}`);
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}`);
|
|
675
|
-
console.log(`${C.cyan}Page ${currentPage + 1}/${totalPages}${C.reset} | ${C.gray}Commands: [n]ext | [p]rev | [f]ilter <keyword> | [q]uit${C.reset}`);
|
|
676
|
-
|
|
677
|
-
rl.question(`\n${C.yellow}[>] Enter Number / Model ID / Command:${C.reset} `, (answer) => {
|
|
678
|
-
const input = answer.trim();
|
|
679
|
-
|
|
680
|
-
if (input.toLowerCase() === 'n') {
|
|
681
|
-
if (currentPage < totalPages - 1) currentPage++;
|
|
682
|
-
displayList();
|
|
683
|
-
} else if (input.toLowerCase() === 'p') {
|
|
684
|
-
if (currentPage > 0) currentPage--;
|
|
685
|
-
displayList();
|
|
686
|
-
} else if (input.toLowerCase() === 'q' || input.toLowerCase() === 'exit') {
|
|
687
|
-
console.log(`${C.gray}Model selection cancelled.${C.reset}\n`);
|
|
688
|
-
startPrompt();
|
|
689
|
-
} else if (input.toLowerCase().startsWith('f ')) {
|
|
690
|
-
const query = input.slice(2).trim().toLowerCase();
|
|
691
|
-
filteredModels = allModels.filter(m => m.id.toLowerCase().includes(query));
|
|
692
|
-
currentPage = 0;
|
|
693
|
-
displayList();
|
|
694
|
-
} else if (!isNaN(input) && input !== '') {
|
|
695
|
-
const num = parseInt(input);
|
|
696
|
-
if (num >= 1 && num <= filteredModels.length) {
|
|
697
|
-
const selected = filteredModels[num - 1].id;
|
|
698
|
-
config.model = selected;
|
|
699
|
-
saveConfig(config);
|
|
700
|
-
console.log(`\n${C.green}[+] Model changed to: ${config.model}${C.reset}\n`);
|
|
701
|
-
startPrompt();
|
|
702
|
-
} else {
|
|
703
|
-
console.log(`${C.red}[x] Invalid number!${C.reset}`);
|
|
704
|
-
setTimeout(displayList, 1000);
|
|
705
|
-
}
|
|
706
|
-
} else if (input.length > 0) {
|
|
707
|
-
config.model = input;
|
|
708
|
-
saveConfig(config);
|
|
709
|
-
console.log(`\n${C.green}[+] Custom Model ID set to: ${config.model}${C.reset}\n`);
|
|
710
|
-
startPrompt();
|
|
711
|
-
} else {
|
|
712
|
-
startPrompt();
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
displayList();
|
|
718
|
-
}
|
|
719
|
-
|
|
720
754
|
async function fetchAvailableModels() {
|
|
721
755
|
if (!config.apiKey) {
|
|
722
756
|
console.log(`${C.red}[x] API Key is not set. Use /config first.${C.reset}\n`);
|
|
@@ -745,7 +779,21 @@ async function fetchAvailableModels() {
|
|
|
745
779
|
const data = await response.json();
|
|
746
780
|
|
|
747
781
|
if (data.data && Array.isArray(data.data) && data.data.length > 0) {
|
|
748
|
-
|
|
782
|
+
interactiveModelSelector(
|
|
783
|
+
data.data,
|
|
784
|
+
(selectedModelId) => {
|
|
785
|
+
config.model = selectedModelId;
|
|
786
|
+
saveConfig(config);
|
|
787
|
+
console.clear();
|
|
788
|
+
console.log(`${C.green}[✔] Model berhasil diubah ke: ${config.model}${C.reset}\n`);
|
|
789
|
+
startPrompt();
|
|
790
|
+
},
|
|
791
|
+
() => {
|
|
792
|
+
console.clear();
|
|
793
|
+
console.log(`${C.gray}Pemilihan model dibatalkan.${C.reset}\n`);
|
|
794
|
+
startPrompt();
|
|
795
|
+
}
|
|
796
|
+
);
|
|
749
797
|
} else {
|
|
750
798
|
console.log(`${C.red}[x] Could not retrieve models list automatically from ${config.provider}.${C.reset}`);
|
|
751
799
|
startPrompt();
|
|
@@ -824,23 +872,23 @@ async function handleChat(prompt, forcedTool = null) {
|
|
|
824
872
|
}
|
|
825
873
|
|
|
826
874
|
function handleUninstall() {
|
|
827
|
-
rl.question(`${C.red}[!]
|
|
875
|
+
rl.question(`${C.red}[!] Apakah kamu yakin ingin menghapus TMPA CLI? (y/N):${C.reset} `, (answer) => {
|
|
828
876
|
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
829
|
-
console.log(`\n${C.yellow}[...]
|
|
877
|
+
console.log(`\n${C.yellow}[...] Membersihkan konfigurasi dan menghapus TMPA CLI...${C.reset}`);
|
|
830
878
|
try {
|
|
831
879
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
832
880
|
fs.unlinkSync(CONFIG_FILE);
|
|
833
881
|
}
|
|
834
|
-
console.log(`${C.green}[+]
|
|
882
|
+
console.log(`${C.green}[+] Konfigurasi lokal berhasil dibersihkan.${C.reset}`);
|
|
835
883
|
execSync('npm uninstall -g tmpa-cli', { stdio: 'inherit' });
|
|
836
|
-
console.log(`\n${C.green}[+] TMPA CLI
|
|
884
|
+
console.log(`\n${C.green}[+] TMPA CLI berhasil di-uninstall sepenuhnya. Sampai jumpa!${C.reset}\n`);
|
|
837
885
|
process.exit(0);
|
|
838
886
|
} catch (err) {
|
|
839
|
-
console.log(`\n${C.red}[x]
|
|
887
|
+
console.log(`\n${C.red}[x] Gagal uninstall otomatis. Silakan jalankan: npm uninstall -g tmpa-cli secara manual.${C.reset}\n`);
|
|
840
888
|
process.exit(0);
|
|
841
889
|
}
|
|
842
890
|
} else {
|
|
843
|
-
console.log(`${C.gray}
|
|
891
|
+
console.log(`${C.gray}Proses uninstall dibatalkan.${C.reset}\n`);
|
|
844
892
|
startPrompt();
|
|
845
893
|
}
|
|
846
894
|
});
|