tmpa-cli 1.0.14 → 1.0.15
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 +87 -35
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -29,7 +29,8 @@ const C = {
|
|
|
29
29
|
yellow: '\x1b[38;2;234;179;8m',
|
|
30
30
|
red: '\x1b[38;2;239;68;68m',
|
|
31
31
|
gray: '\x1b[38;2;148;163;184m',
|
|
32
|
-
darkGray: '\x1b[38;2;71;85;105m'
|
|
32
|
+
darkGray: '\x1b[38;2;71;85;105m',
|
|
33
|
+
bold: '\x1b[1m'
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
const PROVIDERS = {
|
|
@@ -65,6 +66,19 @@ function saveRegistry(registry) {
|
|
|
65
66
|
fs.writeFileSync(REGISTRY_FILE, JSON.stringify(registry, null, 2));
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
// UI Popup Card Helper
|
|
70
|
+
function drawBox(title, contentLines, borderColor = C.cyan) {
|
|
71
|
+
const width = 60;
|
|
72
|
+
console.log(`${borderColor}┌${'─'.repeat(width - 2)}┐${C.reset}`);
|
|
73
|
+
console.log(`${borderColor}│ ${C.bold}${title.padEnd(width - 4)}${C.reset}${borderColor} │${C.reset}`);
|
|
74
|
+
console.log(`${borderColor}├${'─'.repeat(width - 2)}┤${C.reset}`);
|
|
75
|
+
contentLines.forEach(line => {
|
|
76
|
+
// Basic text padding layout
|
|
77
|
+
console.log(`${borderColor}│${C.reset} ${line.padEnd(width - 4)} ${borderColor}│${C.reset}`);
|
|
78
|
+
});
|
|
79
|
+
console.log(`${borderColor}└${'─'.repeat(width - 2)}┘${C.reset}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
68
82
|
let rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
69
83
|
let config = loadConfig();
|
|
70
84
|
let registry = loadRegistry();
|
|
@@ -79,13 +93,13 @@ ${C.c3} ██║ ██║╚██╔╝██║██╔═══╝ █
|
|
|
79
93
|
${C.c4} ██║ ██║ ╚═╝ ██║██║ ██║ ██║${C.reset}
|
|
80
94
|
${C.c4} ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${C.reset}
|
|
81
95
|
${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
|
|
82
|
-
${C.reset}The Multi Platform AI ${C.green}[Interactive
|
|
96
|
+
${C.reset}The Multi Platform AI ${C.green}[Interactive Popup UI Engine]${C.reset}
|
|
83
97
|
${C.gray}/config | /models | /skill | /mcp | /connect | /scan | /exit${C.reset}
|
|
84
98
|
${C.darkGray}────────────────────────────────────────────────────────────${C.reset}
|
|
85
99
|
`);
|
|
86
100
|
}
|
|
87
101
|
|
|
88
|
-
// System
|
|
102
|
+
// System Context Builder
|
|
89
103
|
function getActiveToolsContext() {
|
|
90
104
|
let contextParts = [];
|
|
91
105
|
|
|
@@ -110,36 +124,67 @@ function getActiveToolsContext() {
|
|
|
110
124
|
if (contextParts.length === 0) return "";
|
|
111
125
|
|
|
112
126
|
return "\n\n[SYSTEM CONTEXT: ACTIVE TOOLS & PROTOCOLS]\n" + contextParts.join("\n") +
|
|
113
|
-
"\nIf
|
|
127
|
+
"\nIf user wants to execute a skill/MCP, assist them using available tools.\n";
|
|
114
128
|
}
|
|
115
129
|
|
|
116
|
-
// Handlers for Skills
|
|
130
|
+
// Handlers for Skills with Popup Helper
|
|
117
131
|
function listSkills() {
|
|
118
132
|
console.log(`\n${C.cyan}=== Registered Skills ===${C.reset}`);
|
|
119
133
|
const keys = Object.keys(registry.skills || {});
|
|
134
|
+
|
|
120
135
|
if (keys.length === 0) {
|
|
121
|
-
console.log(`${C.gray}Belum ada skill
|
|
136
|
+
console.log(`${C.gray}Belum ada skill terhubung. Ketik ${C.yellow}/scan${C.gray} atau ${C.yellow}/connect skill <path>${C.reset}\n`);
|
|
122
137
|
return;
|
|
123
138
|
}
|
|
139
|
+
|
|
124
140
|
keys.forEach((name, i) => {
|
|
125
141
|
const item = registry.skills[name];
|
|
126
|
-
console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.path}${C.reset}
|
|
142
|
+
console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.path}${C.reset}`);
|
|
127
143
|
});
|
|
128
144
|
console.log('');
|
|
145
|
+
|
|
146
|
+
// Interactive Action Helper Popup
|
|
147
|
+
const sampleSkill = keys[0] || 'nama_skill';
|
|
148
|
+
drawBox("💡 CARA MENGGUNAKAN SKILL TERDAFTAR", [
|
|
149
|
+
`${C.bold}Perintah yang Bisa Kamu Ketik di Chat:${C.reset}`,
|
|
150
|
+
` 1. Langsung minta AI panggil skill:`,
|
|
151
|
+
` ${C.yellow}TMPA > "Jalankan skill ${sampleSkill}"${C.reset}`,
|
|
152
|
+
` 2. Tanya fungsi skill:`,
|
|
153
|
+
` ${C.yellow}TMPA > "Apa kegunaan dari skill ${sampleSkill}?"${C.reset}`,
|
|
154
|
+
` 3. Hubungkan file JS baru:`,
|
|
155
|
+
` ${C.yellow}TMPA > /connect skill ./path/ke/file.js${C.reset}`
|
|
156
|
+
], C.c1);
|
|
157
|
+
console.log('');
|
|
129
158
|
}
|
|
130
159
|
|
|
160
|
+
// Handlers for MCP with Popup Helper
|
|
131
161
|
function listMCP() {
|
|
132
162
|
console.log(`\n${C.cyan}=== Registered MCP (Model Context Protocol) Servers ===${C.reset}`);
|
|
133
163
|
const keys = Object.keys(registry.mcp || {});
|
|
164
|
+
|
|
134
165
|
if (keys.length === 0) {
|
|
135
|
-
console.log(`${C.gray}Belum ada MCP server terhubung.
|
|
166
|
+
console.log(`${C.gray}Belum ada MCP server terhubung. Ketik ${C.yellow}/scan${C.gray} atau ${C.yellow}/connect mcp <target>${C.reset}\n`);
|
|
136
167
|
return;
|
|
137
168
|
}
|
|
169
|
+
|
|
138
170
|
keys.forEach((name, i) => {
|
|
139
171
|
const item = registry.mcp[name];
|
|
140
|
-
console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.target}${C.reset} [${item.type
|
|
172
|
+
console.log(` ${C.yellow}${i + 1}.${C.reset} ${C.green}${name}${C.reset} -> ${C.gray}${item.target}${C.reset} [${item.type}]`);
|
|
141
173
|
});
|
|
142
174
|
console.log('');
|
|
175
|
+
|
|
176
|
+
// Interactive Action Helper Popup
|
|
177
|
+
const sampleMcp = keys[0] || 'filesystem';
|
|
178
|
+
drawBox("⚡ CARA MENGGUNAKAN MCP SERVER", [
|
|
179
|
+
`${C.bold}Perintah & Integrasi yang Bisa Kamu Gunakan:${C.reset}`,
|
|
180
|
+
` 1. Minta AI akses fitur MCP:`,
|
|
181
|
+
` ${C.yellow}TMPA > "Gunakan MCP ${sampleMcp} untuk analisis data"${C.reset}`,
|
|
182
|
+
` 2. Hubungkan MCP via URL / HTTP SSE:`,
|
|
183
|
+
` ${C.yellow}TMPA > /connect mcp http://localhost:3000/sse${C.reset}`,
|
|
184
|
+
` 3. Pindai server MCP otomatis:`,
|
|
185
|
+
` ${C.yellow}TMPA > /scan${C.reset}`
|
|
186
|
+
], C.c4);
|
|
187
|
+
console.log('');
|
|
143
188
|
}
|
|
144
189
|
|
|
145
190
|
function connectResource(inputArgs) {
|
|
@@ -165,7 +210,7 @@ function connectResource(inputArgs) {
|
|
|
165
210
|
status: 'Active'
|
|
166
211
|
};
|
|
167
212
|
saveRegistry(registry);
|
|
168
|
-
console.log(`${C.green}[+] Skill "${skillName}" berhasil
|
|
213
|
+
console.log(`${C.green}[+] Skill "${skillName}" berhasil terhubung!${C.reset}\n`);
|
|
169
214
|
} else if (type === 'mcp') {
|
|
170
215
|
const mcpName = path.basename(resolvedPath, path.extname(resolvedPath));
|
|
171
216
|
registry.mcp = registry.mcp || {};
|
|
@@ -176,31 +221,26 @@ function connectResource(inputArgs) {
|
|
|
176
221
|
status: 'Connected'
|
|
177
222
|
};
|
|
178
223
|
saveRegistry(registry);
|
|
179
|
-
console.log(`${C.green}[+] MCP Server "${mcpName}" berhasil
|
|
224
|
+
console.log(`${C.green}[+] MCP Server "${mcpName}" berhasil terhubung!${C.reset}\n`);
|
|
180
225
|
} else {
|
|
181
226
|
console.log(`${C.red}[x] Tipe tidak dikenal. Gunakan "skill" atau "mcp".${C.reset}\n`);
|
|
182
227
|
}
|
|
183
228
|
}
|
|
184
229
|
|
|
185
|
-
// Deep Multi-Location Scanner Function
|
|
230
|
+
// Deep Multi-Location Scanner Function with Result Popup Card
|
|
186
231
|
function scanResources() {
|
|
187
|
-
console.log(
|
|
232
|
+
console.log(`\n${C.yellow}[...] Memindai lokasi internal, home user, Gemini CLI & Claude Desktop...${C.reset}`);
|
|
188
233
|
registry = loadRegistry();
|
|
189
234
|
registry.skills = registry.skills || {};
|
|
190
235
|
registry.mcp = registry.mcp || {};
|
|
191
236
|
|
|
192
237
|
const home = os.homedir();
|
|
193
238
|
const searchTargets = [
|
|
194
|
-
// Folder Internal TMPA
|
|
195
239
|
{ type: 'skill', dir: SKILLS_DIR },
|
|
196
240
|
{ type: 'mcp', dir: MCP_DIR },
|
|
197
|
-
|
|
198
|
-
// Folder Umum Pengguna (Direct Home Directory)
|
|
199
241
|
{ type: 'skill', dir: path.join(home, 'skills') },
|
|
200
242
|
{ type: 'mcp', dir: path.join(home, 'mcp') },
|
|
201
243
|
{ type: 'mcp', dir: path.join(home, '.mcp') },
|
|
202
|
-
|
|
203
|
-
// Folder Konfigurasi Gemini CLI & Claude Desktop
|
|
204
244
|
{ type: 'skill', dir: path.join(home, '.gemini', 'skills') },
|
|
205
245
|
{ type: 'mcp', dir: path.join(home, '.gemini', 'mcp') },
|
|
206
246
|
{ type: 'skill', dir: path.join(home, '.config', 'gemini', 'skills') },
|
|
@@ -209,7 +249,7 @@ function scanResources() {
|
|
|
209
249
|
{ type: 'mcp', dir: path.join(home, '.config', 'claude', 'mcp') }
|
|
210
250
|
];
|
|
211
251
|
|
|
212
|
-
let
|
|
252
|
+
let newDetected = [];
|
|
213
253
|
|
|
214
254
|
searchTargets.forEach(({ type, dir }) => {
|
|
215
255
|
if (fs.existsSync(dir)) {
|
|
@@ -219,28 +259,40 @@ function scanResources() {
|
|
|
219
259
|
const fullPath = path.join(dir, item);
|
|
220
260
|
const name = path.basename(item, path.extname(item));
|
|
221
261
|
|
|
222
|
-
if (type === 'skill') {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
} else if (type === 'mcp') {
|
|
229
|
-
if (!registry.mcp[name]) {
|
|
230
|
-
registry.mcp[name] = { target: fullPath, type: 'local', connectedAt: new Date().toISOString(), status: 'Connected' };
|
|
231
|
-
console.log(`${C.green}[+] Terdeteksi MCP: ${name}${C.reset} ${C.gray}(${fullPath})${C.reset}`);
|
|
232
|
-
addedCount++;
|
|
233
|
-
}
|
|
262
|
+
if (type === 'skill' && !registry.skills[name]) {
|
|
263
|
+
registry.skills[name] = { path: fullPath, connectedAt: new Date().toISOString(), status: 'Active' };
|
|
264
|
+
newDetected.push(`[Skill] ${name}`);
|
|
265
|
+
} else if (type === 'mcp' && !registry.mcp[name]) {
|
|
266
|
+
registry.mcp[name] = { target: fullPath, type: 'local', connectedAt: new Date().toISOString(), status: 'Connected' };
|
|
267
|
+
newDetected.push(`[MCP] ${name}`);
|
|
234
268
|
}
|
|
235
269
|
});
|
|
236
|
-
} catch (e) {
|
|
237
|
-
// Skip folder jika permission terikat
|
|
238
|
-
}
|
|
270
|
+
} catch (e) {}
|
|
239
271
|
}
|
|
240
272
|
});
|
|
241
273
|
|
|
242
274
|
saveRegistry(registry);
|
|
243
|
-
|
|
275
|
+
|
|
276
|
+
console.log(`${C.green}[+] Pemindaian selesai.${C.reset}\n`);
|
|
277
|
+
|
|
278
|
+
// POPUP CARD SUMMARY FOR SCAN RESULTS
|
|
279
|
+
if (newDetected.length > 0) {
|
|
280
|
+
drawBox("🎉 ITEM BARU BERHASIL DITEMUKAN!", [
|
|
281
|
+
`${C.green}Berhasil menambahkan ${newDetected.length} resource baru:${C.reset}`,
|
|
282
|
+
...newDetected.slice(0, 4).map(item => ` • ${item}`),
|
|
283
|
+
newDetected.length > 4 ? ` ...dan ${newDetected.length - 4} item lainnya.` : '',
|
|
284
|
+
``,
|
|
285
|
+
`${C.yellow}Ketik /skill atau /mcp untuk melihat daftar lengkap!${C.reset}`
|
|
286
|
+
], C.green);
|
|
287
|
+
} else {
|
|
288
|
+
drawBox("ℹ️ HASIL PEMINDAIAN", [
|
|
289
|
+
`Tidak ada file Skill atau MCP baru yang terdeteksi.`,
|
|
290
|
+
`Semua resource sudah terhubung di registry.`,
|
|
291
|
+
``,
|
|
292
|
+
`Gunakan ${C.yellow}/skill${C.reset} atau ${C.yellow}/mcp${C.reset} untuk melihat item aktif.`
|
|
293
|
+
], C.gray);
|
|
294
|
+
}
|
|
295
|
+
console.log('');
|
|
244
296
|
}
|
|
245
297
|
|
|
246
298
|
function askConfig(callback) {
|