@becrafter/prompt-manager 0.1.22 → 0.1.31

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 (114) hide show
  1. package/package.json +23 -23
  2. package/packages/resources/tools/agent-browser/README.md +640 -0
  3. package/packages/resources/tools/agent-browser/agent-browser.tool.js +1388 -0
  4. package/packages/resources/tools/thinking/README.md +324 -0
  5. package/packages/resources/tools/thinking/thinking.tool.js +911 -0
  6. package/packages/server/README.md +3 -4
  7. package/packages/server/api/admin.routes.js +668 -664
  8. package/packages/server/api/open.routes.js +68 -67
  9. package/packages/server/api/surge.routes.js +5 -6
  10. package/packages/server/api/tool.routes.js +70 -71
  11. package/packages/server/app.js +70 -73
  12. package/packages/server/configs/authors.json +40 -0
  13. package/packages/server/configs/models/built-in/bigmodel.yaml +6 -6
  14. package/packages/server/configs/models/providers.yaml +4 -4
  15. package/packages/server/configs/templates/built-in/general-iteration.yaml +1 -1
  16. package/packages/server/configs/templates/built-in/general-optimize.yaml +1 -1
  17. package/packages/server/configs/templates/built-in/output-format-optimize.yaml +1 -1
  18. package/packages/server/index.js +3 -9
  19. package/packages/server/mcp/heartbeat-patch.js +1 -3
  20. package/packages/server/mcp/mcp.server.js +64 -134
  21. package/packages/server/mcp/prompt.handler.js +101 -95
  22. package/packages/server/middlewares/auth.middleware.js +31 -31
  23. package/packages/server/server.js +60 -45
  24. package/packages/server/services/TerminalService.js +156 -70
  25. package/packages/server/services/WebSocketService.js +35 -34
  26. package/packages/server/services/author-config.service.js +199 -0
  27. package/packages/server/services/manager.js +66 -60
  28. package/packages/server/services/model.service.js +5 -9
  29. package/packages/server/services/optimization.service.js +25 -22
  30. package/packages/server/services/template.service.js +3 -8
  31. package/packages/server/toolm/author-sync.service.js +97 -0
  32. package/packages/server/toolm/index.js +1 -2
  33. package/packages/server/toolm/package-installer.service.js +47 -50
  34. package/packages/server/toolm/tool-context.service.js +64 -62
  35. package/packages/server/toolm/tool-dependency.service.js +28 -30
  36. package/packages/server/toolm/tool-description-generator-optimized.service.js +55 -55
  37. package/packages/server/toolm/tool-description-generator.service.js +20 -23
  38. package/packages/server/toolm/tool-environment.service.js +45 -44
  39. package/packages/server/toolm/tool-execution.service.js +49 -48
  40. package/packages/server/toolm/tool-loader.service.js +13 -18
  41. package/packages/server/toolm/tool-logger.service.js +33 -39
  42. package/packages/server/toolm/tool-manager.handler.js +17 -15
  43. package/packages/server/toolm/tool-manual-generator.service.js +107 -87
  44. package/packages/server/toolm/tool-mode-handlers.service.js +52 -59
  45. package/packages/server/toolm/tool-storage.service.js +11 -12
  46. package/packages/server/toolm/tool-sync.service.js +36 -39
  47. package/packages/server/toolm/tool-utils.js +0 -1
  48. package/packages/server/toolm/tool-yaml-parser.service.js +12 -11
  49. package/packages/server/toolm/validate-system.js +56 -84
  50. package/packages/server/utils/config.js +97 -12
  51. package/packages/server/utils/logger.js +1 -1
  52. package/packages/server/utils/port-checker.js +8 -8
  53. package/packages/server/utils/util.js +470 -467
  54. package/packages/resources/tools/cognitive-thinking/README.md +0 -284
  55. package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +0 -837
  56. package/packages/server/mcp/sequential-thinking.handler.js +0 -318
  57. package/packages/server/mcp/think-plan.handler.js +0 -274
  58. package/packages/server/mcp/thinking-toolkit.handler.js +0 -380
  59. package/packages/web/0.d1c5a72339dfc32ad86a.js +0 -1
  60. package/packages/web/112.8807b976372b2b0541a8.js +0 -1
  61. package/packages/web/130.584c7e365da413f5d9be.js +0 -1
  62. package/packages/web/142.72c985bc29720f975cca.js +0 -1
  63. package/packages/web/165.a05fc53bf84d18db36b8.js +0 -2
  64. package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +0 -9
  65. package/packages/web/203.724ab9f717b80554c397.js +0 -1
  66. package/packages/web/241.bf941d4f02866795f64a.js +0 -1
  67. package/packages/web/249.54cfb224af63f5f5ec55.js +0 -1
  68. package/packages/web/291.6df35042f8f296fca7cd.js +0 -1
  69. package/packages/web/319.2fab900a31b29873f666.js +0 -1
  70. package/packages/web/32.c78d866281995ec33a7b.js +0 -1
  71. package/packages/web/325.9ca297d0f73f38468ce9.js +0 -1
  72. package/packages/web/366.2f9b48fdbf8eee039e57.js +0 -1
  73. package/packages/web/378.6be08c612cd5a3ef97dc.js +0 -1
  74. package/packages/web/393.7a2f817515c5e90623d7.js +0 -1
  75. package/packages/web/412.062df5f732d5ba203415.js +0 -1
  76. package/packages/web/426.08656fef4918b3fb19ad.js +0 -1
  77. package/packages/web/465.2be8018327130a3bd798.js +0 -1
  78. package/packages/web/48.8ca96fc93667a715e67a.js +0 -1
  79. package/packages/web/480.44c1f1a2927486ac3d4f.js +0 -1
  80. package/packages/web/489.e041a8d0db15dc96d607.js +0 -1
  81. package/packages/web/490.9ffb26c907de020d671b.js +0 -1
  82. package/packages/web/492.58781369e348d91fc06a.js +0 -1
  83. package/packages/web/495.ed63e99791a87167c6b3.js +0 -1
  84. package/packages/web/510.4cc07ab7d30d5c1cd17f.js +0 -1
  85. package/packages/web/543.3af155ed4fa237664308.js +0 -1
  86. package/packages/web/567.f04ab60f8e2c2fb0745a.js +0 -1
  87. package/packages/web/592.f3ad085fa9c1849daa06.js +0 -1
  88. package/packages/web/616.b03fb801b3433b17750f.js +0 -1
  89. package/packages/web/617.d88def54921d2c4dc44c.js +0 -1
  90. package/packages/web/641.d30787d674f548928261.js +0 -1
  91. package/packages/web/672.5269c8399fa42a5af95d.js +0 -1
  92. package/packages/web/731.97cab92b71811c502bda.js +0 -1
  93. package/packages/web/746.3947c6f0235407e420fb.js +0 -1
  94. package/packages/web/756.a53233b3f3913900d5ac.js +0 -1
  95. package/packages/web/77.68801af593a28a631fbf.js +0 -1
  96. package/packages/web/802.53b2bff3cf2a69f7b80c.js +0 -1
  97. package/packages/web/815.b6dfab82265f56c7e046.js +0 -1
  98. package/packages/web/821.f5a13e5c735aac244eb9.js +0 -1
  99. package/packages/web/846.b9bf97d5f559270675ce.js +0 -1
  100. package/packages/web/869.7c10403f500e6201407f.js +0 -1
  101. package/packages/web/885.135050364f99e6924fb5.js +0 -1
  102. package/packages/web/901.fd5aeb9df630609a2b43.js +0 -1
  103. package/packages/web/928.f67e590de3caa4daa3ae.js +0 -1
  104. package/packages/web/955.d833403521ba4dd567ee.js +0 -1
  105. package/packages/web/981.a45cb745cf424044c8c8.js +0 -1
  106. package/packages/web/992.645320b60c74c8787482.js +0 -1
  107. package/packages/web/996.ed9a963dc9e7439eca9a.js +0 -1
  108. package/packages/web/css/codemirror-theme_xq-light.css +0 -43
  109. package/packages/web/css/codemirror.css +0 -344
  110. package/packages/web/css/main.196f434e6a88cd448158.css +0 -7278
  111. package/packages/web/css/terminal-fix.css +0 -571
  112. package/packages/web/index.html +0 -3
  113. package/packages/web/main.dceff50c7307dda04873.js +0 -2
  114. package/packages/web/main.dceff50c7307dda04873.js.LICENSE.txt +0 -3
