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.
Files changed (3) hide show
  1. package/README.md +48 -4
  2. package/bin/index.js +147 -22
  3. 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 --> Update or change stored API Key and API Endpoint
53
- /clear --> Clear the terminal screen and display the main banner
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;6x;182;212m',
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 | /connect : Web Integration | /uninstall : Remove | /exit : Exit${C.reset}
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
- rl.question(`${C.yellow}[>] Enter API Key:${C.reset} `, (apiKey) => {
65
- rl.question(`${C.yellow}[>] Enter Endpoint URL (Press Enter for Default Gemini):${C.reset} `, (endpoint) => {
66
- config.apiKey = apiKey.trim();
67
- config.endpoint = endpoint.trim() || 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent';
68
- saveConfig(config);
69
- console.log(`${C.green}[+] Configuration saved successfully!${C.reset}\n`);
70
- if (callback) callback();
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
- const isGoogle = targetEndpoint.includes('googleapis.com');
88
- const url = isGoogle ? `${targetEndpoint}?key=${config.apiKey}` : targetEndpoint;
200
+ let url = config.endpoint;
201
+ let headers = { 'Content-Type': 'application/json' };
202
+ let bodyData = {};
89
203
 
90
- const bodyData = isGoogle
91
- ? { contents: [{ parts: [{ text: prompt }] }] }
92
- : { prompt: prompt, apiKey: config.apiKey };
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: { 'Content-Type': 'application/json' },
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.candidates && data.candidates[0]?.content?.parts[0]?.text) {
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 === '/connect') {
152
- console.log(`\n${C.c4}[!] [COMING SOON] Web integration & auth login features will be available in the next release.${C.reset}\n`);
153
- startPrompt();
277
+ } else if (cmd === '/models') {
278
+ fetchAvailableModels();
154
279
  } else if (cmd === '/uninstall') {
155
280
  handleUninstall();
156
281
  } else if (cmd === '') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmpa-cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "bin": {