tmpa-cli 1.0.9 → 1.0.11

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 +83 -47
  2. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -63,7 +63,7 @@ ${C.darkGray}──────────────────────
63
63
  `);
64
64
  }
65
65
 
66
- const rl = readline.createInterface({
66
+ let rl = readline.createInterface({
67
67
  input: process.stdin,
68
68
  output: process.stdout
69
69
  });
@@ -102,26 +102,101 @@ function askConfig(callback) {
102
102
  config.endpoint = selected.endpoint;
103
103
  config.model = selected.defaultModel;
104
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`);
105
+ console.log(`${C.green}[+] Connected to ${selected.name}. Default model: ${selected.defaultModel}${C.reset}\n`);
107
106
  if (callback) callback();
108
107
  }
109
108
  });
110
109
  });
111
110
  }
112
111
 
112
+ function selectModelCLI(allModels) {
113
+ let filteredModels = [...allModels];
114
+ let currentPage = 0;
115
+ const pageSize = 12;
116
+
117
+ function displayList() {
118
+ console.clear();
119
+ const totalPages = Math.ceil(filteredModels.length / pageSize) || 1;
120
+ if (currentPage >= totalPages) currentPage = totalPages - 1;
121
+ if (currentPage < 0) currentPage = 0;
122
+
123
+ const startIdx = currentPage * pageSize;
124
+ const pageItems = filteredModels.slice(startIdx, startIdx + pageSize);
125
+
126
+ console.log(`${C.cyan}=== Models Selector for ${config.provider} (${filteredModels.length} models) ===${C.reset}`);
127
+ console.log(`${C.gray}Current Active: ${C.green}${config.model || 'None'}${C.reset}`);
128
+ console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}`);
129
+
130
+ if (pageItems.length === 0) {
131
+ console.log(`${C.red} No models found matching filter.${C.reset}`);
132
+ } else {
133
+ pageItems.forEach((m, idx) => {
134
+ const itemNum = startIdx + idx + 1;
135
+ const isCurrent = m.id === config.model;
136
+ const bullet = isCurrent ? `${C.green}●${C.reset}` : `${C.gray}○${C.reset}`;
137
+ console.log(` ${bullet} ${C.yellow}${itemNum.toString().padStart(3, ' ')}.${C.reset} ${m.id}`);
138
+ });
139
+ }
140
+
141
+ console.log(`${C.darkGray}────────────────────────────────────────────────────────────${C.reset}`);
142
+ console.log(`${C.cyan}Page ${currentPage + 1}/${totalPages}${C.reset} | ${C.gray}Commands: [n]ext | [p]rev | [f]ilter <keyword> | [q]uit${C.reset}`);
143
+
144
+ rl.question(`\n${C.yellow}[>] Enter Number / Model ID / Command:${C.reset} `, (answer) => {
145
+ const input = answer.trim();
146
+
147
+ if (input.toLowerCase() === 'n') {
148
+ if (currentPage < totalPages - 1) currentPage++;
149
+ displayList();
150
+ } else if (input.toLowerCase() === 'p') {
151
+ if (currentPage > 0) currentPage--;
152
+ displayList();
153
+ } else if (input.toLowerCase() === 'q' || input.toLowerCase() === 'exit') {
154
+ console.log(`${C.gray}Model selection cancelled.${C.reset}\n`);
155
+ startPrompt();
156
+ } else if (input.toLowerCase().startsWith('f ')) {
157
+ const query = input.slice(2).trim().toLowerCase();
158
+ filteredModels = allModels.filter(m => m.id.toLowerCase().includes(query));
159
+ currentPage = 0;
160
+ displayList();
161
+ } else if (!isNaN(input) && input !== '') {
162
+ const num = parseInt(input);
163
+ if (num >= 1 && num <= filteredModels.length) {
164
+ const selected = filteredModels[num - 1].id;
165
+ config.model = selected;
166
+ saveConfig(config);
167
+ console.log(`\n${C.green}[+] Model changed to: ${config.model}${C.reset}\n`);
168
+ startPrompt();
169
+ } else {
170
+ console.log(`${C.red}[x] Invalid number!${C.reset}`);
171
+ setTimeout(displayList, 1000);
172
+ }
173
+ } else if (input.length > 0) {
174
+ // Jika memasukkan nama model spesifik secara langsung
175
+ config.model = input;
176
+ saveConfig(config);
177
+ console.log(`\n${C.green}[+] Custom Model ID set to: ${config.model}${C.reset}\n`);
178
+ startPrompt();
179
+ } else {
180
+ startPrompt();
181
+ }
182
+ });
183
+ }
184
+
185
+ displayList();
186
+ }
187
+
113
188
  async function fetchAvailableModels() {
114
189
  if (!config.apiKey) {
115
190
  console.log(`${C.red}[x] API Key is not set. Use /config first.${C.reset}\n`);
116
191
  return startPrompt();
117
192
  }
118
193
 
119
- console.log(`${C.yellow}[...] Fetching full model list from ${config.provider || 'Provider'}...${C.reset}`);
194
+ console.log(`${C.yellow}[...] Fetching models list from ${config.provider || 'Provider'}...${C.reset}`);
120
195
 
121
196
  try {
122
197
  let url = config.endpoint;
123
198
  if (url.includes('googleapis.com')) {
124
- console.log(`${C.yellow}[!] Gemini Default REST API uses endpoint-defined model: ${config.model}${C.reset}\n`);
199
+ console.log(`${C.yellow}[!] Gemini Default REST API uses fixed model: ${config.model}${C.reset}\n`);
125
200
  return startPrompt();
126
201
  }
127
202
 
@@ -137,50 +212,11 @@ async function fetchAvailableModels() {
137
212
 
138
213
  const data = await response.json();
139
214
 
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
- });
215
+ if (data.data && Array.isArray(data.data) && data.data.length > 0) {
216
+ selectModelCLI(data.data);
174
217
  } else {
175
218
  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
- });
219
+ startPrompt();
184
220
  }
185
221
  } catch (err) {
186
222
  console.log(`${C.red}[x] Error fetching models: ${err.message}${C.reset}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmpa-cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "bin": {