tmpa-cli 1.0.7 β 1.0.9
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/README.md +48 -4
- package/bin/index.js +147 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,18 +25,21 @@ Make sure you have **Node.js** (v18+) installed in your terminal. Run the follow
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
npm install -g tmpa-cli
|
|
28
|
+
```
|
|
28
29
|
|
|
29
30
|
2. Installation via GitHub
|
|
30
31
|
βYou can also install directly from the GitHub repository:
|
|
31
32
|
|
|
33
|
+
```bash
|
|
32
34
|
npm install -g git+[https://github.com/zayyanathariz63-pixel/TMPA-CLI.git](https://github.com/zayyanathariz63-pixel/TMPA-CLI.git)
|
|
35
|
+
```
|
|
33
36
|
|
|
34
37
|
π Usage
|
|
35
38
|
βOnce installed, simply open your terminal and type:
|
|
36
39
|
|
|
37
|
-
bash
|
|
40
|
+
```bash
|
|
38
41
|
tmpa
|
|
39
|
-
|
|
42
|
+
```
|
|
40
43
|
π First-Time Setup
|
|
41
44
|
βWhen you run the application for the first time, you will be prompted to enter:
|
|
42
45
|
|
|
@@ -49,10 +52,11 @@ tmpa
|
|
|
49
52
|
βWhile inside the TMPA > chat session, you can use the following control commands:
|
|
50
53
|
|
|
51
54
|
Command Description
|
|
52
|
-
/config
|
|
53
|
-
/clear
|
|
55
|
+
/config--> Update or change stored API Key and API Endpoint
|
|
56
|
+
/clear--> Clear the terminal screen and display the main banner
|
|
54
57
|
/exit --> Exit the TMPA CLI application
|
|
55
58
|
|
|
59
|
+
|
|
56
60
|
Preview Example :
|
|
57
61
|
βββββββββββββ βββββββββββ ββββββ
|
|
58
62
|
ββββββββββββββ βββββββββββββββββββββ
|
|
@@ -65,6 +69,46 @@ Preview Example :
|
|
|
65
69
|
/config : Change API | /clear : Clear Screen | /exit : Exit
|
|
66
70
|
βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
67
71
|
|
|
72
|
+
|
|
73
|
+
## π¦ Prerequisites
|
|
74
|
+
|
|
75
|
+
Make sure you have **Node.js** (`v18.0.0` or higher) installed in your system:
|
|
76
|
+
|
|
77
|
+
windows :
|
|
78
|
+
```bash
|
|
79
|
+
winget install OpenJS.NodeJS
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Linux :
|
|
83
|
+
```bash
|
|
84
|
+
sudo apt update
|
|
85
|
+
sudo apt install nodejs npm
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. macOS :
|
|
89
|
+
```bash
|
|
90
|
+
brew install node
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
π How to Check the Installation Results: Once the process is complete, close and reopen your terminal, then type the following command to verify that npm is installed:
|
|
94
|
+
|
|
95
|
+
node.js :
|
|
96
|
+
```bash
|
|
97
|
+
node -v
|
|
98
|
+
```
|
|
99
|
+
npm :
|
|
100
|
+
```bash
|
|
101
|
+
npm -v
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
If you are using Termux (Android), you can install or update Node.js v18+ using:
|
|
106
|
+
|
|
107
|
+
```Bash
|
|
108
|
+
pkg update && pkg install nodejs-lts -y
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
|
|
68
112
|
TMPA > hello, who are you?
|
|
69
113
|
TMPA CLI processing...
|
|
70
114
|
TMPA CLI : I am an AI assistant ready to help you!
|
package/bin/index.js
CHANGED
|
@@ -15,13 +15,23 @@ const C = {
|
|
|
15
15
|
c3: '\x1b[38;2;99;102;241m',
|
|
16
16
|
c4: '\x1b[38;2;168;85;247m',
|
|
17
17
|
green: '\x1b[38;2;34;197;94m',
|
|
18
|
-
cyan: '\x1b[38;2;
|
|
18
|
+
cyan: '\x1b[38;2;6;182;212m',
|
|
19
19
|
yellow: '\x1b[38;2;234;179;8m',
|
|
20
20
|
red: '\x1b[38;2;239;68;68m',
|
|
21
21
|
gray: '\x1b[38;2;148;163;184m',
|
|
22
22
|
darkGray: '\x1b[38;2;71;85;105m'
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
const PROVIDERS = {
|
|
26
|
+
'1': { name: 'OpenRouter', endpoint: 'https://openrouter.ai/api/v1', defaultModel: 'google/gemini-2.5-flash' },
|
|
27
|
+
'2': { name: 'Groq', endpoint: 'https://api.groq.com/openai/v1', defaultModel: 'llama-3.3-70b-versatile' },
|
|
28
|
+
'3': { name: 'NVIDIA NIM', endpoint: 'https://integrate.api.nvidia.com/v1', defaultModel: 'meta/llama-3.1-70b-instruct' },
|
|
29
|
+
'4': { name: 'OpenAI', endpoint: 'https://api.openai.com/v1', defaultModel: 'gpt-4o-mini' },
|
|
30
|
+
'5': { name: 'Anthropic', endpoint: 'https://api.anthropic.com/v1', defaultModel: 'claude-3-5-haiku-20241022' },
|
|
31
|
+
'6': { name: 'Google Gemini', endpoint: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent', defaultModel: 'gemini-2.5-flash' },
|
|
32
|
+
'7': { name: 'Custom / Auto-Detect', endpoint: '', defaultModel: '' }
|
|
33
|
+
};
|
|
34
|
+
|
|
25
35
|
function loadConfig() {
|
|
26
36
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
27
37
|
try {
|
|
@@ -48,7 +58,7 @@ ${C.c4} βββ βββ βββ ββββββ βββ β
|
|
|
48
58
|
${C.c4} βββ βββ ββββββ βββ βββ${C.reset}
|
|
49
59
|
${C.darkGray}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${C.reset}
|
|
50
60
|
${C.reset}The Multi Platform AI ${C.green}[Interactive Mode]${C.reset}
|
|
51
|
-
${C.gray}/config : Set API | /
|
|
61
|
+
${C.gray}/config : Set API | /models : View & Select Models | /uninstall : Remove | /exit : Exit${C.reset}
|
|
52
62
|
${C.darkGray}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${C.reset}
|
|
53
63
|
`);
|
|
54
64
|
}
|
|
@@ -61,45 +71,161 @@ const rl = readline.createInterface({
|
|
|
61
71
|
let config = loadConfig();
|
|
62
72
|
|
|
63
73
|
function askConfig(callback) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
console.log(`\n${C.cyan}[+] Choose AI Provider:${C.reset}`);
|
|
75
|
+
console.log(` ${C.yellow}1.${C.reset} OpenRouter`);
|
|
76
|
+
console.log(` ${C.yellow}2.${C.reset} Groq`);
|
|
77
|
+
console.log(` ${C.yellow}3.${C.reset} NVIDIA NIM`);
|
|
78
|
+
console.log(` ${C.yellow}4.${C.reset} OpenAI`);
|
|
79
|
+
console.log(` ${C.yellow}5.${C.reset} Anthropic`);
|
|
80
|
+
console.log(` ${C.yellow}6.${C.reset} Google Gemini (Default)`);
|
|
81
|
+
console.log(` ${C.yellow}7.${C.reset} Custom / Auto-Detect Endpoint\n`);
|
|
82
|
+
|
|
83
|
+
rl.question(`${C.yellow}[>] Select Provider (1-7):${C.reset} `, (choice) => {
|
|
84
|
+
const selected = PROVIDERS[choice.trim()] || PROVIDERS['6'];
|
|
85
|
+
|
|
86
|
+
rl.question(`${C.yellow}[>] Enter API Key for ${selected.name}:${C.reset} `, (apiKey) => {
|
|
87
|
+
if (choice.trim() === '7') {
|
|
88
|
+
rl.question(`${C.yellow}[>] Enter Custom Base URL / Endpoint:${C.reset} `, (customUrl) => {
|
|
89
|
+
rl.question(`${C.yellow}[>] Enter Specific Model Name:${C.reset} `, (customModel) => {
|
|
90
|
+
config.provider = 'Custom';
|
|
91
|
+
config.apiKey = apiKey.trim();
|
|
92
|
+
config.endpoint = customUrl.trim();
|
|
93
|
+
config.model = customModel.trim();
|
|
94
|
+
saveConfig(config);
|
|
95
|
+
console.log(`${C.green}[+] Configuration saved successfully!${C.reset}\n`);
|
|
96
|
+
if (callback) callback();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
config.provider = selected.name;
|
|
101
|
+
config.apiKey = apiKey.trim();
|
|
102
|
+
config.endpoint = selected.endpoint;
|
|
103
|
+
config.model = selected.defaultModel;
|
|
104
|
+
saveConfig(config);
|
|
105
|
+
console.log(`${C.green}[+] Connected to ${selected.name}. Default model: ${selected.defaultModel}${C.reset}`);
|
|
106
|
+
console.log(`${C.gray}(Tip: Run /models anytime to see all available models or type a custom model ID)${C.reset}\n`);
|
|
107
|
+
if (callback) callback();
|
|
108
|
+
}
|
|
71
109
|
});
|
|
72
110
|
});
|
|
73
111
|
}
|
|
74
112
|
|
|
113
|
+
async function fetchAvailableModels() {
|
|
114
|
+
if (!config.apiKey) {
|
|
115
|
+
console.log(`${C.red}[x] API Key is not set. Use /config first.${C.reset}\n`);
|
|
116
|
+
return startPrompt();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`${C.yellow}[...] Fetching full model list from ${config.provider || 'Provider'}...${C.reset}`);
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
let url = config.endpoint;
|
|
123
|
+
if (url.includes('googleapis.com')) {
|
|
124
|
+
console.log(`${C.yellow}[!] Gemini Default REST API uses endpoint-defined model: ${config.model}${C.reset}\n`);
|
|
125
|
+
return startPrompt();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let modelsUrl = url.endsWith('/models') ? url : `${url.replace(/\/chat\/completions$/, '')}/models`;
|
|
129
|
+
|
|
130
|
+
const response = await fetch(modelsUrl, {
|
|
131
|
+
method: 'GET',
|
|
132
|
+
headers: {
|
|
133
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
134
|
+
'Content-Type': 'application/json'
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const data = await response.json();
|
|
139
|
+
|
|
140
|
+
if (data.data && Array.isArray(data.data)) {
|
|
141
|
+
console.log(`\n${C.cyan}=== Available Models for ${config.provider} (${data.data.length} total) ===${C.reset}`);
|
|
142
|
+
|
|
143
|
+
// Ambil hingga 50 model populer/teratas untuk tampilan cepat
|
|
144
|
+
const displayedModels = data.data.slice(0, 50);
|
|
145
|
+
displayedModels.forEach((m, idx) => {
|
|
146
|
+
const num = (idx + 1).toString().padStart(2, ' ');
|
|
147
|
+
console.log(` ${C.yellow}${num}.${C.reset} ${m.id}`);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (data.data.length > 50) {
|
|
151
|
+
console.log(`${C.gray}... and ${data.data.length - 50} more models available on ${config.provider}.${C.reset}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(`${C.darkGray}------------------------------------------------------------${C.reset}`);
|
|
155
|
+
console.log(`${C.gray}Current active model: ${C.green}${config.model}${C.reset}`);
|
|
156
|
+
|
|
157
|
+
rl.question(`\n${C.yellow}[>] Enter number (1-${displayedModels.length}) OR type specific Model ID (e.g. meta/llama-3.1-70b-instruct):${C.reset} `, (input) => {
|
|
158
|
+
const val = input.trim();
|
|
159
|
+
if (!val) {
|
|
160
|
+
console.log(`${C.gray}Keeping current model: ${config.model}${C.reset}\n`);
|
|
161
|
+
} else if (!isNaN(val) && parseInt(val) >= 1 && parseInt(val) <= displayedModels.length) {
|
|
162
|
+
const selectedModel = displayedModels[parseInt(val) - 1].id;
|
|
163
|
+
config.model = selectedModel;
|
|
164
|
+
saveConfig(config);
|
|
165
|
+
console.log(`${C.green}[+] Model updated to: ${config.model}${C.reset}\n`);
|
|
166
|
+
} else {
|
|
167
|
+
// User memasukkan ID kustom/spesifik sendiri
|
|
168
|
+
config.model = val;
|
|
169
|
+
saveConfig(config);
|
|
170
|
+
console.log(`${C.green}[+] Custom Model ID saved: ${config.model}${C.reset}\n`);
|
|
171
|
+
}
|
|
172
|
+
startPrompt();
|
|
173
|
+
});
|
|
174
|
+
} else {
|
|
175
|
+
console.log(`${C.red}[x] Could not retrieve models list automatically from ${config.provider}.${C.reset}`);
|
|
176
|
+
rl.question(`${C.yellow}[>] Enter specific Model ID manually:${C.reset} `, (manualModel) => {
|
|
177
|
+
if (manualModel.trim()) {
|
|
178
|
+
config.model = manualModel.trim();
|
|
179
|
+
saveConfig(config);
|
|
180
|
+
console.log(`${C.green}[+] Model updated to: ${config.model}${C.reset}\n`);
|
|
181
|
+
}
|
|
182
|
+
startPrompt();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
} catch (err) {
|
|
186
|
+
console.log(`${C.red}[x] Error fetching models: ${err.message}${C.reset}\n`);
|
|
187
|
+
startPrompt();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
75
191
|
async function handleChat(prompt) {
|
|
76
192
|
if (!config.apiKey) {
|
|
77
193
|
console.log(`${C.yellow}[!] API Key is not set.${C.reset}`);
|
|
78
194
|
return askConfig(() => startPrompt());
|
|
79
195
|
}
|
|
80
196
|
|
|
81
|
-
const defaultEndpoint = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
|
|
82
|
-
const targetEndpoint = config.endpoint || defaultEndpoint;
|
|
83
|
-
|
|
84
197
|
console.log(`${C.yellow}TMPA CLI processing...${C.reset}`);
|
|
85
198
|
|
|
86
199
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
200
|
+
let url = config.endpoint;
|
|
201
|
+
let headers = { 'Content-Type': 'application/json' };
|
|
202
|
+
let bodyData = {};
|
|
89
203
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
: {
|
|
204
|
+
if (url.includes('googleapis.com')) {
|
|
205
|
+
url = `${url}?key=${config.apiKey}`;
|
|
206
|
+
bodyData = { contents: [{ parts: [{ text: prompt }] }] };
|
|
207
|
+
} else {
|
|
208
|
+
if (!url.endsWith('/chat/completions')) {
|
|
209
|
+
url = `${url.replace(/\/$/, '')}/chat/completions`;
|
|
210
|
+
}
|
|
211
|
+
headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
212
|
+
bodyData = {
|
|
213
|
+
model: config.model || 'gpt-3.5-turbo',
|
|
214
|
+
messages: [{ role: 'user', content: prompt }]
|
|
215
|
+
};
|
|
216
|
+
}
|
|
93
217
|
|
|
94
218
|
const response = await fetch(url, {
|
|
95
219
|
method: 'POST',
|
|
96
|
-
headers:
|
|
220
|
+
headers: headers,
|
|
97
221
|
body: JSON.stringify(bodyData)
|
|
98
222
|
});
|
|
99
223
|
|
|
100
224
|
const data = await response.json();
|
|
101
225
|
|
|
102
|
-
if (data.
|
|
226
|
+
if (data.choices && data.choices[0]?.message?.content) {
|
|
227
|
+
console.log(`\n${C.c1}TMPA CLI (${config.model || 'AI'}) :${C.reset} ${data.choices[0].message.content}\n`);
|
|
228
|
+
} else if (data.candidates && data.candidates[0]?.content?.parts[0]?.text) {
|
|
103
229
|
console.log(`\n${C.c1}TMPA CLI :${C.reset} ${data.candidates[0].content.parts[0].text}\n`);
|
|
104
230
|
} else if (data.error) {
|
|
105
231
|
console.log(`\n${C.red}[x] API Error: ${data.error.message || JSON.stringify(data.error)}${C.reset}\n`);
|
|
@@ -148,9 +274,8 @@ function startPrompt() {
|
|
|
148
274
|
startPrompt();
|
|
149
275
|
} else if (cmd === '/config') {
|
|
150
276
|
askConfig(() => startPrompt());
|
|
151
|
-
} else if (cmd === '/
|
|
152
|
-
|
|
153
|
-
startPrompt();
|
|
277
|
+
} else if (cmd === '/models') {
|
|
278
|
+
fetchAvailableModels();
|
|
154
279
|
} else if (cmd === '/uninstall') {
|
|
155
280
|
handleUninstall();
|
|
156
281
|
} else if (cmd === '') {
|