@@ -8,87 +8,88 @@ import { util } from '../utils/util.js';
8
8
  const router = express.Router();
9
9
 
10
10
  router.get('/prompts', (req, res) => {
11
- try {
12
- const prompts = util.getPromptsFromFiles();
11
+ try {
12
+ const prompts = util.getPromptsFromFiles();
13
13
 
14
- // 过滤出启用的提示词
15
- const filtered = prompts.filter(prompt => {
16
- // 检查提示词本身是否启用
17
- const promptActive = prompt.enabled === true;
18
- if (!promptActive) return false;
19
-
20
- // 检查目录状态 - util.getPromptsFromFiles() 已经正确处理了继承的启用状态
21
- // groupEnabled 已经考虑了父目录的禁用状态
22
- const groupActive = prompt.groupEnabled !== false;
23
- return groupActive;
24
- });
25
- logger.debug(`filtered prompts: ${JSON.stringify(filtered)}`);
14
+ // 过滤出启用的提示词
15
+ const filtered = prompts.filter(prompt => {
16
+ // 检查提示词本身是否启用
17
+ const promptActive = prompt.enabled === true;
18
+ if (!promptActive) return false;
26
19
 
27
- // 判断是否有搜索参数,且搜索参数名为search
28
- if (req.query.search) {
29
- const search = req.query.search;
20
+ // 检查目录状态 - util.getPromptsFromFiles() 已经正确处理了继承的启用状态
21
+ // groupEnabled 已经考虑了父目录的禁用状态
22
+ const groupActive = prompt.groupEnabled !== false;
23
+ return groupActive;
24
+ });
25
+ logger.debug(`filtered prompts: ${JSON.stringify(filtered)}`);
30
26
 
31
- // 实现相似度匹配算法
32
- const searchResults = filtered.map(prompt => {
33
- const score = util.calculateSimilarityScore(search, prompt);
34
- return {
35
- prompt: {
36
- id: prompt.uniqueId,
37
- name: prompt.name,
38
- description: prompt.description || `Prompt: ${prompt.name}`,
39
- metadata: {
40
- // fileName: prompt.fileName,
41
- fullPath: prompt.relativePath
42
- }
43
- },
44
- score: score
45
- };
46
- })
47
- .filter(result => result.score > 0) // 只返回有匹配的结果
48
- .sort((a, b) => b.score - a.score); // 按相似度得分降序排列
27
+ // 判断是否有搜索参数,且搜索参数名为search
28
+ if (req.query.search) {
29
+ const search = req.query.search;
49
30
 
50
- // 只返回prompt字段
51
- res.json(searchResults.map(result => result.prompt));
52
- } else {
53
- // 无搜索参数时,返回精简信息
54
- const simplifiedPrompts = filtered.map(prompt => ({
55
- id: prompt.uniqueId,
56
- name: prompt.name,
57
- description: prompt.description || `Prompt: ${prompt.name}`,
58
- metadata: {
59
- // fileName: prompt.fileName,
60
- fullPath: prompt.relativePath
61
- }
62
- }));
31
+ // 实现相似度匹配算法
32
+ const searchResults = filtered
33
+ .map(prompt => {
34
+ const score = util.calculateSimilarityScore(search, prompt);
35
+ return {
36
+ prompt: {
37
+ id: prompt.uniqueId,
38
+ name: prompt.name,
39
+ description: prompt.description || `Prompt: ${prompt.name}`,
40
+ metadata: {
41
+ // fileName: prompt.fileName,
42
+ fullPath: prompt.relativePath
43
+ }
44
+ },
45
+ score
46
+ };
47
+ })
48
+ .filter(result => result.score > 0) // 只返回有匹配的结果
49
+ .sort((a, b) => b.score - a.score); // 按相似度得分降序排列
63
50
 
64
- res.json(simplifiedPrompts);
51
+ // 只返回prompt字段
52
+ res.json(searchResults.map(result => result.prompt));
53
+ } else {
54
+ // 无搜索参数时,返回精简信息
55
+ const simplifiedPrompts = filtered.map(prompt => ({
56
+ id: prompt.uniqueId,
57
+ name: prompt.name,
58
+ description: prompt.description || `Prompt: ${prompt.name}`,
59
+ metadata: {
60
+ // fileName: prompt.fileName,
61
+ fullPath: prompt.relativePath
65
62
  }
66
- } catch (error) {
67
- res.status(500).json({ error: error.message });
63
+ }));
64
+
65
+ res.json(simplifiedPrompts);
68
66
  }
67
+ } catch (error) {
68
+ res.status(500).json({ error: error.message });
69
+ }
69
70
  });
70
71
 
71
72
  // 查看提示词内容
72
73
  router.post('/process', async (req, res) => {
73
- try {
74
- const { promptName, arguments: args } = req.body;
75
-
76
- if (!promptName) {
77
- return res.status(400).json({ error: 'Missing promptName' });
78
- }
74
+ try {
75
+ const { promptName, arguments: args } = req.body;
79
76
 
80
- const prompts = util.getPromptsFromFiles();
81
- const prompt = prompts.find(p => p.name === promptName);
77
+ if (!promptName) {
78
+ return res.status(400).json({ error: 'Missing promptName' });
79
+ }
82
80
 
83
- if (!prompt) {
84
- return res.status(404).json({ error: `Prompt "${promptName}" not found` });
85
- }
81
+ const prompts = util.getPromptsFromFiles();
82
+ const prompt = prompts.find(p => p.name === promptName);
86
83
 
87
- const processedPrompt = await util.processPromptContent(prompt, args);
88
- res.json({ processedText: processedPrompt });
89
- } catch (error) {
90
- res.status(500).json({ error: error.message });
84
+ if (!prompt) {
85
+ return res.status(404).json({ error: `Prompt "${promptName}" not found` });
91
86
  }
87
+
88
+ const processedPrompt = await util.processPromptContent(prompt, args);
89
+ res.json({ processedText: processedPrompt });
90
+ } catch (error) {
91
+ res.status(500).json({ error: error.message });
92
+ }
92
93
  });
93
94
 
94
- export const openRouter = router;
95
+ export const openRouter = router;
@@ -19,18 +19,17 @@ const surgeProxy = createProxyMiddleware({
19
19
  // 当路由已经去除了 /surge 前缀后,路径变为 /test_prompts.json
20
20
  // 我们需要将其重写为 /assets/test_prompts.json
21
21
  pathRewrite: {
22
- '^/': '/assets/', // 将 / 开头的路径重写为 /assets/ 开头
22
+ '^/': '/assets/' // 将 / 开头的路径重写为 /assets/ 开头
23
23
  },
24
24
  // 设置代理请求头
25
- onProxyReq: (proxyReq, req, res) => {
25
+ onProxyReq: (_proxyReq, _req, _res) => {
26
26
  // 可以在这里添加自定义逻辑,如设置请求头等
27
- console.log(`代理请求: ${req.method} ${req.url} -> ${surgeTarget}${req.url.replace(/^\/(.*)/, '/assets/$1')}`);
28
27
  },
29
- onProxyRes: (proxyRes, req, res) => {
28
+ onProxyRes: (proxyRes, _req, _res) => {
30
29
  // 可以在这里添加自定义逻辑,如修改响应头等
31
30
  proxyRes.headers['surge-proxy'] = 'enabled';
32
31
  },
33
- onError: (err, req, res) => {
32
+ onError: (err, _req, res) => {
34
33
  console.error('Surge 代理错误:', err);
35
34
  res.status(500).send('代理错误');
36
35
  }
@@ -40,4 +39,4 @@ const surgeProxy = createProxyMiddleware({
40
39
  // 由于在 app.js 中已经使用了 /surge 路径前缀,这里直接处理所有请求
41
40
  router.use(surgeProxy);
42
41
 
43
- export const surgeRouter = router;
42
+ export const surgeRouter = router;
@@ -11,19 +11,20 @@ import fse from 'fs-extra';
11
11
  import { logger } from '../utils/logger.js';
12
12
  import { toolLoaderService } from '../toolm/tool-loader.service.js';
13
13
  import { pathExists } from '../toolm/tool-utils.js';
14
- import os from 'os';
14
+ import { config } from '../utils/config.js';
15
+ import { authorConfigService } from '../services/author-config.service.js';
15
16
 
16
17
  // 配置 multer 用于处理文件上传
17
18
  const upload = multer({
18
19
  storage: multer.diskStorage({
19
20
  destination: (req, file, cb) => {
20
- const uploadDir = path.join(os.homedir(), '.prompt-manager', 'temp');
21
+ const uploadDir = config.getTempDir();
21
22
  fs.ensureDirSync(uploadDir);
22
23
  cb(null, uploadDir);
23
24
  },
24
25
  filename: (req, file, cb) => {
25
26
  // 生成唯一文件名,避免并发上传冲突
26
- const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1E9)}-${file.originalname}`;
27
+ const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1e9)}-${file.originalname}`;
27
28
  cb(null, uniqueName);
28
29
  }
29
30
  }),
@@ -53,14 +54,7 @@ router.get('/list', async (req, res) => {
53
54
  await toolLoaderService.initialize();
54
55
  }
55
56
 
56
- const {
57
- search,
58
- category,
59
- tags,
60
- author,
61
- page = 1,
62
- limit = 20
63
- } = req.query;
57
+ const { search, category, tags, author, page = 1, limit = 20 } = req.query;
64
58
 
65
59
  // 获取所有工具
66
60
  let tools = toolLoaderService.getAllTools();
@@ -76,9 +70,7 @@ router.get('/list', async (req, res) => {
76
70
  }
77
71
 
78
72
  if (category) {
79
- tools = tools.filter(tool =>
80
- tool.metadata.category === category
81
- );
73
+ tools = tools.filter(tool => tool.metadata.category === category);
82
74
  }
83
75
 
84
76
  if (tags) {
@@ -91,9 +83,7 @@ router.get('/list', async (req, res) => {
91
83
 
92
84
  if (author) {
93
85
  const authorLower = author.toLowerCase();
94
- tools = tools.filter(tool =>
95
- tool.metadata.author?.toLowerCase() === authorLower
96
- );
86
+ tools = tools.filter(tool => tool.metadata.author?.toLowerCase() === authorLower);
97
87
  }
98
88
 
99
89
  // 排序
@@ -105,21 +95,37 @@ router.get('/list', async (req, res) => {
105
95
  const endIndex = startIndex + limit;
106
96
  const paginatedTools = tools.slice(startIndex, endIndex);
107
97
 
108
- // 格式化返回数据
109
- const formattedTools = paginatedTools.map(tool => {
110
- const metadata = tool.metadata || {};
111
- return {
112
- id: metadata.id || tool.name,
113
- name: metadata.name || tool.name,
114
- description: metadata.description || '',
115
- version: metadata.version || '1.0.0',
116
- category: metadata.category || 'other',
117
- author: metadata.author || 'Prompt Manager',
118
- tags: metadata.tags || [],
119
- scenarios: metadata.scenarios || [],
120
- limitations: metadata.limitations || []
121
- };
122
- });
98
+ const formattedTools = await Promise.all(
99
+ paginatedTools.map(async tool => {
100
+ const metadata = tool.metadata || {};
101
+ const authorName = metadata.author || 'BeCrafter';
102
+
103
+ const authorInfo = await authorConfigService.resolveAuthor(authorName);
104
+
105
+ return {
106
+ id: metadata.id || tool.name,
107
+ name: metadata.name || tool.name,
108
+ description: metadata.description || '',
109
+ version: metadata.version || '1.0.0',
110
+ category: metadata.category || 'other',
111
+ author: authorInfo.name,
112
+ author_info: {
113
+ id: authorInfo.id,
114
+ name: authorInfo.name,
115
+ github: authorInfo.github,
116
+ homepage: authorInfo.homepage,
117
+ bio: authorInfo.bio,
118
+ featured: authorInfo.featured,
119
+ sort_order: authorInfo.sort_order,
120
+ aliases: authorInfo.aliases,
121
+ avatar_url: authorInfo.avatar_url
122
+ },
123
+ tags: metadata.tags || [],
124
+ scenarios: metadata.scenarios || [],
125
+ limitations: metadata.limitations || []
126
+ };
127
+ })
128
+ );
123
129
 
124
130
  const response = {
125
131
  success: true,
@@ -130,7 +136,6 @@ router.get('/list', async (req, res) => {
130
136
  };
131
137
 
132
138
  res.json(response);
133
-
134
139
  } catch (error) {
135
140
  logger.error('获取工具列表失败:', error);
136
141
  res.status(500).json({
@@ -151,7 +156,7 @@ router.get('/detail/:toolName', async (req, res) => {
151
156
  }
152
157
 
153
158
  const { toolName } = req.params;
154
-
159
+
155
160
  // 检查工具是否存在
156
161
  if (!toolLoaderService.hasTool(toolName)) {
157
162
  return res.status(404).json({
@@ -182,7 +187,6 @@ router.get('/detail/:toolName', async (req, res) => {
182
187
  success: true,
183
188
  tool: toolDetail
184
189
  });
185
-
186
190
  } catch (error) {
187
191
  logger.error('获取工具详情失败:', error);
188
192
  res.status(500).json({
@@ -203,7 +207,7 @@ router.get('/readme/:toolName', async (req, res) => {
203
207
  }
204
208
 
205
209
  const { toolName } = req.params;
206
-
210
+
207
211
  // 检查工具是否存在
208
212
  if (!toolLoaderService.hasTool(toolName)) {
209
213
  return res.status(404).json({
@@ -212,13 +216,11 @@ router.get('/readme/:toolName', async (req, res) => {
212
216
  });
213
217
  }
214
218
 
215
- const tool = toolLoaderService.getTool(toolName);
216
-
217
219
  // 查找 README.md 文件
218
- const toolboxDir = path.join(os.homedir(), '.prompt-manager', 'toolbox', toolName);
220
+ const toolboxDir = config.getToolDir(toolName);
219
221
  const readmePath = path.join(toolboxDir, 'README.md');
220
-
221
- if (!await pathExists(readmePath)) {
222
+
223
+ if (!(await pathExists(readmePath))) {
222
224
  return res.status(404).json({
223
225
  success: false,
224
226
  error: `工具 '${toolName}' 的 README.md 文件不存在`
@@ -227,13 +229,12 @@ router.get('/readme/:toolName', async (req, res) => {
227
229
 
228
230
  const fs = await import('fs');
229
231
  const readmeContent = await fs.promises.readFile(readmePath, 'utf-8');
230
-
232
+
231
233
  res.json({
232
234
  success: true,
233
235
  toolName,
234
236
  content: readmeContent
235
237
  });
236
-
237
238
  } catch (error) {
238
239
  logger.error('读取工具 README 失败:', error);
239
240
  res.status(500).json({
@@ -245,7 +246,7 @@ router.get('/readme/:toolName', async (req, res) => {
245
246
 
246
247
  /**
247
248
  * 上传工具包
248
- *
249
+ *
249
250
  * 上传内容必须是 .zip 文件
250
251
  * 上传后需要做工具名的重复性检查,重复的不允许会给出提示,让用户自己判断是否需要覆盖
251
252
  * 解压缩 .zip 文件,然后检查里面是否存在规范约定的两个文件,至少存在这两个
@@ -275,9 +276,9 @@ router.post('/upload', upload.single('file'), async (req, res) => {
275
276
  }
276
277
 
277
278
  // 创建临时解压目录
278
- const tempDir = path.join(os.homedir(), '.prompt-manager', 'temp');
279
+ const tempDir = config.getTempDir();
279
280
  fs.ensureDirSync(tempDir);
280
- extractedDir = path.join(tempDir, `extracted_${Date.now()}_${Math.round(Math.random() * 1E9)}`);
281
+ extractedDir = path.join(tempDir, `extracted_${Date.now()}_${Math.round(Math.random() * 1e9)}`);
281
282
  fs.ensureDirSync(extractedDir);
282
283
 
283
284
  // 解压ZIP文件
@@ -286,10 +287,10 @@ router.post('/upload', upload.single('file'), async (req, res) => {
286
287
 
287
288
  // 检查解压后的目录结构
288
289
  const files = fs.readdirSync(extractedDir);
289
-
290
+
290
291
  // 查找工具文件(以 .tool.js 结尾的文件)
291
- const toolFiles = files.filter(file =>
292
- file.endsWith('.tool.js') && fs.statSync(path.join(extractedDir, file)).isFile()
292
+ const toolFiles = files.filter(
293
+ file => file.endsWith('.tool.js') && fs.statSync(path.join(extractedDir, file)).isFile()
293
294
  );
294
295
 
295
296
  if (toolFiles.length === 0) {
@@ -304,8 +305,8 @@ router.post('/upload', upload.single('file'), async (req, res) => {
304
305
  const toolName = toolFileName.replace('.tool.js', '');
305
306
 
306
307
  // 检查是否存在 README.md
307
- const hasReadme = files.some(file =>
308
- file.toLowerCase() === 'readme.md' && fs.statSync(path.join(extractedDir, file)).isFile()
308
+ const hasReadme = files.some(
309
+ file => file.toLowerCase() === 'readme.md' && fs.statSync(path.join(extractedDir, file)).isFile()
309
310
  );
310
311
 
311
312
  if (!hasReadme) {
@@ -316,7 +317,7 @@ router.post('/upload', upload.single('file'), async (req, res) => {
316
317
  }
317
318
 
318
319
  // 检查工具是否已存在
319
- const toolboxDir = path.join(os.homedir(), '.prompt-manager', 'toolbox');
320
+ const toolboxDir = config.getToolboxDir();
320
321
  const targetToolDir = path.join(toolboxDir, toolName);
321
322
  const toolExists = await pathExists(targetToolDir);
322
323
 
@@ -325,7 +326,7 @@ router.post('/upload', upload.single('file'), async (req, res) => {
325
326
  return res.status(409).json({
326
327
  success: false,
327
328
  error: `工具 "${toolName}" 已存在`,
328
- toolName: toolName,
329
+ toolName,
329
330
  canOverwrite: true
330
331
  });
331
332
  }
@@ -341,7 +342,7 @@ router.post('/upload', upload.single('file'), async (req, res) => {
341
342
 
342
343
  // 检查工具文件是否可导入(语法验证)
343
344
  const toolFilePath = path.join(targetToolDir, toolFileName);
344
- if (!await pathExists(toolFilePath)) {
345
+ if (!(await pathExists(toolFilePath))) {
345
346
  return res.status(500).json({
346
347
  success: false,
347
348
  error: `工具文件 ${toolFileName} 不存在`
@@ -353,19 +354,19 @@ router.post('/upload', upload.single('file'), async (req, res) => {
353
354
  try {
354
355
  const toolModule = await import(`file://${toolFilePath}`);
355
356
  tool = toolModule.default || toolModule;
356
-
357
+
357
358
  // 验证工具接口是否符合规范
358
359
  if (typeof tool.execute !== 'function') {
359
360
  return res.status(400).json({
360
361
  success: false,
361
- error: `工具文件缺少必需的 execute 方法`
362
+ error: '工具文件缺少必需的 execute 方法'
362
363
  });
363
364
  }
364
-
365
+
365
366
  // 运行测试验证工具是否能正常工作
366
367
  const { createToolContext } = await import('../toolm/tool-context.service.js');
367
- const toolContext = await createToolContext(toolName, tool);
368
-
368
+ await createToolContext(toolName, tool);
369
+
369
370
  // 执行一个简单的测试,检查工具是否能被正确初始化
370
371
  if (typeof tool.getMetadata === 'function') {
371
372
  try {
@@ -377,13 +378,12 @@ router.post('/upload', upload.single('file'), async (req, res) => {
377
378
  logger.warn(`工具 ${toolName} 的 getMetadata 方法调用失败:`, metaError.message);
378
379
  }
379
380
  }
380
-
381
+
381
382
  // 简单测试 execute 方法是否存在
382
383
  if (tool.execute && typeof tool.execute === 'function') {
383
384
  // 为了安全起见,不实际执行工具,只验证其签名
384
385
  logger.info(`工具 ${toolName} 的 execute 方法存在,签名验证通过`);
385
386
  }
386
-
387
387
  } catch (importError) {
388
388
  // 清理失败的工具目录
389
389
  await fse.remove(targetToolDir);
@@ -423,7 +423,7 @@ router.post('/upload', upload.single('file'), async (req, res) => {
423
423
  // 重新加载工具
424
424
  await toolLoaderService.reload();
425
425
  }
426
-
426
+
427
427
  // 验证工具是否可以被加载
428
428
  if (toolLoaderService.hasTool(toolName)) {
429
429
  logger.info(`工具 ${toolName} 验证通过并已加载`);
@@ -435,22 +435,21 @@ router.post('/upload', upload.single('file'), async (req, res) => {
435
435
  res.json({
436
436
  success: true,
437
437
  message: `工具 ${toolName} 上传成功`,
438
- toolName: toolName,
438
+ toolName,
439
439
  overwritten: toolExists && req.body.overwrite === 'true'
440
440
  });
441
-
442
441
  } catch (error) {
443
442
  logger.error('工具上传失败:', error);
444
-
443
+
445
444
  // 清理临时文件
446
445
  try {
447
- if (extractedDir && await pathExists(extractedDir)) {
446
+ if (extractedDir && (await pathExists(extractedDir))) {
448
447
  await fse.remove(extractedDir);
449
448
  }
450
449
  } catch (cleanupError) {
451
450
  logger.error('清理临时文件失败:', cleanupError);
452
451
  }
453
-
452
+
454
453
  res.status(500).json({
455
454
  success: false,
456
455
  error: error.message
@@ -458,16 +457,16 @@ router.post('/upload', upload.single('file'), async (req, res) => {
458
457
  } finally {
459
458
  // 确保临时上传的ZIP文件被清理
460
459
  try {
461
- if (tempZipPath && await pathExists(tempZipPath)) {
460
+ if (tempZipPath && (await pathExists(tempZipPath))) {
462
461
  await fse.remove(tempZipPath);
463
462
  }
464
463
  } catch (cleanupError) {
465
464
  logger.error('清理上传文件失败:', cleanupError);
466
465
  }
467
-
466
+
468
467
  // 确保临时解压目录被清理
469
468
  try {
470
- if (extractedDir && await pathExists(extractedDir)) {
469
+ if (extractedDir && (await pathExists(extractedDir))) {
471
470
  await fse.remove(extractedDir);
472
471
  }
473
472
  } catch (cleanupError) {
@@ -476,4 +475,4 @@ router.post('/upload', upload.single('file'), async (req, res) => {
476
475
  }
477
476
  });
478
477
 
479
- export { router as toolRouter };
478
+ export { router as toolRouter };