cmdvault 1.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/README.md +433 -0
- package/bin/cm.js +3 -0
- package/index.js +412 -0
- package/lib/ai-config.js +108 -0
- package/lib/ai-providers.js +314 -0
- package/lib/editor.js +52 -0
- package/lib/executor.js +37 -0
- package/lib/storage.js +73 -0
- package/package.json +36 -0
package/index.js
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
const { program } = require('commander');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const Table = require('cli-table3');
|
|
4
|
+
const storage = require('./lib/storage');
|
|
5
|
+
const { executeCommand, printExecutionMessage } = require('./lib/executor');
|
|
6
|
+
const { openEditor } = require('./lib/editor');
|
|
7
|
+
const aiConfig = require('./lib/ai-config');
|
|
8
|
+
const { getSupportedProviders, generateCommand } = require('./lib/ai-providers');
|
|
9
|
+
const readline = require('readline');
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('cm')
|
|
13
|
+
.description('CmdVault - A smart terminal assistant')
|
|
14
|
+
.version('1.0.0');
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command('s <key> <command...>')
|
|
18
|
+
.description('Save a command with a key')
|
|
19
|
+
.allowUnknownOption()
|
|
20
|
+
.action(async (key, commandParts) => {
|
|
21
|
+
if (key.length < 2) {
|
|
22
|
+
console.error(chalk.red('✗ Key must be at least 2 characters long.'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const command = commandParts.join(' ');
|
|
27
|
+
|
|
28
|
+
if (storage.commandExists(key)) {
|
|
29
|
+
const answer = await askConfirmation(
|
|
30
|
+
chalk.yellow(`Key "${key}" already exists. Overwrite? (y/n): `)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
if (!answer) {
|
|
34
|
+
console.log(chalk.red('Operation cancelled.'));
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await executeCommand(command);
|
|
41
|
+
storage.setCommand(key, command);
|
|
42
|
+
console.log(chalk.green(`\n✓ Command saved under key "${key}"`));
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(chalk.red(`\n✗ Command failed: ${error.message}`));
|
|
45
|
+
|
|
46
|
+
const answer = await askConfirmation(
|
|
47
|
+
chalk.yellow(`Save command anyway? (y/n): `)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
if (answer) {
|
|
51
|
+
storage.setCommand(key, command);
|
|
52
|
+
console.log(chalk.green(`✓ Command saved under key "${key}"`));
|
|
53
|
+
}
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command('c <key>')
|
|
60
|
+
.description('Copy/expand a stored command to terminal (does not execute)')
|
|
61
|
+
.action((key) => {
|
|
62
|
+
if (!storage.commandExists(key)) {
|
|
63
|
+
console.error(chalk.red(`✗ Key "${key}" not found.`));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const command = storage.getCommand(key);
|
|
68
|
+
console.log(command);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
program
|
|
72
|
+
.command('list')
|
|
73
|
+
.description('List all saved commands')
|
|
74
|
+
.action(() => {
|
|
75
|
+
const commands = storage.getAllCommands();
|
|
76
|
+
const keys = Object.keys(commands);
|
|
77
|
+
|
|
78
|
+
if (keys.length === 0) {
|
|
79
|
+
console.log(chalk.yellow('No commands saved yet.'));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const table = new Table({
|
|
84
|
+
head: [chalk.cyan('Key'), chalk.cyan('Command')],
|
|
85
|
+
colWidths: [15, 65],
|
|
86
|
+
wordWrap: true
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
keys.sort().forEach(key => {
|
|
90
|
+
table.push([chalk.green(key), commands[key]]);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
console.log(table.toString());
|
|
94
|
+
console.log(chalk.gray(`\nTotal: ${keys.length} command(s)`));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
program
|
|
98
|
+
.command('d <key>')
|
|
99
|
+
.description('Delete a saved command')
|
|
100
|
+
.action(async (key) => {
|
|
101
|
+
if (!storage.commandExists(key)) {
|
|
102
|
+
console.error(chalk.red(`✗ Key "${key}" not found.`));
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const command = storage.getCommand(key);
|
|
107
|
+
console.log(chalk.yellow(`Command: ${command}`));
|
|
108
|
+
|
|
109
|
+
const answer = await askConfirmation(
|
|
110
|
+
chalk.yellow(`Delete key "${key}"? (y/n): `)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (answer) {
|
|
114
|
+
storage.deleteCommand(key);
|
|
115
|
+
console.log(chalk.green(`✓ Key "${key}" deleted.`));
|
|
116
|
+
} else {
|
|
117
|
+
console.log(chalk.red('Operation cancelled.'));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
program
|
|
122
|
+
.command('config')
|
|
123
|
+
.description('Configure AI providers for command generation')
|
|
124
|
+
.action(async () => {
|
|
125
|
+
console.log(chalk.cyan.bold('\n🤖 CmdVault AI Configuration\n'));
|
|
126
|
+
|
|
127
|
+
const providers = aiConfig.getAllProviders();
|
|
128
|
+
const defaultProvider = aiConfig.getDefaultProvider();
|
|
129
|
+
|
|
130
|
+
if (providers.length > 0) {
|
|
131
|
+
console.log(chalk.green('Current providers:'));
|
|
132
|
+
providers.forEach(p => {
|
|
133
|
+
const isDefault = defaultProvider && p.name === defaultProvider.name;
|
|
134
|
+
const marker = isDefault ? chalk.yellow(' (default)') : '';
|
|
135
|
+
console.log(` • ${chalk.cyan(p.name)}${marker}`);
|
|
136
|
+
});
|
|
137
|
+
console.log('');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const rl = readline.createInterface({
|
|
141
|
+
input: process.stdin,
|
|
142
|
+
output: process.stdout
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const supportedProviders = getSupportedProviders();
|
|
146
|
+
|
|
147
|
+
console.log(chalk.cyan('Available AI Providers:'));
|
|
148
|
+
const providerKeys = Object.keys(supportedProviders);
|
|
149
|
+
providerKeys.forEach((key, index) => {
|
|
150
|
+
console.log(` ${index + 1}. ${supportedProviders[key].name}`);
|
|
151
|
+
});
|
|
152
|
+
console.log(` ${providerKeys.length + 1}. Remove a provider`);
|
|
153
|
+
console.log(` ${providerKeys.length + 2}. Set default provider`);
|
|
154
|
+
console.log(` ${providerKeys.length + 3}. Exit\n`);
|
|
155
|
+
|
|
156
|
+
rl.question(chalk.yellow('Select an option: '), async (choice) => {
|
|
157
|
+
const choiceNum = parseInt(choice);
|
|
158
|
+
|
|
159
|
+
if (choiceNum === providerKeys.length + 3 || isNaN(choiceNum)) {
|
|
160
|
+
rl.close();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (choiceNum === providerKeys.length + 1) {
|
|
165
|
+
if (providers.length === 0) {
|
|
166
|
+
console.log(chalk.red('No providers configured.'));
|
|
167
|
+
rl.close();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(chalk.cyan('\nConfigured providers:'));
|
|
172
|
+
providers.forEach((p, i) => {
|
|
173
|
+
console.log(` ${i + 1}. ${p.name}`);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
rl.question(chalk.yellow('\nSelect provider to remove: '), (removeChoice) => {
|
|
177
|
+
const removeNum = parseInt(removeChoice);
|
|
178
|
+
if (removeNum > 0 && removeNum <= providers.length) {
|
|
179
|
+
const providerToRemove = providers[removeNum - 1];
|
|
180
|
+
aiConfig.removeProvider(providerToRemove.name);
|
|
181
|
+
console.log(chalk.green(`✓ Provider "${providerToRemove.name}" removed.`));
|
|
182
|
+
} else {
|
|
183
|
+
console.log(chalk.red('Invalid selection.'));
|
|
184
|
+
}
|
|
185
|
+
rl.close();
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (choiceNum === providerKeys.length + 2) {
|
|
191
|
+
if (providers.length === 0) {
|
|
192
|
+
console.log(chalk.red('No providers configured.'));
|
|
193
|
+
rl.close();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log(chalk.cyan('\nConfigured providers:'));
|
|
198
|
+
providers.forEach((p, i) => {
|
|
199
|
+
console.log(` ${i + 1}. ${p.name}`);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
rl.question(chalk.yellow('\nSelect default provider: '), (defaultChoice) => {
|
|
203
|
+
const defaultNum = parseInt(defaultChoice);
|
|
204
|
+
if (defaultNum > 0 && defaultNum <= providers.length) {
|
|
205
|
+
const providerToSetDefault = providers[defaultNum - 1];
|
|
206
|
+
aiConfig.setDefaultProvider(providerToSetDefault.name);
|
|
207
|
+
console.log(chalk.green(`✓ Default provider set to "${providerToSetDefault.name}".`));
|
|
208
|
+
} else {
|
|
209
|
+
console.log(chalk.red('Invalid selection.'));
|
|
210
|
+
}
|
|
211
|
+
rl.close();
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (choiceNum > 0 && choiceNum <= providerKeys.length) {
|
|
217
|
+
const selectedKey = providerKeys[choiceNum - 1];
|
|
218
|
+
const selectedProvider = supportedProviders[selectedKey];
|
|
219
|
+
|
|
220
|
+
console.log(chalk.cyan(`\nConfiguring: ${selectedProvider.name}`));
|
|
221
|
+
|
|
222
|
+
rl.question(chalk.yellow('Enter API Key: '), (apiKey) => {
|
|
223
|
+
if (!apiKey || apiKey.trim() === '') {
|
|
224
|
+
console.log(chalk.red('API Key cannot be empty.'));
|
|
225
|
+
rl.close();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const isFirstProvider = providers.length === 0;
|
|
230
|
+
|
|
231
|
+
if (isFirstProvider) {
|
|
232
|
+
aiConfig.addProvider(selectedKey, apiKey.trim(), true);
|
|
233
|
+
console.log(chalk.green(`✓ Provider "${selectedKey}" added and set as default.`));
|
|
234
|
+
rl.close();
|
|
235
|
+
} else {
|
|
236
|
+
rl.question(chalk.yellow('Set as default provider? (y/n): '), (setDefault) => {
|
|
237
|
+
const isDefault = setDefault.toLowerCase() === 'y' || setDefault.toLowerCase() === 'yes';
|
|
238
|
+
aiConfig.addProvider(selectedKey, apiKey.trim(), isDefault);
|
|
239
|
+
|
|
240
|
+
if (isDefault) {
|
|
241
|
+
console.log(chalk.green(`✓ Provider "${selectedKey}" added and set as default.`));
|
|
242
|
+
} else {
|
|
243
|
+
console.log(chalk.green(`✓ Provider "${selectedKey}" added.`));
|
|
244
|
+
}
|
|
245
|
+
rl.close();
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
} else {
|
|
250
|
+
console.log(chalk.red('Invalid selection.'));
|
|
251
|
+
rl.close();
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
program
|
|
257
|
+
.command('e <key>')
|
|
258
|
+
.description('Edit a saved command')
|
|
259
|
+
.action(async (key) => {
|
|
260
|
+
if (!storage.commandExists(key)) {
|
|
261
|
+
console.error(chalk.red(`✗ Key "${key}" not found.`));
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const currentCommand = storage.getCommand(key);
|
|
266
|
+
console.log(chalk.cyan(`Current command: ${currentCommand}`));
|
|
267
|
+
console.log(chalk.gray('Opening editor...\n'));
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
const editedCommand = openEditor(currentCommand);
|
|
271
|
+
|
|
272
|
+
if (!editedCommand) {
|
|
273
|
+
console.log(chalk.red('✗ Command cannot be empty. Operation cancelled.'));
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (editedCommand === currentCommand) {
|
|
278
|
+
console.log(chalk.yellow('No changes made.'));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
storage.setCommand(key, editedCommand);
|
|
283
|
+
console.log(chalk.green(`✓ Key "${key}" updated.`));
|
|
284
|
+
console.log(chalk.cyan(`New command: ${editedCommand}`));
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error(chalk.red(`✗ Editor error: ${error.message}`));
|
|
287
|
+
process.exit(1);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
program
|
|
292
|
+
.argument('[args...]')
|
|
293
|
+
.description('Execute a command or retrieve a stored command')
|
|
294
|
+
.action(async (args) => {
|
|
295
|
+
if (args.length === 0) {
|
|
296
|
+
program.help();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const firstArg = args[0];
|
|
301
|
+
|
|
302
|
+
if (storage.commandExists(firstArg) && args.length === 1) {
|
|
303
|
+
const storedCommand = storage.getCommand(firstArg);
|
|
304
|
+
console.log(chalk.cyan(`[CM] Executing stored command: ${storedCommand}\n`));
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
await executeCommand(storedCommand);
|
|
308
|
+
printExecutionMessage(storedCommand);
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error(chalk.red(`\n✗ Command failed: ${error.message}`));
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
const command = args.join(' ');
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
await executeCommand(command);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
console.error(chalk.red(`✗ Command failed: ${error.message}`));
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
function askConfirmation(question) {
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
const rl = readline.createInterface({
|
|
328
|
+
input: process.stdin,
|
|
329
|
+
output: process.stdout
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
rl.question(question, (answer) => {
|
|
333
|
+
rl.close();
|
|
334
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function handleAiGeneration() {
|
|
340
|
+
const args = process.argv.slice(2);
|
|
341
|
+
|
|
342
|
+
const gIndex = args.findIndex(arg => arg === '-g' || arg === '--generate');
|
|
343
|
+
|
|
344
|
+
if (gIndex !== -1 && args[gIndex + 1]) {
|
|
345
|
+
const prompt = args[gIndex + 1];
|
|
346
|
+
|
|
347
|
+
const defaultProvider = aiConfig.getDefaultProvider();
|
|
348
|
+
|
|
349
|
+
if (!defaultProvider) {
|
|
350
|
+
console.error(chalk.red('✗ No AI provider configured.'));
|
|
351
|
+
console.log(chalk.yellow('Run "cm config" to set up an AI provider.'));
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
console.log(chalk.cyan(`🤖 Generating command using ${defaultProvider.name}...`));
|
|
356
|
+
console.log(chalk.gray(`Prompt: "${prompt}"\n`));
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
const generatedCommand = await generateCommand(
|
|
360
|
+
defaultProvider.name,
|
|
361
|
+
defaultProvider.apiKey,
|
|
362
|
+
prompt
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
const cleanCommand = generatedCommand
|
|
366
|
+
.replace(/^```[\w]*\n?/g, '')
|
|
367
|
+
.replace(/\n?```$/g, '')
|
|
368
|
+
.replace(/^["']|["']$/g, '')
|
|
369
|
+
.trim();
|
|
370
|
+
|
|
371
|
+
console.log(chalk.green('✓ Generated command:'));
|
|
372
|
+
console.log(chalk.blackBright.bold(` ${cleanCommand}\n`));
|
|
373
|
+
|
|
374
|
+
const answer = await askConfirmation(
|
|
375
|
+
chalk.yellow('Execute this command? (y/n): ')
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
if (answer) {
|
|
379
|
+
console.log('');
|
|
380
|
+
try {
|
|
381
|
+
await executeCommand(cleanCommand);
|
|
382
|
+
printExecutionMessage(cleanCommand);
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.error(chalk.red(`\n✗ Command failed: ${error.message}`));
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
} else {
|
|
388
|
+
console.log(chalk.gray('Command not executed.'));
|
|
389
|
+
console.log(chalk.gray(`You can copy it: ${cleanCommand}`));
|
|
390
|
+
}
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error(chalk.red(`✗ AI generation failed: ${error.message}`));
|
|
393
|
+
console.log(chalk.yellow('\nTips:'));
|
|
394
|
+
console.log(' • Check your API key is valid');
|
|
395
|
+
console.log(' • Ensure you have internet connection');
|
|
396
|
+
console.log(' • Verify your API provider account has credits');
|
|
397
|
+
process.exit(1);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
process.exit(0);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
(async () => {
|
|
405
|
+
await handleAiGeneration();
|
|
406
|
+
|
|
407
|
+
program.parse(process.argv);
|
|
408
|
+
|
|
409
|
+
if (process.argv.length === 2) {
|
|
410
|
+
program.help();
|
|
411
|
+
}
|
|
412
|
+
})();
|
package/lib/ai-config.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const KI_DIR = path.join(os.homedir(), '.cmvault');
|
|
6
|
+
const AI_CONFIG_FILE = path.join(KI_DIR, 'ai-config.json');
|
|
7
|
+
|
|
8
|
+
function ensureKiDirectory() {
|
|
9
|
+
if (!fs.existsSync(KI_DIR)) {
|
|
10
|
+
fs.mkdirSync(KI_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function ensureAiConfigFile() {
|
|
15
|
+
ensureKiDirectory();
|
|
16
|
+
if (!fs.existsSync(AI_CONFIG_FILE)) {
|
|
17
|
+
const defaultConfig = {
|
|
18
|
+
providers: [],
|
|
19
|
+
defaultProvider: null
|
|
20
|
+
};
|
|
21
|
+
fs.writeFileSync(AI_CONFIG_FILE, JSON.stringify(defaultConfig, null, 2));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadAiConfig() {
|
|
26
|
+
ensureAiConfigFile();
|
|
27
|
+
try {
|
|
28
|
+
const data = fs.readFileSync(AI_CONFIG_FILE, 'utf8');
|
|
29
|
+
return JSON.parse(data);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return { providers: [], defaultProvider: null };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function saveAiConfig(config) {
|
|
36
|
+
ensureAiConfigFile();
|
|
37
|
+
fs.writeFileSync(AI_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function addProvider(name, apiKey, isDefault = false) {
|
|
41
|
+
const config = loadAiConfig();
|
|
42
|
+
|
|
43
|
+
const existingIndex = config.providers.findIndex(p => p.name === name);
|
|
44
|
+
|
|
45
|
+
if (existingIndex !== -1) {
|
|
46
|
+
config.providers[existingIndex].apiKey = apiKey;
|
|
47
|
+
} else {
|
|
48
|
+
config.providers.push({ name, apiKey });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (isDefault || config.providers.length === 1) {
|
|
52
|
+
config.defaultProvider = name;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
saveAiConfig(config);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function removeProvider(name) {
|
|
59
|
+
const config = loadAiConfig();
|
|
60
|
+
config.providers = config.providers.filter(p => p.name !== name);
|
|
61
|
+
|
|
62
|
+
if (config.defaultProvider === name) {
|
|
63
|
+
config.defaultProvider = config.providers.length > 0 ? config.providers[0].name : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
saveAiConfig(config);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function setDefaultProvider(name) {
|
|
70
|
+
const config = loadAiConfig();
|
|
71
|
+
const provider = config.providers.find(p => p.name === name);
|
|
72
|
+
|
|
73
|
+
if (!provider) {
|
|
74
|
+
throw new Error(`Provider "${name}" not found`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
config.defaultProvider = name;
|
|
78
|
+
saveAiConfig(config);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getDefaultProvider() {
|
|
82
|
+
const config = loadAiConfig();
|
|
83
|
+
if (!config.defaultProvider) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return config.providers.find(p => p.name === config.defaultProvider);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getAllProviders() {
|
|
91
|
+
const config = loadAiConfig();
|
|
92
|
+
return config.providers;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getProvider(name) {
|
|
96
|
+
const config = loadAiConfig();
|
|
97
|
+
return config.providers.find(p => p.name === name);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = {
|
|
101
|
+
addProvider,
|
|
102
|
+
removeProvider,
|
|
103
|
+
setDefaultProvider,
|
|
104
|
+
getDefaultProvider,
|
|
105
|
+
getAllProviders,
|
|
106
|
+
getProvider,
|
|
107
|
+
AI_CONFIG_FILE
|
|
108
|
+
};
|