deepfish-ai 1.0.8

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/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "deepfish-ai",
3
+ "version": "1.0.8",
4
+ "description": "An AI command-line tool that converts natural language instructions into operating system commands and file operations, supporting Ollama, DeepSeek, and other models compatible with the OpenAI API specification.",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "ai": "src/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "ai",
14
+ "deepseek",
15
+ "cli",
16
+ "command-line",
17
+ "cmd",
18
+ "openai",
19
+ "ollama",
20
+ "deepfish"
21
+ ],
22
+ "author": "Roman",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/qq306863030/deepfish.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/qq306863030/deepfish/issues"
30
+ },
31
+ "homepage": "https://github.com/qq306863030/deepfish#readme",
32
+ "dependencies": {
33
+ "axios": "^1.13.5",
34
+ "chalk": "^4.1.0",
35
+ "commander": "^11.0.0",
36
+ "dayjs": "^1.11.19",
37
+ "fs-extra": "^11.3.3",
38
+ "iconv-lite": "^0.7.2",
39
+ "inquirer": "^9.0.0",
40
+ "lodash": "^4.17.23",
41
+ "openai": "^6.18.0",
42
+ "shelljs": "^0.10.0"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^10.0.1",
46
+ "@eslint/json": "^1.0.1",
47
+ "eslint": "^10.0.3",
48
+ "globals": "^17.4.0"
49
+ },
50
+ "files": [
51
+ "src",
52
+ "README.md",
53
+ "README_CN.md",
54
+ "LICENSE"
55
+ ]
56
+ }
package/src/cli.js ADDED
@@ -0,0 +1,650 @@
1
+ #!/usr/bin/env node
2
+ const { program } = require("commander");
3
+ const inquirer = require("inquirer");
4
+ const fs = require("fs");
5
+ const AICLI = require("./core/AICLI");
6
+ const { logSuccess, logError, addExtensionToConfig, removeExtensionFromConfig, viewExtensionsFromConfig, getConfigPath } = require("./core/utils");
7
+ const userConfigPath = getConfigPath()
8
+ const getDefaultConfig = require("./core/DefaultConfig");
9
+
10
+ async function handleMissingConfig() {
11
+ logError("Configuration file not initialized");
12
+
13
+ // Create new configuration file with empty ai array
14
+ console.log("Creating new configuration file:", userConfigPath);
15
+ const configContent = `module.exports = ${JSON.stringify(getDefaultConfig(), null, 2)}`;
16
+ fs.writeFileSync(userConfigPath, configContent);
17
+ console.log("Configuration file created with empty AI configurations.");
18
+ }
19
+
20
+ async function runSetupCommand(isAdd = false) {
21
+ console.log("AI Service Configuration");
22
+ console.log("=".repeat(50));
23
+
24
+ let currentConfig = {};
25
+ if (fs.existsSync(userConfigPath)) {
26
+ try {
27
+ currentConfig = require(userConfigPath);
28
+ } catch (error) {
29
+ logError(
30
+ "Warning: Could not load existing configuration:",
31
+ error.message,
32
+ );
33
+ }
34
+ } else {
35
+ currentConfig = getDefaultConfig();
36
+ }
37
+
38
+ const questions = [
39
+ {
40
+ type: "input",
41
+ name: "name",
42
+ message: "Enter AI configuration name:",
43
+ when: () => isAdd,
44
+ validate: (value) => {
45
+ if (value.trim() === "") {
46
+ return "Configuration name cannot be empty";
47
+ }
48
+ // Check if configuration with the same name already exists
49
+ if (fs.existsSync(userConfigPath)) {
50
+ try {
51
+ const existingConfig = require(userConfigPath);
52
+ if (existingConfig.ai && Array.isArray(existingConfig.ai)) {
53
+ const existingIndex = existingConfig.ai.findIndex(config => config.name === value.trim());
54
+ if (existingIndex !== -1) {
55
+ return "Configuration with this name already exists. Please enter a different name.";
56
+ }
57
+ }
58
+ } catch (error) {
59
+ // Ignore error if config file cannot be loaded
60
+ }
61
+ }
62
+ return true;
63
+ },
64
+ },
65
+ {
66
+ type: "list",
67
+ name: "type",
68
+ message: "Select AI service type:",
69
+ choices: [
70
+ { name: "Ollama (Local)", value: "ollama" },
71
+ { name: "DeepSeek (Online)", value: "deepseek" },
72
+ { name: "OpenAI (Online)", value: "openai" },
73
+ ],
74
+ default: currentConfig.ai?.[0]?.type || "ollama",
75
+ },
76
+ {
77
+ type: "input",
78
+ name: "otherType",
79
+ message: "Enter custom AI service type:",
80
+ when: (answers) => answers.type === "other",
81
+ default: currentConfig.ai?.[0]?.type || "custom",
82
+ },
83
+ {
84
+ type: "input",
85
+ name: "baseUrl",
86
+ message: "Enter API base URL:",
87
+ when: (answers) => answers.type !== "other",
88
+ default: (answers) => {
89
+ switch (answers.type) {
90
+ case "ollama":
91
+ return "http://localhost:11434/v1";
92
+ case "deepseek":
93
+ return "https://api.deepseek.com";
94
+ case "openai":
95
+ return "https://api.openai.com/v1";
96
+ default:
97
+ return currentConfig.ai?.[0]?.baseUrl || "";
98
+ }
99
+ },
100
+ },
101
+ {
102
+ type: "input",
103
+ name: "otherBaseUrl",
104
+ message: "Enter API base URL:",
105
+ when: (answers) => answers.type === "other",
106
+ default: currentConfig.ai?.[0]?.baseUrl || "",
107
+ },
108
+ {
109
+ type: "list",
110
+ name: "model",
111
+ message: "Select DeepSeek model:",
112
+ when: (answers) => answers.type === "deepseek",
113
+ choices: [
114
+ { name: "deepseek-chat", value: "deepseek-chat" },
115
+ { name: "deepseek-reasoner", value: "deepseek-reasoner" },
116
+ { name: "Other", value: "other" },
117
+ ],
118
+ default: "deepseek-reasoner",
119
+ },
120
+ {
121
+ type: "input",
122
+ name: "model",
123
+ message: "Enter model name:",
124
+ when: (answers) => answers.type !== "other" && answers.type !== "deepseek",
125
+ default: (answers) => {
126
+ switch (answers.type) {
127
+ case "ollama":
128
+ return "deepseek-v3.2:cloud";
129
+ case "openai":
130
+ return "gpt-4";
131
+ default:
132
+ return currentConfig.ai?.[0]?.model || "";
133
+ }
134
+ },
135
+ },
136
+ {
137
+ type: "input",
138
+ name: "deepseekOtherModel",
139
+ message: "Enter DeepSeek model name:",
140
+ when: (answers) => answers.type === "deepseek" && answers.model === "other",
141
+ default: currentConfig.ai?.[0]?.model || "",
142
+ },
143
+ {
144
+ type: "input",
145
+ name: "otherModel",
146
+ message: "Enter model name:",
147
+ when: (answers) => answers.type === "other",
148
+ default: currentConfig.ai?.[0]?.model || "",
149
+ },
150
+ {
151
+ type: "input",
152
+ name: "apiKey",
153
+ message: "Enter API key:",
154
+ when: (answers) =>
155
+ answers.type === "deepseek" || answers.type === "openai",
156
+ default: "",
157
+ },
158
+ {
159
+ type: "input",
160
+ name: "otherApiKey",
161
+ message: "Enter API key:",
162
+ when: (answers) => answers.type === "other",
163
+ default: currentConfig.ai?.[0]?.apiKey || "",
164
+ },
165
+ {
166
+ type: "number",
167
+ name: "temperature",
168
+ message: "Enter temperature (0-2):",
169
+ default: 0.7,
170
+ validate: (value) =>
171
+ (value >= 0 && value <= 2) || "Temperature must be between 0 and 2",
172
+ },
173
+ {
174
+ type: "number",
175
+ name: "maxTokens",
176
+ message: "Enter max tokens:",
177
+ default: 8192,
178
+ validate: (value) => value > 0 || "Max tokens must be greater than 0",
179
+ },
180
+ {
181
+ type: "confirm",
182
+ name: "stream",
183
+ message: "Enable streaming output:",
184
+ default: true,
185
+ },
186
+ ];
187
+
188
+ const answers = await inquirer.default.prompt(questions);
189
+
190
+ // Check if name is empty when adding new configuration
191
+ if (isAdd && (!answers.name || answers.name.trim() === "")) {
192
+ console.log("Configuration name cannot be empty");
193
+ process.exit(1);
194
+ }
195
+
196
+ // Check if configuration with the same name already exists
197
+ if (isAdd && fs.existsSync(userConfigPath)) {
198
+ try {
199
+ const existingConfig = require(userConfigPath);
200
+ if (existingConfig.ai && Array.isArray(existingConfig.ai)) {
201
+ const existingIndex = existingConfig.ai.findIndex(config => config.name === answers.name.trim());
202
+ if (existingIndex !== -1) {
203
+ console.log(`Configuration with name "${answers.name}" already exists. Please enter a different name.`);
204
+ await runSetupCommand(isAdd);
205
+ return;
206
+ }
207
+ }
208
+ } catch (error) {
209
+ // Ignore error if config file cannot be loaded
210
+ }
211
+ }
212
+
213
+ const aiConfig = {
214
+ name: answers.name || "default",
215
+ type: answers.type === "other" ? answers.otherType : answers.type,
216
+ baseUrl: answers.type === "other" ? answers.otherBaseUrl : answers.baseUrl,
217
+ model: answers.type === "other" ? answers.otherModel : (answers.type === "deepseek" && answers.model === "other" ? answers.deepseekOtherModel : answers.model),
218
+ apiKey: answers.type === "ollama" ? 'ollama' : answers.apiKey,
219
+ temperature: answers.temperature,
220
+ maxTokens: answers.maxTokens,
221
+ stream: answers.stream,
222
+ };
223
+
224
+ if (isAdd) {
225
+ // Add new AI configuration
226
+ const existingConfig = fs.existsSync(userConfigPath) ? require(userConfigPath) : getDefaultConfig();
227
+
228
+ // Check if configuration with the same name already exists
229
+ const existingIndex = existingConfig.ai.findIndex(config => config.name === aiConfig.name);
230
+ if (existingIndex !== -1) {
231
+ logError(`Configuration with name "${aiConfig.name}" already exists.`);
232
+ return;
233
+ }
234
+
235
+ existingConfig.ai.push(aiConfig);
236
+ const configContent = `module.exports = ${JSON.stringify(existingConfig, null, 2)}`;
237
+ fs.writeFileSync(userConfigPath, configContent);
238
+
239
+ logSuccess(`AI configuration "${aiConfig.name}" added successfully!`);
240
+ } else {
241
+ // Update default configuration
242
+ const existingConfig = fs.existsSync(userConfigPath) ? require(userConfigPath) : getDefaultConfig();
243
+
244
+ // Add the new configuration to the array
245
+ existingConfig.ai.push(aiConfig);
246
+ existingConfig.currentAi = aiConfig.name;
247
+
248
+ const configContent = `module.exports = ${JSON.stringify(existingConfig, null, 2)}`;
249
+ fs.writeFileSync(userConfigPath, configContent);
250
+
251
+ logSuccess("\nConfiguration saved successfully to:", userConfigPath);
252
+ }
253
+
254
+ console.log("=".repeat(50));
255
+ console.log("AI configuration details:");
256
+ console.log(`Name: ${aiConfig.name}`);
257
+ console.log(`Type: ${aiConfig.type}`);
258
+ console.log(`API Base URL: ${aiConfig.baseUrl}`);
259
+ console.log(`Model: ${aiConfig.model}`);
260
+ if (aiConfig.apiKey) {
261
+ console.log(`API Key: ${aiConfig.apiKey.substring(0, 8)}...`);
262
+ }
263
+ console.log(`Temperature: ${aiConfig.temperature}`);
264
+ console.log(`Max Tokens: ${aiConfig.maxTokens}`);
265
+ console.log(`Streaming Output: ${aiConfig.stream ? 'Enabled' : 'Disabled'}`);
266
+ console.log("=".repeat(50));
267
+ }
268
+
269
+ program
270
+ .version("1.0.0")
271
+ .description(
272
+ "A command-line tool that uses AI to execute commands and manipulate files",
273
+ )
274
+ .option("-p, --prompt <prompt>", "The prompt to send to the AI")
275
+ .option("-i, --interactive", "Start interactive mode")
276
+ .arguments("[prompt...]")
277
+ .action((prompt) => {
278
+ program.prompt = Array.isArray(prompt) ? prompt.join(" ") : prompt || "";
279
+ });
280
+
281
+ const extCommand = program
282
+ .command("ext")
283
+ .description("Extension management commands");
284
+
285
+ extCommand
286
+ .command("add <filename>")
287
+ .description("Add extension tool to the configuration")
288
+ .action((filename) => {
289
+ addExtensionToConfig(filename);
290
+ });
291
+
292
+ extCommand
293
+ .command("del <filename>")
294
+ .description("Remove extension tool from the configuration")
295
+ .action((filename) => {
296
+ removeExtensionFromConfig(filename);
297
+ });
298
+
299
+ extCommand
300
+ .command("ls")
301
+ .description("List all extension tools in the configuration")
302
+ .action(() => {
303
+ viewExtensionsFromConfig();
304
+ });
305
+
306
+ const configCommand = program
307
+ .command("config")
308
+ .description("Configure AI service settings");
309
+
310
+
311
+ configCommand
312
+ .command("edit")
313
+ .description("Edit configuration file with notepad")
314
+ .action(async () => {
315
+ if (fs.existsSync(userConfigPath)) {
316
+ // File exists, open for editing
317
+ const { exec } = require("child_process");
318
+ exec(`notepad "${userConfigPath}"`, (error) => {
319
+ if (error) {
320
+ logError("Error opening configuration file:", error.message);
321
+ }
322
+ });
323
+ } else {
324
+ // File doesn't exist, prompt to create
325
+ logError("Configuration file not initialized");
326
+
327
+ const { createConfig } = await inquirer.default.prompt([
328
+ {
329
+ type: "confirm",
330
+ name: "createConfig",
331
+ message: "Would you like to create a configuration file now?",
332
+ default: true,
333
+ },
334
+ ]);
335
+
336
+ if (createConfig) {
337
+ // Create new configuration file with empty ai array
338
+ console.log("Creating new configuration file:", userConfigPath);
339
+ const newConfig = getDefaultConfig();
340
+ const configContent = `module.exports = ${JSON.stringify(newConfig, null, 2)}`;
341
+ fs.writeFileSync(userConfigPath, configContent);
342
+ console.log("Configuration file created with empty AI configurations.");
343
+ }
344
+ // Don't open the file after creating it
345
+ }
346
+ });
347
+
348
+ configCommand
349
+ .command("clear")
350
+ .description("Delete the configuration file")
351
+ .action(async () => {
352
+ if (!fs.existsSync(userConfigPath)) {
353
+ console.log("Configuration file does not exist");
354
+ return;
355
+ }
356
+
357
+ const { confirm } = await inquirer.default.prompt([
358
+ {
359
+ type: "confirm",
360
+ name: "confirm",
361
+ message: "Are you sure you want to delete the configuration file?",
362
+ default: false,
363
+ },
364
+ ]);
365
+
366
+ if (confirm) {
367
+ fs.unlinkSync(userConfigPath);
368
+ logSuccess("Configuration file deleted successfully:", userConfigPath);
369
+ } else {
370
+ console.log("Operation cancelled");
371
+ }
372
+ });
373
+
374
+ configCommand
375
+ .command("reset")
376
+ .description("Reset configuration file")
377
+ .action(async () => {
378
+ if (fs.existsSync(userConfigPath)) {
379
+ const { confirm } = await inquirer.default.prompt([
380
+ {
381
+ type: "confirm",
382
+ name: "confirm",
383
+ message: "Are you sure you want to reset the configuration file?",
384
+ default: false,
385
+ },
386
+ ]);
387
+
388
+ if (confirm) {
389
+ console.log("Resetting configuration file:", userConfigPath);
390
+ // Create new default configuration and overwrite existing file
391
+ const configContent = `module.exports = ${JSON.stringify(getDefaultConfig(), null, 2)}`;
392
+ fs.writeFileSync(userConfigPath, configContent);
393
+ console.log("Configuration file has been reset to default settings.");
394
+ } else {
395
+ console.log("Operation cancelled");
396
+ process.exit(0);
397
+ }
398
+ } else {
399
+ // Create new configuration file with empty ai array
400
+ const newConfig = getDefaultConfig();
401
+ const configContent = `module.exports = ${JSON.stringify(newConfig, null, 2)}`;
402
+ fs.writeFileSync(userConfigPath, configContent);
403
+ console.log("Configuration file created with empty AI configurations.");
404
+ }
405
+ });
406
+
407
+ configCommand
408
+ .command("add")
409
+ .description("Add a new AI configuration")
410
+ .action(async () => {
411
+ await runSetupCommand(true);
412
+ });
413
+
414
+ configCommand
415
+ .command("ls")
416
+ .description("List all AI configurations")
417
+ .action(async () => {
418
+ if (!fs.existsSync(userConfigPath)) {
419
+ await handleMissingConfig();
420
+ return;
421
+ }
422
+
423
+ try {
424
+ const currentConfig = require(userConfigPath);
425
+ console.log("AI Configurations");
426
+ console.log("=".repeat(50));
427
+
428
+ if (currentConfig.ai && Array.isArray(currentConfig.ai)) {
429
+ if (currentConfig.ai.length === 0) {
430
+ logError("No AI configurations found.");
431
+ } else {
432
+ currentConfig.ai.forEach((config, index) => {
433
+ const isCurrent = currentConfig.currentAi === config.name;
434
+ console.log(`${config.name} ${isCurrent ? '(current)' : ''}`);
435
+ });
436
+ }
437
+ } else {
438
+ logError("No AI configurations found.");
439
+ }
440
+
441
+ console.log("=".repeat(50));
442
+ } catch (error) {
443
+ logError("Error loading configuration:", error.message);
444
+ }
445
+ });
446
+
447
+ configCommand
448
+ .command("use <name>")
449
+ .description("Set the specified AI configuration as current")
450
+ .action(async (name) => {
451
+ if (!fs.existsSync(userConfigPath)) {
452
+ await handleMissingConfig();
453
+ return;
454
+ }
455
+
456
+ try {
457
+ const currentConfig = require(userConfigPath);
458
+
459
+ // Check if configuration with the specified name exists
460
+ const aiConfig = currentConfig.ai.find(config => config.name === name);
461
+ if (!aiConfig) {
462
+ logError(`Configuration with name "${name}" not found.`);
463
+ return;
464
+ }
465
+
466
+ // Update current AI configuration
467
+ currentConfig.currentAi = name;
468
+ const configContent = `module.exports = ${JSON.stringify(currentConfig, null, 2)}`;
469
+ fs.writeFileSync(userConfigPath, configContent);
470
+
471
+ logSuccess(`Current AI configuration set to "${name}" successfully.`);
472
+ } catch (error) {
473
+ logError("Error loading configuration:", error.message);
474
+ }
475
+ });
476
+
477
+ configCommand
478
+ .command("del <name>")
479
+ .description("Delete the specified AI configuration")
480
+ .action(async (name) => {
481
+ if (!fs.existsSync(userConfigPath)) {
482
+ await handleMissingConfig();
483
+ return;
484
+ }
485
+
486
+ try {
487
+ const currentConfig = require(userConfigPath);
488
+
489
+ // Check if configuration with the specified name exists
490
+ const existingIndex = currentConfig.ai.findIndex(config => config.name === name);
491
+ if (existingIndex === -1) {
492
+ console.log(`Configuration with name "${name}" not found.`);
493
+ return;
494
+ }
495
+
496
+ // Check if it's the current configuration
497
+ if (currentConfig.currentAi === name) {
498
+ console.log(`Cannot delete current configuration "${name}".`);
499
+ return;
500
+ }
501
+
502
+ // Remove the configuration
503
+ currentConfig.ai.splice(existingIndex, 1);
504
+ const configContent = `module.exports = ${JSON.stringify(currentConfig, null, 2)}`;
505
+ fs.writeFileSync(userConfigPath, configContent);
506
+
507
+ logSuccess(`AI configuration "${name}" deleted successfully!`);
508
+ } catch (error) {
509
+ logError("Error loading configuration:", error.message);
510
+ }
511
+ });
512
+
513
+ configCommand
514
+ .command("view [name]")
515
+ .description("View details of the specified AI configuration")
516
+ .action(async (name) => {
517
+ if (!fs.existsSync(userConfigPath)) {
518
+ logError("Configuration file not initialized");
519
+
520
+ const { createConfig } = await inquirer.default.prompt([
521
+ {
522
+ type: "confirm",
523
+ name: "createConfig",
524
+ message: "Would you like to create a configuration file now?",
525
+ default: true,
526
+ },
527
+ ]);
528
+
529
+ if (createConfig) {
530
+ // Create new configuration file with empty ai array
531
+ console.log("Creating new configuration file:", userConfigPath);
532
+ const newConfig = getDefaultConfig();
533
+ const configContent = `module.exports = ${JSON.stringify(newConfig, null, 2)}`;
534
+ fs.writeFileSync(userConfigPath, configContent);
535
+ console.log("Configuration file created with empty AI configurations.");
536
+ }
537
+ return;
538
+ }
539
+
540
+ try {
541
+ const currentConfig = require(userConfigPath);
542
+
543
+ let aiConfig;
544
+ if (name) {
545
+ // View specified configuration
546
+ aiConfig = currentConfig.ai.find(config => config.name === name);
547
+ if (!aiConfig) {
548
+ logError(`Configuration with name "${name}" not found.`);
549
+ return;
550
+ }
551
+ } else {
552
+ // 检查ai列表是否为空
553
+ if (!currentConfig.ai || !Array.isArray(currentConfig.ai) || currentConfig.ai.length === 0) {
554
+ logError("No AI configurations found.");
555
+ logError("Please use 'ai config add' to add a new AI configuration.");
556
+ return;
557
+ }
558
+ // View current configuration
559
+ const currentName = currentConfig.currentAi;
560
+ if (!currentName || currentName.trim() === "") {
561
+ logError("No current AI configuration set.");
562
+ logError("Please use 'ai config use <name>' to set a current configuration.");
563
+ return;
564
+ }
565
+ // Check if ai array exists and is not empty
566
+ if (!currentConfig.ai || !Array.isArray(currentConfig.ai) || currentConfig.ai.length === 0) {
567
+ logError("No AI configurations found.");
568
+ logError("Please use 'ai config add' to add a new AI configuration.");
569
+ return;
570
+ }
571
+ aiConfig = currentConfig.ai.find(config => config.name === currentName);
572
+ if (!aiConfig) {
573
+ logError(`Current AI configuration "${currentName}" not found.`);
574
+ return;
575
+ }
576
+ }
577
+
578
+ console.log("AI Configuration Details");
579
+ console.log("=".repeat(50));
580
+ console.log(`Name: ${aiConfig.name}`);
581
+ console.log(`Type: ${aiConfig.type}`);
582
+ console.log(`API Base URL: ${aiConfig.baseUrl}`);
583
+ console.log(`Model: ${aiConfig.model}`);
584
+ if (aiConfig.apiKey) {
585
+ console.log(`API Key: ${aiConfig.apiKey.substring(0, 8)}...`);
586
+ }
587
+ console.log(`Temperature: ${aiConfig.temperature}`);
588
+ console.log(`Max Tokens: ${aiConfig.maxTokens}`);
589
+ console.log(`Streaming Output: ${aiConfig.stream ? 'Enabled' : 'Disabled'}`);
590
+ console.log(`Is Current: ${currentConfig.currentAi === aiConfig.name ? 'Yes' : 'No'}`);
591
+ console.log(`File Path: ${userConfigPath}`);
592
+ console.log("=".repeat(50));
593
+ } catch (error) {
594
+ logError("Error loading configuration:", error.message);
595
+ }
596
+ });
597
+
598
+
599
+
600
+ async function main() {
601
+ try {
602
+ if (program.args && (program.args[0] === "config" || program.args[0] === "ext")) {
603
+ return;
604
+ }
605
+ const options = program.opts();
606
+ let prompt;
607
+
608
+ if (program.prompt) {
609
+ prompt = program.prompt;
610
+ } else if (options.prompt) {
611
+ prompt = options.prompt;
612
+ } else if (!program.args || program.args.length === 0) {
613
+ options.interactive = true;
614
+ } else {
615
+ prompt = program.args.join(" ");
616
+ }
617
+ if (!fs.existsSync(userConfigPath)) {
618
+ await handleMissingConfig();
619
+ return;
620
+ }
621
+ const config = require(userConfigPath);
622
+ // 判断当前列表是否为空
623
+ if (!config.ai || !Array.isArray(config.ai) || config.ai.length === 0) {
624
+ logError("No AI configurations found.");
625
+ logError("Please use 'ai config add' to add a new AI configuration.");
626
+ return;
627
+ }
628
+ // 判断当前是否有设置当前配置
629
+ if (!config.currentAi || config.currentAi.trim() === "") {
630
+ logError("No current AI configuration set.");
631
+ logError("Please use 'ai config use <name>' to set a current configuration.");
632
+ return;
633
+ }
634
+ const cli = new AICLI(config);
635
+ if (options.interactive) {
636
+ cli.startInteractive();
637
+ return;
638
+ }
639
+
640
+ if (prompt) {
641
+ cli.run(prompt);
642
+ }
643
+ } catch (error) {
644
+ logError(error.stack);
645
+ }
646
+ }
647
+
648
+ program.parse(process.argv);
649
+
650
+ main();