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.
Files changed (62) hide show
  1. package/README.md +126 -368
  2. package/dist/index.js +23320 -0
  3. package/dist/serve/client/assets/index-DUHYC91l.js +1 -0
  4. package/dist/serve/client/assets/index-zcrdNLZs.css +1 -0
  5. package/dist/serve/client/index.html +14 -0
  6. package/dist/serve/pm2-server.js +21015 -0
  7. package/dist/serve/server/entry-server.mjs +224 -0
  8. package/package.json +61 -83
  9. package/LICENSE +0 -21
  10. package/README_CN.md +0 -460
  11. package/src/AgentRobot/AgentRobotFactory/MainAgentRobot.js +0 -88
  12. package/src/AgentRobot/AgentRobotFactory/SubAgentRobot.js +0 -45
  13. package/src/AgentRobot/AgentRobotFactory/SubSkillAgentRobot.js +0 -45
  14. package/src/AgentRobot/AgentRobotFactory/index.js +0 -48
  15. package/src/AgentRobot/BaseAgentRobot/Brain.js +0 -210
  16. package/src/AgentRobot/BaseAgentRobot/BrainEvent.js +0 -17
  17. package/src/AgentRobot/BaseAgentRobot/Hand.js +0 -119
  18. package/src/AgentRobot/BaseAgentRobot/Heart.js +0 -0
  19. package/src/AgentRobot/BaseAgentRobot/Logger.js +0 -114
  20. package/src/AgentRobot/BaseAgentRobot/ScreenPrinter.js +0 -49
  21. package/src/AgentRobot/BaseAgentRobot/index.js +0 -266
  22. package/src/AgentRobot/BaseAgentRobot/lazy-tools/AliBailian.js +0 -997
  23. package/src/AgentRobot/BaseAgentRobot/lazy-tools/doc-transform.js +0 -204
  24. package/src/AgentRobot/BaseAgentRobot/lazy-tools/docx.js +0 -1286
  25. package/src/AgentRobot/BaseAgentRobot/lazy-tools/img.js +0 -765
  26. package/src/AgentRobot/BaseAgentRobot/lazy-tools/pdf.js +0 -736
  27. package/src/AgentRobot/BaseAgentRobot/lazy-tools/pptx.js +0 -567
  28. package/src/AgentRobot/BaseAgentRobot/lazy-tools/video.js +0 -36
  29. package/src/AgentRobot/BaseAgentRobot/lazy-tools/xlsx.js +0 -611
  30. package/src/AgentRobot/BaseAgentRobot/tools/BaseTools.js +0 -13
  31. package/src/AgentRobot/BaseAgentRobot/tools/CreateAgentTools.js +0 -158
  32. package/src/AgentRobot/BaseAgentRobot/tools/FileTools.js +0 -768
  33. package/src/AgentRobot/BaseAgentRobot/tools/GenerateTools.js +0 -441
  34. package/src/AgentRobot/BaseAgentRobot/tools/InquirerTools.js +0 -244
  35. package/src/AgentRobot/BaseAgentRobot/tools/SystemTools.js +0 -424
  36. package/src/AgentRobot/BaseAgentRobot/tools/TaskTools.js +0 -211
  37. package/src/AgentRobot/BaseAgentRobot/tools/TestTools.js +0 -100
  38. package/src/AgentRobot/BaseAgentRobot/tools/UserTool.js +0 -87
  39. package/src/AgentRobot/BaseAgentRobot/tools/WebTools.js +0 -257
  40. package/src/AgentRobot/BaseAgentRobot/utils/AIRequest.js +0 -297
  41. package/src/AgentRobot/BaseAgentRobot/utils/AIToolManager.js +0 -131
  42. package/src/AgentRobot/BaseAgentRobot/utils/AgentTree.js +0 -66
  43. package/src/AgentRobot/BaseAgentRobot/utils/AttachmentToolScanner.js +0 -235
  44. package/src/AgentRobot/BaseAgentRobot/utils/MessageCompresser.js +0 -236
  45. package/src/AgentRobot/BaseAgentRobot/utils/aiConsole.js +0 -74
  46. package/src/AgentRobot/BaseAgentRobot/utils/aiInquirer.js +0 -78
  47. package/src/AgentRobot/BaseAgentRobot/utils/analyzeReturn.test.js +0 -104
  48. package/src/AgentRobot/BaseAgentRobot/utils/copilot.js +0 -117
  49. package/src/AgentRobot/BaseAgentRobot/utils/node-root.js +0 -138
  50. package/src/AgentRobot/BaseAgentRobot/utils/normal.js +0 -399
  51. package/src/cli/ConfigManager.js +0 -283
  52. package/src/cli/DefaultConfig.js +0 -98
  53. package/src/cli/GlobalVariable.js +0 -8
  54. package/src/cli/MemoryManager.js +0 -53
  55. package/src/cli/SkillConfigManager.js +0 -354
  56. package/src/cli/SkillParser.js +0 -58
  57. package/src/cli/ai-auth.js +0 -231
  58. package/src/cli/ai-config.js +0 -225
  59. package/src/cli/ai-memory.js +0 -22
  60. package/src/cli/ai-skill.js +0 -65
  61. package/src/cli/index.js +0 -77
  62. package/src/index.js +0 -54
