deepfish-ai 1.0.8 → 1.0.12
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 +47 -10
- package/README_CN.md +44 -11
- package/package.json +9 -7
- package/src/cli/ConfigManager.js +231 -0
- package/src/cli/ExtConfigManager.js +90 -0
- package/src/cli/ai-config.js +186 -0
- package/src/cli/ai-ext.js +36 -0
- package/src/cli/configTools.js +90 -0
- package/src/cli/index.js +68 -0
- package/src/core/AICLI.js +4 -9
- package/src/core/GlobalVariable.js +1 -0
- package/src/core/ai-services/AIService.js +2 -0
- package/src/core/ai-services/AiWorker/AIMessageManager.js +2 -2
- package/src/core/ai-services/AiWorker/AiAgent.js +1 -1
- package/src/core/ai-services/AiWorker/AiPrompt.js +5 -4
- package/src/core/ai-services/AiWorker/AiRecorder.js +2 -3
- package/src/core/ai-services/AiWorker/AiTools.js +10 -7
- package/src/core/ai-services/AiWorker/index.js +6 -6
- package/src/core/extension/DefaultExtension.js +108 -45
- package/src/core/extension/ExtensionManager.js +76 -29
- package/src/core/utils/log.js +146 -0
- package/src/core/utils/node-root.js +140 -0
- package/src/core/utils/normal.js +21 -0
- package/src/cli.js +0 -650
- package/src/core/DefaultConfig.js +0 -14
- package/src/core/utils.js +0 -261
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<div align="center" style="display:flex;align-items: center;justify-content: center;">
|
|
2
|
-
<img src="./images/
|
|
3
|
-
<span style="font-size: 30px;font-weight: bold;color:#3386FE">DeepFish</span>
|
|
2
|
+
<img src="./images/title-img.png" alt="DeepFish" width="300" />
|
|
4
3
|
</div>
|
|
5
4
|
|
|
6
5
|
---
|
|
@@ -25,13 +24,44 @@
|
|
|
25
24
|
/>
|
|
26
25
|
</div>
|
|
27
26
|
|
|
28
|
-
<img src="./images/banner.png" alt="
|
|
27
|
+
<img src="./images/banner.png" alt="banner" style="width:100%;text-align:center;" />
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
- [English](README.md) | [中文](README_CN.md)
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
## Table of Contents
|
|
34
|
+
|
|
35
|
+
- [Table of Contents](#table-of-contents)
|
|
36
|
+
- [1. Introduction](#1-introduction)
|
|
37
|
+
- [2. Installation](#2-installation)
|
|
38
|
+
- [Prerequisites](#prerequisites)
|
|
39
|
+
- [Installation via npm](#installation-via-npm)
|
|
40
|
+
- [Installation from Source](#installation-from-source)
|
|
41
|
+
- [3. Quick Start](#3-quick-start)
|
|
42
|
+
- [4. Configuration](#4-configuration)
|
|
43
|
+
- [Initial Setup](#initial-setup)
|
|
44
|
+
- [Configuration Commands](#configuration-commands)
|
|
45
|
+
- [Configuration File Structure](#configuration-file-structure)
|
|
46
|
+
- [5. Usage](#5-usage)
|
|
47
|
+
- [Interactive Mode](#interactive-mode)
|
|
48
|
+
- [Direct Command Mode](#direct-command-mode)
|
|
49
|
+
- [Usage Examples](#usage-examples)
|
|
50
|
+
- [6. Extension Development](#6-extension-development)
|
|
51
|
+
- [Creating an Extension](#creating-an-extension)
|
|
52
|
+
- [Registering Extensions](#registering-extensions)
|
|
53
|
+
- [7. Recommendations](#7-recommendations)
|
|
54
|
+
- [AI Service Selection](#ai-service-selection)
|
|
55
|
+
- [8. Usage Notes](#8-usage-notes)
|
|
56
|
+
- [Using Relative Paths](#using-relative-paths)
|
|
57
|
+
- [9. Troubleshooting](#9-troubleshooting)
|
|
58
|
+
- [Configuration Issues](#configuration-issues)
|
|
59
|
+
- [AI Service Connection](#ai-service-connection)
|
|
60
|
+
- [Extension Not Loading](#extension-not-loading)
|
|
61
|
+
- [10. Contributing](#10-contributing)
|
|
62
|
+
- [11. License](#11-license)
|
|
63
|
+
- [12. Support](#12-support)
|
|
64
|
+
|
|
35
65
|
|
|
36
66
|
|
|
37
67
|
## 1. Introduction
|
|
@@ -66,7 +96,7 @@ npm install -g deepfish-ai
|
|
|
66
96
|
### Installation from Source
|
|
67
97
|
|
|
68
98
|
```bash
|
|
69
|
-
git clone https://github.com/qq306863030/deepfish.git
|
|
99
|
+
git clone https://github.com/qq306863030/deepfish-ai.git
|
|
70
100
|
cd deepfish
|
|
71
101
|
npm install
|
|
72
102
|
npm link
|
|
@@ -259,7 +289,7 @@ module.exports = {
|
|
|
259
289
|
};
|
|
260
290
|
```
|
|
261
291
|
|
|
262
|
-
|
|
292
|
+
### Registering Extensions
|
|
263
293
|
|
|
264
294
|
**Method 1: Using Command Line**
|
|
265
295
|
|
|
@@ -284,11 +314,18 @@ module.exports = {
|
|
|
284
314
|
|
|
285
315
|
**Method 3: Automatic Scanning**
|
|
286
316
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
317
|
+
Rules for automatic scanning of extension modules upon program startup:
|
|
318
|
+
|
|
319
|
+
1. Scanning locations:
|
|
320
|
+
- node_modules in the root directory
|
|
321
|
+
- node_modules in the command execution directory
|
|
322
|
+
- the command execution directory itself
|
|
291
323
|
|
|
324
|
+
2. Scanned files:
|
|
325
|
+
- Extension packages under the @deepfish-ai directory
|
|
326
|
+
- Extension packages starting with "deepfish-"
|
|
327
|
+
- JavaScript extension files in the command execution directory, which are automatically loaded if they contain the strings 'module.exports', 'descriptions', and 'functions'
|
|
328
|
+
|
|
292
329
|
## 7. Recommendations
|
|
293
330
|
|
|
294
331
|
### AI Service Selection
|
package/README_CN.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<div align="center" style="display:flex;align-items: center;justify-content: center;">
|
|
2
|
-
<img src="./images/
|
|
3
|
-
<span style="font-size: 30px;font-weight: bold;color:#3386FE">DeepFish</span>
|
|
2
|
+
<img src="./images/title-img.png" alt="DeepFish" width="300" />
|
|
4
3
|
</div>
|
|
5
4
|
|
|
6
5
|
---
|
|
@@ -25,15 +24,44 @@
|
|
|
25
24
|
/>
|
|
26
25
|
</div>
|
|
27
26
|
|
|
28
|
-
<img src="./images/banner.png" alt="
|
|
27
|
+
<img src="./images/banner.png" alt="banner" style="width:100%;text-align:center;" />
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
- [English](README.md) | [中文](README_CN.md)
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
## 目录
|
|
35
|
+
|
|
36
|
+
- [目录](#目录)
|
|
37
|
+
- [1. 介绍](#1-介绍)
|
|
38
|
+
- [2. 安装](#2-安装)
|
|
39
|
+
- [前置要求](#前置要求)
|
|
40
|
+
- [通过npm安装](#通过npm安装)
|
|
41
|
+
- [从源码安装](#从源码安装)
|
|
42
|
+
- [3. 快速使用](#3-快速使用)
|
|
43
|
+
- [4. 配置](#4-配置)
|
|
44
|
+
- [初始设置](#初始设置)
|
|
45
|
+
- [配置命令](#配置命令)
|
|
46
|
+
- [配置文件结构](#配置文件结构)
|
|
47
|
+
- [5. 使用方法](#5-使用方法)
|
|
48
|
+
- [交互模式](#交互模式)
|
|
49
|
+
- [直接命令模式](#直接命令模式)
|
|
50
|
+
- [使用示例](#使用示例)
|
|
51
|
+
- [6. 扩展开发](#6-扩展开发)
|
|
52
|
+
- [创建扩展](#创建扩展)
|
|
53
|
+
- [注册扩展](#注册扩展)
|
|
54
|
+
- [7. 建议](#7-建议)
|
|
55
|
+
- [AI服务选择](#ai服务选择)
|
|
56
|
+
- [8. 使用说明](#8-使用说明)
|
|
57
|
+
- [使用相对路径](#使用相对路径)
|
|
58
|
+
- [9. 故障排除](#9-故障排除)
|
|
59
|
+
- [配置问题](#配置问题)
|
|
60
|
+
- [AI服务连接](#ai服务连接)
|
|
61
|
+
- [扩展未加载](#扩展未加载)
|
|
62
|
+
- [10. 贡献](#10-贡献)
|
|
63
|
+
- [11. 许可证](#11-许可证)
|
|
64
|
+
- [12. 支持](#12-支持)
|
|
37
65
|
|
|
38
66
|
## 1. 介绍
|
|
39
67
|
|
|
@@ -66,7 +94,7 @@ npm install -g deepfish-ai
|
|
|
66
94
|
### 从源码安装
|
|
67
95
|
|
|
68
96
|
```bash
|
|
69
|
-
git clone https://github.com/qq306863030/deepfish.git
|
|
97
|
+
git clone https://github.com/qq306863030/deepfish-ai.git
|
|
70
98
|
cd deepfish
|
|
71
99
|
npm install
|
|
72
100
|
npm link
|
|
@@ -259,7 +287,7 @@ module.exports = {
|
|
|
259
287
|
};
|
|
260
288
|
```
|
|
261
289
|
|
|
262
|
-
|
|
290
|
+
### 注册扩展
|
|
263
291
|
|
|
264
292
|
**方法1:使用命令行**
|
|
265
293
|
|
|
@@ -284,10 +312,15 @@ module.exports = {
|
|
|
284
312
|
|
|
285
313
|
**方法3:自动扫描**
|
|
286
314
|
|
|
287
|
-
|
|
288
|
-
1
|
|
289
|
-
|
|
290
|
-
|
|
315
|
+
程序启动时自动扫描扩展模块的规则:
|
|
316
|
+
1. 扫描位置:
|
|
317
|
+
- 根目录的node_modules
|
|
318
|
+
- 命令执行目录的node_modules
|
|
319
|
+
- 命令执行目录
|
|
320
|
+
2. 扫描文件:
|
|
321
|
+
- @deepfish-ai目录下的扩展包
|
|
322
|
+
- deepfish-开头的扩展包
|
|
323
|
+
- 命令执行目录的js扩展文件,js文件内包含'module.exports'、'descriptions'和'functions'字符串则视为扩展文件自动加载
|
|
291
324
|
|
|
292
325
|
## 7. 建议
|
|
293
326
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepfish-ai",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.12",
|
|
4
|
+
"description": "This is an AI-driven command-line tool built on Node.js, equipped with AI agent and workflow capabilities. It is compatible with a wide range of AI models, can convert natural language into cross-system terminal and file operation commands, and features high extensibility. It supports complex tasks such as translation, content creation, and format conversion, while allowing custom extensions to be automatically generated via AI.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"ai": "src/cli.js"
|
|
7
|
+
"ai": "src/cli/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"keywords": [
|
|
13
13
|
"ai",
|
|
14
14
|
"deepseek",
|
|
15
|
+
"agent",
|
|
16
|
+
"assistant",
|
|
15
17
|
"cli",
|
|
16
18
|
"command-line",
|
|
17
19
|
"cmd",
|
|
@@ -23,12 +25,12 @@
|
|
|
23
25
|
"license": "MIT",
|
|
24
26
|
"repository": {
|
|
25
27
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/qq306863030/deepfish.git"
|
|
28
|
+
"url": "https://github.com/qq306863030/deepfish-ai.git"
|
|
27
29
|
},
|
|
28
30
|
"bugs": {
|
|
29
|
-
"url": "https://github.com/qq306863030/deepfish/issues"
|
|
31
|
+
"url": "https://github.com/qq306863030/deepfish-ai/issues"
|
|
30
32
|
},
|
|
31
|
-
"homepage": "https://github.com/qq306863030/deepfish#readme",
|
|
33
|
+
"homepage": "https://github.com/qq306863030/deepfish-ai#readme",
|
|
32
34
|
"dependencies": {
|
|
33
35
|
"axios": "^1.13.5",
|
|
34
36
|
"chalk": "^4.1.0",
|
|
@@ -53,4 +55,4 @@
|
|
|
53
55
|
"README_CN.md",
|
|
54
56
|
"LICENSE"
|
|
55
57
|
]
|
|
56
|
-
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const os = require('os')
|
|
3
|
+
const fs = require('fs-extra')
|
|
4
|
+
const { defaultConfig } = require('./configTools')
|
|
5
|
+
const { logSuccess, logError, logInfo } = require('../core/utils/log')
|
|
6
|
+
const { GlobalVariable } = require('../core/globalVariable')
|
|
7
|
+
|
|
8
|
+
class ConfigManager {
|
|
9
|
+
config = null
|
|
10
|
+
configDir = path.join(os.homedir(), './.deepfish-ai')
|
|
11
|
+
configPath = path.join(this.configDir, './config.js')
|
|
12
|
+
constructor() {
|
|
13
|
+
this.initConfig()
|
|
14
|
+
GlobalVariable.configManager = this
|
|
15
|
+
}
|
|
16
|
+
// 初始化config
|
|
17
|
+
initConfig() {
|
|
18
|
+
fs.ensureDirSync(this.configDir)
|
|
19
|
+
// 判断之前版本的配置文件是否存在,如果存在则迁移到新目录
|
|
20
|
+
const isConfigExists = this.checkConfigExists()
|
|
21
|
+
if (
|
|
22
|
+
!isConfigExists &&
|
|
23
|
+
fs.pathExistsSync(path.join(os.homedir(), '.ai-cmd.config.js'))
|
|
24
|
+
) {
|
|
25
|
+
fs.moveSync(path.join(os.homedir(), '.ai-cmd.config.js'), this.configPath)
|
|
26
|
+
} else if (!isConfigExists) {
|
|
27
|
+
this._writeConfig()
|
|
28
|
+
}
|
|
29
|
+
this.config = this._getConfig()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
edit() {
|
|
33
|
+
const { exec } = require('child_process')
|
|
34
|
+
const platform = process.platform
|
|
35
|
+
|
|
36
|
+
let openCommand
|
|
37
|
+
if (process.env.EDITOR) {
|
|
38
|
+
openCommand = `${process.env.EDITOR} "${this.configPath}"`
|
|
39
|
+
} else if (platform === 'darwin') {
|
|
40
|
+
openCommand = `open -e "${this.configPath}"`
|
|
41
|
+
} else if (platform === 'win32') {
|
|
42
|
+
openCommand = `notepad "${this.configPath}"`
|
|
43
|
+
} else {
|
|
44
|
+
openCommand = `xdg-open "${this.configPath}"`
|
|
45
|
+
}
|
|
46
|
+
exec(openCommand, (error) => {
|
|
47
|
+
if (error) {
|
|
48
|
+
logError('Error opening configuration file:', error.message)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 判断config是否存在
|
|
54
|
+
checkConfigExists() {
|
|
55
|
+
return fs.pathExistsSync(this.configPath)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 重名验证
|
|
59
|
+
checkName(aiName) {
|
|
60
|
+
const existingIndex = this.config.ai.findIndex(
|
|
61
|
+
(item) => item.name === aiName,
|
|
62
|
+
)
|
|
63
|
+
return existingIndex !== -1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isAiListEmpty() {
|
|
67
|
+
return this.config.ai && this.config.ai.length === 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 添加一个aiConfig
|
|
71
|
+
addAiConfig(aiConfig) {
|
|
72
|
+
this.config.ai.push(aiConfig)
|
|
73
|
+
this._writeConfig(this.config)
|
|
74
|
+
logSuccess(`AI configuration "${aiConfig.name}" added successfully!`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 删除一个aiConfig
|
|
78
|
+
delAiConfig(aiName) {
|
|
79
|
+
const existingIndex = this.config.ai.findIndex(
|
|
80
|
+
(item) => item.name === aiName,
|
|
81
|
+
)
|
|
82
|
+
if (existingIndex === -1) {
|
|
83
|
+
logError(`Configuration with name "${aiName}" not found.`)
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
const currentAi = this.config.currentAi
|
|
87
|
+
// Check if it's the current configuration
|
|
88
|
+
if (currentAi === aiName) {
|
|
89
|
+
logError(`Cannot delete current configuration "${aiName}".`)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
// Remove the configuration
|
|
93
|
+
this.config.ai.splice(existingIndex, 1)
|
|
94
|
+
this._writeConfig(this.config)
|
|
95
|
+
logSuccess(`AI configuration "${aiName}" deleted successfully!`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 设置当前Ai
|
|
99
|
+
setCurrentAi(aiName) {
|
|
100
|
+
// 查看列表中是否存在
|
|
101
|
+
const existingIndex = this.config.ai.findIndex(
|
|
102
|
+
(item) => item.name === aiName,
|
|
103
|
+
)
|
|
104
|
+
if (existingIndex === -1) {
|
|
105
|
+
logError(`Configuration with name "${aiName}" not found.`)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
this.config.currentAi = aiName
|
|
109
|
+
this._writeConfig(this.config)
|
|
110
|
+
logSuccess(`Current AI configuration set to "${aiName}" successfully!`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getCurrentAiConfig() {
|
|
114
|
+
return this.config.ai.find((item) => item.name === this.config.currentAi)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getCurrentAi() {
|
|
118
|
+
return this.config.currentAi
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_getAiConfig(aiName) {
|
|
122
|
+
return this.config.ai.find((item) => item.name === aiName)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 获取Ai列表
|
|
126
|
+
getAiList() {
|
|
127
|
+
console.log('AI Configurations')
|
|
128
|
+
console.log('='.repeat(50))
|
|
129
|
+
if (this.config.ai && Array.isArray(this.config.ai)) {
|
|
130
|
+
if (this.config.ai.length === 0) {
|
|
131
|
+
logError('No AI configurations found.')
|
|
132
|
+
} else {
|
|
133
|
+
this.config.ai.forEach((config, index) => {
|
|
134
|
+
const isCurrent = this.config.currentAi === config.name
|
|
135
|
+
logInfo(`${config.name} ${isCurrent ? '(current)' : ''}`)
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
logError('No AI configurations found.')
|
|
140
|
+
}
|
|
141
|
+
console.log('='.repeat(50))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 重置config
|
|
145
|
+
resetConfig() {
|
|
146
|
+
console.log('Resetting configuration file:', this.configPath)
|
|
147
|
+
this._writeConfig()
|
|
148
|
+
this.config = this._getConfig()
|
|
149
|
+
logError('Configuration file has been reset to default settings.')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 查看ai详情
|
|
153
|
+
viewAiConfigDetail(aiName) {
|
|
154
|
+
if (this.isAiListEmpty()) {
|
|
155
|
+
logError('No AI configurations found. Please add an AI configuration first.')
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
if (!aiName) {
|
|
159
|
+
aiName = this.config.currentAi
|
|
160
|
+
if (!aiName) {
|
|
161
|
+
logError('No current AI configuration set. Please input "ai config use <name>" to set a current configuration.')
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const aiConfig = this._getAiConfig(aiName)
|
|
166
|
+
if (!aiConfig) {
|
|
167
|
+
logError('AI configuration not found. Please check the name and try again.')
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
logSuccess('AI Configuration Details')
|
|
171
|
+
logSuccess('='.repeat(50))
|
|
172
|
+
logInfo(`Name: ${aiConfig.name}`)
|
|
173
|
+
logInfo(`Type: ${aiConfig.type}`)
|
|
174
|
+
logInfo(`API Base URL: ${aiConfig.baseUrl}`)
|
|
175
|
+
logInfo(`Model: ${aiConfig.model}`)
|
|
176
|
+
if (aiConfig.apiKey) {
|
|
177
|
+
logInfo(`API Key: ${aiConfig.apiKey}`)
|
|
178
|
+
}
|
|
179
|
+
logInfo(`Temperature: ${aiConfig.temperature}`)
|
|
180
|
+
logInfo(`Max Tokens: ${aiConfig.maxTokens}`)
|
|
181
|
+
logInfo(`Streaming Output: ${aiConfig.stream ? 'Enabled' : 'Disabled'}`)
|
|
182
|
+
logInfo(
|
|
183
|
+
`Is Current: ${this.config.currentAi === aiConfig.name ? 'Yes' : 'No'}`,
|
|
184
|
+
)
|
|
185
|
+
logInfo(`File Path: ${this.configPath}`)
|
|
186
|
+
logSuccess('='.repeat(50))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 更新扩展
|
|
190
|
+
updateExtensions(extensions) {
|
|
191
|
+
this.config.extensions = extensions
|
|
192
|
+
this._writeConfig(this.config)
|
|
193
|
+
logSuccess('Extensions updated successfully!')
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// 删除扩展
|
|
197
|
+
removeExtensionByIndex(extIndex) {
|
|
198
|
+
const filePath = this.config.extensions.splice(extIndex, 1)
|
|
199
|
+
this._writeConfig(this.config)
|
|
200
|
+
logSuccess(
|
|
201
|
+
`Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
removeExtensionByPath(filePath) {
|
|
206
|
+
this.config.extensions = this.config.extensions.filter(
|
|
207
|
+
(ext) => ext !== filePath,
|
|
208
|
+
)
|
|
209
|
+
this._writeConfig(this.config)
|
|
210
|
+
logSuccess(
|
|
211
|
+
`Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
_getConfig() {
|
|
216
|
+
return require(this.configPath)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 写入配置
|
|
220
|
+
_writeConfig(config) {
|
|
221
|
+
if (!config) {
|
|
222
|
+
config = defaultConfig
|
|
223
|
+
}
|
|
224
|
+
fs.writeFileSync(
|
|
225
|
+
this.configPath,
|
|
226
|
+
`module.exports = ${JSON.stringify(config, null, 2)}`,
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = ConfigManager
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs-extra");
|
|
3
|
+
const { GlobalVariable } = require('../core/globalVariable')
|
|
4
|
+
const { logError, logSuccess } = require('../core/utils/log');
|
|
5
|
+
const { traverseFiles } = require("./configTools");
|
|
6
|
+
|
|
7
|
+
class ExtConfigManager {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.configManager = GlobalVariable.configManager
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// 添加
|
|
13
|
+
add(fileName) {
|
|
14
|
+
// 检查 fileName 是否为空
|
|
15
|
+
if (!fileName) {
|
|
16
|
+
logError('Extension file name is required.')
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
const filePath = path.resolve(process.cwd(), fileName)
|
|
20
|
+
// 判断是否路径是文件还是目录
|
|
21
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
22
|
+
// 扫描目录和子目录下所有js、cjs文件
|
|
23
|
+
const files = traverseFiles()
|
|
24
|
+
const jsFiles = files.filter(
|
|
25
|
+
(file) => file.endsWith('.js') || file.endsWith('.cjs'),
|
|
26
|
+
)
|
|
27
|
+
jsFiles.forEach((jsFile) => {
|
|
28
|
+
// 读取文件,查询文件内是否存在‘descriptions’和‘functions’
|
|
29
|
+
const fileContent = fs.readFileSync(jsFile, 'utf-8')
|
|
30
|
+
if (
|
|
31
|
+
fileContent.includes('module.exports') &&
|
|
32
|
+
fileContent.includes('descriptions') &&
|
|
33
|
+
fileContent.includes('functions')
|
|
34
|
+
) {
|
|
35
|
+
this.add(jsFile)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
// 判断文件是否存在
|
|
41
|
+
if (!fs.existsSync(filePath)) {
|
|
42
|
+
logError(`File not found: ${filePath}`)
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
const userConfig = this.configManager.config
|
|
46
|
+
userConfig.extensions.push(filePath)
|
|
47
|
+
// 数组去重
|
|
48
|
+
this.configManager.updateExtensions([...new Set(userConfig.extensions)])
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 删除
|
|
52
|
+
remove(fileName) {
|
|
53
|
+
const userConfig = this.configManager.config
|
|
54
|
+
// 增加对数字索引的支持
|
|
55
|
+
if (!isNaN(Number(fileName))) {
|
|
56
|
+
const extIndex = Number(fileName)
|
|
57
|
+
if (extIndex < 0 || extIndex >= userConfig.extensions.length) {
|
|
58
|
+
logError(`Invalid extension index: ${extIndex}`)
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
this.configManager.removeExtensionByIndex(extIndex)
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
const filePath = path.resolve(process.cwd(), fileName)
|
|
65
|
+
this.configManager.removeExtensionByPath(filePath)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 查看列表
|
|
69
|
+
viewList() {
|
|
70
|
+
const extensions = this.configManager.config.extensions
|
|
71
|
+
if (extensions && Array.isArray(extensions)) {
|
|
72
|
+
console.log('='.repeat(50))
|
|
73
|
+
// 打印扩展列表,并加上索引
|
|
74
|
+
if (extensions.length === 0) {
|
|
75
|
+
console.log(`No extensions in config.`)
|
|
76
|
+
} else {
|
|
77
|
+
console.log('Extensions in config:')
|
|
78
|
+
extensions.forEach((ext, index) => {
|
|
79
|
+
console.log(`[${index}] ${ext}`)
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
console.log('='.repeat(50))
|
|
83
|
+
} else {
|
|
84
|
+
logSuccess(`No extensions in config.`)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
module.exports = ExtConfigManager
|