deepfish-ai 1.0.17 → 1.0.18

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 CHANGED
@@ -10,13 +10,13 @@
10
10
  alt="WeChat"
11
11
  src="https://img.shields.io/badge/WeChat-MrRoman_123-green.svg"
12
12
  />
13
- <a href="https://github.com/qq306863030/deepfish">
13
+ <a href="https://github.com/qq306863030/deepfish-ai">
14
14
  <img
15
15
  alt="GitHub"
16
- src="https://img.shields.io/badge/GitHub-DeepFish-blue.svg"
16
+ src="https://img.shields.io/badge/GitHub-DeepFish AI-blue.svg"
17
17
  /></a>
18
- <a href="https://www.npmjs.com/package/deepfish">
19
- <img alt="NPM" src="https://img.shields.io/badge/NPM-DeepFish-blue.svg"
18
+ <a href="https://www.npmjs.com/package/deepfish-ai">
19
+ <img alt="NPM" src="https://img.shields.io/badge/NPM-DeepFish AI-blue.svg"
20
20
  /></a>
21
21
  <img
22
22
  alt="Code License"
@@ -289,6 +289,9 @@ ai "Classify all files under the 'model' directory into the 'model2' directory b
289
289
  ```bash
290
290
  ai "Create a task list: 1.xxxx; 2.xxxx; ..."
291
291
  ai "Execute task list" # Start execution
292
+
293
+ ai "I want to implement an extension tool for long-form novel writing that supports large-scale writing, maintains contextual logic coherence, and avoids AI context explosion issues. This extension tool may be a bit complex to implement. You need to carefully read the extension tool generation rules first, then create a task list"
294
+ ai "Execute task list" # Start execution
292
295
  ```
293
296
 
294
297
  ## 6. Extension Development
package/README_CN.md CHANGED
@@ -10,13 +10,13 @@
10
10
  alt="WeChat"
11
11
  src="https://img.shields.io/badge/WeChat-MrRoman_123-green.svg"
12
12
  />
13
- <a href="https://github.com/qq306863030/deepfish">
13
+ <a href="https://github.com/qq306863030/deepfish-ai">
14
14
  <img
15
15
  alt="GitHub"
16
- src="https://img.shields.io/badge/GitHub-DeepFish-blue.svg"
16
+ src="https://img.shields.io/badge/GitHub-DeepFish AI-blue.svg"
17
17
  /></a>
18
- <a href="https://www.npmjs.com/package/deepfish">
19
- <img alt="NPM" src="https://img.shields.io/badge/NPM-DeepFish-blue.svg"
18
+ <a href="https://www.npmjs.com/package/deepfish-ai">
19
+ <img alt="NPM" src="https://img.shields.io/badge/NPM-DeepFish AI-blue.svg"
20
20
  /></a>
21
21
  <img
22
22
  alt="Code License"
@@ -287,6 +287,9 @@ ai "将model目录下的所有文件按月份分类到model2目录中,日期
287
287
  ```bash
288
288
  ai "创建一个任务列表,1.xxxx;2.xxxx;..."
289
289
  ai "执行任务列表" # 开始执行
290
+
291
+ ai "我要实现一个用于长篇小说创作的扩展工具,支持大篇幅写作,保持上下文逻辑连贯,避免AI上下文爆炸问题。这个扩展工具实现起来可能有点复杂,你需要先仔细阅读扩展工具生成规则,然后创建一个任务列表"
292
+ ai "执行任务列表" # 开始执行
290
293
  ```
291
294
 
292
295
  ## 6. 扩展开发
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepfish-ai",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
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": {
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-23 15:23:42
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-26 10:34:01
5
+ * @LastEditTime: 2026-03-27 10:30:40
6
6
  * @FilePath: \deepfish\src\cli\SkillConfigManager.js
7
7
  * @Description: Skill configuration manager
8
8
  */
