@anh3d0nic/qwen-code-termux-ice 20.0.1 → 21.0.0
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/qwen-ice +0 -7
- package/package.json +2 -3
- package/scripts/postinstall.cjs +2 -3
- package/bin/api-setup-launcher.js +0 -14
- package/bin/qwen-ice-api-setup +0 -340
package/bin/qwen-ice
CHANGED
|
@@ -137,7 +137,6 @@ OPTIONS:
|
|
|
137
137
|
--model <provider> Use specific model (qwen, groq, gemini, openai, dashscope)
|
|
138
138
|
|
|
139
139
|
COMMANDS:
|
|
140
|
-
api-setup API key manager
|
|
141
140
|
status Show status (keys, models, memory)
|
|
142
141
|
reset Clear memory (keep API keys)
|
|
143
142
|
uninstall Clean uninstall with backup
|
|
@@ -146,7 +145,6 @@ EXAMPLES:
|
|
|
146
145
|
qwen-ice "fix this error" Run single query
|
|
147
146
|
qwen-ice -y "npm install" YOLO mode (auto-approve)
|
|
148
147
|
qwen-ice --model groq Use Groq provider
|
|
149
|
-
qwen-ice api-setup Configure API keys
|
|
150
148
|
qwen-ice status Check status
|
|
151
149
|
`);
|
|
152
150
|
}
|
|
@@ -190,7 +188,6 @@ API KEYS:
|
|
|
190
188
|
const label = key.type === 'oauth' ? '(OAuth)' : '';
|
|
191
189
|
const calls = key.call_count || 0;
|
|
192
190
|
const lastUsed = key.last_used ? new Date(key.last_used).toLocaleDateString() : 'never';
|
|
193
|
-
const invalidMark = !key.active && key.type !== 'oauth' ? ' (invalid key - run api-setup to fix)' : '';
|
|
194
191
|
console.log(`${status} ${key.id.padEnd(15)} ${label.padEnd(8)} — active, ${calls} calls${invalidMark}`);
|
|
195
192
|
if (key.last_used) console.log(` last used: ${lastUsed}`);
|
|
196
193
|
}
|
|
@@ -227,9 +224,7 @@ PIPELINE:
|
|
|
227
224
|
}
|
|
228
225
|
|
|
229
226
|
function runApiSetup() {
|
|
230
|
-
const scriptPath = path.join(INSTALL_DIR, 'bin', 'qwen-ice-api-setup');
|
|
231
227
|
if (!fs.existsSync(scriptPath)) {
|
|
232
|
-
console.error('❌ api-setup not found. Reinstall ICE.');
|
|
233
228
|
return;
|
|
234
229
|
}
|
|
235
230
|
const child = spawn('node', [scriptPath], { stdio: 'inherit' });
|
|
@@ -273,7 +268,6 @@ function printColdStart() {
|
|
|
273
268
|
const providers = loadApiConfig().keys?.filter(k => k.active).length || 0;
|
|
274
269
|
|
|
275
270
|
if (patternsCount === 0 && summary.total_queries === 0) {
|
|
276
|
-
console.log(`\n❄️ Welcome to Qwen Code ICE v${VERSION}\n🔑 Run: qwen-ice api-setup to configure your API keys\n`);
|
|
277
271
|
} else {
|
|
278
272
|
console.log(`\n❄️ Qwen Code ICE v${VERSION} ready`);
|
|
279
273
|
console.log(`🧠 ${patternsCount} patterns loaded | 📊 Avg quality: ${avgQuality}/10 | 🔑 ${providers} providers active`);
|
|
@@ -354,7 +348,6 @@ async function main() {
|
|
|
354
348
|
if (helpFlag) { printHelp(); process.exit(0); }
|
|
355
349
|
if (statusFlag) { printStatus(); process.exit(0); }
|
|
356
350
|
|
|
357
|
-
if (command === 'api-setup' || args[0] === 'api-setup') { runApiSetup(); return; }
|
|
358
351
|
if (command === 'status' || args[0] === 'status') { printStatus(); process.exit(0); }
|
|
359
352
|
if (command === 'reset' || args[0] === 'reset') { resetMemory(); process.exit(0); }
|
|
360
353
|
if (command === 'uninstall' || args[0] === 'uninstall') { runUninstall(); return; }
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anh3d0nic/qwen-code-termux-ice",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "21.0.0",
|
|
4
4
|
"description": "Qwen Code ICE v16.0.5 — Compounding Intelligence with proper npm install structure",
|
|
5
5
|
"main": "core/ice-v16.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"qwen-ice": "./bin/qwen-ice"
|
|
8
|
-
"qwen-ice-api-setup": "./bin/qwen-ice-api-setup"
|
|
7
|
+
"qwen-ice": "./bin/qwen-ice"
|
|
9
8
|
},
|
|
10
9
|
"scripts": {
|
|
11
10
|
"postinstall": "node scripts/postinstall.cjs",
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -29,10 +29,10 @@ const DIRS = [
|
|
|
29
29
|
// Files to copy from package to install dir
|
|
30
30
|
const FILES_TO_COPY = [
|
|
31
31
|
{ src: 'scripts/ice-v15.js', dest: 'core/ice-v15.js' },
|
|
32
|
+
{ src: 'scripts/api-caller.js', dest: 'core/api-caller.js' },
|
|
32
33
|
{ src: 'scripts/ice-v14.js', dest: 'core/ice-v14.js' },
|
|
33
34
|
{ src: 'scripts/ice-v13.js', dest: 'core/ice-v13.js' },
|
|
34
35
|
{ src: 'bin/qwen-ice', dest: 'bin/qwen-ice' },
|
|
35
|
-
{ src: 'bin/qwen-ice-api-setup', dest: 'bin/qwen-ice-api-setup' }
|
|
36
36
|
];
|
|
37
37
|
|
|
38
38
|
// JSON files to preserve from ~/.qwen/
|
|
@@ -177,7 +177,6 @@ function createSymlinks() {
|
|
|
177
177
|
// Create symlinks
|
|
178
178
|
const symlinks = [
|
|
179
179
|
{ target: path.join(INSTALL_DIR, 'bin', 'qwen-ice'), link: path.join(binDir, 'qwen-ice') },
|
|
180
|
-
{ target: path.join(INSTALL_DIR, 'bin', 'qwen-ice-api-setup'), link: path.join(binDir, 'qwen-ice-api-setup') }
|
|
181
180
|
];
|
|
182
181
|
|
|
183
182
|
symlinks.forEach(({ target, link }) => {
|
|
@@ -223,7 +222,7 @@ function main() {
|
|
|
223
222
|
console.log(' qwen-ice "query" — Single query');
|
|
224
223
|
console.log(' qwen-ice --version — Show version');
|
|
225
224
|
console.log(' qwen-ice --help — Show help');
|
|
226
|
-
|
|
225
|
+
|
|
227
226
|
console.log(' qwen-ice exit — Show session summary\n');
|
|
228
227
|
}
|
|
229
228
|
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { execSync } = require('child_process');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
const ICE_HOME = '/data/data/com.termux/files/.qwen-ice';
|
|
6
|
-
const isTermux = process.env.PREFIX?.includes('com.termux') || process.env.TERMUX_VERSION !== undefined;
|
|
7
|
-
const actualIceHome = isTermux ? ICE_HOME : path.join(process.env.HOME || '~', '.qwen-ice');
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
execSync(`node "${path.join(actualIceHome, 'bin', 'qwen-ice-api-setup')}"`, { stdio: 'inherit' });
|
|
11
|
-
} catch (e) {
|
|
12
|
-
console.error('❌ Qwen ICE not installed. Run: npm install -g @anh3d0nic/qwen-code-termux-ice');
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
package/bin/qwen-ice-api-setup
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
#!/data/data/com.termux/files/usr/bin/node
|
|
2
|
-
/**
|
|
3
|
-
* ❄️ ICE v16.0.0 — API Key Manager
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const readline = require('readline');
|
|
9
|
-
const https = require('https');
|
|
10
|
-
|
|
11
|
-
const INSTALL_DIR = '/data/data/com.termux/files/.qwen-ice';
|
|
12
|
-
const CONFIG_DIR = path.join(INSTALL_DIR, 'config');
|
|
13
|
-
const API_KEYS_FILE = path.join(CONFIG_DIR, 'api-keys.json');
|
|
14
|
-
|
|
15
|
-
function loadApiConfig() {
|
|
16
|
-
try {
|
|
17
|
-
if (fs.existsSync(API_KEYS_FILE)) {
|
|
18
|
-
return JSON.parse(fs.readFileSync(API_KEYS_FILE, 'utf8'));
|
|
19
|
-
}
|
|
20
|
-
} catch (err) {}
|
|
21
|
-
return {
|
|
22
|
-
keys: [{
|
|
23
|
-
id: 'qwen-oauth',
|
|
24
|
-
provider: 'qwen',
|
|
25
|
-
type: 'oauth',
|
|
26
|
-
model: 'qwen3-coder-plus',
|
|
27
|
-
active: true,
|
|
28
|
-
note: 'Uses existing Qwen OAuth — do not modify'
|
|
29
|
-
}],
|
|
30
|
-
default_provider: 'qwen',
|
|
31
|
-
fallback_order: ['qwen', 'gemini', 'groq', 'openai', 'dashscope']
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function saveApiConfig(config) {
|
|
36
|
-
fs.writeFileSync(API_KEYS_FILE, JSON.stringify(config, null, 2));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function createInterface() {
|
|
40
|
-
return readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function printMenu() {
|
|
44
|
-
console.log(`
|
|
45
|
-
┌─────────────────────────────────┐
|
|
46
|
-
│ Qwen ICE API Key Manager │
|
|
47
|
-
├─────────────────────────────────┤
|
|
48
|
-
│ 1. View configured APIs │
|
|
49
|
-
│ 2. Add new API key │
|
|
50
|
-
│ 3. Remove API key │
|
|
51
|
-
│ 4. Test all API keys │
|
|
52
|
-
│ 5. Set default provider │
|
|
53
|
-
│ 6. Exit │
|
|
54
|
-
└─────────────────────────────────┘
|
|
55
|
-
`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function viewConfiguredAPIs(config) {
|
|
59
|
-
console.log('\n📋 Configured API Keys:\n');
|
|
60
|
-
for (const key of config.keys) {
|
|
61
|
-
const status = key.active ? '✅' : '❌';
|
|
62
|
-
const oauth = key.type === 'oauth' ? ' (OAuth)' : '';
|
|
63
|
-
const defaultMark = key.provider === config.default_provider ? ' [DEFAULT]' : '';
|
|
64
|
-
const calls = key.call_count || 0;
|
|
65
|
-
const lastUsed = key.last_used ? new Date(key.last_used).toLocaleString() : 'never';
|
|
66
|
-
console.log(`${status} ${key.id}${oauth}${defaultMark}`);
|
|
67
|
-
console.log(` Provider: ${key.provider}`);
|
|
68
|
-
console.log(` Model: ${key.model || 'N/A'}`);
|
|
69
|
-
console.log(` Calls: ${calls} | Last used: ${lastUsed}`);
|
|
70
|
-
if (key.note) console.log(` Note: ${key.note}`);
|
|
71
|
-
console.log('');
|
|
72
|
-
}
|
|
73
|
-
console.log(`Fallback order: ${config.fallback_order.join(' → ')}\n`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function addNewApiKey(config) {
|
|
77
|
-
const rl = createInterface();
|
|
78
|
-
try {
|
|
79
|
-
console.log('\nSelect provider:');
|
|
80
|
-
console.log('1. groq');
|
|
81
|
-
console.log('2. gemini');
|
|
82
|
-
console.log('3. openai');
|
|
83
|
-
console.log('4. dashscope');
|
|
84
|
-
console.log('5. qwen (API key, not OAuth)');
|
|
85
|
-
|
|
86
|
-
const provider = await new Promise(resolve => {
|
|
87
|
-
rl.question('Provider (1-5): ', answer => {
|
|
88
|
-
const providers = { '1': 'groq', '2': 'gemini', '3': 'openai', '4': 'dashscope', '5': 'qwen' };
|
|
89
|
-
resolve(providers[answer] || 'groq');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const defaultModels = {
|
|
94
|
-
groq: 'llama-3.1-70b-versatile',
|
|
95
|
-
gemini: 'gemini-2.0-flash',
|
|
96
|
-
openai: 'gpt-4o',
|
|
97
|
-
dashscope: 'qwen-turbo',
|
|
98
|
-
qwen: 'qwen3-coder-plus'
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const model = await new Promise(resolve => {
|
|
102
|
-
rl.question(`Model [${defaultModels[provider]}]: `, answer => {
|
|
103
|
-
resolve(answer.trim() || defaultModels[provider]);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const apiKey = await new Promise(resolve => {
|
|
108
|
-
const keyNames = { groq: 'gsk_...', gemini: 'AIza...', openai: 'sk-...', dashscope: 'sk-...', qwen: 'sk-...' };
|
|
109
|
-
rl.question(`Enter ${provider} API key (${keyNames[provider]}): `, resolve);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
if (!apiKey) {
|
|
113
|
-
console.log('❌ API key cannot be empty');
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const id = `${provider}-${Date.now().toString(36)}`;
|
|
118
|
-
const newKey = { id, provider, key: apiKey, model, active: true, added: new Date().toISOString(), last_used: null, call_count: 0 };
|
|
119
|
-
|
|
120
|
-
config.keys.push(newKey);
|
|
121
|
-
saveApiConfig(config);
|
|
122
|
-
console.log(`\n✅ Added ${provider} API key: ${id}`);
|
|
123
|
-
} finally {
|
|
124
|
-
rl.close();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function removeApiKey(config) {
|
|
129
|
-
const rl = createInterface();
|
|
130
|
-
try {
|
|
131
|
-
console.log('\nKeys to remove (enter ID):');
|
|
132
|
-
for (const key of config.keys) {
|
|
133
|
-
if (key.type !== 'oauth') {
|
|
134
|
-
console.log(` - ${key.id} (${key.provider})`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const keyId = await new Promise(resolve => {
|
|
139
|
-
rl.question('Enter key ID to remove (or "cancel"): ', resolve);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
if (keyId.toLowerCase() === 'cancel') {
|
|
143
|
-
console.log('Cancelled');
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const index = config.keys.findIndex(k => k.id === keyId);
|
|
148
|
-
if (index === -1) {
|
|
149
|
-
console.log('❌ Key not found');
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (config.keys[index].type === 'oauth') {
|
|
154
|
-
console.log('❌ Cannot remove OAuth key');
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
config.keys.splice(index, 1);
|
|
159
|
-
saveApiConfig(config);
|
|
160
|
-
console.log(`✅ Removed key: ${keyId}`);
|
|
161
|
-
} finally {
|
|
162
|
-
rl.close();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function testProvider(key, provider, model) {
|
|
167
|
-
return new Promise((resolve) => {
|
|
168
|
-
let req;
|
|
169
|
-
|
|
170
|
-
if (provider === 'groq') {
|
|
171
|
-
const data = JSON.stringify({
|
|
172
|
-
model: model || 'llama-3.1-70b-versatile',
|
|
173
|
-
messages: [{ role: 'user', content: 'Hi' }],
|
|
174
|
-
max_tokens: 10
|
|
175
|
-
});
|
|
176
|
-
const options = {
|
|
177
|
-
hostname: 'api.groq.com',
|
|
178
|
-
port: 443,
|
|
179
|
-
path: '/openai/v1/chat/completions',
|
|
180
|
-
method: 'POST',
|
|
181
|
-
headers: {
|
|
182
|
-
'Content-Type': 'application/json',
|
|
183
|
-
'Authorization': `Bearer ${key}`,
|
|
184
|
-
'Content-Length': data.length
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
req = https.request(options, (res) => {
|
|
188
|
-
let responseData = '';
|
|
189
|
-
res.on('data', chunk => responseData += chunk);
|
|
190
|
-
res.on('end', () => {
|
|
191
|
-
if (res.statusCode === 200) resolve({ success: true, message: 'OK' });
|
|
192
|
-
else if (res.statusCode === 401) resolve({ success: false, message: 'Invalid API key' });
|
|
193
|
-
else if (res.statusCode === 429) resolve({ success: false, message: 'Rate limit exceeded' });
|
|
194
|
-
else resolve({ success: false, message: `Error ${res.statusCode}` });
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
} else if (provider === 'gemini') {
|
|
198
|
-
const data = JSON.stringify({ contents: [{ parts: [{ text: 'Hi' }] }] });
|
|
199
|
-
const options = {
|
|
200
|
-
hostname: 'generativelanguage.googleapis.com',
|
|
201
|
-
port: 443,
|
|
202
|
-
path: `/v1beta/models/${model || 'gemini-2.0-flash'}:generateContent?key=${key}`,
|
|
203
|
-
method: 'POST',
|
|
204
|
-
headers: {
|
|
205
|
-
'Content-Type': 'application/json',
|
|
206
|
-
'Content-Length': data.length
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
req = https.request(options, (res) => {
|
|
210
|
-
let responseData = '';
|
|
211
|
-
res.on('data', chunk => responseData += chunk);
|
|
212
|
-
res.on('end', () => {
|
|
213
|
-
if (res.statusCode === 200) resolve({ success: true, message: 'OK' });
|
|
214
|
-
else if (res.statusCode === 400) resolve({ success: false, message: 'Invalid API key or model' });
|
|
215
|
-
else if (res.statusCode === 429) resolve({ success: false, message: 'Rate limit exceeded' });
|
|
216
|
-
else resolve({ success: false, message: `Error ${res.statusCode}` });
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
} else if (provider === 'openai') {
|
|
220
|
-
const data = JSON.stringify({
|
|
221
|
-
model: model || 'gpt-4o',
|
|
222
|
-
messages: [{ role: 'user', content: 'Hi' }],
|
|
223
|
-
max_tokens: 10
|
|
224
|
-
});
|
|
225
|
-
const options = {
|
|
226
|
-
hostname: 'api.openai.com',
|
|
227
|
-
port: 443,
|
|
228
|
-
path: '/v1/chat/completions',
|
|
229
|
-
method: 'POST',
|
|
230
|
-
headers: {
|
|
231
|
-
'Content-Type': 'application/json',
|
|
232
|
-
'Authorization': `Bearer ${key}`,
|
|
233
|
-
'Content-Length': data.length
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
req = https.request(options, (res) => {
|
|
237
|
-
let responseData = '';
|
|
238
|
-
res.on('data', chunk => responseData += chunk);
|
|
239
|
-
res.on('end', () => {
|
|
240
|
-
if (res.statusCode === 200) resolve({ success: true, message: 'OK' });
|
|
241
|
-
else if (res.statusCode === 401) resolve({ success: false, message: 'Invalid API key' });
|
|
242
|
-
else if (res.statusCode === 429) resolve({ success: false, message: 'Rate limit exceeded' });
|
|
243
|
-
else resolve({ success: false, message: `Error ${res.statusCode}` });
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
} else {
|
|
247
|
-
resolve({ success: false, message: 'Provider not supported for testing' });
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
req.on('error', (err) => resolve({ success: false, message: err.message }));
|
|
252
|
-
req.setTimeout(10000, () => {
|
|
253
|
-
resolve({ success: false, message: 'Timeout' });
|
|
254
|
-
req.destroy();
|
|
255
|
-
});
|
|
256
|
-
req.write(data);
|
|
257
|
-
req.end();
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
async function testAllApiKeys(config) {
|
|
262
|
-
console.log('\n🧪 Testing API keys...\n');
|
|
263
|
-
for (const key of config.keys) {
|
|
264
|
-
if (key.type === 'oauth') {
|
|
265
|
-
console.log(`✅ ${key.id} (OAuth) - Skipped (uses built-in auth)`);
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
process.stdout.write(`Testing ${key.id} (${key.provider})... `);
|
|
269
|
-
try {
|
|
270
|
-
const result = await testProvider(key.key, key.provider, key.model);
|
|
271
|
-
if (result.success) {
|
|
272
|
-
console.log('✅ OK');
|
|
273
|
-
key.active = true;
|
|
274
|
-
} else {
|
|
275
|
-
console.log(`❌ ${result.message}`);
|
|
276
|
-
if (result.message.includes('Invalid')) key.active = false;
|
|
277
|
-
}
|
|
278
|
-
} catch (err) {
|
|
279
|
-
console.log(`❌ ${err.message}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
saveApiConfig(config);
|
|
283
|
-
console.log('\n');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async function setDefaultProvider(config) {
|
|
287
|
-
const rl = createInterface();
|
|
288
|
-
try {
|
|
289
|
-
console.log('\nAvailable providers:');
|
|
290
|
-
const providers = [...new Set(config.keys.filter(k => k.active).map(k => k.provider))];
|
|
291
|
-
providers.forEach((p, i) => console.log(` ${i + 1}. ${p}`));
|
|
292
|
-
|
|
293
|
-
const answer = await new Promise(resolve => {
|
|
294
|
-
rl.question('Select default provider (name or number): ', resolve);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
let selected = answer.trim();
|
|
298
|
-
const num = parseInt(selected) - 1;
|
|
299
|
-
if (!isNaN(num) && providers[num]) selected = providers[num];
|
|
300
|
-
|
|
301
|
-
if (!providers.includes(selected)) {
|
|
302
|
-
console.log('❌ Invalid provider');
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
config.default_provider = selected;
|
|
307
|
-
saveApiConfig(config);
|
|
308
|
-
console.log(`✅ Default provider set to: ${selected}`);
|
|
309
|
-
} finally {
|
|
310
|
-
rl.close();
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function main() {
|
|
315
|
-
const config = loadApiConfig();
|
|
316
|
-
printMenu();
|
|
317
|
-
const rl = createInterface();
|
|
318
|
-
|
|
319
|
-
const ask = async () => {
|
|
320
|
-
rl.question('Select option (1-6): ', async (answer) => {
|
|
321
|
-
switch (answer.trim()) {
|
|
322
|
-
case '1': viewConfiguredAPIs(config); printMenu(); ask(); break;
|
|
323
|
-
case '2': await addNewApiKey(config); printMenu(); ask(); break;
|
|
324
|
-
case '3': await removeApiKey(config); printMenu(); ask(); break;
|
|
325
|
-
case '4': await testAllApiKeys(config); printMenu(); ask(); break;
|
|
326
|
-
case '5': await setDefaultProvider(config); printMenu(); ask(); break;
|
|
327
|
-
case '6': console.log('👋 Goodbye!'); rl.close(); break;
|
|
328
|
-
default: console.log('Invalid option. Please enter 1-6.'); printMenu(); ask();
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
ask();
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (require.main === module) {
|
|
337
|
-
main();
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
module.exports = { loadApiConfig, saveApiConfig, viewConfiguredAPIs };
|