deepfish-ai 1.0.29 → 2.0.2
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 +126 -368
- package/dist/index.js +23320 -0
- package/dist/serve/client/assets/index-DUHYC91l.js +1 -0
- package/dist/serve/client/assets/index-zcrdNLZs.css +1 -0
- package/dist/serve/client/index.html +14 -0
- package/dist/serve/pm2-server.js +21015 -0
- package/dist/serve/server/entry-server.mjs +224 -0
- package/package.json +61 -83
- package/LICENSE +0 -21
- package/README_CN.md +0 -460
- package/src/AgentRobot/AgentRobotFactory/MainAgentRobot.js +0 -88
- package/src/AgentRobot/AgentRobotFactory/SubAgentRobot.js +0 -45
- package/src/AgentRobot/AgentRobotFactory/SubSkillAgentRobot.js +0 -45
- package/src/AgentRobot/AgentRobotFactory/index.js +0 -48
- package/src/AgentRobot/BaseAgentRobot/Brain.js +0 -210
- package/src/AgentRobot/BaseAgentRobot/BrainEvent.js +0 -17
- package/src/AgentRobot/BaseAgentRobot/Hand.js +0 -119
- package/src/AgentRobot/BaseAgentRobot/Heart.js +0 -0
- package/src/AgentRobot/BaseAgentRobot/Logger.js +0 -114
- package/src/AgentRobot/BaseAgentRobot/ScreenPrinter.js +0 -49
- package/src/AgentRobot/BaseAgentRobot/index.js +0 -266
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/AliBailian.js +0 -997
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/doc-transform.js +0 -204
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/docx.js +0 -1286
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/img.js +0 -765
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/pdf.js +0 -736
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/pptx.js +0 -567
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/video.js +0 -36
- package/src/AgentRobot/BaseAgentRobot/lazy-tools/xlsx.js +0 -611
- package/src/AgentRobot/BaseAgentRobot/tools/BaseTools.js +0 -13
- package/src/AgentRobot/BaseAgentRobot/tools/CreateAgentTools.js +0 -158
- package/src/AgentRobot/BaseAgentRobot/tools/FileTools.js +0 -768
- package/src/AgentRobot/BaseAgentRobot/tools/GenerateTools.js +0 -441
- package/src/AgentRobot/BaseAgentRobot/tools/InquirerTools.js +0 -244
- package/src/AgentRobot/BaseAgentRobot/tools/SystemTools.js +0 -424
- package/src/AgentRobot/BaseAgentRobot/tools/TaskTools.js +0 -211
- package/src/AgentRobot/BaseAgentRobot/tools/TestTools.js +0 -100
- package/src/AgentRobot/BaseAgentRobot/tools/UserTool.js +0 -87
- package/src/AgentRobot/BaseAgentRobot/tools/WebTools.js +0 -257
- package/src/AgentRobot/BaseAgentRobot/utils/AIRequest.js +0 -297
- package/src/AgentRobot/BaseAgentRobot/utils/AIToolManager.js +0 -131
- package/src/AgentRobot/BaseAgentRobot/utils/AgentTree.js +0 -66
- package/src/AgentRobot/BaseAgentRobot/utils/AttachmentToolScanner.js +0 -235
- package/src/AgentRobot/BaseAgentRobot/utils/MessageCompresser.js +0 -236
- package/src/AgentRobot/BaseAgentRobot/utils/aiConsole.js +0 -74
- package/src/AgentRobot/BaseAgentRobot/utils/aiInquirer.js +0 -78
- package/src/AgentRobot/BaseAgentRobot/utils/analyzeReturn.test.js +0 -104
- package/src/AgentRobot/BaseAgentRobot/utils/copilot.js +0 -117
- package/src/AgentRobot/BaseAgentRobot/utils/node-root.js +0 -138
- package/src/AgentRobot/BaseAgentRobot/utils/normal.js +0 -399
- package/src/cli/ConfigManager.js +0 -283
- package/src/cli/DefaultConfig.js +0 -98
- package/src/cli/GlobalVariable.js +0 -8
- package/src/cli/MemoryManager.js +0 -53
- package/src/cli/SkillConfigManager.js +0 -354
- package/src/cli/SkillParser.js +0 -58
- package/src/cli/ai-auth.js +0 -231
- package/src/cli/ai-config.js +0 -225
- package/src/cli/ai-memory.js +0 -22
- package/src/cli/ai-skill.js +0 -65
- package/src/cli/index.js +0 -77
- package/src/index.js +0 -54
|
@@ -1,399 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const fs = require('fs-extra')
|
|
3
|
-
const chardet = require('chardet')
|
|
4
|
-
const os = require('os')
|
|
5
|
-
const { spawn } = require('child_process')
|
|
6
|
-
|
|
7
|
-
// 对象字符串转对象
|
|
8
|
-
function objStrToObj(str) {
|
|
9
|
-
try {
|
|
10
|
-
if (typeof str === 'string') {
|
|
11
|
-
return eval(`(${str})`)
|
|
12
|
-
} else {
|
|
13
|
-
return str
|
|
14
|
-
}
|
|
15
|
-
} catch (error) {
|
|
16
|
-
throw new Error(`对象转换失败:${error.message}`)
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function delay(ms) {
|
|
21
|
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 遍历目录和子目录下所有文件
|
|
25
|
-
function traverseFiles() {
|
|
26
|
-
try {
|
|
27
|
-
const currentDir = process.cwd()
|
|
28
|
-
const allFiles = []
|
|
29
|
-
const currentItems = fs.readdirSync(currentDir, { withFileTypes: true })
|
|
30
|
-
for (const item of currentItems) {
|
|
31
|
-
const itemPath = path.join(currentDir, item.name)
|
|
32
|
-
if (item.isFile()) {
|
|
33
|
-
allFiles.push(itemPath)
|
|
34
|
-
continue
|
|
35
|
-
}
|
|
36
|
-
if (item.isDirectory()) {
|
|
37
|
-
try {
|
|
38
|
-
const subItems = fs.readdirSync(itemPath, { withFileTypes: true })
|
|
39
|
-
for (const subItem of subItems) {
|
|
40
|
-
if (subItem.isFile()) {
|
|
41
|
-
allFiles.push(path.join(itemPath, subItem.name))
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
} catch (subErr) {
|
|
45
|
-
console.warn(`读取子目录失败 ${itemPath}:${subErr.message}`)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return allFiles
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.error(`遍历目录失败:${err.message}`)
|
|
52
|
-
return []
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 打开目录
|
|
57
|
-
function openDirectory(dirPath) {
|
|
58
|
-
// 打开目录
|
|
59
|
-
const platform = process.platform
|
|
60
|
-
let command
|
|
61
|
-
let args
|
|
62
|
-
const dir = dirPath
|
|
63
|
-
if (platform === 'darwin') {
|
|
64
|
-
command = 'open'
|
|
65
|
-
args = [dir]
|
|
66
|
-
} else if (platform === 'win32') {
|
|
67
|
-
command = 'explorer.exe'
|
|
68
|
-
args = [dir]
|
|
69
|
-
} else {
|
|
70
|
-
command = 'xdg-open'
|
|
71
|
-
args = [dir]
|
|
72
|
-
}
|
|
73
|
-
const child = spawn(command, args, {
|
|
74
|
-
detached: true,
|
|
75
|
-
stdio: 'ignore',
|
|
76
|
-
})
|
|
77
|
-
child.on('error', (error) => {
|
|
78
|
-
console.error(`Error opening directory "${dirPath}": ${error.message}`)
|
|
79
|
-
})
|
|
80
|
-
child.unref()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// 判断编码类型
|
|
84
|
-
function detectEncoding(buffer) {
|
|
85
|
-
if (!buffer) {
|
|
86
|
-
const platform = os.platform()
|
|
87
|
-
return platform === 'win32' ? 'gbk' : 'utf-8'
|
|
88
|
-
}
|
|
89
|
-
const encoding = chardet.detect(buffer)
|
|
90
|
-
if (encoding?.toLowerCase() === 'utf-8') {
|
|
91
|
-
return 'utf-8'
|
|
92
|
-
} else if (['gbk', 'gb2312', 'gb18030'].includes(encoding?.toLowerCase())) {
|
|
93
|
-
return 'gbk'
|
|
94
|
-
} else {
|
|
95
|
-
const platform = os.platform()
|
|
96
|
-
return platform === 'win32' ? 'gbk' : 'utf-8'
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function sleep(ms) {
|
|
101
|
-
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 判断代码是否有返回值
|
|
105
|
-
function analyzeReturn(code) {
|
|
106
|
-
if (typeof code !== 'string' || !code.trim()) {
|
|
107
|
-
return {
|
|
108
|
-
hasReturn: false,
|
|
109
|
-
hasReturnValue: false,
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// 移除字符串和注释,避免把文本中的 return 误判为代码关键字。
|
|
114
|
-
function stripStringsAndComments(input) {
|
|
115
|
-
const chars = input.split('')
|
|
116
|
-
let i = 0
|
|
117
|
-
let state = 'normal'
|
|
118
|
-
|
|
119
|
-
while (i < chars.length) {
|
|
120
|
-
const ch = chars[i]
|
|
121
|
-
const next = chars[i + 1]
|
|
122
|
-
|
|
123
|
-
if (state === 'normal') {
|
|
124
|
-
if (ch === '/' && next === '/') {
|
|
125
|
-
state = 'line-comment'
|
|
126
|
-
chars[i] = ' '
|
|
127
|
-
chars[i + 1] = ' '
|
|
128
|
-
i += 2
|
|
129
|
-
continue
|
|
130
|
-
}
|
|
131
|
-
if (ch === '/' && next === '*') {
|
|
132
|
-
state = 'block-comment'
|
|
133
|
-
chars[i] = ' '
|
|
134
|
-
chars[i + 1] = ' '
|
|
135
|
-
i += 2
|
|
136
|
-
continue
|
|
137
|
-
}
|
|
138
|
-
if (ch === "'") {
|
|
139
|
-
state = 'single-quote'
|
|
140
|
-
chars[i] = ' '
|
|
141
|
-
i += 1
|
|
142
|
-
continue
|
|
143
|
-
}
|
|
144
|
-
if (ch === '"') {
|
|
145
|
-
state = 'double-quote'
|
|
146
|
-
chars[i] = ' '
|
|
147
|
-
i += 1
|
|
148
|
-
continue
|
|
149
|
-
}
|
|
150
|
-
if (ch === '`') {
|
|
151
|
-
state = 'template'
|
|
152
|
-
chars[i] = ' '
|
|
153
|
-
i += 1
|
|
154
|
-
continue
|
|
155
|
-
}
|
|
156
|
-
i += 1
|
|
157
|
-
continue
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (state === 'line-comment') {
|
|
161
|
-
if (ch === '\n') {
|
|
162
|
-
state = 'normal'
|
|
163
|
-
} else {
|
|
164
|
-
chars[i] = ' '
|
|
165
|
-
}
|
|
166
|
-
i += 1
|
|
167
|
-
continue
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (state === 'block-comment') {
|
|
171
|
-
if (ch === '*' && next === '/') {
|
|
172
|
-
chars[i] = ' '
|
|
173
|
-
chars[i + 1] = ' '
|
|
174
|
-
state = 'normal'
|
|
175
|
-
i += 2
|
|
176
|
-
} else {
|
|
177
|
-
if (ch !== '\n') {
|
|
178
|
-
chars[i] = ' '
|
|
179
|
-
}
|
|
180
|
-
i += 1
|
|
181
|
-
}
|
|
182
|
-
continue
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (state === 'single-quote') {
|
|
186
|
-
if (ch === '\\') {
|
|
187
|
-
chars[i] = ' '
|
|
188
|
-
if (i + 1 < chars.length) {
|
|
189
|
-
chars[i + 1] = ' '
|
|
190
|
-
}
|
|
191
|
-
i += 2
|
|
192
|
-
continue
|
|
193
|
-
}
|
|
194
|
-
chars[i] = ch === '\n' ? '\n' : ' '
|
|
195
|
-
if (ch === "'") {
|
|
196
|
-
state = 'normal'
|
|
197
|
-
}
|
|
198
|
-
i += 1
|
|
199
|
-
continue
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (state === 'double-quote') {
|
|
203
|
-
if (ch === '\\') {
|
|
204
|
-
chars[i] = ' '
|
|
205
|
-
if (i + 1 < chars.length) {
|
|
206
|
-
chars[i + 1] = ' '
|
|
207
|
-
}
|
|
208
|
-
i += 2
|
|
209
|
-
continue
|
|
210
|
-
}
|
|
211
|
-
chars[i] = ch === '\n' ? '\n' : ' '
|
|
212
|
-
if (ch === '"') {
|
|
213
|
-
state = 'normal'
|
|
214
|
-
}
|
|
215
|
-
i += 1
|
|
216
|
-
continue
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (state === 'template') {
|
|
220
|
-
if (ch === '\\') {
|
|
221
|
-
chars[i] = ' '
|
|
222
|
-
if (i + 1 < chars.length) {
|
|
223
|
-
chars[i + 1] = ' '
|
|
224
|
-
}
|
|
225
|
-
i += 2
|
|
226
|
-
continue
|
|
227
|
-
}
|
|
228
|
-
chars[i] = ch === '\n' ? '\n' : ' '
|
|
229
|
-
if (ch === '`') {
|
|
230
|
-
state = 'normal'
|
|
231
|
-
}
|
|
232
|
-
i += 1
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return chars.join('')
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function isReturnWithValue(input, startIndex) {
|
|
240
|
-
let i = startIndex
|
|
241
|
-
while (i < input.length) {
|
|
242
|
-
const ch = input[i]
|
|
243
|
-
const next = input[i + 1]
|
|
244
|
-
if (ch === ' ' || ch === '\t' || ch === '\r') {
|
|
245
|
-
i += 1
|
|
246
|
-
continue
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (ch === '/' && next === '/') {
|
|
250
|
-
i += 2
|
|
251
|
-
while (i < input.length && input[i] !== '\n') {
|
|
252
|
-
i += 1
|
|
253
|
-
}
|
|
254
|
-
continue
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (ch === '/' && next === '*') {
|
|
258
|
-
i += 2
|
|
259
|
-
while (i < input.length) {
|
|
260
|
-
if (input[i] === '*' && input[i + 1] === '/') {
|
|
261
|
-
i += 2
|
|
262
|
-
break
|
|
263
|
-
}
|
|
264
|
-
i += 1
|
|
265
|
-
}
|
|
266
|
-
continue
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (ch === '\n' || ch === ';' || ch === '}' || ch === ')') {
|
|
270
|
-
return false
|
|
271
|
-
}
|
|
272
|
-
return true
|
|
273
|
-
}
|
|
274
|
-
return false
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function isControlKeyword(token) {
|
|
278
|
-
return ['if', 'for', 'while', 'switch', 'catch', 'with'].includes(token)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const cleaned = stripStringsAndComments(code)
|
|
282
|
-
const tokenRegex = /[A-Za-z_$][\w$]*|=>|[{}()\[\]]/g
|
|
283
|
-
const blockStack = []
|
|
284
|
-
const parenStack = []
|
|
285
|
-
let functionDepth = 0
|
|
286
|
-
let pendingFunctionBlock = 0
|
|
287
|
-
let pendingArrow = false
|
|
288
|
-
let hasReturn = false
|
|
289
|
-
let hasReturnValue = false
|
|
290
|
-
let lastToken = ''
|
|
291
|
-
let recentClosedParen = null
|
|
292
|
-
let match
|
|
293
|
-
|
|
294
|
-
while ((match = tokenRegex.exec(cleaned)) !== null) {
|
|
295
|
-
const token = match[0]
|
|
296
|
-
const index = match.index
|
|
297
|
-
|
|
298
|
-
if (token === '(') {
|
|
299
|
-
parenStack.push({
|
|
300
|
-
beforeToken: lastToken,
|
|
301
|
-
})
|
|
302
|
-
lastToken = token
|
|
303
|
-
continue
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (token === ')') {
|
|
307
|
-
recentClosedParen = parenStack.pop() || null
|
|
308
|
-
lastToken = token
|
|
309
|
-
continue
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (token === 'function') {
|
|
313
|
-
pendingFunctionBlock += 1
|
|
314
|
-
pendingArrow = false
|
|
315
|
-
lastToken = token
|
|
316
|
-
recentClosedParen = null
|
|
317
|
-
continue
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (token === '=>') {
|
|
321
|
-
pendingArrow = true
|
|
322
|
-
lastToken = token
|
|
323
|
-
recentClosedParen = null
|
|
324
|
-
continue
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (token === '{') {
|
|
328
|
-
let isFunctionBlock = false
|
|
329
|
-
if (pendingFunctionBlock > 0 || pendingArrow) {
|
|
330
|
-
isFunctionBlock = true
|
|
331
|
-
} else if (lastToken === ')' && recentClosedParen) {
|
|
332
|
-
const beforeToken = recentClosedParen.beforeToken
|
|
333
|
-
if (beforeToken && !isControlKeyword(beforeToken)) {
|
|
334
|
-
// 识别 class/object method 这类无 function 关键字的方法体。
|
|
335
|
-
isFunctionBlock = true
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (isFunctionBlock) {
|
|
340
|
-
blockStack.push('function')
|
|
341
|
-
functionDepth += 1
|
|
342
|
-
if (pendingFunctionBlock > 0) {
|
|
343
|
-
pendingFunctionBlock -= 1
|
|
344
|
-
}
|
|
345
|
-
} else {
|
|
346
|
-
blockStack.push('block')
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
pendingArrow = false
|
|
350
|
-
lastToken = token
|
|
351
|
-
recentClosedParen = null
|
|
352
|
-
continue
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (token === '}') {
|
|
356
|
-
const top = blockStack.pop()
|
|
357
|
-
if (top === 'function' && functionDepth > 0) {
|
|
358
|
-
functionDepth -= 1
|
|
359
|
-
}
|
|
360
|
-
pendingArrow = false
|
|
361
|
-
lastToken = token
|
|
362
|
-
recentClosedParen = null
|
|
363
|
-
continue
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (token === 'return' && functionDepth === 0) {
|
|
367
|
-
hasReturn = true
|
|
368
|
-
if (isReturnWithValue(code, index + token.length)) {
|
|
369
|
-
hasReturnValue = true
|
|
370
|
-
}
|
|
371
|
-
if (hasReturn && hasReturnValue) {
|
|
372
|
-
break
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if (pendingArrow) {
|
|
377
|
-
// 箭头函数表达式体不带 {} 时,不会有 return 关键字参与判断。
|
|
378
|
-
pendingArrow = false
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
lastToken = token
|
|
382
|
-
recentClosedParen = null
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return {
|
|
386
|
-
hasReturn,
|
|
387
|
-
hasReturnValue,
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
module.exports = {
|
|
392
|
-
objStrToObj,
|
|
393
|
-
delay,
|
|
394
|
-
traverseFiles,
|
|
395
|
-
openDirectory,
|
|
396
|
-
detectEncoding,
|
|
397
|
-
sleep,
|
|
398
|
-
analyzeReturn,
|
|
399
|
-
}
|
package/src/cli/ConfigManager.js
DELETED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const os = require('os')
|
|
3
|
-
const fs = require('fs-extra')
|
|
4
|
-
const { exec } = require('child_process')
|
|
5
|
-
const lodash = require('lodash')
|
|
6
|
-
const { defaultConfig } = require('./DefaultConfig.js')
|
|
7
|
-
const { GlobalVariable } = require('./GlobalVariable.js')
|
|
8
|
-
const { openDirectory } = require('../AgentRobot/BaseAgentRobot/utils/normal.js')
|
|
9
|
-
const aiConsole = require('../AgentRobot/BaseAgentRobot/utils/aiConsole.js')
|
|
10
|
-
|
|
11
|
-
class ConfigManager {
|
|
12
|
-
config = null
|
|
13
|
-
configDir = path.join(os.homedir(), './.deepfish-ai')
|
|
14
|
-
configPath = path.join(this.configDir, './config.js')
|
|
15
|
-
constructor() {
|
|
16
|
-
this.initConfig()
|
|
17
|
-
GlobalVariable.configManager = this
|
|
18
|
-
}
|
|
19
|
-
// 初始化config
|
|
20
|
-
initConfig() {
|
|
21
|
-
fs.ensureDirSync(this.configDir)
|
|
22
|
-
// 判断之前版本的配置文件是否存在,如果存在则迁移到新目录
|
|
23
|
-
const isConfigExists = this.checkConfigExists()
|
|
24
|
-
if (
|
|
25
|
-
!isConfigExists &&
|
|
26
|
-
fs.pathExistsSync(path.join(os.homedir(), '.ai-cmd.config.js'))
|
|
27
|
-
) {
|
|
28
|
-
fs.moveSync(path.join(os.homedir(), '.ai-cmd.config.js'), this.configPath)
|
|
29
|
-
} else if (!isConfigExists) {
|
|
30
|
-
this.writeConfig()
|
|
31
|
-
}
|
|
32
|
-
this.config = this.getConfig()
|
|
33
|
-
this.writeConfig(this.config)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
dir() {
|
|
37
|
-
openDirectory(this.configDir)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
edit() {
|
|
41
|
-
const platform = process.platform
|
|
42
|
-
|
|
43
|
-
let openCommand
|
|
44
|
-
if (process.env.EDITOR) {
|
|
45
|
-
openCommand = `${process.env.EDITOR} "${this.configPath}"`
|
|
46
|
-
} else if (platform === 'darwin') {
|
|
47
|
-
openCommand = `open -e "${this.configPath}"`
|
|
48
|
-
} else if (platform === 'win32') {
|
|
49
|
-
openCommand = `notepad "${this.configPath}"`
|
|
50
|
-
} else {
|
|
51
|
-
openCommand = `xdg-open "${this.configPath}"`
|
|
52
|
-
}
|
|
53
|
-
exec(openCommand, (error) => {
|
|
54
|
-
if (error) {
|
|
55
|
-
aiConsole.logError('Error opening configuration file:', error.message)
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// 判断config是否存在
|
|
61
|
-
checkConfigExists() {
|
|
62
|
-
return fs.pathExistsSync(this.configPath)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 重名验证
|
|
66
|
-
checkName(aiName) {
|
|
67
|
-
const existingIndex = this.config.ai.findIndex(
|
|
68
|
-
(item) => item.name === aiName,
|
|
69
|
-
)
|
|
70
|
-
return existingIndex !== -1
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
isAiListEmpty() {
|
|
74
|
-
return this.config.ai && this.config.ai.length === 0
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 添加一个aiConfig
|
|
78
|
-
addAiConfig(aiConfig) {
|
|
79
|
-
this.config.ai.push(aiConfig)
|
|
80
|
-
this.writeConfig(this.config)
|
|
81
|
-
aiConsole.logSuccess(`AI configuration "${aiConfig.name}" added successfully!`)
|
|
82
|
-
return aiConfig
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 删除一个aiConfig
|
|
86
|
-
delAiConfig(aiName) {
|
|
87
|
-
const existingIndex = this.config.ai.findIndex(
|
|
88
|
-
(item) => item.name === aiName,
|
|
89
|
-
)
|
|
90
|
-
if (existingIndex === -1) {
|
|
91
|
-
aiConsole.logError(`Configuration with name "${aiName}" not found.`)
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
const currentAi = this.config.currentAi
|
|
95
|
-
// Check if it's the current configuration
|
|
96
|
-
if (currentAi === aiName) {
|
|
97
|
-
aiConsole.logError(`Cannot delete current configuration "${aiName}".`)
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
// Remove the configuration
|
|
101
|
-
this.config.ai.splice(existingIndex, 1)
|
|
102
|
-
this.writeConfig(this.config)
|
|
103
|
-
aiConsole.logSuccess(`AI configuration "${aiName}" deleted successfully!`)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 设置当前Ai
|
|
107
|
-
setCurrentAi(aiName) {
|
|
108
|
-
// 查看列表中是否存在
|
|
109
|
-
const existingIndex = this.config.ai.findIndex(
|
|
110
|
-
(item) => item.name === aiName,
|
|
111
|
-
)
|
|
112
|
-
if (existingIndex === -1) {
|
|
113
|
-
aiConsole.logError(`Configuration with name "${aiName}" not found.`)
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
this.config.currentAi = aiName
|
|
117
|
-
this.writeConfig(this.config)
|
|
118
|
-
aiConsole.logSuccess(`Current AI configuration set to "${aiName}" successfully!`)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
getCurrentAiConfig() {
|
|
122
|
-
return this.config.ai.find((item) => item.name === this.config.currentAi)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getCurrentAi() {
|
|
126
|
-
return this.config.currentAi
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
_getAiConfig(aiName) {
|
|
130
|
-
return this.config.ai.find((item) => item.name === aiName)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
getAiConfig(aiName) {
|
|
134
|
-
return this._getAiConfig(aiName)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
updateAiConfigByName(aiName, updater) {
|
|
138
|
-
const existingIndex = this.config.ai.findIndex(
|
|
139
|
-
(item) => item.name === aiName,
|
|
140
|
-
)
|
|
141
|
-
if (existingIndex === -1) {
|
|
142
|
-
aiConsole.logError(`Configuration with name "${aiName}" not found.`)
|
|
143
|
-
return null
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const current = this.config.ai[existingIndex]
|
|
147
|
-
const next = typeof updater === 'function'
|
|
148
|
-
? updater(lodash.cloneDeep(current))
|
|
149
|
-
: lodash.merge(lodash.cloneDeep(current), updater)
|
|
150
|
-
|
|
151
|
-
this.config.ai[existingIndex] = next
|
|
152
|
-
this.writeConfig(this.config)
|
|
153
|
-
return next
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 获取Ai列表
|
|
157
|
-
getAiList() {
|
|
158
|
-
console.log('AI Configurations')
|
|
159
|
-
console.log('='.repeat(50))
|
|
160
|
-
if (this.config.ai && Array.isArray(this.config.ai)) {
|
|
161
|
-
if (this.config.ai.length === 0) {
|
|
162
|
-
aiConsole.logError('No AI configurations found.')
|
|
163
|
-
} else {
|
|
164
|
-
this.config.ai.forEach((config, index) => {
|
|
165
|
-
const isCurrent = this.config.currentAi === config.name
|
|
166
|
-
aiConsole.logInfo(`${config.name} ${isCurrent ? '(current)' : ''}`)
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
} else {
|
|
170
|
-
aiConsole.logError('No AI configurations found.')
|
|
171
|
-
}
|
|
172
|
-
console.log('='.repeat(50))
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// 重置config
|
|
176
|
-
resetConfig() {
|
|
177
|
-
console.log('Resetting configuration file:', this.configPath)
|
|
178
|
-
this.writeConfig()
|
|
179
|
-
this.config = this.getConfig()
|
|
180
|
-
aiConsole.logSuccess('Configuration file has been reset to default settings.')
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// 查看ai详情
|
|
184
|
-
viewAiConfigDetail(aiName) {
|
|
185
|
-
if (this.isAiListEmpty()) {
|
|
186
|
-
aiConsole.logError(
|
|
187
|
-
'No AI configurations found. Please add an AI configuration first.',
|
|
188
|
-
)
|
|
189
|
-
return
|
|
190
|
-
}
|
|
191
|
-
if (!aiName) {
|
|
192
|
-
aiName = this.config.currentAi
|
|
193
|
-
if (!aiName) {
|
|
194
|
-
aiConsole.logError(
|
|
195
|
-
'No current AI configuration set. Please input "ai config use <name>" to set a current configuration.',
|
|
196
|
-
)
|
|
197
|
-
return
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
const aiConfig = this._getAiConfig(aiName)
|
|
201
|
-
if (!aiConfig) {
|
|
202
|
-
aiConsole.logError(
|
|
203
|
-
'AI configuration not found. Please check the name and try again.',
|
|
204
|
-
)
|
|
205
|
-
return
|
|
206
|
-
}
|
|
207
|
-
aiConsole.logSuccess('AI Configuration Details')
|
|
208
|
-
aiConsole.logSuccess('='.repeat(50))
|
|
209
|
-
aiConsole.logInfo(`Name: ${aiConfig.name}`)
|
|
210
|
-
aiConsole.logInfo(`Type: ${aiConfig.type}`)
|
|
211
|
-
aiConsole.logInfo(`API Base URL: ${aiConfig.baseUrl}`)
|
|
212
|
-
aiConsole.logInfo(`Model: ${aiConfig.model}`)
|
|
213
|
-
if (aiConfig.apiKey) {
|
|
214
|
-
const maskPrefix = String(aiConfig.apiKey).slice(0, 6)
|
|
215
|
-
aiConsole.logInfo(`API Key: ${maskPrefix}... (masked)`)
|
|
216
|
-
}
|
|
217
|
-
aiConsole.logInfo(`Temperature: ${aiConfig.temperature}`)
|
|
218
|
-
aiConsole.logInfo(`Max Tokens: ${aiConfig.maxTokens}`)
|
|
219
|
-
aiConsole.logInfo(`Streaming Output: ${aiConfig.stream ? 'Enabled' : 'Disabled'}`)
|
|
220
|
-
aiConsole.logInfo(
|
|
221
|
-
`Is Current: ${this.config.currentAi === aiConfig.name ? 'Yes' : 'No'}`,
|
|
222
|
-
)
|
|
223
|
-
aiConsole.logInfo(`File Path: ${this.configPath}`)
|
|
224
|
-
aiConsole.logSuccess('='.repeat(50))
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// 更新扩展
|
|
228
|
-
updateExtensions(extensions) {
|
|
229
|
-
this.config.extensions = extensions
|
|
230
|
-
this.writeConfig(this.config)
|
|
231
|
-
aiConsole.logSuccess('Extensions updated successfully!')
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// 删除扩展
|
|
235
|
-
removeExtensionByIndex(extIndex) {
|
|
236
|
-
const filePath = this.config.extensions.splice(extIndex, 1)
|
|
237
|
-
this.writeConfig(this.config)
|
|
238
|
-
aiConsole.logSuccess(
|
|
239
|
-
`Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
|
|
240
|
-
)
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
removeExtensionByPath(filePath) {
|
|
244
|
-
this.config.extensions = this.config.extensions.filter(
|
|
245
|
-
(ext) => ext !== filePath,
|
|
246
|
-
)
|
|
247
|
-
this.writeConfig(this.config)
|
|
248
|
-
aiConsole.logSuccess(
|
|
249
|
-
`Extension removed from config: ${filePath}.You can run 'ai ext ls' to view the changes.`,
|
|
250
|
-
)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
getConfig() {
|
|
254
|
-
const config = require(this.configPath)
|
|
255
|
-
return lodash.merge(lodash.cloneDeep(defaultConfig), config)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
getAppConfig() {
|
|
259
|
-
const config = require(this.configPath)
|
|
260
|
-
const mergedConfig = lodash.merge(lodash.cloneDeep(defaultConfig), config)
|
|
261
|
-
if (mergedConfig.currentAi) {
|
|
262
|
-
const aiConfig = mergedConfig.ai.find(
|
|
263
|
-
(item) => item.name === mergedConfig.currentAi,
|
|
264
|
-
)
|
|
265
|
-
mergedConfig.aiConfig = aiConfig
|
|
266
|
-
}
|
|
267
|
-
return mergedConfig
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// 写入配置
|
|
271
|
-
writeConfig(config) {
|
|
272
|
-
if (!config) {
|
|
273
|
-
config = lodash.cloneDeep(defaultConfig)
|
|
274
|
-
}
|
|
275
|
-
fs.writeFileSync(
|
|
276
|
-
this.configPath,
|
|
277
|
-
`module.exports = ${JSON.stringify(config, null, 2)}`,
|
|
278
|
-
)
|
|
279
|
-
this.config = config
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
module.exports = ConfigManager
|