tmpa-cli 1.0.11 → 1.0.12

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 +137 -15
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -6,7 +6,15 @@ const path = require('path');
6
6
  const os = require('os');
7
7
  const { execSync } = require('child_process');
8
8
 
9
+ const TMPA_DIR = path.join(os.homedir(), '.tmpa');
10
+ const SKILLS_DIR = path.join(TMPA_DIR, 'skills');
11
+ const MCP_DIR = path.join(TMPA_DIR, 'mcp');
9
12
  const CONFIG_FILE = path.join(os.homedir(), '.tmpa_config.json');
13
+ const REGISTRY_FILE = path.join(TMPA_DIR, 'registry.json');
14
+
15
+ if (!fs.existsSync(TMPA_DIR)) fs.mkdirSync(TMPA_DIR, { recursive: true });
16
+ if (!fs.existsSync(SKILLS_DIR)) fs.mkdirSync(SKILLS_DIR, { recursive: true });
17
+ if (!fs.existsSync(MCP_DIR)) fs.mkdirSync(MCP_DIR, { recursive: true });
10
18
 
11
19
  const C = {
12
20
  reset: '\x1b[0m',
@@ -34,11 +42,7 @@ const PROVIDERS = {
34
42
 
35
43
  function loadConfig() {
36
44
  if (fs.existsSync(CONFIG_FILE)) {
37
- try {
38
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
39
- } catch (e) {
40
- return {};
41
- }
45
+ try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch (e) { return {}; }
42
46
  }
43
47
  return {};
44
48
  }
@@ -47,6 +51,21 @@ function saveConfig(config) {
47
51
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
48
52
  }
49
53
 
54
+ function loadRegistry() {
55
+ if (fs.existsSync(REGISTRY_FILE)) {
56
+ try { return JSON.parse(fs.readFileSync(REGISTRY_FILE, 'utf8')); } catch (e) { return { skills: {}, mcp: {} }; }
57
+ }
58
+ return { skills: {}, mcp: {} };
59
+ }
60
+
61
+ function saveRegistry(registry) {
62
+ fs.writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2));
63
+ }
64
+
65
+ let rl = readline.createInterface({ input: process.stdin, output: process.stdout });
66
+ let config = loadConfig();
67
+ let registry = loadRegistry();
68
+
50
69
  function showBanner() {
51
70
  console.clear();
52
71
  console.log(`
@@ -58,18 +77,11 @@ ${C.c4} ██║ ██║ ╚═╝ ██║██║ ██║ █
58
77
  ${C.c4} ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${C.reset}
59
78
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
60
79
  ${C.reset}The Multi Platform AI ${C.green}[Interactive Mode]${C.reset}
61
- ${C.gray}/config : Set API | /models : View & Select Models | /uninstall : Remove | /exit : Exit${C.reset}
80
+ ${C.gray}/config | /models | /skill | /mcp | /connect | /scan | /exit${C.reset}
62
81
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
63
82
  `);
64
83
  }
65
84
 
66
- let rl = readline.createInterface({
67
- input: process.stdin,
68
- output: process.stdout
69
- });
70
-
71
- let config = loadConfig();
72
-
73
85
  function askConfig(callback) {
74
86
  console.log(`\n${C.cyan}[+] Choose AI Provider:${C.reset}`);
75
87
  console.log(` ${C.yellow}1.${C.reset} OpenRouter`);
@@ -171,7 +183,6 @@ function selectModelCLI(allModels) {
171
183
  setTimeout(displayList, 1000);
172
184
  }
173
185
  } else if (input.length > 0) {
174
- // Jika memasukkan nama model spesifik secara langsung
175
186
  config.model = input;
176
187
  saveConfig(config);
177
188
  console.log(`\n${C.green}[+] Custom Model ID set to: ${config.model}${C.reset}\n`);
@@ -298,6 +309,106 @@ function handleUninstall() {
298
309
  });
299
310
  }
300
311
 