@@ -46,7 +46,7 @@ class SkillConfigManager {
46
46
  preLoadSkills() {
47
47
  const skills = this.configManager.config.skills.filter((skill) => skill.enable)
48
48
  if (skills.length === 0) {
49
- return ''
49
+ return '### 暂无可以使用的Skill'
50
50
  }
51
51
  const table = skills
52
52
  .map((s) => `| ${s.name} | ${s.description} | ${s.location} | ${s.skillFilePath} |`)
@@ -268,7 +268,10 @@ ${table}
268
268
  return
269
269
  }
270
270
  const { skill, index } = skillObj
271
- const skillPath = skill.location
271
+ let skillPath = skill.location
272
+ if (!skillPath) {
273
+ skillPath = path.join(this.skillDir, skill.skillDirName)
274
+ }
272
275
  userConfig.skills = userConfig.skills.filter((_, i) => i !== index)
273
276
  this.configManager.writeConfig(userConfig)
274
277
  if (fs.existsSync(skillPath)) {
@@ -4,7 +4,7 @@ const { GlobalVariable } = require("../../globalVariable")
4
4
  * @Author: Roman 306863030@qq.com
5
5
  * @Date: 2026-03-17 09:12:22
6
6
  * @LastEditors: Roman 306863030@qq.com
7
- * @LastEditTime: 2026-03-26 16:56:47
7
+ * @LastEditTime: 2026-03-27 10:32:06
8
8
  * @FilePath: \deepfish\src\core\ai-services\AiWorker\AiPrompt.js
9
9
  * @Description: AI请求提示词
10
10
  * @
@@ -22,7 +22,10 @@ const AiAgentSystemPrompt = () => {
22
22
  语言类型: 与用户输入语言一致
23
23
 
24
24
  ### 工具使用规则
25
- 系统中内置了一些可以直接调用的工具函数,如可调用 executeJSCode 运行 Node.js 代码处理复杂逻辑;可调用 executeCommand 运行系统命令行工具(如 git、npm 等),工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
25
+ 1.系统中有两种工具可以调用:一种是系统内置的工具函数(扩展工具),另一种是Skill工具包。优先使用系统内置工具函数,只有在系统内置工具函数无法满足需求时才使用Skill工具包。
26
+ 2.创建工具函数时,需要先调用generateExtensionRule函数查看生成规则
27
+ 3.创建Skill工具包时,需要先调用generateSkillPackageRule函数查看生成规则
28
+ 4.工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
26
29
 
27
30
  ### 大文本文件处理规则(分步执行)
28
31
  处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
@@ -109,7 +112,10 @@ const TaskAiAgentSystemPrompt = () => {
109
112
  语言类型: 与用户输入语言一致
110
113
 
111
114
  ### 工具使用规则
112
- 系统中内置了一些可以直接调用的工具函数,如可调用 executeJSCode 运行 Node.js 代码处理复杂逻辑;可调用 executeCommand 运行系统命令行工具(如 git、npm 等),工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
115
+ 1.系统中有两种工具可以调用:一种是系统内置的工具函数(扩展工具),另一种是Skill工具包。优先使用系统内置工具函数,只有在系统内置工具函数无法满足需求时才使用Skill工具包。
116
+ 2.创建工具函数时,需要先调用generateExtensionRule函数查看生成规则
117
+ 3.创建Skill工具包时,需要先调用generateSkillPackageRule函数查看生成规则
118
+ 4.工具调用需确保语法/指令符合当前操作系统规范(Windows/macOS/Linux 区分)。
113
119
 
114
120
  ### 大文本文件处理规则(分步执行)
115
121
  处理长文档等大文件(单文件>${maxBlockFileSize}KB)时,必须按以下步骤分块处理:
@@ -2,7 +2,7 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-17 11:59:19
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-26 18:49:38
5
+ * @LastEditTime: 2026-03-27 10:33:37
6
6
  * @FilePath: \deepfish\src\core\extension\ExtensionManager.js
7
7
  * @Description: 扩展函数管理
8
8
  * @
@@ -12,6 +12,7 @@ const SystemExtension = require('./SystemExtension')
12
12
  const FileExtension = require('./FileExtension')
13
13
  const InquirerExtension = require('./InquirerExtension')
14
14
  const TestExtension = require('./TestExtension')
15
+ const GenerateExtension = require('./GenerateExtension')
15
16
  const path = require('path')
16
17
  const fs = require('fs-extra')
17
18
  const axios = require('axios')
@@ -39,6 +40,7 @@ class ExtensionManager {
39
40
  InquirerExtension.descriptions,
40
41
  TestExtension.descriptions,
41
42
  TaskExtension.descriptions,
43
+ GenerateExtension.descriptions,
42
44
  BaseExtension.descriptions,
43
45
  )
44
46
  this.extensions.functions = Object.assign(
@@ -48,6 +50,8 @@ class ExtensionManager {
48
50
  InquirerExtension.functions,
49
51
  TestExtension.functions,
50
52
  TaskExtension.functions,
53
+ GenerateExtension.functions,
54
+ BaseExtension.functions,
51
55
  )
52
56
  }
53
57
 
@@ -2,159 +2,159 @@
2
2
  * @Author: Roman 306863030@qq.com
3
3
  * @Date: 2026-03-17 11:59:19
4
4
  * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-03-20 16:52:45
5
+ * @LastEditTime: 2026-03-27 13:12:59
6
6
  * @FilePath: \deepfish\src\core\extension\FileExtension.js
7
7
  * @Description: 文件处理扩展函数
8
8
  * @
9
9
  */
10
- const path = require("path");
11
- const fs = require("fs-extra");
10
+ const path = require('path')
11
+ const fs = require('fs-extra')
12
12
 
13
13
  async function createFile(filePath, content) {
14
14
  try {
15
- const fullPath = path.resolve(process.cwd(), filePath);
16
- const dirPath = path.dirname(fullPath);
15
+ const fullPath = path.resolve(process.cwd(), filePath)
16
+ const dirPath = path.dirname(fullPath)
17
17
 
18
18
  if (!fs.existsSync(dirPath)) {
19
- fs.mkdirSync(dirPath, { recursive: true });
19
+ fs.mkdirSync(dirPath, { recursive: true })
20
20
  }
21
- fs.writeFileSync(fullPath, content);
22
- return true;
21
+ fs.writeFileSync(fullPath, content)
22
+ return true
23
23
  } catch (error) {
24
- return false;
24
+ return false
25
25
  }
26
26
  }
27
27
 
28
28
  async function modifyFile(filePath, content) {
29
29
  try {
30
- const fullPath = path.resolve(process.cwd(), filePath);
30
+ const fullPath = path.resolve(process.cwd(), filePath)
31
31
 
32
32
  if (!fs.existsSync(fullPath)) {
33
- return false;
33
+ return false
34
34
  }
35
35
 
36
- fs.writeFileSync(fullPath, content);
37
- return true;
36
+ fs.writeFileSync(fullPath, content)
37
+ return true
38
38
  } catch (error) {
39
- return false;
39
+ return false
40
40
  }
41
41
  }
42
42
 
43
43
  async function readFile(filePath) {
44
44
  try {
45
- const fullPath = path.resolve(process.cwd(), filePath);
45
+ const fullPath = path.resolve(process.cwd(), filePath)
46
46
 
47
47
  if (!fs.existsSync(fullPath)) {
48
- return null;
48
+ return null
49
49
  }
50
50
 
51
- const content = fs.readFileSync(fullPath, "utf8");
52
- return content;
51
+ const content = fs.readFileSync(fullPath, 'utf8')
52
+ return content
53
53
  } catch (error) {
54
- return null;
54
+ return null
55
55
  }
56
56
  }
57
57
 
58
58
  async function appendToFile(filePath, content) {
59
59
  try {
60
- const fullPath = path.resolve(process.cwd(), filePath);
60
+ const fullPath = path.resolve(process.cwd(), filePath)
61
61
 
62
62
  if (!fs.existsSync(fullPath)) {
63
- return false;
63
+ return false
64
64
  }
65
65
 
66
- fs.appendFileSync(fullPath, content);
67
- return true;
66
+ fs.appendFileSync(fullPath, content)
67
+ return true
68
68
  } catch (error) {
69
- return false;
69
+ return false
70
70
  }
71
71
  }
72
72
 
73
73
  function fileExists(filePath) {
74
- const fullPath = path.resolve(process.cwd(), filePath);
75
- return fs.existsSync(fullPath);
74
+ const fullPath = path.resolve(process.cwd(), filePath)
75
+ return fs.existsSync(fullPath)
76
76
  }
77
77
 
78
78
  async function createDirectory(dirPath) {
79
79
  try {
80
- const fullPath = path.resolve(process.cwd(), dirPath);
80
+ const fullPath = path.resolve(process.cwd(), dirPath)
81
81
  if (!fs.existsSync(fullPath)) {
82
- fs.mkdirSync(fullPath, { recursive: true });
82
+ fs.mkdirSync(fullPath, { recursive: true })
83
83
  }
84
- return true;
84
+ return true
85
85
  } catch (error) {
86
- return false;
86
+ return false
87
87
  }
88
88
  }
89
89
 
90
90
  async function deleteFile(filePath) {
91
91
  try {
92
- const fullPath = path.resolve(process.cwd(), filePath);
92
+ const fullPath = path.resolve(process.cwd(), filePath)
93
93
 
94
94
  if (fs.existsSync(fullPath)) {
95
- fs.unlinkSync(fullPath);
95
+ fs.unlinkSync(fullPath)
96
96
  }
97
- return true;
97
+ return true
98
98
  } catch (error) {
99
- return false;
99
+ return false
100
100
  }
101
101
  }
102
102
 
103
103
  async function deleteDirectory(dirPath) {
104
104
  try {
105
- const fullPath = path.resolve(process.cwd(), dirPath);
105
+ const fullPath = path.resolve(process.cwd(), dirPath)
106
106
 
107
107
  if (fs.existsSync(fullPath)) {
108
- fs.rmSync(fullPath, { recursive: true, force: true });
108
+ fs.rmSync(fullPath, { recursive: true, force: true })
109
109
  }
110
- return true;
110
+ return true
111
111
  } catch (error) {
112
- return false;
112
+ return false
113
113
  }
114
114
  }
115
115
 
116
116
  async function rename(oldPath, newPath) {
117
117
  try {
118
- const fullOldPath = path.resolve(process.cwd(), oldPath);
119
- const fullNewPath = path.resolve(process.cwd(), newPath);
118
+ const fullOldPath = path.resolve(process.cwd(), oldPath)
119
+ const fullNewPath = path.resolve(process.cwd(), newPath)
120
120
 
121
121
  if (fs.existsSync(fullOldPath)) {
122
- fs.renameSync(fullOldPath, fullNewPath);
122
+ fs.renameSync(fullOldPath, fullNewPath)
123
123
  }
124
- return true;
124
+ return true
125
125
  } catch (error) {
126
- return false;
126
+ return false
127
127
  }
128
128
  }
129
129
 
130
130
  async function moveFile(sourcePath, destinationPath) {
131
131
  try {
132
- const fullSourcePath = path.resolve(process.cwd(), sourcePath);
133
- const fullDestPath = path.resolve(process.cwd(), destinationPath);
134
- const destDirPath = path.dirname(fullDestPath);
132
+ const fullSourcePath = path.resolve(process.cwd(), sourcePath)
133
+ const fullDestPath = path.resolve(process.cwd(), destinationPath)
134
+ const destDirPath = path.dirname(fullDestPath)
135
135
 
136
136
  if (!fs.existsSync(destDirPath)) {
137
- fs.mkdirSync(destDirPath, { recursive: true });
137
+ fs.mkdirSync(destDirPath, { recursive: true })
138
138
  }
139
139
 
140
140
  if (fs.existsSync(fullSourcePath)) {
141
- fs.renameSync(fullSourcePath, fullDestPath);
141
+ fs.renameSync(fullSourcePath, fullDestPath)
142
142
  }
143
- return true;
143
+ return true
144
144
  } catch (error) {
145
- return false;
145
+ return false
146
146
  }
147
147
  }
148
148
 
149
149
  async function getFileInfo(filePath) {
150
150
  try {
151
- const fullPath = path.resolve(process.cwd(), filePath);
151
+ const fullPath = path.resolve(process.cwd(), filePath)
152
152
 
153
153
  if (!fs.existsSync(fullPath)) {
154
- return null;
154
+ return null
155
155
  }
156
156
 
157
- const stats = fs.statSync(fullPath);
157
+ const stats = fs.statSync(fullPath)
158
158
  return {
159
159
  path: fullPath,
160
160
  size: stats.size,
@@ -163,257 +163,255 @@ async function getFileInfo(filePath) {
163
163
  ctime: stats.ctime,
164
164
  isFile: stats.isFile(),
165
165
  isDirectory: stats.isDirectory(),
166
- };
166
+ }
167
167
  } catch (error) {
168
- return null;
168
+ return null
169
169
  }
170
170
  }
171
171
 
172
172
  async function getFileNameList(dirPath) {
173
173
  try {
174
- const fullPath = path.resolve(process.cwd(), dirPath);
174
+ const fullPath = path.resolve(process.cwd(), dirPath)
175
175
  if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isDirectory()) {
176
- return [];
176
+ return []
177
177
  }
178
- const files = fs
179
- .readdirSync(fullPath)
180
- .filter((file) => file !== "ai-history" && file !== "ai-log");
181
- return files;
178
+ const files = fs.readdirSync(fullPath)
179
+ return files
182
180
  } catch (error) {
183
- return [];
181
+ return []
184
182
  }
185
183
  }
186
184
 
187
185
  async function clearDirectory(dirPath) {
188
186
  try {
189
- const fullPath = path.resolve(process.cwd(), dirPath);
187
+ const fullPath = path.resolve(process.cwd(), dirPath)
190
188
 
191
189
  if (!fs.existsSync(fullPath)) {
192
- return false;
190
+ return false
193
191
  }
194
192
 
195
193
  if (!fs.statSync(fullPath).isDirectory()) {
196
- return false;
194
+ return false
197
195
  }
198
196
 
199
- const files = fs.readdirSync(fullPath);
197
+ const files = fs.readdirSync(fullPath)
200
198
 
201
199
  for (const file of files) {
202
- const filePath = path.join(fullPath, file);
200
+ const filePath = path.join(fullPath, file)
203
201
  if (fs.statSync(filePath).isDirectory()) {
204
- fs.rmSync(filePath, { recursive: true, force: true });
202
+ fs.rmSync(filePath, { recursive: true, force: true })
205
203
  } else {
206
- fs.unlinkSync(filePath);
204
+ fs.unlinkSync(filePath)
207
205
  }
208
206
  }
209
207
 
210
- return true;
208
+ return true
211
209
  } catch (error) {
212
- return false;
210
+ return false
213
211
  }
214
212
  }
215
213
 
216
214
  const descriptions = [
217
215
  {
218
- type: "function",
216
+ type: 'function',
219
217
  function: {
220
- name: "createFile",
218
+ name: 'createFile',
221
219
  description:
222
- "创建一个包含指定内容的新文件,返回布尔值表示操作是否成功。如果目录不存在会自动创建目录结构。",
220
+ '创建一个包含指定内容的新文件,返回布尔值表示操作是否成功。如果目录不存在会自动创建目录结构。',
223
221
  parameters: {
224
- type: "object",
222
+ type: 'object',
225
223
  properties: {
226
- filePath: { type: "string" },
227
- content: { type: "string" },
224
+ filePath: { type: 'string' },
225
+ content: { type: 'string' },
228
226
  },
229
- required: ["filePath", "content"],
227
+ required: ['filePath', 'content'],
230
228
  },
231
229
  },
232
230
  },
233
231
  {
234
- type: "function",
232
+ type: 'function',
235
233
  function: {
236
- name: "modifyFile",
234
+ name: 'modifyFile',
237
235
  description:
238
- "修改指定文件的内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。",
236
+ '修改指定文件的内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。',
239
237
  parameters: {
240
- type: "object",
238
+ type: 'object',
241
239
  properties: {
242
- filePath: { type: "string" },
243
- content: { type: "string" },
240
+ filePath: { type: 'string' },
241
+ content: { type: 'string' },
244
242
  },
245
- required: ["filePath", "content"],
243
+ required: ['filePath', 'content'],
246
244
  },
247
245
  },
248
246
  },
249
247
  {
250
- type: "function",
248
+ type: 'function',
251
249
  function: {
252
- name: "readFile",
250
+ name: 'readFile',
253
251
  description:
254
- "读取指定文件的内容,返回文件内容字符串。如果文件不存在或读取失败则返回null。",
252
+ '读取指定文件的内容,返回文件内容字符串。如果文件不存在或读取失败则返回null。',
255
253
  parameters: {
256
- type: "object",
254
+ type: 'object',
257
255
  properties: {
258
- filePath: { type: "string" },
256
+ filePath: { type: 'string' },
259
257
  },
260
- required: ["filePath"],
258
+ required: ['filePath'],
261
259
  },
262
260
  },
263
261
  },
264
262
  {
265
- type: "function",
263
+ type: 'function',
266
264
  function: {
267
- name: "appendToFile",
265
+ name: 'appendToFile',
268
266
  description:
269
- "向指定文件追加内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。",
267
+ '向指定文件追加内容,返回布尔值表示操作是否成功。如果文件不存在则返回false。',
270
268
  parameters: {
271
- type: "object",
269
+ type: 'object',
272
270
  properties: {
273
- filePath: { type: "string" },
274
- content: { type: "string" },
271
+ filePath: { type: 'string' },
272
+ content: { type: 'string' },
275
273
  },
276
- required: ["filePath", "content"],
274
+ required: ['filePath', 'content'],
277
275
  },
278
276
  },
279
277
  },
280
278
  {
281
- type: "function",
279
+ type: 'function',
282
280
  function: {
283
- name: "fileExists",
284
- description: "检查指定文件是否存在,返回布尔值。",
281
+ name: 'fileExists',
282
+ description: '检查指定文件是否存在,返回布尔值。',
285
283
  parameters: {
286
- type: "object",
284
+ type: 'object',
287
285
  properties: {
288
- filePath: { type: "string" },
286
+ filePath: { type: 'string' },
289
287
  },
290
- required: ["filePath"],
288
+ required: ['filePath'],
291
289
  },
292
290
  },
293
291
  },
294
292
  {
295
- type: "function",
293
+ type: 'function',
296
294
  function: {
297
- name: "createDirectory",
295
+ name: 'createDirectory',
298
296
  description:
299
- "创建一个新目录,返回布尔值表示操作是否成功。支持递归创建目录结构。",
297
+ '创建一个新目录,返回布尔值表示操作是否成功。支持递归创建目录结构。',
300
298
  parameters: {
301
- type: "object",
299
+ type: 'object',
302
300
  properties: {
303
- dirPath: { type: "string" },
301
+ dirPath: { type: 'string' },
304
302
  },
305
- required: ["dirPath"],
303
+ required: ['dirPath'],
306
304
  },
307
305
  },
308
306
  },
309
307
  {
310
- type: "function",
308
+ type: 'function',
311
309
  function: {
312
- name: "deleteFile",
310
+ name: 'deleteFile',
313
311
  description:
314
- "删除指定文件,返回布尔值表示操作是否成功。如果文件不存在也会返回true。",
312
+ '删除指定文件,返回布尔值表示操作是否成功。如果文件不存在也会返回true。',
315
313
  parameters: {
316
- type: "object",
314
+ type: 'object',
317
315
  properties: {
318
- filePath: { type: "string" },
316
+ filePath: { type: 'string' },
319
317
  },
320
- required: ["filePath"],
318
+ required: ['filePath'],
321
319
  },
322
320
  },
323
321
  },
324
322
  {
325
- type: "function",
323
+ type: 'function',
326
324
  function: {
327
- name: "deleteDirectory",
325
+ name: 'deleteDirectory',
328
326
  description:
329
- "删除指定目录,返回布尔值表示操作是否成功。支持递归删除目录及其内容。如果目录不存在也会返回true。",
327
+ '删除指定目录,返回布尔值表示操作是否成功。支持递归删除目录及其内容。如果目录不存在也会返回true。',
330
328
  parameters: {
331
- type: "object",
329
+ type: 'object',
332
330
  properties: {
333
- dirPath: { type: "string" },
331
+ dirPath: { type: 'string' },
334
332
  },
335
- required: ["dirPath"],
333
+ required: ['dirPath'],
336
334
  },
337
335
  },
338
336
  },
339
337
  {
340
- type: "function",
338
+ type: 'function',
341
339
  function: {
342
- name: "rename",
340
+ name: 'rename',
343
341
  description:
344
- "重命名文件或目录,返回布尔值表示操作是否成功。如果原文件不存在也会返回true。",
342
+ '重命名文件或目录,返回布尔值表示操作是否成功。如果原文件不存在也会返回true。',
345
343
  parameters: {
346
- type: "object",
344
+ type: 'object',
347
345
  properties: {
348
- oldPath: { type: "string" },
349
- newPath: { type: "string" },
346
+ oldPath: { type: 'string' },
347
+ newPath: { type: 'string' },
350
348
  },
351
- required: ["oldPath", "newPath"],
349
+ required: ['oldPath', 'newPath'],
352
350
  },
353
351
  },
354
352
  },
355
353
  {
356
- type: "function",
354
+ type: 'function',
357
355
  function: {
358
- name: "moveFile",
356
+ name: 'moveFile',
359
357
  description:
360
- "移动文件,返回布尔值表示操作是否成功。如果目标目录不存在会自动创建。如果源文件不存在也会返回true。",
358
+ '移动文件,返回布尔值表示操作是否成功。如果目标目录不存在会自动创建。如果源文件不存在也会返回true。',
361
359
  parameters: {
362
- type: "object",
360
+ type: 'object',
363
361
  properties: {
364
- sourcePath: { type: "string" },
365
- destinationPath: { type: "string" },
362
+ sourcePath: { type: 'string' },
363
+ destinationPath: { type: 'string' },
366
364
  },
367
- required: ["sourcePath", "destinationPath"],
365
+ required: ['sourcePath', 'destinationPath'],
368
366
  },
369
367
  },
370
368
  },
371
369
  {
372
- type: "function",
370
+ type: 'function',
373
371
  function: {
374
- name: "getFileInfo",
372
+ name: 'getFileInfo',
375
373
  description:
376
- "获取指定文件的信息,返回文件信息对象。如果文件不存在或获取失败则返回null。返回对象包含path、size、birthtime、mtime、ctime、isFile、isDirectory等属性。",
374
+ '获取指定文件的信息,返回文件信息对象。如果文件不存在或获取失败则返回null。返回对象包含path、size、birthtime、mtime、ctime、isFile、isDirectory等属性。',
377
375
  parameters: {
378
- type: "object",
376
+ type: 'object',
379
377
  properties: {
380
- filePath: { type: "string" },
378
+ filePath: { type: 'string' },
381
379
  },
382
- required: ["filePath"],
380
+ required: ['filePath'],
383
381
  },
384
382
  },
385
383
  },
386
384
  {
387
- type: "function",
385
+ type: 'function',
388
386
  function: {
389
- name: "getFileNameList",
387
+ name: 'getFileNameList',
390
388
  description:
391
- "获取指定目录下的所有文件名,返回文件名数组。如果目录不存在或不是目录则返回空数组。",
389
+ '获取指定目录下的所有文件名,返回文件名数组。如果目录不存在或不是目录则返回空数组。',
392
390
  parameters: {
393
- type: "object",
391
+ type: 'object',
394
392
  properties: {
395
- dirPath: { type: "string" },
393
+ dirPath: { type: 'string' },
396
394
  },
397
- required: ["dirPath"],
395
+ required: ['dirPath'],
398
396
  },
399
397
  },
400
398
  },
401
399
  {
402
- type: "function",
400
+ type: 'function',
403
401
  function: {
404
- name: "clearDirectory",
402
+ name: 'clearDirectory',
405
403
  description:
406
- "清空指定目录的内容,返回布尔值表示操作是否成功。如果目录不存在或不是目录则返回false。",
404
+ '清空指定目录的内容,返回布尔值表示操作是否成功。如果目录不存在或不是目录则返回false。',
407
405
  parameters: {
408
- type: "object",
406
+ type: 'object',
409
407
  properties: {
410
- dirPath: { type: "string" },
408
+ dirPath: { type: 'string' },
411
409
  },
412
- required: ["dirPath"],
410
+ required: ['dirPath'],
413
411
  },
414
412
  },
415
413
  },
416
- ];
414
+ ]
417
415
 
418
416
  const functions = {
419
417
  createFile,
@@ -429,11 +427,12 @@ const functions = {
429
427
  getFileInfo,
430
428
  getFileNameList,
431
429
  clearDirectory,
432
- };
430
+ }
433
431
 
434
432
  module.exports = {
435
433
  name: 'FileExtension',
436
- extensionDescription: "提供文件和目录的创建、读取、修改、删除、移动、重命名、信息获取等文件系统操作功能",
434
+ extensionDescription:
435
+ '提供文件和目录的创建、读取、修改、删除、移动、重命名、信息获取等文件系统操作功能',
437
436
  descriptions,
438
437
  functions,
439
- };
438
+ }
@@ -45,15 +45,17 @@ async function generateExtensionRule(goal) {
45
45
  2. package.json配置:
46
46
  - name字段值:与项目名称一致,即"deepfish-「项目功能名称」"
47
47
  - version字段值:初始版本设置为1.0.0
48
- - description字段值:简要描述该项目的核心功能和价值
48
+ - description字段值:用专业英文简要描述该项目的核心功能和价值, 以"A DeepFish AI extension tool for"开头
49
49
  - git仓库地址:固定为 https://github.com/qq306863030/deepfish-extensions.git
50
50
  - author设置为"DeepFish AI"
51
51
  - type字段设置为"commonjs",确保模块系统兼容
52
- 3. 主文件:项目入口文件必须命名为index.js
53
- 4. 文档文件:项目根目录需新增2个文档文件:
54
- - README_CN.md(中文说明文档)
55
- - README.md(英文说明文档)
56
- 5. 主测试文件:test.js
52
+ 3. 文件结构
53
+ - 主文件:项目入口文件必须命名为index.js
54
+ - 子文件:复杂的逻辑可以拆分到其他.js文件中;将descriptions、functions拆分到子文件;
55
+ - 文档文件:项目根目录需新增2个文档文件:
56
+ - README_CN.md(中文说明文档)
57
+ - README.md(英文说明文档)
58
+ - 主测试文件:test.js
57
59
 
58
60
  ### 第二步:index.js 完整开发规范
59
61
  #### 2.1 核心输出要求
@@ -76,6 +78,7 @@ async function generateExtensionRule(goal) {
76
78
  5. 函数中的this.aiCli在运行时指向DeepFish AI的运行时环境,可以通过this.aiCli访问到AI配置、工具函数等资源
77
79
  6. 尽量保持代码思路清晰,避免过度复杂的逻辑嵌套,必要时可以适当拆分函数、添加注释说明或拆分成多个文件
78
80
  7. 需要创建的是DeepFish AI的扩展工具,并非创建Skill工具包,因此不需要编写SKILL.md文件
81
+ 8. 对于复杂的的扩展功能,需要在functions中输出一个说明函数,只需返回一个markdown类型的字符串,专门用于解释当前扩展工具的使用方法、参数说明、示例等内容,函数名称为「extensionRule」,如「systemFileManagement_extensionRule」;函数描述需要强调调用该扩展模块前必须先阅读该规则文档。
79
82
 
80
83
  #### 2.3 基础代码模板(必须遵循)
81
84
  const descriptions = []
@@ -87,7 +90,19 @@ module.exports = {
87
90
  functions,
88
91
  }
89
92
 
90
- #### 2.4 参考示例(可参考格式)
93
+ #### 2.4 参考示例(可参考格式,展示多文件拆分结构)
94
+
95
+ ##### index.js(主文件)
96
+ const descriptions = require('./descriptions')
97
+ const functions = require('./functions')
98
+ module.exports = {
99
+ name: 'systemFileManagement',
100
+ extensionDescription: '提供文件管理相关功能,包括文件重命名、复制等操作',
101
+ descriptions,
102
+ functions,
103
+ }
104
+
105
+ ##### descriptions.js(描述子文件)
91
106
  const descriptions = [
92
107
  {
93
108
  name: 'systemFileManagement_renameFile',
@@ -100,27 +115,38 @@ const descriptions = [
100
115
  },
101
116
  },
102
117
  },
118
+ {
119
+ name: 'systemFileManagement_copyFile',
120
+ description: '系统文件管理:复制文件',
121
+ parameters: {
122
+ type: 'object',
123
+ properties: {
124
+ srcPath: { type: 'string', description: '源文件路径' },
125
+ destPath: { type: 'string', description: '目标文件路径' },
126
+ },
127
+ },
128
+ },
103
129
  ]
130
+ module.exports = descriptions
131
+
132
+ ##### functions.js(函数子文件)
104
133
  const functions = {
105
- systemFileManagement_renameFile: (oldPath, newPath) => {
134
+ systemFileManagement_renameFile: function(oldPath, newPath) {
106
135
  return this.aiCli.Tools.rename(oldPath, newPath)
107
136
  },
137
+ systemFileManagement_copyFile: function(srcPath, destPath) {
138
+ return this.aiCli.Tools.copyFile(srcPath, destPath)
139
+ },
108
140
  }
109
- module.exports = {
110
- name: 'systemFileManagement',
111
- extensionDescription: '提供文件管理相关功能,包括文件重命名等操作',
112
- descriptions,
113
- functions,
114
- }
141
+ module.exports = functions
115
142
 
116
143
  ### 第三步:测试规则
117
144
  1. 测试目标:至少覆盖扩展中的核心函数(建议覆盖每个对外函数),验证“正常输入可用、关键边界可处理、异常输入有明确反馈”。
118
145
  2. 测试文件:统一在 test.js 编写可直接运行的测试脚本,结构清晰,包含“准备数据 → 执行函数 → 断言结果 → 输出结论”。
119
- 3. 运行时注入要求:必须模拟 DeepFish 运行时环境,确保函数可正确使用 this.aiCli 上下文。
146
+ 3. 运行时注入要求:必须确保函数可正确使用 this.aiCli 上下文。
120
147
  - 环境创建方式:
121
148
  "const { AICLI } = require('${packagePath}')\nconst aiCli = new AICLI();"
122
149
  - 调用方式:为模块导出的functions绑定aiCli上下文,示例:functions.aiCli = aiCli;
123
- - 若函数依赖 this.aiCli.Tools/this.aiCli.aiConfig,需在测试中验证其可被正常访问。
124
150
  4. 断言与输出规范:每个用例需打印“用例名称、输入、期望、实际、是否通过(PASS/FAIL)”;全部执行后输出汇总(总数、通过数、失败数)。
125
151
  5. 失败处理:出现异常时不得静默吞错,需捕获并输出可定位信息(错误消息、对应用例、关键参数)。
126
152
  6. 副作用控制:测试过程中创建的临时文件必须使用 tmp_test_ 前缀,并在测试结束后清理。
@@ -138,9 +164,10 @@ module.exports = {
138
164
  - 清晰说明当前NPM包的核心定位、整体功能价值、适用场景
139
165
  - 语言简洁易懂,无需技术细节,聚焦「做什么」而非「怎么做」
140
166
  2. 快速开始:
141
- - 明确说明安装步骤,顺序不可颠倒:
142
- 先安装deepfish-ai全局库:npm install deepfish-ai -g
143
- 再安装当前项目库:npm install @deepfish-ai/项目功能名称 -g
167
+ - 明确说明安装步骤:
168
+ 全局安装deepfish-ainpm install deepfish-ai -g
169
+ 全局安装当前项目:npm install @deepfish-ai/项目功能名称 -g
170
+ ③ 在命令行中输入:ai 「扩展的某一个功能」。如:添加了一个查询天气的扩展。则输入:ai 查询一下今天的天气
144
171
  3. 函数列表及功能描述:
145
172
  - 列出当前项目中所有函数名称
146
173
  - 对应说明每个函数的核心功能