tmpa-cli 1.0.16 → 1.0.18

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 +160 -67
  2. package/package.json +6 -2
package/bin/index.js CHANGED
@@ -4,7 +4,7 @@ const readline = require('readline');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const os = require('os');
7
- const { execSync, spawn } = require('child_process');
7
+ const { execSync } = require('child_process');
8
8
 
9
9
  // Base Paths
10
10
  const TMPA_DIR = path.join(os.homedir(), '.tmpa');
@@ -43,7 +43,6 @@ const PROVIDERS = {
43
43
  '7': { name: 'Custom / Auto-Detect', endpoint: '', defaultModel: '' }
44
44
  };
45
45
 
46
- // Config & Registry Helpers
47
46
  function loadConfig() {
48
47
  if (fs.existsSync(CONFIG_FILE)) {
49
48
  try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch (e) { return {}; }
@@ -66,7 +65,6 @@ function saveRegistry(registry) {
66
65
  fs.writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2));
67
66
  }
68
67
 
69
- // UI Popup Card Helper
70
68
  function drawBox(title, contentLines, borderColor = C.cyan) {
71
69
  const width = 64;
72
70
  console.log(`${borderColor}┌${'─'.repeat(width - 2)}┐${C.reset}`);
@@ -92,47 +90,173 @@ ${C.c3} ██║ ██║╚██╔╝██║██╔═══╝ █
92
90
  ${C.c4} ██║ ██║ ╚═╝ ██║██║ ██║ ██║${C.reset}
93
91
  ${C.c4} ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${C.reset}
94
92
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
95
- ${C.reset}The Multi Platform AI ${C.green}[Dynamic Tool Slash Engine]${C.reset}
96
- ${C.gray}/config | /models | /skill | /mcp | /connect | /scan | /exit${C.reset}
93
+ ${C.reset}The Multi Platform AI ${C.green}[MCP Hub & Tool Engine]${C.reset}
94
+ ${C.gray}/config | /models | /skill | /mcp | /new-mcp | /scan | /exit${C.reset}
97
95
  ${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
98
96
  `);
99
97
  }
100
98
 
101
- // Dynamic System Context Builder
102
- function getActiveToolsContext(forcedTool = null) {
103
- let contextParts = [];
99
+ function readResourceContent(targetPath) {
100
+ if (!fs.existsSync(targetPath)) return "[Resource file/directory not found on local system]";
101
+
102
+ const stat = fs.statSync(targetPath);
103
+ if (stat.isFile()) {
104
+ try {
105
+ return fs.readFileSync(targetPath, 'utf8');
106
+ } catch (e) {
107
+ return `[Error reading file: ${e.message}]`;
108
+ }
109
+ } else if (stat.isDirectory()) {
110
+ const candidateFiles = ['SKILL.md', 'skill.md', 'PROMPT.md', 'README.md', 'index.js', 'index.ts', 'main.py'];
111
+ for (const file of candidateFiles) {
112
+ const full = path.join(targetPath, file);
113
+ if (fs.existsSync(full)) {
114
+ try {
115
+ return `--- Content from ${file} ---\n` + fs.readFileSync(full, 'utf8');
116
+ } catch (e) {}
117
+ }
118
+ }
104
119
 
120
+ try {
121
+ const files = fs.readdirSync(targetPath);
122
+ let combinedText = `Directory Contents for ${path.basename(targetPath)}:\n`;
123
+ files.slice(0, 5).forEach(f => {
124
+ const fp = path.join(targetPath, f);
125
+ if (fs.statSync(fp).isFile()) {
126
+ combinedText += `\n--- File: ${f} ---\n` + fs.readFileSync(fp, 'utf8').slice(0, 2000);
127
+ }
128
+ });
129
+ return combinedText;
130
+ } catch (e) {
131
+ return `[Directory found at ${targetPath}, but unable to parse files]`;
132
+ }
133
+ }
134
+ return "[Unknown resource format]";
135
+ }
136
+
137
+ function getActiveToolsContext(forcedTool = null) {
105
138
  if (forcedTool) {
106
- contextParts.push(`[CRITICAL INSTRUCTION: FORCED TOOL EXECUTION]`);
107
- contextParts.push(`User explicitly called tool command: /${forcedTool.type}-${forcedTool.name}`);
108
- contextParts.push(`Target Path/URL: ${forcedTool.target}`);
109
- contextParts.push(`You MUST use and invoke this ${forcedTool.type.toUpperCase()} tool to handle user prompt below.\n`);
139
+ let rawContent = "";
140
+ if (forcedTool.type === 'mcp') {
141
+ rawContent = `MCP Server Info:
142
+ Name: ${forcedTool.name}
143
+ Target/Endpoint: ${forcedTool.target}
144
+ Type: ${forcedTool.mcpType || 'HTTP/SSE'}
145
+ Auth Token: ${forcedTool.authToken ? 'Provided' : 'None'}`;
146
+ } else {
147
+ rawContent = readResourceContent(forcedTool.target);
148
+ }
149
+
150
+ return `\n\n[STRICT TOOL EXECUTION SYSTEM DIRECTIVE]
151
+ YOU ARE NOW STRICTLY ACTING AS THE FOLLOWING ${forcedTool.type.toUpperCase()} TOOL: "${forcedTool.name}".
152
+ DO NOT REFER TO OTHER TOOLS OR GENERAL ASSISTANT CAPABILITIES. FOCUS 100% ON EXECUTING THIS TOOL INSTRUCTION.
153
+
154
+ --- TOOL INSTRUCTION & CODE CONTENT ---
155
+ ${rawContent}
156
+ --- END TOOL INSTRUCTION ---
157
+
158
+ Executing User Prompt under this tool context only:\n`;
110
159
  }
111
-
160
+
161
+ let contextParts = [];
112
162
  const activeSkills = Object.keys(registry.skills || {});
113
163
  if (activeSkills.length > 0) {
114
164
  contextParts.push("AVAILABLE SKILLS:");
115
- activeSkills.forEach(name => {
116
- const s = registry.skills[name];
117
- contextParts.push(`- /skill-${name} -> Path: ${s.path}`);
118
- });
165
+ activeSkills.forEach(name => contextParts.push(`- /skill-${name}`));
119
166
  }
120
167
 
121
168
  const activeMCP = Object.keys(registry.mcp || {});
122
169
  if (activeMCP.length > 0) {
123
170
  contextParts.push("AVAILABLE MCP SERVERS:");
124
- activeMCP.forEach(name => {
171
+ activeMCP.forEach(name => contextParts.push(`- /mcp-${name}`));
172
+ }
173
+
174
+ if (contextParts.length === 0) return "";
175
+ return "\n\n[SYSTEM ENVIRONMENT SUMMARY]\n" + contextParts.join("\n") + "\n";
176
+ }
177
+
178
+ // RUANGAN KHUSUS MCP CENTER
179
+ function showMCPHub() {
180
+ console.log(`\n${C.c4}============================================================${C.reset}`);
181
+ console.log(`${C.c4} 🔌 MCP (MODEL CONTEXT PROTOCOL) CENTER ${C.reset}`);
182
+ console.log(`${C.c4}============================================================${C.reset}\n`);
183
+
184
+ const keys = Object.keys(registry.mcp || {});
185
+
186
+ if (keys.length === 0) {
187
+ console.log(`${C.yellow} [!] Belum ada MCP Server yang terhubung saat ini.${C.reset}`);
188
+ console.log(`${C.gray} Gunakan perintah ${C.green}/new-mcp${C.gray} untuk mendaftarkan MCP baru.${C.reset}\n`);
189
+ } else {
190
+ console.log(`${C.bold}Daftar MCP Server Aktif:${C.reset}`);
191
+ keys.forEach((name, i) => {
125
192
  const m = registry.mcp[name];
126
- contextParts.push(`- /mcp-${name} -> Target: ${m.target} (${m.type})`);
193
+ const typeBadge = m.type === 'remote' ? `${C.cyan}[Remote SSE/HTTP]${C.reset}` : `${C.green}[Local Stdio]${C.reset}`;
194
+ console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.bold}${name}${C.reset} ${typeBadge}`);
195
+ console.log(` ↳ Target: ${C.gray}${m.target}${C.reset}`);
196
+ if (m.authToken) console.log(` ↳ Auth : ${C.green}Encrypted/Token set${C.reset}`);
127
197
  });
