deepfish-ai 1.0.13 → 1.0.16

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.
@@ -0,0 +1,415 @@
1
+ /**
2
+ * @Author: Roman 306863030@qq.com
3
+ * @Date: 2026-03-17 11:59:19
4
+ * @LastEditors: roman_123 306863030@qq.com
5
+ * @LastEditTime: 2026-03-26 00:54:25
6
+ * @FilePath: \deepfish\src\core\extension\SystemExtension.js
7
+ * @Description: 默认扩展函数
8
+ * @
9
+ */
10
+ const path = require('path')
11
+ const { logError, logSuccess, logInfo, getConfigPath } = require('../utils/log')
12
+ const iconv = require('iconv-lite') // 用于编码转换
13
+ const { cloneDeep } = require('lodash')
14
+ const { aiRequestSingle } = require('../ai-services/AiWorker/AiTools')
15
+ const { spawnSync } = require('child_process')
16
+ const { detectEncoding } = require('../utils/normal')
17
+
18
+ // 执行系统命令
19
+ // 执行系统命令(全平台兼容:Windows/PowerShell/CentOS)
20
+ function executeCommand(command, timeout = -1) {
21
+ logSuccess(`Executing system command: ${command}; ${timeout > 0 ? `Timeout: ${timeout}ms` : 'No timeout limit'}`)
22
+ try {
23
+ const result = spawnSync(command, {
24
+ cwd: process.cwd(),
25
+ stdio: 'pipe',
26
+ shell: true,
27
+ encoding: 'buffer',
28
+ windowsHide: true,
29
+ argv0: 'deepfish-shell',
30
+ timeout: timeout > 0 ? timeout : undefined,
31
+ })
32
+ let targetEncoding = this.config?.encoding
33
+ if (!targetEncoding || targetEncoding === 'auto') {
34
+ targetEncoding = detectEncoding(result.stdout || result.stderr)
35
+ }
36
+ const stdout = iconv.decode(result.stdout, targetEncoding)
37
+ const stderr = iconv.decode(result.stderr, targetEncoding)
38
+ const code = result.status
39
+ if (stderr && !stderr.trim().startsWith('WARNING')) {
40
+ const error = new Error(`Command failed (code ${code}): ${stderr.trim()}`)
41
+ logError(`Execute error: ${error.message}`)
42
+ return `Execute error: ${error.message}`
43
+ }
44
+ logSuccess(`${stdout}\nCommand executed successfully`)
45
+ return stdout || 'Command executed successfully'
46
+ } catch (decodeError) {
47
+ logError(`Encoding convert error: ${decodeError.message}`)
48
+ return `Failed to parse command output: ${decodeError.message}`
49
+ }
50
+ }
51
+
52
+ // 请求ai服务
53
+ async function requestAI(
54
+ systemDescription,
55
+ prompt,
56
+ temperature = this.aiConfig.temperature,
57
+ ) {
58
+ logSuccess(`Requesting AI`)
59
+ if (
60
+ typeof systemDescription === 'object' &&
61
+ systemDescription.systemDescription
62
+ ) {
63
+ prompt = systemDescription.prompt || prompt || ''
64
+ systemDescription = systemDescription.systemDescription || ''
65
+ }
66
+ try {
67
+ logInfo(`aiSystem: ${systemDescription}`)
68
+ logInfo(`aiPrompt: ${prompt}`)
69
+ let aiConfig = this.aiConfig
70
+ if (temperature !== aiConfig.temperature) {
71
+ aiConfig = cloneDeep(aiConfig)
72
+ aiConfig.temperature = temperature
73
+ }
74
+ const response = await aiRequestSingle(
75
+ this.aiService.client,
76
+ aiConfig,
77
+ systemDescription,
78
+ prompt,
79
+ )
80
+ logInfo(`aiResponse: ${response}`)
81
+ return response
82
+ } catch (error) {
83
+ logError(`Error executing AI function: ${error.message}`)
84
+ throw error
85
+ }
86
+ }
87
+
88
+ // 执行js代码
89
+ async function executeJSCode(code) {
90
+ logSuccess('Executing JavaScript code: ')
91
+ logSuccess(code)
92
+
93
+ try {
94
+ const { functions } = this.extensionManager.extensions
95
+ const Func = new Function(
96
+ 'Tools',
97
+ 'require',
98
+ `return (async () => {
99
+ this.logMessages = []
100
+ const originalLog = console.log
101
+ const newLog = function () {
102
+ originalLog.apply(console, arguments)
103
+ this.logMessages.push(Array.from(arguments).join(' '))
104
+ }
105
+ console.log = newLog.bind(this)
106
+ ${code}
107
+ console.log = originalLog
108
+ return this.logMessages.join('\\n')
109
+ })()`,
110
+ )
111
+ const originalRequire = require
112
+ const newRequire = (modulePath) => {
113
+ if (modulePath.startsWith('./')) {
114
+ const resolvedPath = path.resolve('.', modulePath)
115
+ return originalRequire(resolvedPath)
116
+ }
117
+ return originalRequire(modulePath)
118
+ }
119
+
120
+ const result = await Func(functions, newRequire)
121
+
122
+ return result || ''
123
+ } catch (error) {
124
+ logError(`Error executing code: ${error.stack}`)
125
+ throw error
126
+ }
127
+ }
128
+ // 生成一个扩展函数文件 关键字:内置函数、扩展工具
129
+ async function getExtensionFileRule(goal) {
130
+ const newGoal = `
131
+ ### 任务目标
132
+ 基于指定规则创建一个标准化的Node.js NPM项目,实现用户目标:${goal},最终输出符合AI工作流调用规范的函数模块,并配套中英文说明文档。
133
+
134
+ ### 第一步:项目初始化
135
+ 1. 目录创建:新建目录,目录名称以"deepfish-"开头,如"deepfish-「项目功能名称」",作为NPM项目根目录
136
+ 2. package.json配置:
137
+ - name字段值:@deepfish-ai/项目功能名称(替换「项目功能名称」为实际功能名)
138
+ - git仓库地址:固定为 https://github.com/qq306863030/deepfish-extensions.git
139
+ - author设置为"DeepFish AI",
140
+ 3. 主文件:项目入口文件必须命名为index.js
141
+ 4. 文档文件:项目根目录需新增2个文档文件:
142
+ - README_CN.md(中文说明文档)
143
+ - README.md(英文说明文档)
144
+
145
+ ### 第二步:index.js 完整开发规范
146
+ #### 2.1 核心输出要求
147
+ 文件需输出四个核心字段,且代码逻辑清晰、可运行:
148
+ - name:字符串类型,扩展的名称标识
149
+ - extensionDescription:字符串类型,扩展功能的简要描述,说明该扩展提供的核心能力
150
+ - descriptions:数组类型,每个元素为OpenAI可识别的函数描述对象
151
+ - functions:对象类型,key为函数名称,value为函数方法体
152
+
153
+ #### 2.2 开发强制规则
154
+ 1. 参数一致性:functions中函数的入参,必须与descriptions中对应函数声明的parameters完全一致
155
+ 2. 命名规范:
156
+ - 函数名称前缀:「领域用途+分隔符」(如systemFileManagement_)
157
+ - 函数描述开头:统一格式「领域用途+分隔符+功能描述」(如系统文件管理:重命名文件)
158
+ 3. 内置工具函数调用:函数内部会自动注入所有内置工具函数,可以通过this.Tools获取,示例:
159
+ - this.Tools.requestAI(systemDescription, prompt, temperature)
160
+ - this.Tools.readFile(filePath)
161
+ - 其他文件处理类内置函数(运行时自动注入)
162
+ 4. 函数数量:至少包含1个可被AI工作流调用的函数
163
+ 5. 函数中的this在运行时指向DeepFish AI的运行时环境,可以通过this访问到AI配置、工具函数等资源,因此在创建扩展时需要注意this的指向
164
+ 6. 尽量保持代码思路清晰,避免过度复杂的逻辑嵌套,必要时可以适当拆分函数、添加注释说明或拆分成多个文件
165
+ 7. 需要创建的是DeepFish AI的扩展工具,并非创建Skill工具包,因此不需要编写SKILL.md文件
166
+
167
+ #### 2.3 基础代码模板(必须遵循)
168
+ const descriptions = []
169
+ const functions = {}
170
+ module.exports = {
171
+ name: '扩展名称',
172
+ extensionDescription: '扩展功能的简要描述',
173
+ descriptions,
174
+ functions,
175
+ }
176
+
177
+ #### 2.4 参考示例(可参考格式)
178
+ const descriptions = [
179
+ {
180
+ name: 'systemFileManagement_renameFile',
181
+ description: '系统文件管理:重命名文件',
182
+ parameters: {
183
+ type: 'object',
184
+ properties: {
185
+ oldPath: { type: 'string', description: '旧文件路径' },
186
+ newPath: { type: 'string', description: '新文件路径' },
187
+ },
188
+ },
189
+ },
190
+ ]
191
+ const functions = {
192
+ systemFileManagement_renameFile: (oldPath, newPath) => {
193
+ return this.Tools.rename(oldPath, newPath)
194
+ },
195
+ }
196
+ module.exports = {
197
+ name: 'systemFileManagement',
198
+ extensionDescription: '提供文件管理相关功能,包括文件重命名等操作',
199
+ descriptions,
200
+ functions,
201
+ }
202
+
203
+ ### 第三步:README文档规范
204
+ #### 3.1 通用要求
205
+ - 两个文档需在标题下方包含「中英文切换标签」(如文档顶部标注「English | 中文」/「中文 | English」)
206
+ - 结构保持一致,仅语言不同,核心模块顺序不可调整
207
+ - 文件名称README_CN.md(中文)、README.md(英文)
208
+ - 链接使用相对路径,如[中文](./README_CN.md)
209
+
210
+ #### 3.2 核心模块
211
+ 1. 总体功能描述:
212
+ - 清晰说明当前NPM包的核心定位、整体功能价值、适用场景
213
+ - 语言简洁易懂,无需技术细节,聚焦「做什么」而非「怎么做」
214
+ 2. 快速开始:
215
+ - 明确说明安装步骤,顺序不可颠倒:
216
+ ① 先安装deepfish-ai全局库:npm install deepfish-ai -g
217
+ ② 再安装当前项目库:npm install @deepfish-ai/项目功能名称 -g
218
+ 3. 函数列表及功能描述:
219
+ - 列出当前项目中所有函数名称
220
+ - 对应说明每个函数的核心功能
221
+ - 无需编写各个函数的具体使用方法
222
+ `
223
+ return newGoal
224
+ }
225
+
226
+ // 获取ai的配置
227
+ function getAiConfig() {
228
+ return cloneDeep(this.aiConfig)
229
+ }
230
+
231
+ // 获取ai的配置文件所在目录
232
+ function getAiConfigPath() {
233
+ return getConfigPath()
234
+ }
235
+
236
+ // 加载skill
237
+ function executeSkill(skillFilePath, subGoalPrompt = '') {
238
+ const skillContent = this.skillConfigManager.loadSkill(skillFilePath)
239
+ if (!subGoalPrompt) {
240
+ return skillContent
241
+ }
242
+ // 调用子工作流完成目标
243
+ return this.aiService.subSkillWorkflow(skillContent, subGoalPrompt)
244
+ }
245
+
246
+ // 了解自己
247
+ function getSelfInfo() {
248
+ // 返回自己的代码路径、package.json路径、readme路径等基本信息,供AI有选择的了解自己,回答用户的问题
249
+ const homeDir = path.resolve(__dirname, '../../../')
250
+ return {
251
+ codePath: {
252
+ description: 'DeepFish AI程序代码路径',
253
+ value: homeDir,
254
+ },
255
+ packageJsonPath: {
256
+ description: 'DeepFish AI程序package.json文件路径',
257
+ value: path.resolve(homeDir, 'package.json'),
258
+ },
259
+ readmeCNPath: {
260
+ description: 'DeepFish AI程序中文文档路径',
261
+ value: path.resolve(homeDir, 'README_CN.md'),
262
+ },
263
+ readmeENPath: {
264
+ description: 'DeepFish AI程序英文文档路径',
265
+ value: path.resolve(homeDir, 'README.md'),
266
+ },
267
+ version: {
268
+ description: 'DeepFish AI程序版本',
269
+ value: "v" + require(path.resolve(homeDir, 'package.json')).version,
270
+ }
271
+ }
272
+ }
273
+
274
+ const descriptions = [
275
+ {
276
+ type: 'function',
277
+ function: {
278
+ name: 'executeCommand',
279
+ description:
280
+ '执行系统命令,返回执行结果。适用于运行shell命令、系统工具等。command为需要执行的系统命令字符串,如"ls -l"; timeout为命令执行的超时时间,单位为毫秒,-1表示不限制超时时间, 默认值为-1。注意:如果执行多条命令,且需要保持会话,使用命令链的方式执行。命令执行失败时会抛出错误,成功时返回命令执行结果字符串或"System command executed successfully"。',
281
+ parameters: {
282
+ type: 'object',
283
+ properties: {
284
+ command: { type: 'string' },
285
+ timeout: { type: 'number' },
286
+ },
287
+ required: ['command'],
288
+ },
289
+ },
290
+ },
291
+ {
292
+ type: 'function',
293
+ function: {
294
+ name: 'requestAI',
295
+ description:
296
+ '请求AI服务处理简单任务,如随机生成一段话、翻译文本、数学计算、代码分析、知识检索等。通过systemDescription参数指定AI的行为和限制,prompt参数输入任务描述, temperature参数指定AI的温度(0-2之间的浮点数,默认为用户配置)。返回AI处理后的结果字符串,执行失败时会抛出错误。',
297
+ parameters: {
298
+ type: 'object',
299
+ properties: {
300
+ systemDescription: { type: 'string' },
301
+ prompt: { type: 'string' },
302
+ temperature: { type: 'number' },
303
+ },
304
+ required: ['systemDescription', 'prompt'],
305
+ },
306
+ },
307
+ },
308
+ {
309
+ type: 'function',
310
+ function: {
311
+ name: 'executeJSCode',
312
+ description:
313
+ '执行JavaScript代码,返回代码执行结果。代码中可通过Tools命名空间直接调用其他工具函数(如await Tools.createFile(),注意:不需要使用require引入),Tools中引入了一些常用库可直接调用(Tools.fs="fs-extra", Tools.dayjs="dayjs", Tools.axios="axios", Tools.lodash="lodash"),支持引入自定义模块(需使用绝对路径)。注意:1.代码中不要使用__dirname获取当前目录,请使用path.resolve(".")来获取当前目录。2.执行失败时会抛出错误,成功时返回代码执行结果或空字符串。',
314
+ parameters: {
315
+ type: 'object',
316
+ properties: {
317
+ code: { type: 'string' },
318
+ },
319
+ required: ['code'],
320
+ },
321
+ },
322
+ },
323
+
324
+ {
325
+ type: 'function',
326
+ function: {
327
+ name: 'getExtensionFileRule',
328
+ description:
329
+ '如果用户需要为本程序ai工作流生成一个或多个工具函数作为一个工作流执行过程中调用的扩展工具,则需要先调用此函数获取生成扩展文件的规则;示例:生成一个扩展工具: 能够产生一个随机数的函数;',
330
+ parameters: {
331
+ type: 'object',
332
+ properties: {
333
+ goal: { type: 'string' },
334
+ },
335
+ required: ['goal'],
336
+ },
337
+ },
338
+ },
339
+ {
340
+ type: 'function',
341
+ function: {
342
+ name: 'getAiConfig',
343
+ description: '获取ai请求接口的配置参数',
344
+ parameters: {
345
+ type: 'object',
346
+ properties: {},
347
+ required: [],
348
+ },
349
+ },
350
+ },
351
+ {
352
+ type: 'function',
353
+ function: {
354
+ name: 'getAiConfigPath',
355
+ description: '获取ai请求接口配置的文件地址',
356
+ parameters: {
357
+ type: 'object',
358
+ properties: {},
359
+ required: [],
360
+ },
361
+ },
362
+ },
363
+ {
364
+ type: 'function',
365
+ function: {
366
+ name: 'executeSkill',
367
+ description:
368
+ '加载并执行指定路径的skill,以该skill提供的工具函数为基础,启动子工作流完成目标任务。skillFilePath为SKILL.md文件的绝对路径,subGoalPrompt为子工作流需要完成的目标描述,留空则仅加载skill不执行子任务。',
369
+ parameters: {
370
+ type: 'object',
371
+ properties: {
372
+ skillFilePath: {
373
+ type: 'string',
374
+ description: 'SKILL.md文件的绝对路径',
375
+ },
376
+ subGoalPrompt: {
377
+ type: 'string',
378
+ description: '子工作流需要完成的目标描述,留空则仅加载skill',
379
+ },
380
+ },
381
+ required: ['skillFilePath'],
382
+ },
383
+ },
384
+ },
385
+ {
386
+ type: 'function',
387
+ function: {
388
+ name: 'getSelfInfo',
389
+ description:
390
+ '获取DeepFish AI程序的基本信息、命令行等,供AI有选择的了解自己,回答用户的问题。',
391
+ parameters: {
392
+ type: 'object',
393
+ properties: {},
394
+ required: [],
395
+ },
396
+ }
397
+ }
398
+ ]
399
+ const functions = {
400
+ executeCommand,
401
+ requestAI,
402
+ executeJSCode,
403
+ getExtensionFileRule,
404
+ getAiConfig,
405
+ getAiConfigPath,
406
+ executeSkill,
407
+ getSelfInfo,
408
+ }
409
+
410
+ module.exports = {
411
+ name: 'SystemExtension',
412
+ extensionDescription: "提供系统命令执行、AI请求、JS代码执行、扩展文件生成规则、AI配置管理、Skill加载执行等核心系统功能",
413
+ descriptions,
414
+ functions,
415
+ }
@@ -0,0 +1,67 @@
1
+ // 执行测试任务
2
+ function executeTestTask(subGoalPrompt = "") {
3
+ // 调用子工作流完成目标
4
+ return this.aiService.subTestWorkflow(subGoalPrompt)
5
+ }
6
+
7
+ // 生成测试任务
8
+ function generateTestTaskRule(goal) {
9
+ return `
10
+ 用户测试任务:${goal}。
11
+ 请在当前目录下生成一个Markdown格式的程序功能测试说明文档,文档标题固定为“xxx测试任务”(其中“xxx”替换为具体的程序功能测试任务名称,需与我提供的程序功能测试目标完全一致)。生成文档前,请先仔细研读我给出的程序功能测试任务目标,明确程序待测试的功能模块、核心测试需求、测试范围及测试重点,精准理解每个功能的预期表现,确保完全掌握测试任务要求后再进行文档撰写。
12
+
13
+ 文档核心内容需围绕程序功能测试任务目标,针对程序的每个待测试功能,制定**可逐条执行、无歧义、覆盖全面**的功能测试用例,每个测试用例需明确对应程序功能模块、具体测试场景、详细测试步骤(步骤需具体可操作,可直接供测试人员执行,明确操作路径、输入数据、操作顺序,避免模糊表述);同时,为每个测试用例对应明确、可验证的测试期望结果,期望结果需与测试步骤一一对应,清晰界定程序功能正常运行的标准,明确功能执行后应呈现的具体效果、输出结果或状态,无模糊不清的表述。
14
+
15
+ 补充要求:1. 测试用例需按程序功能模块分类、按测试优先级排序,每个测试用例标注唯一编号,便于区分、执行和追溯;2. 文档格式需符合Markdown规范,标题层级清晰(文档标题为一级标题,功能模块分组用二级标题,测试用例用三级标题或有序列表),排版整洁,便于阅读、编辑和后续维护;3. 严格贴合程序功能测试任务目标,聚焦程序功能的正确性、完整性,不添加无关内容,不遗漏核心功能测试场景,不规避边界场景,确保测试用例的针对性、完整性和有效性,能充分验证程序各功能是否符合预期。
16
+ `}
17
+
18
+ const descriptions = [
19
+ {
20
+ type: "function",
21
+ function: {
22
+ name: "generateTestTaskRule",
23
+ description:
24
+ "根据用户提供的程序功能测试目标,生成一份标准化的Markdown格式功能测试说明文档的规则提示词。返回的提示词将指导AI生成包含完整测试用例(测试步骤、期望结果、用例编号)的测试文档。适用于用户需要对程序进行功能测试等场景。",
25
+ parameters: {
26
+ type: "object",
27
+ properties: {
28
+ goal: {
29
+ type: "string",
30
+ description: "程序功能测试目标描述,需明确待测试的功能模块、测试范围和测试重点",
31
+ },
32
+ },
33
+ required: ["goal"],
34
+ },
35
+ },
36
+ },
37
+ {
38
+ type: "function",
39
+ function: {
40
+ name: "executeTestTask",
41
+ description:
42
+ "执行测试任务,启动一个专用的AI子工作流来完成指定的某一项测试目标。子工作流将根据测试任务描述,自动执行测试步骤并验证测试结果。适用于需要AI自动化执行功能测试的场景。",
43
+ parameters: {
44
+ type: "object",
45
+ properties: {
46
+ subGoalPrompt: {
47
+ type: "string",
48
+ description: "测试子工作流需要完成的目标描述,描述具体的测试任务内容",
49
+ },
50
+ },
51
+ required: ["subGoalPrompt"],
52
+ },
53
+ },
54
+ },
55
+ ];
56
+
57
+ const functions = {
58
+ executeTestTask,
59
+ generateTestTaskRule,
60
+ };
61
+
62
+ module.exports = {
63
+ name: 'TestExtension',
64
+ extensionDescription: "提供程序功能测试任务的生成和执行功能,支持自动化测试工作流",
65
+ descriptions,
66
+ functions,
67
+ };
@@ -15,6 +15,14 @@ function logError(message) {
15
15
  log(message, '#ed7f7f')
16
16
  }