312
+ function listSkills() {
313
+ console.log(`\n${C.cyan}=== Registered Skills ===${C.reset}`);
314
+ const keys = Object.keys(registry.skills || {});
315
+ if (keys.length === 0) {
316
+ console.log(`${C.gray}Belum ada skill yang terhubung. Gunakan ${C.yellow}/connect skill <path>${C.gray} untuk menghubungkan.${C.reset}\n`);
317
+ return;
318
+ }
319
+ keys.forEach((name, i) => {
320
+ const item = registry.skills[name];
321
+ console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.path}${C.reset} [${item.status || 'Active'}]`);
322
+ });
323
+ console.log('');
324
+ }
325
+
326
+ function listMCP() {
327
+ console.log(`\n${C.cyan}=== Registered MCP (Model Context Protocol) Servers ===${C.reset}`);
328
+ const keys = Object.keys(registry.mcp || {});
329
+ if (keys.length === 0) {
330
+ console.log(`${C.gray}Belum ada MCP server terhubung. Gunakan ${C.yellow}/connect mcp <target>${C.gray} untuk menghubungkan.${C.reset}\n`);
331
+ return;
332
+ }
333
+ keys.forEach((name, i) => {
334
+ const item = registry.mcp[name];
335
+ console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.target}${C.reset} [${item.type || 'local'}]`);
336
+ });
337
+ console.log('');
338
+ }
339
+
340
+ function connectResource(inputArgs) {
341
+ const parts = inputArgs.trim().split(/\s+/);
342
+ const type = parts[0]?.toLowerCase();
343
+ const targetPath = parts.slice(1).join(' ');
344
+
345
+ if (!type || !targetPath) {
346
+ console.log(`${C.red}[x] Format salah! Gunakan:${C.reset}`);
347
+ console.log(` ${C.yellow}/connect skill <filepath_atau_folder>${C.reset}`);
348
+ console.log(` ${C.yellow}/connect mcp <filepath_atau_url>${C.reset}\n`);
349
+ return;
350
+ }
351
+
352
+ const resolvedPath = path.resolve(targetPath);
353
+
354
+ if (type === 'skill') {
355
+ const skillName = path.basename(resolvedPath, path.extname(resolvedPath));
356
+ registry.skills = registry.skills || {};
357
+ registry.skills[skillName] = {
358
+ path: resolvedPath,
359
+ connectedAt: new Date().toISOString(),
360
+ status: 'Active'
361
+ };
362
+ saveRegistry(registry);
363
+ console.log(`${C.green}[+] Skill "${skillName}" berhasil dihubungkan dari: ${resolvedPath}${C.reset}\n`);
364
+ } else if (type === 'mcp') {
365
+ const mcpName = path.basename(resolvedPath, path.extname(resolvedPath));
366
+ registry.mcp = registry.mcp || {};
367
+ registry.mcp[mcpName] = {
368
+ target: targetPath,
369
+ type: targetPath.startsWith('http') ? 'remote' : 'local',
370
+ connectedAt: new Date().toISOString(),
371
+ status: 'Connected'
372
+ };
373
+ saveRegistry(registry);
374
+ console.log(`${C.green}[+] MCP Server "${mcpName}" berhasil dihubungkan!${C.reset}\n`);
375
+ } else {
376
+ console.log(`${C.red}[x] Tipe tidak dikenal. Gunakan "skill" atau "mcp".${C.reset}\n`);
377
+ }
378
+ }
379
+
380
+ function scanResources() {
381
+ console.log(`${C.yellow}[...] Memindai folder ~/.tmpa/skills dan ~/.tmpa/mcp...${C.reset}`);
382
+ registry = loadRegistry();
383
+
384
+ if (fs.existsSync(SKILLS_DIR)) {
385
+ const files = fs.readdirSync(SKILLS_DIR);
386
+ files.forEach(file => {
387
+ const fullPath = path.join(SKILLS_DIR, file);
388
+ const name = path.basename(file, path.extname(file));
389
+ if (!registry.skills[name]) {
390
+ registry.skills[name] = { path: fullPath, connectedAt: new Date().toISOString(), status: 'Active' };
391
+ console.log(`${C.green}[+] Auto-detected skill: ${name}${C.reset}`);
392
+ }
393
+ });
394
+ }
395
+
396
+ if (fs.existsSync(MCP_DIR)) {
397
+ const files = fs.readdirSync(MCP_DIR);
398
+ files.forEach(file => {
399
+ const fullPath = path.join(MCP_DIR, file);
400
+ const name = path.basename(file, path.extname(file));
401
+ if (!registry.mcp[name]) {
402
+ registry.mcp[name] = { target: fullPath, type: 'local', connectedAt: new Date().toISOString(), status: 'Connected' };
403
+ console.log(`${C.green}[+] Auto-detected MCP: ${name}${C.reset}`);
404
+ }
405
+ });
406
+ }
407
+
408
+ saveRegistry(registry);
409
+ console.log(`${C.green}[+] Pemindaian selesai.${C.reset}\n`);
410
+ }
411
+
301
412
  function startPrompt() {
302
413
  rl.question(`${C.c1}TMPA >${C.reset} `, (input) => {
303
414
  const cmd = input.trim();
@@ -312,6 +423,18 @@ function startPrompt() {
312
423
  askConfig(() => startPrompt());
313
424
  } else if (cmd === '/models') {
314
425
  fetchAvailableModels();
426
+ } else if (cmd === '/skill') {
427
+ listSkills();
428
+ startPrompt();
429
+ } else if (cmd === '/mcp') {
430
+ listMCP();
431
+ startPrompt();
432
+ } else if (cmd.startsWith('/connect')) {
433
+ connectResource(cmd.replace('/connect', ''));
434
+ startPrompt();
435
+ } else if (cmd === '/scan') {
436
+ scanResources();
437
+ startPrompt();
315
438
  } else if (cmd === '/uninstall') {
316
439
  handleUninstall();
317
440
  } else if (cmd === '') {
@@ -322,7 +445,6 @@ function startPrompt() {
322
445
  });
323
446
  }
324
447
 
325
- // Program Execution
326
448
  showBanner();
327
449
  if (!config.apiKey) {
328
450
  askConfig(() => startPrompt());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmpa-cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "bin": {