198
+ console.log('');
128
199
  }
129
200
 
130
- if (contextParts.length === 0) return "";
201
+ const lines = [
202
+ `${C.bold}Command Instan MCP:${C.reset}`,
203
+ `${C.yellow}/new-mcp${C.reset} 👉 Tambah MCP Server Baru (Wizard)`,
204
+ `${C.yellow}/mcp-<nama>${C.reset} <prompt> 👉 Eksekusi MCP secara spesifik`,
205
+ `${C.yellow}/scan${C.reset} 👉 Pindai folder .mcp otomatis`
206
+ ];
131
207
 
132
- return "\n\n[SYSTEM CONTEXT: REGISTERED TOOLS & PROTOCOLS]\n" + contextParts.join("\n") + "\n";
208
+ drawBox("💡 PETUNJUK RUANG MCP", lines, C.c4);
209
+ console.log('');
210
+ }
211
+
212
+ // WIZARD KONFIGURASI MCP BARU (/new-mcp)
213
+ function createNewMCPWizard(callback) {
214
+ console.log(`\n${C.cyan}=== 🛠️ SETUP MCP (MODEL CONTEXT PROTOCOL) BARU ===${C.reset}\n`);
215
+
216
+ rl.question(`${C.yellow}[1/4] Masukkan Nama MCP Server (misal: stitch, github, filesystem):${C.reset} `, (nameInput) => {
217
+ const mcpName = nameInput.trim().toLowerCase().replace(/\s+/g, '-');
218
+ if (!mcpName) {
219
+ console.log(`${C.red}[x] Nama MCP tidak boleh kosong.${C.reset}\n`);
220
+ return callback();
221
+ }
222
+
223
+ console.log(`\n${C.cyan}Pilih Tipe Koneksi MCP:${C.reset}`);
224
+ console.log(` ${C.yellow}1.${C.reset} Remote URL / SSE Endpoint (misal: https://mcp.example.com/sse)`);
225
+ console.log(` ${C.yellow}2.${C.reset} Local Command / File Path (misal: npx -y @modelcontextprotocol/server-filesystem)`);
226
+
227
+ rl.question(`\n${C.yellow}[2/4] Pilih Tipe (1/2):${C.reset} `, (typeChoice) => {
228
+ const isRemote = typeChoice.trim() === '1';
229
+
230
+ rl.question(`${C.yellow}[3/4] Masukkan Target URL / Command Path:${C.reset} `, (targetInput) => {
231
+ const target = targetInput.trim();
232
+ if (!target) {
233
+ console.log(`${C.red}[x] Target tidak boleh kosong.${C.reset}\n`);
234
+ return callback();
235
+ }
236
+
237
+ rl.question(`${C.yellow}[4/4] Masukkan Auth Token / API Key (Tekan Enter jika tidak ada):${C.reset} `, (tokenInput) => {
238
+ const authToken = tokenInput.trim();
239
+
240
+ registry.mcp = registry.mcp || {};
241
+ registry.mcp[mcpName] = {
242
+ target: target,
243
+ type: isRemote ? 'remote' : 'local',
244
+ authToken: authToken || null,
245
+ connectedAt: new Date().toISOString(),
246
+ status: 'Connected'
247
+ };
248
+
249
+ saveRegistry(registry);
250
+
251
+ console.log(`\n${C.green}[✔] MCP Server "${mcpName}" berhasil ditambahkan!${C.reset}`);
252
+ console.log(`${C.gray}Gunakan perintah instan: ${C.yellow}/mcp-${mcpName} <prompt kamu>${C.reset}\n`);
253
+ callback();
254
+ });
255
+ });
256
+ });
257
+ });
133
258
  }