17
17
 
18
+ function logWarning(message) {
19
+ log(message, '#f2c94c')
20
+ }
21
+
22
+ function logDisabled(message) {
23
+ log(message, '#999999')
24
+ }
25
+
18
26
  function writeLine(msg1, msg2 = '', color = 'blue') {
19
27
  if (color === 'blue') {
20
28
  process.stdout.write('\r' + chalk.hex('#6dd2ea')(msg1) + ' ' + msg2)
@@ -134,6 +142,8 @@ module.exports = {
134
142
  logInfo,
135
143
  logSuccess,
136
144
  logError,
145
+ logWarning,
146
+ logDisabled,
137
147
  loading,
138
148
  writeLine,
139
149
  streamOutput,
@@ -1,3 +1,9 @@
1
+ const path = require('path')
2
+ const fs = require('fs-extra')
3
+ const chardet = require('chardet')
4
+ const os = require('os') // 用于判断系统类型
5
+ const { logError } = require('./log')
6
+
1
7
  // 对象字符串转对象
2
8
  function objStrToObj(str) {
3
9
  try {
@@ -15,7 +21,87 @@ function delay(ms) {
15
21
  return new Promise((resolve) => setTimeout(resolve, ms))
16
22
  }
17
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 { spawn } = require('child_process')
60
+ const platform = process.platform
61
+ let command
62
+ let args
63
+ const dir = dirPath
64
+ if (platform === 'darwin') {
65
+ command = 'open'
66
+ args = [dir]
67
+ } else if (platform === 'win32') {
68
+ command = 'explorer.exe'
69
+ args = [dir]
70
+ } else {
71
+ command = 'xdg-open'
72
+ args = [dir]
73
+ }
74
+ const child = spawn(command, args, {
75
+ detached: true,
76
+ stdio: 'ignore',
77
+ })
78
+ child.on('error', (error) => {
79
+ logError(`Error opening directory "${dirPath}": ${error.message}`)
80
+ })
81
+ child.unref()
82
+ }
83
+
84
+ // 判断编码类型
85
+ function detectEncoding(buffer) {
86
+ if (!buffer) {
87
+ const platform = os.platform()
88
+ return platform === 'win32' ? 'gbk' : 'utf-8'
89
+ }
90
+ const encoding = chardet.detect(buffer)
91
+ if (encoding?.toLowerCase() === 'utf-8') {
92
+ return 'utf-8'
93
+ } else if (['gbk', 'gb2312', 'gb18030'].includes(encoding?.toLowerCase())) {
94
+ return 'gbk'
95
+ } else {
96
+ const platform = os.platform()
97
+ return platform === 'win32' ? 'gbk' : 'utf-8'
98
+ }
99
+ }
100
+
18
101
  module.exports = {
19
102
  objStrToObj,
20
103
  delay,
104
+ traverseFiles,
105
+ openDirectory,
106
+ detectEncoding,
21
107
  }
@@ -1,90 +0,0 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
-
4
- const defaultConfig = {
5
- ai: [],
6
- currentAi: "",
7
- maxIterations: -1, // ai完成工作流的最大迭代次数
8
- maxMessagesLength: 50000, // 最大压缩长度
9
- maxMessagesCount: 40, // 最大压缩数量
10
- extensions: [],
11
- isRecordHistory: false, // 是否创建工作流执行记录文件,用于因意外终止恢复工作流
12
- isLog: false, // 是否创建工作流执行日志
13
- };
14
-
15
- const aiCliConfig = {
16
- DeepSeek: {
17
- baseUrl: "https://api.deepseek.com",
18
- model: {
19
- list: ["deepseek-chat", "deepseek-reasoner", "other"],
20
- defaultValue: "",
21
- },
22
- type: 'deepseek',
23
- apiKey: "",
24
- temperature: 0.7,
25
- maxTokens: 8192,
26
- stream: true,
27
- },
28
- Ollama: {
29
- baseUrl: "http://localhost:11434/v1",
30
- model: {
31
- list: [],
32
- defaultValue: "deepseek-v3.2:cloud",
33
- },
34
- type: 'ollama',
35
- apiKey: "ollama",
36
- temperature: 0.7,
37
- maxTokens: 8192,
38
- stream: true,
39
- },
40
- OpenAI: {
41
- baseUrl: "https://api.openai.com/v1",
42
- model: {
43
- list: [],
44
- defaultValue: "gpt-4",
45
- },
46
- type: "openai",
47
- apiKey: "",
48
- temperature: 0.7,
49
- maxTokens: 8192,
50
- stream: true,
51
- },
52
- };
53
-
54
- // 遍历目录和子目录下所有文件
55
- function traverseFiles() {
56
- try {
57
- const currentDir = process.cwd();
58
- const allFiles = [];
59
- const currentItems = fs.readdirSync(currentDir, { withFileTypes: true });
60
- for (const item of currentItems) {
61
- const itemPath = path.join(currentDir, item.name);
62
- if (item.isFile()) {
63
- allFiles.push(itemPath);
64
- continue;
65
- }
66
- if (item.isDirectory()) {
67
- try {
68
- const subItems = fs.readdirSync(itemPath, { withFileTypes: true });
69
- for (const subItem of subItems) {
70
- if (subItem.isFile()) {
71
- allFiles.push(path.join(itemPath, subItem.name));
72
- }
73
- }
74
- } catch (subErr) {
75
- console.warn(`读取子目录失败 ${itemPath}:${subErr.message}`);
76
- }
77
- }
78
- }
79
- return allFiles;
80
- } catch (err) {
81
- console.error(`遍历目录失败:${err.message}`);
82
- return [];
83
- }
84
- }
85
-
86
- module.exports = {
87
- aiCliConfig,
88
- defaultConfig,
89
- traverseFiles
90
- };