smoothie-code 2.0.2 → 2.0.3
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/config.json +4 -11
- package/dist/select-models.js +81 -43
- package/package.json +1 -1
package/config.json
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"openrouter_models": [
|
|
3
3
|
{
|
|
4
|
-
"id": "
|
|
5
|
-
"label": "
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"id": "qwen/qwen3.6-plus:free",
|
|
9
|
-
"label": "Qwen: Qwen3.6 Plus (free)"
|
|
10
|
-
},
|
|
11
|
-
{
|
|
12
|
-
"id": "z-ai/glm-5v-turbo",
|
|
13
|
-
"label": "Z.ai: GLM 5V Turbo"
|
|
4
|
+
"id": "openai/gpt-5.4-nano",
|
|
5
|
+
"label": "OpenAI: GPT-5.4 Nano"
|
|
14
6
|
}
|
|
15
7
|
],
|
|
16
8
|
"auto_blend": true,
|
|
17
9
|
"leaderboard": true,
|
|
18
|
-
"github": "hotairbag"
|
|
10
|
+
"github": "hotairbag",
|
|
11
|
+
"auto_review": true
|
|
19
12
|
}
|
package/dist/select-models.js
CHANGED
|
@@ -173,72 +173,110 @@ async function cmdPick(apiKey, configPath) {
|
|
|
173
173
|
claude: ['anthropic'],
|
|
174
174
|
codex: ['openai'],
|
|
175
175
|
gemini: ['google'],
|
|
176
|
-
cursor: [],
|
|
176
|
+
cursor: [],
|
|
177
177
|
};
|
|
178
178
|
const excluded = excludePrefixes[platform] || [];
|
|
179
179
|
topModels = topModels.filter(m => !excluded.some(prefix => m.id.startsWith(prefix + '/')));
|
|
180
|
-
|
|
181
|
-
// Default selection: first 3
|
|
180
|
+
// Track selection + any extra models added by ID
|
|
182
181
|
const selected = new Set([0, 1, 2]);
|
|
183
|
-
|
|
184
|
-
console.log('');
|
|
185
|
-
for (let i = 0; i < topModels.length; i++) {
|
|
186
|
-
const check = selected.has(i) ? '\x1b[32m✓\x1b[0m' : ' ';
|
|
187
|
-
const num = String(i + 1).padStart(2, ' ');
|
|
188
|
-
console.log(` ${check} ${num}. ${topModels[i].label}`);
|
|
189
|
-
}
|
|
190
|
-
console.log('');
|
|
182
|
+
const extras = [];
|
|
191
183
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
184
|
+
function printList() {
|
|
185
|
+
console.log('');
|
|
186
|
+
console.log(' \x1b[90mSee trending: https://openrouter.ai/rankings/programming\x1b[0m');
|
|
187
|
+
console.log('');
|
|
188
|
+
for (let i = 0; i < topModels.length; i++) {
|
|
189
|
+
const check = selected.has(i) ? '\x1b[32m✓\x1b[0m' : ' ';
|
|
190
|
+
const num = String(i + 1).padStart(2, ' ');
|
|
191
|
+
console.log(` ${check} ${num}. ${topModels[i].label}`);
|
|
192
|
+
}
|
|
193
|
+
for (const e of extras) {
|
|
194
|
+
console.log(` \x1b[32m✓\x1b[0m + ${e.label}`);
|
|
195
|
+
}
|
|
196
|
+
const count = selected.size + extras.length;
|
|
197
|
+
const names = [...selected].map(i => topModels[i].label).concat(extras.map(e => e.label));
|
|
198
|
+
console.log('');
|
|
199
|
+
console.log(` \x1b[90mSelected: ${names.join(', ')} (${count} model${count !== 1 ? 's' : ''})\x1b[0m`);
|
|
200
|
+
console.log(' \x1b[90m1-${topModels.length} toggle · model/id add · Enter save · reset defaults\x1b[0m'.replace('${topModels.length}', String(topModels.length)));
|
|
201
|
+
console.log('');
|
|
202
|
+
}
|
|
203
|
+
printList();
|
|
204
|
+
// Interactive loop
|
|
205
|
+
while (true) {
|
|
206
|
+
const answer = await promptQ(rl, ' > ');
|
|
207
|
+
const input = answer.trim();
|
|
208
|
+
if (input === '' || input === 'done') {
|
|
209
|
+
// Save and exit
|
|
210
|
+
if (selected.size + extras.length === 0) {
|
|
211
|
+
console.log(' \x1b[33mNeed at least 1 model\x1b[0m');
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
if (input === 'reset') {
|
|
217
|
+
selected.clear();
|
|
218
|
+
selected.add(0);
|
|
219
|
+
selected.add(1);
|
|
220
|
+
selected.add(2);
|
|
221
|
+
extras.length = 0;
|
|
222
|
+
printList();
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
// Process each token (supports "4 5 7" in one line)
|
|
226
|
+
let changed = false;
|
|
199
227
|
for (const token of input.split(/\s+/)) {
|
|
200
228
|
if (token.includes('/')) {
|
|
201
|
-
//
|
|
229
|
+
// Model ID
|
|
202
230
|
const entry = await lookupModel(apiKey, token);
|
|
203
231
|
if (entry) {
|
|
204
|
-
|
|
205
|
-
|
|
232
|
+
if (!extras.some(e => e.id === entry.id)) {
|
|
233
|
+
extras.push(entry);
|
|
234
|
+
console.log(` \x1b[32m✓\x1b[0m Added ${entry.label}`);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
console.log(` Already added: ${entry.label}`);
|
|
238
|
+
}
|
|
239
|
+
changed = true;
|
|
206
240
|
}
|
|
207
241
|
else {
|
|
208
|
-
console.log(`
|
|
242
|
+
console.log(` \x1b[31m✗\x1b[0m Unknown model: ${token}`);
|
|
209
243
|
}
|
|
210
244
|
}
|
|
211
245
|
else {
|
|
212
246
|
const n = parseInt(token, 10);
|
|
213
|
-
if (n >= 1 && n <= topModels.length)
|
|
214
|
-
|
|
247
|
+
if (n >= 1 && n <= topModels.length) {
|
|
248
|
+
const idx = n - 1;
|
|
249
|
+
if (selected.has(idx)) {
|
|
250
|
+
if (selected.size + extras.length <= 1) {
|
|
251
|
+
console.log(' \x1b[33mNeed at least 1 model\x1b[0m');
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
selected.delete(idx);
|
|
255
|
+
changed = true;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
selected.add(idx);
|
|
260
|
+
changed = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
215
263
|
}
|
|
216
264
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
let finalSelection;
|
|
220
|
-
if (toggleNums.length > 0) {
|
|
221
|
-
finalSelection = toggleNums.map((n) => topModels[n - 1]);
|
|
222
|
-
}
|
|
223
|
-
else if (pastedIds.length > 0) {
|
|
224
|
-
// Keep defaults + add pasted
|
|
225
|
-
finalSelection = [...selected].map((i) => topModels[i]);
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
// Enter with no input → use defaults
|
|
229
|
-
finalSelection = [...selected].map((i) => topModels[i]);
|
|
230
|
-
}
|
|
231
|
-
// Merge pasted IDs
|
|
232
|
-
for (const p of pastedIds) {
|
|
233
|
-
if (!finalSelection.some((m) => m.id === p.id)) {
|
|
234
|
-
finalSelection.push(p);
|
|
265
|
+
if (changed) {
|
|
266
|
+
printList();
|
|
235
267
|
}
|
|
236
268
|
}
|
|
269
|
+
rl.close();
|
|
270
|
+
// Build final selection
|
|
271
|
+
const finalSelection = [
|
|
272
|
+
...[...selected].map(i => topModels[i]),
|
|
273
|
+
...extras,
|
|
274
|
+
];
|
|
237
275
|
// Preserve existing config fields (like auto_review)
|
|
238
276
|
const existing = loadConfig(configPath);
|
|
239
277
|
existing.openrouter_models = finalSelection;
|
|
240
278
|
saveConfig(configPath, existing);
|
|
241
|
-
console.log(`
|
|
279
|
+
console.log(` \x1b[32m✓\x1b[0m ${finalSelection.map(m => m.label).join(', ')}`);
|
|
242
280
|
}
|
|
243
281
|
// ── Main ────────────────────────────────────────────────────────────
|
|
244
282
|
async function main() {
|