@@ -1,98 +0,0 @@
1
- const defaultConfig = {
2
- ai: [],
3
- currentAi: '',
4
- maxIterations: -1, // ai完成工作流的最大迭代次数,-1表示无限制
5
- maxMemoryExpireTime: 30, // 整个会话的最大过期时间,单位天,-1表示无限制, 0表示不记录
6
- maxLogExpireTime: 3, // 日志过期时间,单位天,-1表示无限制,0表示不记录
7
- maxBlockFileSize: 20, // 最大分块文件大小,单位KB;超过该大小的文件需要分块处理
8
- encoding: 'auto', // 命令行编码格式, 可设置为utf-8、gbk等, 也可以设置成auto或空值自动判断
9
- isThinkPrint: true, // 是否打印思考过程
10
- EMBEDDING_API: '', // 向量化接口地址
11
- EMBEDDING_API_KEY: '' // 向量化接口密钥
12
- }
13
-
14
- const aiCliConfig = {
15
- DeepSeek: {
16
- baseUrl: 'https://api.deepseek.com',
17
- model: {
18
- list: ['deepseek-chat', 'deepseek-reasoner', 'deepseek-v4-flash', 'deepseek-v4-pro', 'other'],
19
- defaultValue: '',
20
- },
21
- type: 'deepseek',
22
- apiKey: '',
23
- temperature: 0.7,
24
- maxTokens: -1, // 单位KB
25
- maxContextLength: 64, // 单位KB
26
- stream: true,
27
- },
28
- MiniMax: {
29
- baseUrl: 'https://api.minimaxi.com/v1',
30
- model: {
31
- list: ['MiniMax-M2.5', 'MiniMax-M2.5-highspeed', 'MiniMax-M2.7', 'MiniMax-M2.7-highspeed'],
32
- defaultValue: 'MiniMax-M2.5',
33
- },
34
- type: 'minimax',
35
- apiKey: '',
36
- temperature: 0.7,
37
- maxTokens: -1, // 单位KB
38
- maxContextLength: 64, // 单位KB
39
- stream: true,
40
- },
41
- Qwen: {
42
- baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
43
- model: {
44
- list: ['qwen3.6-plus'],
45
- defaultValue: 'qwen3.6-plus',
46
- },
47
- type: 'qwen',
48
- apiKey: '',
49
- temperature: 0.7,
50
- maxTokens: -1, // 单位KB
51
- maxContextLength: 64, // 单位KB
52
- stream: true,
53
- },
54
- Ollama: {
55
- baseUrl: 'http://localhost:11434/v1',
56
- model: {
57
- list: [],
58
- defaultValue: 'deepseek-v3.2:cloud',
59
- },
60
- type: 'ollama',
61
- apiKey: 'ollama',
62
- temperature: 0.7,
63
- maxTokens: -1, // 单位KB
64
- maxContextLength: 64, // 单位KB
65
- stream: true,
66
- },
67
- OpenAI: {
68
- baseUrl: 'https://api.openai.com/v1',
69
- model: {
70
- list: [],
71
- defaultValue: 'gpt-4',
72
- },
73
- type: 'openai',
74
- apiKey: '',
75
- temperature: 0.7,
76
- maxTokens: -1, // 单位KB
77
- maxContextLength: 64, // 单位KB
78
- stream: true,
79
- },
80
- Copilot: {
81
- baseUrl: 'https://api.githubcopilot.com',
82
- model: {
83
- list: [
84
- 'gpt-4o',
85
- 'gpt-4o-mini',
86
- ],
87
- defaultValue: 'gpt-4o',
88
- },
89
- type: 'copilot',
90
- apiKey: '',
91
- temperature: 0.7,
92
- maxTokens: -1, // 单位KB
93
- maxContextLength: 400, // 单位KB
94
- stream: true,
95
- }
96
- }
97
-
98
- module.exports = { aiCliConfig, defaultConfig }
@@ -1,8 +0,0 @@
1
- const GlobalVariable = {
2
- aiCli: null,
3
- configManager: null,
4
- skillConfigManager: null,
5
- memoryManager: null,
6
- }
7
-
8
- module.exports = { GlobalVariable }
@@ -1,53 +0,0 @@
1
- /**
2
- * @Author: Roman 306863030@qq.com
3
- * @Date: 2026-03-16 09:18:05
4
- * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-04-08 18:31:55
6
- * @FilePath: \deepfish\src\cli\MemoryManager.js
7
- * @Description: 对话历史记录、恢复
8
- * @
9
- */
10
- const fs = require('fs-extra')
11
- const path = require('path')
12
- const { GlobalVariable } = require('./GlobalVariable.js')
13
- const aiConsole = require('../AgentRobot/BaseAgentRobot/utils/aiConsole.js')
14
- const { openDirectory } = require('../AgentRobot/BaseAgentRobot/utils/normal.js')
15
- class MemoryManager {
16
- constructor() {
17
- this.configManager = GlobalVariable.configManager
18
- this.memoryDir = path.join(this.configManager.configDir, 'memory')
19
- this.agentRecordFilePath = path.join(this.memoryDir, 'agentRecord.json')
20
- this.workspace = process.cwd()
21
- }
22
-
23
- openDirectory() {
24
- // 根据路径查看id
25
- const agentRecord = fs.readJSONSync(this.agentRecordFilePath, { throws: false }) || []
26
- const agent = agentRecord?.find(item => {
27
- return item.workspace === this.workspace
28
- })
29
- if (!agent) {
30
- return aiConsole.logError('No memory found for the current directory.')
31
- }
32
- const agentId = agent.agentId
33
- const dir = path.join(this.memoryDir, agentId)
34
- openDirectory(dir)
35
- }
36
-
37
- clearMessage() {
38
- // 根据路径查看id
39
- const agentRecord = fs.readJSONSync(this.agentRecordFilePath, { throws: false }) || []
40
- const agentIndex = agentRecord?.findIndex(item => {
41
- return item.workspace === this.workspace
42
- })
43
- if (!~agentIndex) {
44
- return aiConsole.logError('No memory found for the current directory.')
45
- }
46
- fs.removeSync(path.join(this.memoryDir, agentRecord[agentIndex].agentId))
47
- agentRecord.splice(agentIndex, 1)
48
- fs.writeJSONSync(this.agentRecordFilePath, agentRecord, { spaces: 2 })
49
- aiConsole.logSuccess('Memory cleared.')
50
- }
51
- }
52
-
53
- module.exports = MemoryManager
@@ -1,354 +0,0 @@
1
- /**
2
- * @Author: Roman 306863030@qq.com
3
- * @Date: 2026-03-23 15:23:42
4
- * @LastEditors: Roman 306863030@qq.com
5
- * @LastEditTime: 2026-05-06 14:53:07
6
- * @FilePath: \deepfish\src\cli\SkillConfigManager.js
7
- * @Description: Skill configuration manager
8
- */
9
- const path = require('path')
10
- const { spawnSync } = require('child_process')
11
- const fs = require('fs-extra')
12
- const axios = require('axios')
13
- const cheerio = require('cheerio')
14
- const extract = require('extract-zip')
15
- const { GlobalVariable } = require('./GlobalVariable.js')
16
- const { parseSkillMetadataYaml } = require('./SkillParser.js')
17
- const aiConsole = require('../AgentRobot/BaseAgentRobot/utils/aiConsole.js')
18
- const { openDirectory } = require('../AgentRobot/BaseAgentRobot/utils/normal.js')
19
-
20
- // skill的数据结构: {name: string, enable: boolean, description: string, baseDir: string, skillDirName: string, location: string, skillFilePath: string, homepage: string, metadata: object}
21
- class SkillConfigManager {
22
- constructor() {
23
- this.configManager = GlobalVariable.configManager
24
- // skill目录
25
- this.skillDir = path.join(this.configManager.configDir, './clawSkills')
26
- this.skillFilePath = path.join( this.skillDir, './clawSkills.json')
27
- this.init()
28
- GlobalVariable.skillConfigManager = this
29
- }
30
-
31
- init() {
32
- // 自动创建skill目录
33
- fs.ensureDirSync(this.skillDir)
34
- // 判断是否存在clawSkills.json,如果不存在则创建
35
- if (!fs.existsSync(this.skillFilePath)) {
36
- fs.writeJsonSync(this.skillFilePath, { skills: [] }, { spaces: 2 })
37
- }
38
- this._check()
39
- }
40
-
41
- // 读取skill文件
42
- readSkills() {
43
- const skillsObj = fs.readJSONSync(this.skillFilePath, { throws: false }) || { skills: [] }
44
- return skillsObj.skills
45
- }
46
-
47
- // 写入skill文件
48
- writeSkills(skills) {
49
- fs.writeJSONSync(this.skillFilePath, { skills }, { spaces: 2 })
50
- }
51
-
52
-
53
- openDirectory() {
54
- // 打开目录
55
- openDirectory(this.skillDir)
56
- }
57
-
58
- // 解析skill文件,写入到json中,获取名称、版本、作者、元数据、描述等信息
59
- _parseSkill(skillDirPath) {
60
- const skillMdPath = ['SKILL.md', 'skill.md']
61
- .map((name) => path.join(skillDirPath, name))
62
- .find((filePath) => fs.existsSync(filePath))
63
- if (!skillMdPath) {
64
- return {}
65
- }
66
- const parsed = parseSkillMetadataYaml(skillMdPath)
67
- return parsed
68
- }
69
-
70
- // 查看skills列表
71
- viewList() {
72
- const skills = this.readSkills()
73
- if (skills && Array.isArray(skills)) {
74
- console.log('='.repeat(50))
75
- // 打印扩展列表,并加上索引
76
- if (skills.length === 0) {
77
- console.log(`No skills in config.`)
78
- } else {
79
- console.log('Skills in config:')
80
- skills.forEach((skill, index) => {
81
- console.log(`[${index}] ${skill.name} (${skill.enable ? 'Enabled' : 'Disabled'})`)
82
- })
83
- }
84
- console.log('='.repeat(50))
85
- } else {
86
- aiConsole.logError(`No skills in config.`)
87
- }
88
- }
89
- _check() {
90
- // 如果数组的数量与目录中的数量不一致,则自动同步
91
- const skills = this.readSkills()
92
- const skillDirs = fs.readdirSync(this.skillDir).filter((file) => {
93
- const fullPath = path.join(this.skillDir, file)
94
- return fs.statSync(fullPath).isDirectory() && fs.existsSync(path.join(fullPath, 'SKILL.md'))
95
- })
96
- if (skills.length === skillDirs.length) {
97
- return
98
- }
99
- if (skills.length !== skillDirs.length) {
100
- // 查询未被注册的skill,自动注册
101
- skillDirs.forEach((skillDir) => {
102
- if (
103
- !skills.some(
104
- (skill) => skill.skillDirName === skillDir || skill.name === skillDir,
105
- )
106
- ) {
107
- this._registerSkill(skillDir, false)
108
- }
109
- })
110
- // 查询已注册但目录不存在的skill,自动从列表中删除
111
- skills.forEach((skill) => {
112
- if (!skillDirs.includes(skill.skillDirName)) {
113
- this.remove(skill.name)
114
- }
115
- })
116
- }
117
- }
118
-
119
- // 添加skills
120
- async add(skillName) {
121
- // 从当前目录process.pwd()查询是否存在同名的skill
122
- // 如果存在则判断是否是目录=>1.如果是目录则拷贝到skills目录下,并添加到config中 2.如果是zip文件则解压到skills目录下,并添加到config中
123
- // 如果不存在则提示从ClawHub中下载https://clawhub.ai/
124
- const baseName = path.basename(skillName, '.zip')
125
- const fileNames = fs.readdirSync(process.cwd())
126
- const file = fileNames.find(
127
- (name) => name === baseName || name === `${baseName}.zip`,
128
- )
129
- if (file) {
130
- // 如果存在同名文件,则判断是否是目录
131
- const baseDir = path.join(process.cwd(), file)
132
- if (fs.statSync(baseDir).isDirectory()) {
133
- // 如果是目录,则拷贝到skills目录下,并添加到config中
134
- fs.copySync(baseDir, path.join(this.skillDir, file))
135
- this._registerSkill(baseName)
136
- aiConsole.logSuccess(`Skill "${baseName}" added successfully!`)
137
- } else if (path.extname(file) === '.zip') {
138
- // 如果是zip文件,则解压到skills目录下,并添加到config中
139
- const extractPath = path.join(this.skillDir, baseName)
140
- await extract(baseDir, { dir: extractPath })
141
- this._registerSkill(baseName)
142
- aiConsole.logSuccess(`Skill "${baseName}" added successfully!`)
143
- } else {
144
- aiConsole.logError(`File "${file}" is not a directory or a zip file.`)
145
- }
146
- } else {
147
- aiConsole.logError(
148
- `No skill named "${skillName}" found in current directory. Please download it from ClawHub (https://clawhub.ai/) and place it in the current directory.`,
149
- )
150
- }
151
- }
152
-
153
- // install('https://clawhub.ai/TheSethRose/agent-browser')
154
- async install(skillUrl) {
155
- // 从ClawHub下载zip并解压到skills目录下,并添加到config中
156
- if (!skillUrl || typeof skillUrl !== 'string') {
157
- aiConsole.logError('Invalid skill URL. Please provide a valid ClawHub URL.')
158
- return
159
- }
160
- // 判断url是否是github的url,如果是github的url则使用git命令拉取、执行add函数、删除目录
161
- if (skillUrl.endsWith('.git')) {
162
- spawnSync('git', ['clone', skillUrl], {
163
- stdio: 'inherit',
164
- })
165
- const repoName = path.basename(skillUrl, '.git')
166
- await this.add(repoName)
167
- fs.removeSync(path.join(process.cwd(), repoName))
168
- return
169
- }
170
-
171
- let parsedUrl
172
- try {
173
- parsedUrl = new URL(skillUrl)
174
- } catch (error) {
175
- aiConsole.logError('Invalid skill URL format.')
176
- return
177
- }
178
-
179
- const host = parsedUrl.hostname.toLowerCase()
180
- if (host !== 'clawhub.ai' && host !== 'www.clawhub.ai') {
181
- aiConsole.logError(
182
- 'Only ClawHub URLs are supported, e.g. https://clawhub.ai/author/skill-name',
183
- )
184
- return
185
- }
186
-
187
- const segments = parsedUrl.pathname.split('/').filter(Boolean)
188
- if (segments.length < 2) {
189
- aiConsole.logError(
190
- 'Invalid ClawHub URL. Expected format: https://clawhub.ai/<author>/<skill-name>',
191
- )
192
- return
193
- }
194
-
195
- const skillName = path.basename(segments[1], '.zip')
196
- const skills = this.readSkills()
197
- if (skills.some((skill) => skill.name === skillName)) {
198
- aiConsole.logError(`Skill with name "${skillName}" already exists in config.`)
199
- return
200
- }
201
- // 查看目录是否存在当前的skill
202
- const skillPath = path.join(this.skillDir, skillName)
203
- if (fs.existsSync(skillPath)) {
204
- aiConsole.logError(`Skill "${skillName}" already exists in the skills directory.`)
205
- return
206
- }
207
- const zipFilePath = path.join(this.skillDir, `${skillName}.zip`)
208
- const extractPath = path.join(this.skillDir, skillName)
209
-
210
- try {
211
- // 自动获取download地址
212
- const response = await axios({
213
- method: 'get',
214
- url: skillUrl,
215
- responseType: 'text',
216
- timeout: 30000,
217
- maxRedirects: 5,
218
- validateStatus: (status) => status >= 200 && status < 300,
219
- })
220
-
221
- // 解析HTML获取下载链接
222
- const html = response.data
223
- const $ = cheerio.load(html)
224
- const downloadHref = $('a').filter((i, el) => {
225
- const href = $(el).attr('href')
226
- return href && (href.startsWith('https://wry-manatee-359.convex.site/api/v1/download') || href.endsWith('.zip'))
227
- }).attr('href')
228
-
229
- if (!downloadHref) {
230
- aiConsole.logError(`No download link found for skill "${skillName}".`)
231
- return
232
- }
233
-
234
- const downloadUrl = new URL(downloadHref, parsedUrl.origin).toString()
235
- const zipResponse = await axios({
236
- method: 'get',
237
- url: downloadUrl,
238
- responseType: 'arraybuffer',
239
- timeout: 60000,
240
- maxRedirects: 5,
241
- validateStatus: (status) => status >= 200 && status < 300,
242
- })
243
- fs.writeFileSync(zipFilePath, Buffer.from(zipResponse.data))
244
- await extract(zipFilePath, { dir: extractPath })
245
- this._registerSkill(skillName)
246
- aiConsole.logSuccess(`Skill "${skillName}" installed successfully!`)
247
- } catch (error) {
248
- aiConsole.logError(`Failed to install skill "${skillName}": ${error.message}`)
249
- } finally {
250
- fs.removeSync(zipFilePath)
251
- }
252
- }
253
-
254
- // 根据名称或索引 删除skills
255
- remove(skillName) {
256
- const skills = this.readSkills()
257
- const skillObj = this._getSkill(skills, skillName)
258
- if (!skillObj) {
259
- return
260
- }
261
- const { skill, index } = skillObj
262
- let skillPath = skill.location
263
- if (!skillPath) {
264
- skillPath = path.join(this.skillDir, skill.skillDirName)
265
- }
266
- skills.splice(index, 1)
267
- this.writeSkills(skills)
268
- if (fs.existsSync(skillPath)) {
269
- fs.removeSync(skillPath)
270
- }
271
- aiConsole.logSuccess(`Skill "${skill.name}" removed successfully!`)
272
- }
273
-
274
- // 根据名称或索引 启用skill-限制最大启用100个
275
- enable(skillName) {
276
- const skills = this.readSkills()
277
- const enabledCount = skills.filter((skill) => skill.enable).length
278
- if (enabledCount >= 100) {
279
- aiConsole.logError('Cannot enable more than 100 skills.')
280
- return
281
- }
282
- const skillObj = this._getSkill(skills, skillName)
283
- if (!skillObj) {
284
- return
285
- }
286
- const { skill } = skillObj
287
- skill.enable = true
288
- this.writeSkills(skills)
289
- aiConsole.logSuccess(`Skill "${skill.name}" enabled successfully!`)
290
- }
291
-
292
- // 根据名称或索引 禁用skill
293
- disable(skillName) {
294
- const skills = this.readSkills()
295
- const skillObj = this._getSkill(skills, skillName)
296
- if (!skillObj) {
297
- return
298
- }
299
- const { skill } = skillObj
300
- skill.enable = false
301
- this.writeSkills(skills)
302
- aiConsole.logSuccess(`Skill "${skill.name}" disabled successfully!`)
303
- }
304
-
305
- // 解析skill的描述文件,获取name、description
306
- _registerSkill(skillDirName, enable = true) {
307
- const skills = this.readSkills()
308
- // 同名检测
309
- if (skills.some((skill) => skill.name === skillDirName)) {
310
- throw new Error(
311
- `Skill with name "${skillDirName}" already exists in config.`,
312
- )
313
- }
314
- const skillDirPath = path.join(this.skillDir, skillDirName)
315
- // 获取name、description
316
- const skillInfo = this._parseSkill(skillDirPath)
317
- const name = skillInfo.name || skillDirName
318
- const description = skillInfo.description || ''
319
- skills.push({
320
- name,
321
- description,
322
- enable,
323
- baseDir: this.skillDir,
324
- skillDirName: skillDirName,
325
- ...skillInfo,
326
- })
327
- this.writeSkills(skills)
328
- }
329
-
330
- _getSkill(skills, skillName) {
331
- let index = parseInt(skillName, 10)
332
- let skill = null
333
- if (!isNaN(index)) {
334
- if (index < 0 || index >= skills.length) {
335
- aiConsole.logError(`Skill index "${index}" is out of range.`)
336
- } else {
337
- skill = skills[index]
338
- }
339
- } else {
340
- index = skills.findIndex((skill) => skill.name === skillName)
341
- if (index === -1) {
342
- aiConsole.logError(`Skill with name "${skillName}" not found in config.`)
343
- return
344
- }
345
- skill = skills[index]
346
- }
347
- return {
348
- skill,
349
- index,
350
- }
351
- }
352
- }
353
-
354
- module.exports = SkillConfigManager
@@ -1,58 +0,0 @@
1
- const fs = require('fs-extra')
2
- const path = require('path')
3
- const yaml = require('js-yaml')
4
-
5
- function extractFrontmatter(content, skillPath) {
6
- // Support UTF-8 BOM and both LF/CRLF line endings.
7
- const normalizedContent = content.replace(/^\uFEFF/, '');
8
- const frontmatterMatch = normalizedContent.match(/^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/);
9
- if (!frontmatterMatch) {
10
- throw new Error(`No frontmatter found in ${skillPath}`);
11
- }
12
-
13
- return frontmatterMatch[1];
14
- }
15
-
16
- function parseSkillMetadata(skillPath) {
17
- const content = fs.readFileSync(skillPath, 'utf-8');
18
-
19
- const frontmatter = extractFrontmatter(content, skillPath);
20
- const metadata = {};
21
-
22
- // 解析 key: value 或 key: "quoted value"
23
- const lines = frontmatter.split(/\r?\n/);
24
- for (const line of lines) {
25
- const match = line.match(/^(\w+):\s*(.+)$/);
26
- if (match) {
27
- const [, key, value] = match;
28
- // 去除引号
29
- metadata[key] = value.replace(/^["']|["']$/g, '');
30
- }
31
- }
32
-
33
- return {
34
- name: metadata.name,
35
- description: metadata.description,
36
- homepage: metadata.homepage,
37
- location: path.dirname(skillPath),
38
- skillFilePath: skillPath,
39
- metadata: metadata.metadata || {}
40
- };
41
- }
42
-
43
- function parseSkillMetadataYaml(skillPath) {
44
- const content = fs.readFileSync(skillPath, 'utf-8');
45
- const frontmatterContent = extractFrontmatter(content, skillPath);
46
- const frontmatter = yaml.load(frontmatterContent);
47
-
48
- return {
49
- name: frontmatter.name,
50
- description: frontmatter.description,
51
- homepage: frontmatter.homepage,
52
- location: path.dirname(skillPath),
53
- metadata: frontmatter.metadata || {},
54
- skillFilePath: skillPath,
55
- };
56
- }
57
-
58
- module.exports = { parseSkillMetadata, parseSkillMetadataYaml }