134
259
 
135
- // Handlers for Skills with Dynamic Command Helper
136
260
  function listSkills() {
137
261
  console.log(`\n${C.cyan}=== Registered Skills ===${C.reset}`);
138
262
  const keys = Object.keys(registry.skills || {});
@@ -148,9 +272,8 @@ function listSkills() {
148
272
  });
149
273
  console.log('');
150
274
 
151
- // Interactive Action Helper Popup with dynamic slash commands
152
275
  const lines = [
153
- `${C.bold}Perintah Instan yang Bisa Kamu Ketik Langsung:${C.reset}`,
276
+ `${C.bold}Perintah Instan Skill:${C.reset}`,
154
277
  ``
155
278
  ];
156
279
 
@@ -158,46 +281,10 @@ function listSkills() {
158
281
  lines.push(` ${C.yellow}/skill-${name}${C.reset} <prompt kamu>`);
159
282
  });
160
283
 
161
- lines.push(``);
162
- lines.push(`${C.gray}Contoh: ${C.yellow}/skill-${keys[0]} buatkan animasi intro${C.reset}`);
163
-
164
284
  drawBox("⚡ COMMAND INSTAN SKILL TERSEDIA", lines, C.c1);
165
285
  console.log('');
166
286
  }
167
287
 
168
- // Handlers for MCP with Dynamic Command Helper
169
- function listMCP() {
170
- console.log(`\n${C.cyan}=== Registered MCP (Model Context Protocol) Servers ===${C.reset}`);
171
- const keys = Object.keys(registry.mcp || {});
172
-
173
- if (keys.length === 0) {
174
- console.log(`${C.gray}Belum ada MCP server terhubung. Ketik ${C.yellow}/scan${C.gray} atau ${C.yellow}/connect mcp <target>${C.reset}\n`);
175
- return;
176
- }
177
-
178
- keys.forEach((name, i) => {
179
- const item = registry.mcp[name];
180
- console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.target}${C.reset} [${item.type}]`);
181
- });
182
- console.log('');
183
-
184
- // Interactive Action Helper Popup with dynamic slash commands
185
- const lines = [
186
- `${C.bold}Perintah Instan MCP yang Bisa Kamu Ketik Langsung:${C.reset}`,
187
- ``
188
- ];
189
-
190
- keys.forEach(name => {
191
- lines.push(` ${C.yellow}/mcp-${name}${C.reset} <prompt kamu>`);
192
- });
193
-
194
- lines.push(``);
195
- lines.push(`${C.gray}Contoh: ${C.yellow}/mcp-${keys[0]} sinkronkan file terbaru${C.reset}`);
196
-
197
- drawBox("🔌 COMMAND INSTAN MCP TERSEDIA", lines, C.c4);
198
- console.log('');
199
- }
200
-
201
288
  function connectResource(inputArgs) {
202
289
  const parts = inputArgs.trim().split(/\s+/);
203
290
  const type = parts[0]?.toLowerCase();
@@ -509,7 +596,7 @@ async function handleChat(prompt, forcedTool = null) {
509
596
  return startPrompt();
510
597
  }
511
598
 
512
- console.log(`\n${C.c1}TMPA CLI (${config.model || 'AI'}) :${C.reset} ${aiResponse}\n`);
599
+ console.log(`\n${C.c1}TMPA CLI (${config.model || 'AI'}) :${C.reset}\n${aiResponse}\n`);
513
600
 
514
601
  } catch (error) {
515
602
  console.log(`\n${C.red}[x] Fetch Error: ${error.message}${C.reset}\n`);
@@ -559,8 +646,10 @@ function startPrompt() {
559
646
  listSkills();
560
647
  startPrompt();
561
648
  } else if (cmd === '/mcp') {
562
- listMCP();
649
+ showMCPHub();
563
650
  startPrompt();
651
+ } else if (cmd === '/new-mcp') {
652
+ createNewMCPWizard(() => startPrompt());
564
653
  } else if (cmd.startsWith('/connect')) {
565
654
  connectResource(cmd.replace('/connect', ''));
566
655
  startPrompt();
@@ -570,8 +659,7 @@ function startPrompt() {
570
659
  } else if (cmd === '/uninstall') {
571
660
  handleUninstall();
572
661
  } else if (cmd.startsWith('/skill-')) {
573
- // Dynamic Slash Command for Skill: /skill-remotion-vidio <prompt>
574
- const fullCmd = cmd.slice(7).trim(); // remove '/skill-'
662
+ const fullCmd = cmd.slice(7).trim();
575
663
  const spaceIdx = fullCmd.indexOf(' ');
576
664
  let skillName = fullCmd;
577
665
  let userPrompt = '';
@@ -588,8 +676,7 @@ function startPrompt() {
588
676
  startPrompt();
589
677
  }
590
678
  } else if (cmd.startsWith('/mcp-')) {
591
- // Dynamic Slash Command for MCP: /mcp-stitch <prompt>
592
- const fullCmd = cmd.slice(5).trim(); // remove '/mcp-'
679
+ const fullCmd = cmd.slice(5).trim();
593
680
  const spaceIdx = fullCmd.indexOf(' ');
594
681
  let mcpName = fullCmd;
595
682
  let userPrompt = '';
@@ -600,7 +687,13 @@ function startPrompt() {
600
687
  }
601
688
 
602
689
  if (registry.mcp && registry.mcp[mcpName]) {
603
- handleChat(userPrompt, { type: 'mcp', name: mcpName, target: registry.mcp[mcpName].target });
690
+ handleChat(userPrompt, {
691
+ type: 'mcp',
692
+ name: mcpName,
693
+ target: registry.mcp[mcpName].target,
694
+ mcpType: registry.mcp[mcpName].type,
695
+ authToken: registry.mcp[mcpName].authToken
696
+ });
604
697
  } else {
605
698
  console.log(`${C.red}[x] MCP "${mcpName}" tidak ditemukan di registry. Ketik /mcp untuk melihat daftar.${C.reset}\n`);
606
699
  startPrompt();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmpa-cli",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "bin": {
@@ -14,8 +14,12 @@
14
14
  "author": "",
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
+ "@remotion/cli": "^4.0.506",
17
18
  "chalk": "^4.1.2",
18
19
  "commander": "^11.0.0",
19
- "ora": "^5.4.1"
20
+ "ora": "^5.4.1",
21
+ "react": "^19.2.8",
22
+ "react-dom": "^19.2.8",
23
+ "remotion": "^4.0.506"
20
24
  }
21
25
  }