@becrafter/prompt-manager 0.1.22 → 0.2.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 (114) hide show
  1. package/package.json +31 -24
  2. package/packages/resources/tools/agent-browser/README.md +640 -0
  3. package/packages/resources/tools/agent-browser/agent-browser.tool.js +1389 -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
@@ -7,12 +7,11 @@ import path from 'path';
7
7
  import fs from 'fs';
8
8
  import fse from 'fs-extra';
9
9
  import yaml from 'js-yaml';
10
- import { fileURLToPath } from 'url';
11
10
  import { spawn } from 'child_process';
12
11
  import { logger } from '../utils/logger.js';
13
12
  import { util, GROUP_META_FILENAME } from '../utils/util.js';
14
13
  import { config } from '../utils/config.js';
15
- import {adminAuthMiddleware} from '../middlewares/auth.middleware.js'
14
+ import { adminAuthMiddleware } from '../middlewares/auth.middleware.js';
16
15
  import { templateManager } from '../services/template.service.js';
17
16
  import { modelManager } from '../services/model.service.js';
18
17
  import { optimizationService } from '../services/optimization.service.js';
@@ -21,20 +20,20 @@ import { webSocketService } from '../services/WebSocketService.js';
21
20
  const router = express.Router();
22
21
 
23
22
  // 获取prompts目录路径(在启动时可能被覆盖)
24
- let promptsDir = config.getPromptsDir();
23
+ const promptsDir = config.getPromptsDir();
25
24
  const PROMPT_NAME_REGEX = /^(?![.]{1,2}$)[^\\/:*?"<>|\r\n]{1,64}$/;
26
25
 
27
26
  // 获取服务器配置端点
28
27
  router.get('/config', (req, res) => {
29
- // 检查是否启用了管理员功能
30
- if (!config.adminEnable) {
31
- return res.status(404).json({ error: 'Admin功能未启用' });
32
- }
28
+ // 检查是否启用了管理员功能
29
+ if (!config.adminEnable) {
30
+ return res.status(404).json({ error: 'Admin功能未启用' });
31
+ }
33
32
 
34
- res.json({
35
- requireAuth: config.adminRequireAuth,
36
- adminEnable: config.adminEnable
37
- });
33
+ res.json({
34
+ requireAuth: config.adminRequireAuth,
35
+ adminEnable: config.adminEnable
36
+ });
38
37
  });
39
38
 
40
39
  // 获取公开配置端点(无需认证)
@@ -57,852 +56,857 @@ router.get('/config/public', (req, res) => {
57
56
 
58
57
  // 登录端点
59
58
  router.post('/login', (req, res) => {
60
- // 检查是否启用了管理员功能
61
- if (!config.adminEnable) {
62
- return res.status(404).json({ error: 'Admin功能未启用' });
63
- }
59
+ // 检查是否启用了管理员功能
60
+ if (!config.adminEnable) {
61
+ return res.status(404).json({ error: 'Admin功能未启用' });
62
+ }
64
63
 
65
- // 如果不需要认证,返回默认token
66
- if (!config.adminRequireAuth) {
67
- return res.json({ token: config.admins[0].token });
68
- }
64
+ // 如果不需要认证,返回默认token
65
+ if (!config.adminRequireAuth) {
66
+ return res.json({ token: config.admins[0].token });
67
+ }
69
68
 
70
- const { username, password } = req.body;
69
+ const { username, password } = req.body;
71
70
 
72
- if (!username || !password) {
73
- return res.status(400).json({ error: '用户名和密码是必需的' });
74
- }
71
+ if (!username || !password) {
72
+ return res.status(400).json({ error: '用户名和密码是必需的' });
73
+ }
75
74
 
76
- // 验证凭据
77
- const admin = config.admins.find(a => a.username === username && a.password === password);
78
- if (!admin) {
79
- return res.status(401).json({ error: '无效的用户名或密码' });
80
- }
75
+ // 验证凭据
76
+ const admin = config.admins.find(a => a.username === username && a.password === password);
77
+ if (!admin) {
78
+ return res.status(401).json({ error: '无效的用户名或密码' });
79
+ }
81
80
 
82
- res.json({ token: admin.token });
81
+ res.json({ token: admin.token });
83
82
  });
84
83
 
85
84
  // 获取分组目录
86
85
  router.get('/groups', adminAuthMiddleware, (req, res) => {
87
- try {
88
- const tree = util.buildGroupTree(promptsDir);
89
- const hasDefault = tree.some(node => node.path === 'default');
90
- if (!hasDefault) {
91
- tree.unshift({ name: 'default', path: 'default', children: [], enabled: true });
92
- }
93
- res.json(tree);
94
- } catch (error) {
95
- res.status(500).json({ error: error.message });
96
- }
86
+ try {
87
+ const tree = util.buildGroupTree(promptsDir);
88
+ const hasDefault = tree.some(node => node.path === 'default');
89
+ if (!hasDefault) {
90
+ tree.unshift({ name: 'default', path: 'default', children: [], enabled: true });
91
+ }
92
+ res.json(tree);
93
+ } catch (error) {
94
+ res.status(500).json({ error: error.message });
95
+ }
97
96
  });
98
97
 
99
98
  // 获取所有提示词(支持搜索、过滤和分组)
100
99
  router.get('/prompts', adminAuthMiddleware, (req, res) => {
101
- try {
102
- const prompts = util.getPromptsFromFiles();
103
-
104
- // 处理搜索参数
105
- const search = req.query.search;
106
- const enabled = req.query.enabled === 'true';
107
- const groupPathFilter = req.query.groupPath;
108
- const group = req.query.group;
109
-
110
- let filteredPrompts = prompts;
111
-
112
- // 应用分组过滤
113
- if (groupPathFilter) {
114
- filteredPrompts = filteredPrompts.filter(prompt => (prompt.groupPath || prompt.group || 'default') === groupPathFilter);
115
- } else if (group) {
116
- filteredPrompts = filteredPrompts.filter(prompt => (prompt.group || 'default') === group);
117
- }
100
+ try {
101
+ const prompts = util.getPromptsFromFiles();
118
102
 
119
- // 应用搜索过滤
120
- if (search) {
121
- filteredPrompts = filteredPrompts.filter(prompt =>
122
- prompt.name.includes(search) ||
123
- (prompt.description && prompt.description.includes(search))
124
- );
125
- }
103
+ // 处理搜索参数
104
+ const search = req.query.search;
105
+ const enabled = req.query.enabled === 'true';
106
+ const groupPathFilter = req.query.groupPath;
107
+ const group = req.query.group;
126
108
 
127
- // 应用启用状态过滤
128
- if (enabled) {
129
- filteredPrompts = filteredPrompts.filter(prompt => {
130
- // 检查提示词本身是否启用
131
- const promptActive = prompt.enabled === true;
132
- if (!promptActive) return false;
133
-
134
- // 检查目录状态 - util.getPromptsFromFiles() 已经正确处理了继承的启用状态
135
- // groupEnabled 已经考虑了父目录的禁用状态
136
- const groupActive = prompt.groupEnabled !== false;
137
- return groupActive;
138
- });
139
- }
109
+ let filteredPrompts = prompts;
110
+
111
+ // 应用分组过滤
112
+ if (groupPathFilter) {
113
+ filteredPrompts = filteredPrompts.filter(
114
+ prompt => (prompt.groupPath || prompt.group || 'default') === groupPathFilter
115
+ );
116
+ } else if (group) {
117
+ filteredPrompts = filteredPrompts.filter(prompt => (prompt.group || 'default') === group);
118
+ }
140
119
 
141
- filteredPrompts.sort((a, b) => (a.name || '').localeCompare(b.name || '', 'zh-CN'));
120
+ // 应用搜索过滤
121
+ if (search) {
122
+ filteredPrompts = filteredPrompts.filter(
123
+ prompt => prompt.name.includes(search) || (prompt.description && prompt.description.includes(search))
124
+ );
125
+ }
126
+
127
+ // 应用启用状态过滤
128
+ if (enabled) {
129
+ filteredPrompts = filteredPrompts.filter(prompt => {
130
+ // 检查提示词本身是否启用
131
+ const promptActive = prompt.enabled === true;
132
+ if (!promptActive) return false;
142
133
 
143
- res.json(filteredPrompts);
144
- } catch (error) {
145
- res.status(500).json({ error: error.message });
134
+ // 检查目录状态 - util.getPromptsFromFiles() 已经正确处理了继承的启用状态
135
+ // groupEnabled 已经考虑了父目录的禁用状态
136
+ const groupActive = prompt.groupEnabled !== false;
137
+ return groupActive;
138
+ });
146
139
  }
140
+
141
+ filteredPrompts.sort((a, b) => (a.name || '').localeCompare(b.name || '', 'zh-CN'));
142
+
143
+ res.json(filteredPrompts);
144
+ } catch (error) {
145
+ res.status(500).json({ error: error.message });
146
+ }
147
147
  });
148
148
 
149
149
  // 获取单个提示词
150
150
  router.get('/prompts/:name', adminAuthMiddleware, (req, res) => {
151
- try {
152
- const prompts = util.getPromptsFromFiles();
153
- const targetPath = req.query.path;
154
- let prompt;
155
- if (targetPath) {
156
- prompt = prompts.find(p => p.relativePath === targetPath);
157
- }
158
- if (!prompt) {
159
- prompt = prompts.find(p => p.name === req.params.name);
160
- }
151
+ try {
152
+ const prompts = util.getPromptsFromFiles();
153
+ const targetPath = req.query.path;
154
+ let prompt;
155
+ if (targetPath) {
156
+ prompt = prompts.find(p => p.relativePath === targetPath);
157
+ }
158
+ if (!prompt) {
159
+ prompt = prompts.find(p => p.name === req.params.name);
160
+ }
161
161
 
162
- if (!prompt) {
163
- return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
164
- }
162
+ if (!prompt) {
163
+ return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
164
+ }
165
165
 
166
- // 读取原始YAML文件内容
167
- const promptPath = path.join(promptsDir, prompt.relativePath);
168
- const yamlContent = fs.readFileSync(promptPath, 'utf8');
166
+ // 读取原始YAML文件内容
167
+ const promptPath = path.join(promptsDir, prompt.relativePath);
168
+ const yamlContent = fs.readFileSync(promptPath, 'utf8');
169
169
 
170
- res.json({
171
- ...prompt,
172
- yaml: yamlContent
173
- });
174
- } catch (error) {
175
- res.status(500).json({ error: error.message });
176
- }
170
+ res.json({
171
+ ...prompt,
172
+ yaml: yamlContent
173
+ });
174
+ } catch (error) {
175
+ res.status(500).json({ error: error.message });
176
+ }
177
177
  });
178
178
 
179
179
  // 保存提示词
180
180
  router.post('/prompts', adminAuthMiddleware, (req, res) => {
181
- try {
182
- const { name, group, yaml: yamlContent, relativePath: originalRelativePath } = req.body;
183
- const trimmedName = (name || '').trim();
181
+ try {
182
+ const { name, group, yaml: yamlContent, relativePath: originalRelativePath } = req.body;
183
+ const trimmedName = (name || '').trim();
184
184
 
185
- if (!trimmedName || !yamlContent) {
186
- return res.status(400).json({ error: '名称和YAML内容是必需的' });
187
- }
185
+ if (!trimmedName || !yamlContent) {
186
+ return res.status(400).json({ error: '名称和YAML内容是必需的' });
187
+ }
188
188
 
189
- // 验证名称格式
190
- if (!PROMPT_NAME_REGEX.test(trimmedName)) {
191
- return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? \" < > | 或换行,长度需在1-64字符' });
192
- }
189
+ // 验证名称格式
190
+ if (!PROMPT_NAME_REGEX.test(trimmedName)) {
191
+ return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? " < > | 或换行,长度需在1-64字符' });
192
+ }
193
193
 
194
- // 计算目标路径
195
- const groupName = group || 'default';
196
- const normalizedOriginalPath = originalRelativePath ? path.normalize(originalRelativePath).replace(/\\/g, '/') : null;
194
+ // 计算目标路径
195
+ const groupName = group || 'default';
196
+ const normalizedOriginalPath = originalRelativePath
197
+ ? path.normalize(originalRelativePath).replace(/\\/g, '/')
198
+ : null;
197
199
 
198
- const targetSegments = [];
199
- if (groupName) {
200
- targetSegments.push(groupName);
201
- }
200
+ const targetSegments = [];
201
+ if (groupName) {
202
+ targetSegments.push(groupName);
203
+ }
202
204
 
203
- const finalFileName = `${trimmedName}.yaml`;
204
- targetSegments.push(finalFileName);
205
-
206
- const targetRelativePath = path.posix.join(...targetSegments);
207
- const targetDir = path.join(promptsDir, path.posix.dirname(targetRelativePath));
208
- const filePath = path.join(promptsDir, targetRelativePath);
209
-
210
- fse.ensureDirSync(targetDir);
211
-
212
- // 检查是否重名(同目录下)
213
- const prompts = util.getPromptsFromFiles();
214
- const existingPrompt = prompts.find(p => {
215
- if (p.name !== trimmedName) return false;
216
- const isOriginalFile = normalizedOriginalPath && p.relativePath === normalizedOriginalPath;
217
- if (isOriginalFile) return false;
218
- const sameRelativePath = p.relativePath === targetRelativePath;
219
- if (sameRelativePath) return false;
220
- const sameDirectory = path.posix.dirname(p.relativePath || '') === path.posix.dirname(targetRelativePath);
221
- return sameDirectory;
222
- });
223
-
224
- if (existingPrompt) {
225
- return res.status(400).json({ error: '名称已存在' });
226
- }
205
+ const finalFileName = `${trimmedName}.yaml`;
206
+ targetSegments.push(finalFileName);
227
207
 
228
- // 保存文件
229
- fs.writeFileSync(filePath, yamlContent, 'utf8');
208
+ const targetRelativePath = path.posix.join(...targetSegments);
209
+ const targetDir = path.join(promptsDir, path.posix.dirname(targetRelativePath));
210
+ const filePath = path.join(promptsDir, targetRelativePath);
230
211
 
231
- // 如果目标路径与原始路径不同,删除旧文件
232
- if (normalizedOriginalPath && normalizedOriginalPath !== targetRelativePath) {
233
- const originalFilePath = path.join(promptsDir, normalizedOriginalPath);
234
- if (fs.existsSync(originalFilePath)) {
235
- fs.unlinkSync(originalFilePath);
236
- }
237
- }
212
+ fse.ensureDirSync(targetDir);
238
213
 
239
- res.json({ message: '保存成功', relativePath: targetRelativePath, group: groupName });
240
- } catch (error) {
241
- res.status(500).json({ error: error.message });
214
+ // 检查是否重名(同目录下)
215
+ const prompts = util.getPromptsFromFiles();
216
+ const existingPrompt = prompts.find(p => {
217
+ if (p.name !== trimmedName) return false;
218
+ const isOriginalFile = normalizedOriginalPath && p.relativePath === normalizedOriginalPath;
219
+ if (isOriginalFile) return false;
220
+ const sameRelativePath = p.relativePath === targetRelativePath;
221
+ if (sameRelativePath) return false;
222
+ const sameDirectory = path.posix.dirname(p.relativePath || '') === path.posix.dirname(targetRelativePath);
223
+ return sameDirectory;
224
+ });
225
+
226
+ if (existingPrompt) {
227
+ return res.status(400).json({ error: '名称已存在' });
242
228
  }
229
+
230
+ // 保存文件
231
+ fs.writeFileSync(filePath, yamlContent, 'utf8');
232
+
233
+ // 如果目标路径与原始路径不同,删除旧文件
234
+ if (normalizedOriginalPath && normalizedOriginalPath !== targetRelativePath) {
235
+ const originalFilePath = path.join(promptsDir, normalizedOriginalPath);
236
+ if (fs.existsSync(originalFilePath)) {
237
+ fs.unlinkSync(originalFilePath);
238
+ }
239
+ }
240
+
241
+ res.json({ message: '保存成功', relativePath: targetRelativePath, group: groupName });
242
+ } catch (error) {
243
+ res.status(500).json({ error: error.message });
244
+ }
243
245
  });
244
246
 
245
247
  // 创建新分组目录
246
248
  router.post('/groups', adminAuthMiddleware, (req, res) => {
247
- try {
248
- const { name, parent } = req.body;
249
+ try {
250
+ const { name, parent } = req.body;
249
251
 
250
- if (!name) {
251
- return res.status(400).json({ error: '分组名称是必需的' });
252
- }
252
+ if (!name) {
253
+ return res.status(400).json({ error: '分组名称是必需的' });
254
+ }
253
255
 
254
- // 验证名称格式
255
- if (!util.isValidGroupName(name)) {
256
- return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? \" < > | 或换行,长度需在1-64字符' });
257
- }
256
+ // 验证名称格式
257
+ if (!util.isValidGroupName(name)) {
258
+ return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? " < > | 或换行,长度需在1-64字符' });
259
+ }
258
260
 
259
- // 构建目标目录路径
260
- let targetPath;
261
- if (parent) {
262
- // 验证父级目录路径
263
- const resolvedParent = util.resolveGroupDir(parent);
264
- if (!resolvedParent) {
265
- return res.status(400).json({ error: '无效的父级目录路径' });
266
- }
267
- targetPath = path.join(resolvedParent.dir, name);
268
- } else {
269
- targetPath = path.join(promptsDir, name);
270
- }
261
+ // 构建目标目录路径
262
+ let targetPath;
263
+ if (parent) {
264
+ // 验证父级目录路径
265
+ const resolvedParent = util.resolveGroupDir(parent);
266
+ if (!resolvedParent) {
267
+ return res.status(400).json({ error: '无效的父级目录路径' });
268
+ }
269
+ targetPath = path.join(resolvedParent.dir, name);
270
+ } else {
271
+ targetPath = path.join(promptsDir, name);
272
+ }
271
273
 
272
- // 检查目录是否已存在
273
- if (fs.existsSync(targetPath)) {
274
- return res.status(400).json({ error: '分组已存在' });
275
- }
274
+ // 检查目录是否已存在
275
+ if (fs.existsSync(targetPath)) {
276
+ return res.status(400).json({ error: '分组已存在' });
277
+ }
276
278
 
277
- // 创建目录
278
- fs.mkdirSync(targetPath, { recursive: true });
279
+ // 创建目录
280
+ fs.mkdirSync(targetPath, { recursive: true });
279
281
 
280
- res.json({ message: '分组创建成功' });
281
- } catch (error) {
282
- res.status(500).json({ error: error.message });
283
- }
282
+ res.json({ message: '分组创建成功' });
283
+ } catch (error) {
284
+ res.status(500).json({ error: error.message });
285
+ }
284
286
  });
285
287
 
286
288
  // 重命名分组目录
287
289
  router.patch('/groups/rename', adminAuthMiddleware, (req, res) => {
288
- try {
289
- const { path: groupPath, newName } = req.body || {};
290
- if (!groupPath || !newName) {
291
- return res.status(400).json({ error: '分组路径和新名称是必需的' });
292
- }
293
- if (!util.isValidGroupName(newName)) {
294
- return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? \" < > | 或换行,长度需在1-64字符' });
295
- }
296
- if (groupPath === 'default') {
297
- return res.status(400).json({ error: '默认分组不允许重命名' });
298
- }
290
+ try {
291
+ const { path: groupPath, newName } = req.body || {};
292
+ if (!groupPath || !newName) {
293
+ return res.status(400).json({ error: '分组路径和新名称是必需的' });
294
+ }
295
+ if (!util.isValidGroupName(newName)) {
296
+ return res.status(400).json({ error: '名称格式无效,不能包含 / \\ : * ? " < > | 或换行,长度需在1-64字符' });
297
+ }
298
+ if (groupPath === 'default') {
299
+ return res.status(400).json({ error: '默认分组不允许重命名' });
300
+ }
299
301
 
300
- const resolved = util.resolveGroupDir(groupPath);
301
- if (!resolved) {
302
- return res.status(400).json({ error: '无效的分组路径' });
303
- }
304
- const { dir: oldDir, segments } = resolved;
305
- if (!fs.existsSync(oldDir) || !fs.lstatSync(oldDir).isDirectory()) {
306
- return res.status(404).json({ error: '分组不存在' });
307
- }
302
+ const resolved = util.resolveGroupDir(groupPath);
303
+ if (!resolved) {
304
+ return res.status(400).json({ error: '无效的分组路径' });
305
+ }
306
+ const { dir: oldDir, segments } = resolved;
307
+ if (!fs.existsSync(oldDir) || !fs.lstatSync(oldDir).isDirectory()) {
308
+ return res.status(404).json({ error: '分组不存在' });
309
+ }
308
310
 
309
- const parentSegments = segments.slice(0, -1);
310
- const oldName = segments[segments.length - 1];
311
- if (newName === oldName) {
312
- return res.json({ message: '分组名称未变更', path: groupPath });
313
- }
314
- const newSegments = [...parentSegments, newName];
315
- const newDir = path.resolve(promptsDir, ...newSegments);
316
- if (fs.existsSync(newDir)) {
317
- return res.status(400).json({ error: '目标名称已存在,请选择其他名称' });
318
- }
311
+ const parentSegments = segments.slice(0, -1);
312
+ const oldName = segments[segments.length - 1];
313
+ if (newName === oldName) {
314
+ return res.json({ message: '分组名称未变更', path: groupPath });
315
+ }
316
+ const newSegments = [...parentSegments, newName];
317
+ const newDir = path.resolve(promptsDir, ...newSegments);
318
+ if (fs.existsSync(newDir)) {
319
+ return res.status(400).json({ error: '目标名称已存在,请选择其他名称' });
320
+ }
319
321
 
320
- fse.moveSync(oldDir, newDir);
322
+ fse.moveSync(oldDir, newDir);
321
323
 
322
- res.json({ message: '分组重命名成功', path: newSegments.join('/') });
323
- } catch (error) {
324
- logger.error('分组重命名失败:', error);
325
- res.status(500).json({ error: error.message });
326
- }
324
+ res.json({ message: '分组重命名成功', path: newSegments.join('/') });
325
+ } catch (error) {
326
+ logger.error('分组重命名失败:', error);
327
+ res.status(500).json({ error: error.message });
328
+ }
327
329
  });
328
330
 
329
331
  // 设置分组目录状态
330
332
  router.patch('/groups/status', adminAuthMiddleware, (req, res) => {
331
- try {
332
- const { path: groupPath, enabled } = req.body || {};
333
- if (typeof enabled !== 'boolean') {
334
- return res.status(400).json({ error: '状态值无效' });
335
- }
336
- if (!groupPath) {
337
- return res.status(400).json({ error: '分组路径是必需的' });
338
- }
333
+ try {
334
+ const { path: groupPath, enabled } = req.body || {};
335
+ if (typeof enabled !== 'boolean') {
336
+ return res.status(400).json({ error: '状态值无效' });
337
+ }
338
+ if (!groupPath) {
339
+ return res.status(400).json({ error: '分组路径是必需的' });
340
+ }
339
341
 
340
- const resolved = util.resolveGroupDir(groupPath);
341
- if (!resolved) {
342
- return res.status(400).json({ error: '无效的分组路径' });
343
- }
344
- const { dir } = resolved;
345
- if (!fs.existsSync(dir) || !fs.lstatSync(dir).isDirectory()) {
346
- return res.status(404).json({ error: '分组不存在' });
347
- }
342
+ const resolved = util.resolveGroupDir(groupPath);
343
+ if (!resolved) {
344
+ return res.status(400).json({ error: '无效的分组路径' });
345
+ }
346
+ const { dir } = resolved;
347
+ if (!fs.existsSync(dir) || !fs.lstatSync(dir).isDirectory()) {
348
+ return res.status(404).json({ error: '分组不存在' });
349
+ }
348
350
 
349
- util.writeGroupMeta(dir, { enabled });
351
+ util.writeGroupMeta(dir, { enabled });
350
352
 
351
- res.json({ message: '分组状态已更新', enabled });
352
- } catch (error) {
353
- logger.error('更新分组状态失败:', error);
354
- res.status(500).json({ error: error.message });
355
- }
353
+ res.json({ message: '分组状态已更新', enabled });
354
+ } catch (error) {
355
+ logger.error('更新分组状态失败:', error);
356
+ res.status(500).json({ error: error.message });
357
+ }
356
358
  });
357
359
 
358
360
  // 删除分组目录
359
361
  router.delete('/groups', adminAuthMiddleware, (req, res) => {
360
- try {
361
- const groupPath = req.query.path;
362
- if (!groupPath) {
363
- return res.status(400).json({ error: '分组路径是必需的' });
364
- }
365
- if (groupPath === 'default') {
366
- return res.status(400).json({ error: '默认分组不允许删除' });
367
- }
368
-
369
- const resolved = util.resolveGroupDir(groupPath);
370
- if (!resolved) {
371
- return res.status(400).json({ error: '无效的分组路径' });
372
- }
373
- const { dir } = resolved;
374
- if (!fs.existsSync(dir) || !fs.lstatSync(dir).isDirectory()) {
375
- return res.status(404).json({ error: '分组不存在' });
376
- }
362
+ try {
363
+ const groupPath = req.query.path;
364
+ if (!groupPath) {
365
+ return res.status(400).json({ error: '分组路径是必需的' });
366
+ }
367
+ if (groupPath === 'default') {
368
+ return res.status(400).json({ error: '默认分组不允许删除' });
369
+ }
377
370
 
378
- const entries = fs.readdirSync(dir, { withFileTypes: true })
379
- .filter(entry => entry.name !== GROUP_META_FILENAME && !entry.name.startsWith('.'));
371
+ const resolved = util.resolveGroupDir(groupPath);
372
+ if (!resolved) {
373
+ return res.status(400).json({ error: '无效的分组路径' });
374
+ }
375
+ const { dir } = resolved;
376
+ if (!fs.existsSync(dir) || !fs.lstatSync(dir).isDirectory()) {
377
+ return res.status(404).json({ error: '分组不存在' });
378
+ }
380
379
 
381
- if (entries.length > 0) {
382
- return res.status(400).json({ error: '目录非空,请先移除其下的Prompt或子目录' });
383
- }
380
+ const entries = fs
381
+ .readdirSync(dir, { withFileTypes: true })
382
+ .filter(entry => entry.name !== GROUP_META_FILENAME && !entry.name.startsWith('.'));
384
383
 
385
- fse.removeSync(dir);
386
- res.json({ message: '分组删除成功' });
387
- } catch (error) {
388
- logger.error('删除分组失败:', error);
389
- res.status(500).json({ error: error.message });
384
+ if (entries.length > 0) {
385
+ return res.status(400).json({ error: '目录非空,请先移除其下的Prompt或子目录' });
390
386
  }
387
+
388
+ fse.removeSync(dir);
389
+ res.json({ message: '分组删除成功' });
390
+ } catch (error) {
391
+ logger.error('删除分组失败:', error);
392
+ res.status(500).json({ error: error.message });
393
+ }
391
394
  });
392
395
 
393
396
  // 切换提示词启用状态
394
397
  router.post('/prompts/:name/toggle', adminAuthMiddleware, (req, res) => {
395
- try {
396
- const prompts = util.getPromptsFromFiles();
397
- const targetPath = req.query.path;
398
- let prompt;
399
- if (targetPath) {
400
- prompt = prompts.find(p => p.relativePath === targetPath);
401
- }
402
- if (!prompt) {
403
- prompt = prompts.find(p => p.name === req.params.name);
404
- }
398
+ try {
399
+ const prompts = util.getPromptsFromFiles();
400
+ const targetPath = req.query.path;
401
+ let prompt;
402
+ if (targetPath) {
403
+ prompt = prompts.find(p => p.relativePath === targetPath);
404
+ }
405
+ if (!prompt) {
406
+ prompt = prompts.find(p => p.name === req.params.name);
407
+ }
405
408
 
406
- if (!prompt) {
407
- return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
408
- }
409
+ if (!prompt) {
410
+ return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
411
+ }
409
412
 
410
- // 读取原始YAML文件内容
411
- const promptPath = path.join(promptsDir, prompt.relativePath);
412
- const yamlContent = fs.readFileSync(promptPath, 'utf8');
413
+ // 读取原始YAML文件内容
414
+ const promptPath = path.join(promptsDir, prompt.relativePath);
415
+ const yamlContent = fs.readFileSync(promptPath, 'utf8');
413
416
 
414
- // 解析YAML
415
- const promptData = yaml.load(yamlContent);
417
+ // 解析YAML
418
+ const promptData = yaml.load(yamlContent);
416
419
 
417
- // 切换启用状态
418
- promptData.enabled = !promptData.enabled;
420
+ // 切换启用状态
421
+ promptData.enabled = !promptData.enabled;
419
422
 
420
- // 保存更新后的YAML
421
- const newYamlContent = yaml.dump(promptData);
422
- fs.writeFileSync(promptPath, newYamlContent, 'utf8');
423
+ // 保存更新后的YAML
424
+ const newYamlContent = yaml.dump(promptData);
425
+ fs.writeFileSync(promptPath, newYamlContent, 'utf8');
423
426
 
424
- res.json({ message: '状态切换成功', enabled: promptData.enabled });
425
- } catch (error) {
426
- res.status(500).json({ error: error.message });
427
- }
427
+ res.json({ message: '状态切换成功', enabled: promptData.enabled });
428
+ } catch (error) {
429
+ res.status(500).json({ error: error.message });
430
+ }
428
431
  });
429
432
 
430
433
  // 删除提示词(软删)
431
434
  router.delete('/prompts/:name', adminAuthMiddleware, (req, res) => {
432
- try {
433
- const prompts = util.getPromptsFromFiles();
434
- const targetPath = req.query.path;
435
- let prompt;
436
- if (targetPath) {
437
- prompt = prompts.find(p => p.relativePath === targetPath);
438
- }
439
- if (!prompt) {
440
- prompt = prompts.find(p => p.name === req.params.name);
441
- }
435
+ try {
436
+ const prompts = util.getPromptsFromFiles();
437
+ const targetPath = req.query.path;
438
+ let prompt;
439
+ if (targetPath) {
440
+ prompt = prompts.find(p => p.relativePath === targetPath);
441
+ }
442
+ if (!prompt) {
443
+ prompt = prompts.find(p => p.name === req.params.name);
444
+ }
442
445
 
443
- if (!prompt) {
444
- return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
445
- }
446
+ if (!prompt) {
447
+ return res.status(404).json({ error: `Prompt "${req.params.name}" 未找到` });
448
+ }
446
449
 
447
- // 读取原始文件路径
448
- const promptPath = path.join(promptsDir, prompt.relativePath);
450
+ // 读取原始文件路径
451
+ const promptPath = path.join(promptsDir, prompt.relativePath);
449
452
 
450
- // 直接删除文件
451
- fse.unlinkSync(promptPath);
453
+ // 直接删除文件
454
+ fse.unlinkSync(promptPath);
452
455
 
453
- res.json({ message: '删除成功' });
454
- } catch (error) {
455
- res.status(500).json({ error: error.message });
456
- }
456
+ res.json({ message: '删除成功' });
457
+ } catch (error) {
458
+ res.status(500).json({ error: error.message });
459
+ }
457
460
  });
458
461
 
459
462
  // Markdown预览
460
463
  router.post('/md-preview', adminAuthMiddleware, (req, res) => {
461
- try {
462
- const { yaml: yamlContent, vars } = req.body;
464
+ try {
465
+ const { yaml: yamlContent, vars } = req.body;
463
466
 
464
- if (!yamlContent) {
465
- return res.status(400).json({ error: 'YAML内容是必需的' });
466
- }
467
-
468
- // 解析YAML
469
- const promptData = yaml.load(yamlContent);
467
+ if (!yamlContent) {
468
+ return res.status(400).json({ error: 'YAML内容是必需的' });
469
+ }
470
470
 
471
- // 处理变量替换
472
- let content = '';
473
- if (promptData.messages && Array.isArray(promptData.messages)) {
474
- const userMessages = promptData.messages.filter(msg => msg.role === 'user');
471
+ // 解析YAML
472
+ const promptData = yaml.load(yamlContent);
475
473
 
476
- for (const message of userMessages) {
477
- if (message.content && typeof message.content.text === 'string') {
478
- let text = message.content.text;
474
+ // 处理变量替换
475
+ let content = '';
476
+ if (promptData.messages && Array.isArray(promptData.messages)) {
477
+ const userMessages = promptData.messages.filter(msg => msg.role === 'user');
479
478
 
480
- // 替换变量
481
- if (vars) {
482
- for (const [key, value] of Object.entries(vars)) {
483
- const placeholder = new RegExp(`{{${key}}}`, 'g');
484
- text = text.replace(placeholder, String(value));
485
- }
486
- }
479
+ for (const message of userMessages) {
480
+ if (message.content && typeof message.content.text === 'string') {
481
+ let text = message.content.text;
487
482
 
488
- content += text + '\n\n';
489
- }
483
+ // 替换变量
484
+ if (vars) {
485
+ for (const [key, value] of Object.entries(vars)) {
486
+ const placeholder = new RegExp(`{{${key}}}`, 'g');
487
+ text = text.replace(placeholder, String(value));
490
488
  }
491
- }
492
-
493
- // 简单的Markdown转HTML(实际应用中可以使用专门的库)
494
- const html = content
495
- .replace(/&/g, '&amp;')
496
- .replace(/</g, '&lt;')
497
- .replace(/>/g, '&gt;')
498
- .replace(/\n/g, '<br>')
499
- .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
500
- .replace(/\*(.*?)\*/g, '<em>$1</em>')
501
- .replace(/`(.*?)`/g, '<code>$1</code>')
502
- .replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
503
- .replace(/### (.*?)(<br>|$)/g, '<h3>$1</h3>')
504
- .replace(/## (.*?)(<br>|$)/g, '<h2>$1</h2>')
505
- .replace(/# (.*?)(<br>|$)/g, '<h1>$1</h1>');
506
-
507
- res.json({ html });
508
- } catch (error) {
509
- res.status(500).json({ error: error.message });
510
- }
489
+ }
490
+
491
+ content += `${text}\n\n`;
492
+ }
493
+ }
494
+ }
495
+
496
+ // 简单的Markdown转HTML(实际应用中可以使用专门的库)
497
+ const html = content
498
+ .replace(/&/g, '&amp;')
499
+ .replace(/</g, '&lt;')
500
+ .replace(/>/g, '&gt;')
501
+ .replace(/\n/g, '<br>')
502
+ .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
503
+ .replace(/\*(.*?)\*/g, '<em>$1</em>')
504
+ .replace(/`(.*?)`/g, '<code>$1</code>')
505
+ .replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
506
+ .replace(/### (.*?)(<br>|$)/g, '<h3>$1</h3>')
507
+ .replace(/## (.*?)(<br>|$)/g, '<h2>$1</h2>')
508
+ .replace(/# (.*?)(<br>|$)/g, '<h1>$1</h1>');
509
+
510
+ res.json({ html });
511
+ } catch (error) {
512
+ res.status(500).json({ error: error.message });
513
+ }
511
514
  });
512
515
 
513
516
  // 执行终端命令
514
517
  router.post('/terminal/execute', adminAuthMiddleware, (req, res) => {
515
- try {
516
- const { command, cwd } = req.body;
518
+ try {
519
+ const { command, cwd } = req.body;
520
+
521
+ if (!command) {
522
+ return res.status(400).json({ error: '命令是必需的' });
523
+ }
524
+
525
+ // 设置执行选项
526
+ const options = {
527
+ cwd: cwd || process.cwd(),
528
+ shell: true,
529
+ env: { ...process.env, FORCE_COLOR: '1' } // 启用颜色输出
530
+ };
531
+
532
+ let output = '';
533
+ let errorOutput = '';
534
+ let exitCode = null;
535
+
536
+ const child = spawn(command, [], options);
537
+
538
+ // 设置超时(5分钟)
539
+ const timeout = setTimeout(
540
+ () => {
541
+ child.kill('SIGTERM');
542
+ res.status(408).json({ error: '命令执行超时' });
543
+ },
544
+ 5 * 60 * 1000
545
+ );
546
+
547
+ // 监听标准输出
548
+ child.stdout.on('data', data => {
549
+ const chunk = data.toString();
550
+ output += chunk;
551
+ });
517
552
 
518
- if (!command) {
519
- return res.status(400).json({ error: '命令是必需的' });
520
- }
553
+ // 监听错误输出
554
+ child.stderr.on('data', data => {
555
+ const chunk = data.toString();
556
+ errorOutput += chunk;
557
+ });
521
558
 
522
- // 设置执行选项
523
- const options = {
524
- cwd: cwd || process.cwd(),
525
- shell: true,
526
- env: { ...process.env, FORCE_COLOR: '1' } // 启用颜色输出
527
- };
528
-
529
- let output = '';
530
- let errorOutput = '';
531
- let exitCode = null;
532
-
533
- const child = spawn(command, [], options);
534
-
535
- // 设置超时(5分钟)
536
- const timeout = setTimeout(() => {
537
- child.kill('SIGTERM');
538
- res.status(408).json({ error: '命令执行超时' });
539
- }, 5 * 60 * 1000);
540
-
541
- // 监听标准输出
542
- child.stdout.on('data', (data) => {
543
- const chunk = data.toString();
544
- output += chunk;
545
- });
546
-
547
- // 监听错误输出
548
- child.stderr.on('data', (data) => {
549
- const chunk = data.toString();
550
- errorOutput += chunk;
551
- });
552
-
553
- // 监听进程结束
554
- child.on('close', (code) => {
555
- clearTimeout(timeout);
556
- exitCode = code;
557
-
558
- res.json({
559
- success: true,
560
- command,
561
- output,
562
- errorOutput,
563
- exitCode,
564
- cwd: options.cwd
565
- });
566
- });
567
-
568
- // 监听错误
569
- child.on('error', (error) => {
570
- clearTimeout(timeout);
571
- logger.error('终端命令执行错误:', error);
572
- res.status(500).json({ error: `命令执行失败: ${error.message}` });
573
- });
574
-
575
- } catch (error) {
576
- logger.error('终端命令执行异常:', error);
577
- res.status(500).json({ error: error.message });
578
- }
559
+ // 监听进程结束
560
+ child.on('close', code => {
561
+ clearTimeout(timeout);
562
+ exitCode = code;
563
+
564
+ res.json({
565
+ success: true,
566
+ command,
567
+ output,
568
+ errorOutput,
569
+ exitCode,
570
+ cwd: options.cwd
571
+ });
572
+ });
573
+
574
+ // 监听错误
575
+ child.on('error', error => {
576
+ clearTimeout(timeout);
577
+ logger.error('终端命令执行错误:', error);
578
+ res.status(500).json({ error: `命令执行失败: ${error.message}` });
579
+ });
580
+ } catch (error) {
581
+ logger.error('终端命令执行异常:', error);
582
+ res.status(500).json({ error: error.message });
583
+ }
579
584
  });
580
585
 
581
586
  // 获取当前工作目录
582
587
  router.get('/terminal/cwd', adminAuthMiddleware, (req, res) => {
583
- try {
584
- res.json({
585
- cwd: process.cwd(),
586
- home: process.env.HOME || process.env.USERPROFILE
587
- });
588
- } catch (error) {
589
- res.status(500).json({ error: error.message });
590
- }
588
+ try {
589
+ res.json({
590
+ cwd: process.cwd(),
591
+ home: process.env.HOME || process.env.USERPROFILE
592
+ });
593
+ } catch (error) {
594
+ res.status(500).json({ error: error.message });
595
+ }
591
596
  });
592
597
 
593
598
  // 列出目录内容
594
599
  router.get('/terminal/ls', adminAuthMiddleware, (req, res) => {
595
- try {
596
- const { path: targetPath = '.' } = req.query;
597
- const fullPath = path.resolve(targetPath);
600
+ try {
601
+ const { path: targetPath = '.' } = req.query;
602
+ const fullPath = path.resolve(targetPath);
598
603
 
599
- // 检查路径是否存在
600
- if (!fs.existsSync(fullPath)) {
601
- return res.status(404).json({ error: '路径不存在' });
602
- }
604
+ // 检查路径是否存在
605
+ if (!fs.existsSync(fullPath)) {
606
+ return res.status(404).json({ error: '路径不存在' });
607
+ }
603
608
 
604
- // 检查是否是目录
605
- const stat = fs.statSync(fullPath);
606
- if (!stat.isDirectory()) {
607
- return res.status(400).json({ error: '路径不是目录' });
608
- }
609
+ // 检查是否是目录
610
+ const stat = fs.statSync(fullPath);
611
+ if (!stat.isDirectory()) {
612
+ return res.status(400).json({ error: '路径不是目录' });
613
+ }
609
614
 
610
- // 读取目录内容
611
- const items = fs.readdirSync(fullPath).map(item => {
612
- const itemPath = path.join(fullPath, item);
613
- const itemStat = fs.statSync(itemPath);
614
-
615
- return {
616
- name: item,
617
- path: itemPath,
618
- type: itemStat.isDirectory() ? 'directory' : 'file',
619
- size: itemStat.size,
620
- modified: itemStat.mtime.toISOString()
621
- };
622
- });
623
-
624
- // 排序:目录在前,文件在后,按名称排序
625
- items.sort((a, b) => {
626
- if (a.type !== b.type) {
627
- return a.type === 'directory' ? -1 : 1;
628
- }
629
- return a.name.localeCompare(b.name);
630
- });
615
+ // 读取目录内容
616
+ const items = fs.readdirSync(fullPath).map(item => {
617
+ const itemPath = path.join(fullPath, item);
618
+ const itemStat = fs.statSync(itemPath);
631
619
 
632
- res.json({
633
- success: true,
634
- path: fullPath,
635
- items
636
- });
620
+ return {
621
+ name: item,
622
+ path: itemPath,
623
+ type: itemStat.isDirectory() ? 'directory' : 'file',
624
+ size: itemStat.size,
625
+ modified: itemStat.mtime.toISOString()
626
+ };
627
+ });
637
628
 
638
- } catch (error) {
639
- logger.error('列出目录内容失败:', error);
640
- res.status(500).json({ error: error.message });
641
- }
629
+ // 排序:目录在前,文件在后,按名称排序
630
+ items.sort((a, b) => {
631
+ if (a.type !== b.type) {
632
+ return a.type === 'directory' ? -1 : 1;
633
+ }
634
+ return a.name.localeCompare(b.name);
635
+ });
636
+
637
+ res.json({
638
+ success: true,
639
+ path: fullPath,
640
+ items
641
+ });
642
+ } catch (error) {
643
+ logger.error('列出目录内容失败:', error);
644
+ res.status(500).json({ error: error.message });
645
+ }
642
646
  });
643
647
 
644
648
  // ==================== 优化相关路由 ====================
645
649
 
646
650
  // 优化提示词(流式)
647
651
  router.post('/prompts/optimize', adminAuthMiddleware, async (req, res) => {
648
- try {
649
- const { prompt, templateId, modelId, sessionId } = req.body;
650
-
651
- if (!prompt || !templateId || !modelId) {
652
- return res.status(400).json({ error: '提示词、模板ID和模型ID是必需的' });
653
- }
654
-
655
- // 设置 SSE 响应头
656
- res.setHeader('Content-Type', 'text/event-stream');
657
- res.setHeader('Cache-Control', 'no-cache');
658
- res.setHeader('Connection', 'keep-alive');
659
- res.setHeader('Access-Control-Allow-Origin', '*');
660
-
661
- // 调用优化服务(流式)
662
- await optimizationService.optimizePrompt(
663
- prompt,
664
- templateId,
665
- modelId,
666
- (chunk) => {
667
- // 流式输出回调
668
- res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
669
- },
670
- sessionId
671
- );
672
-
673
- // 发送完成信号
674
- res.write('data: [DONE]\n\n');
675
- res.end();
676
- } catch (error) {
677
- logger.error('优化提示词失败:', error);
678
- // 格式化错误信息,添加用户友好的前缀
679
- const errorMessage = `模型执行失败: ${error.message}`;
680
- res.write(`data: ${JSON.stringify({ error: errorMessage })}\n\n`);
681
- res.end();
682
- }
652
+ try {
653
+ const { prompt, templateId, modelId, sessionId } = req.body;
654
+
655
+ if (!prompt || !templateId || !modelId) {
656
+ return res.status(400).json({ error: '提示词、模板ID和模型ID是必需的' });
657
+ }
658
+
659
+ // 设置 SSE 响应头
660
+ res.setHeader('Content-Type', 'text/event-stream');
661
+ res.setHeader('Cache-Control', 'no-cache');
662
+ res.setHeader('Connection', 'keep-alive');
663
+ res.setHeader('Access-Control-Allow-Origin', '*');
664
+
665
+ // 调用优化服务(流式)
666
+ await optimizationService.optimizePrompt(
667
+ prompt,
668
+ templateId,
669
+ modelId,
670
+ chunk => {
671
+ // 流式输出回调
672
+ res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
673
+ },
674
+ sessionId
675
+ );
676
+
677
+ // 发送完成信号
678
+ res.write('data: [DONE]\n\n');
679
+ res.end();
680
+ } catch (error) {
681
+ logger.error('优化提示词失败:', error);
682
+ // 格式化错误信息,添加用户友好的前缀
683
+ const errorMessage = `模型执行失败: ${error.message}`;
684
+ res.write(`data: ${JSON.stringify({ error: errorMessage })}\n\n`);
685
+ res.end();
686
+ }
683
687
  });
684
688
 
685
689
  // 迭代优化(流式)
686
690
  router.post('/prompts/optimize/iterate', adminAuthMiddleware, async (req, res) => {
687
- try {
688
- const { currentResult, templateId, modelId, sessionId, guideText } = req.body;
689
-
690
- if (!currentResult || !templateId || !modelId || !sessionId) {
691
- return res.status(400).json({ error: '当前结果、模板ID、模型ID和会话ID是必需的' });
692
- }
693
-
694
- // 设置 SSE 响应头
695
- res.setHeader('Content-Type', 'text/event-stream');
696
- res.setHeader('Cache-Control', 'no-cache');
697
- res.setHeader('Connection', 'keep-alive');
698
- res.setHeader('Access-Control-Allow-Origin', '*');
699
-
700
- // 调用迭代优化服务(流式)
701
- await optimizationService.iterateOptimization(
702
- currentResult,
703
- templateId,
704
- modelId,
705
- (chunk) => {
706
- // 流式输出回调
707
- res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
708
- },
709
- sessionId,
710
- guideText // 传递优化指导参数
711
- );
712
-
713
- // 发送完成信号
714
- res.write('data: [DONE]\n\n');
715
- res.end();
716
- } catch (error) {
717
- logger.error('迭代优化失败:', error);
718
- // 格式化错误信息,添加用户友好的前缀
719
- const errorMessage = `模型执行失败: ${error.message}`;
720
- res.write(`data: ${JSON.stringify({ error: errorMessage })}\n\n`);
721
- res.end();
722
- }
691
+ try {
692
+ const { currentResult, templateId, modelId, sessionId, guideText } = req.body;
693
+
694
+ if (!currentResult || !templateId || !modelId || !sessionId) {
695
+ return res.status(400).json({ error: '当前结果、模板ID、模型ID和会话ID是必需的' });
696
+ }
697
+
698
+ // 设置 SSE 响应头
699
+ res.setHeader('Content-Type', 'text/event-stream');
700
+ res.setHeader('Cache-Control', 'no-cache');
701
+ res.setHeader('Connection', 'keep-alive');
702
+ res.setHeader('Access-Control-Allow-Origin', '*');
703
+
704
+ // 调用迭代优化服务(流式)
705
+ await optimizationService.iterateOptimization(
706
+ currentResult,
707
+ templateId,
708
+ modelId,
709
+ chunk => {
710
+ // 流式输出回调
711
+ res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
712
+ },
713
+ sessionId,
714
+ guideText // 传递优化指导参数
715
+ );
716
+
717
+ // 发送完成信号
718
+ res.write('data: [DONE]\n\n');
719
+ res.end();
720
+ } catch (error) {
721
+ logger.error('迭代优化失败:', error);
722
+ // 格式化错误信息,添加用户友好的前缀
723
+ const errorMessage = `模型执行失败: ${error.message}`;
724
+ res.write(`data: ${JSON.stringify({ error: errorMessage })}\n\n`);
725
+ res.end();
726
+ }
723
727
  });
724
728
 
725
729
  // 清除会话迭代信息
726
730
  router.delete('/prompts/optimize/session/:sessionId', adminAuthMiddleware, (req, res) => {
727
- try {
728
- const { sessionId } = req.params;
729
- optimizationService.clearSession(sessionId);
730
- res.json({ message: '会话已清除' });
731
- } catch (error) {
732
- logger.error('清除会话失败:', error);
733
- res.status(500).json({ error: error.message });
734
- }
731
+ try {
732
+ const { sessionId } = req.params;
733
+ optimizationService.clearSession(sessionId);
734
+ res.json({ message: '会话已清除' });
735
+ } catch (error) {
736
+ logger.error('清除会话失败:', error);
737
+ res.status(500).json({ error: error.message });
738
+ }
735
739
  });
736
740
 
737
741
  // 获取会话迭代信息
738
742
  router.get('/prompts/optimize/session/:sessionId', adminAuthMiddleware, (req, res) => {
739
- try {
740
- const { sessionId } = req.params;
741
- const sessionInfo = optimizationService.getSessionInfo(sessionId);
742
- res.json(sessionInfo);
743
- } catch (error) {
744
- logger.error('获取会话信息失败:', error);
745
- res.status(500).json({ error: error.message });
746
- }
743
+ try {
744
+ const { sessionId } = req.params;
745
+ const sessionInfo = optimizationService.getSessionInfo(sessionId);
746
+ res.json(sessionInfo);
747
+ } catch (error) {
748
+ logger.error('获取会话信息失败:', error);
749
+ res.status(500).json({ error: error.message });
750
+ }
747
751
  });
748
752
 
749
753
  // ==================== 模板管理路由 ====================
750
754
 
751
755
  // 获取所有模板
752
756
  router.get('/optimization/templates', adminAuthMiddleware, (req, res) => {
753
- try {
754
- const templates = templateManager.getTemplates();
755
- res.json(templates);
756
- } catch (error) {
757
- logger.error('获取模板列表失败:', error);
758
- res.status(500).json({ error: error.message });
759
- }
757
+ try {
758
+ const templates = templateManager.getTemplates();
759
+ res.json(templates);
760
+ } catch (error) {
761
+ logger.error('获取模板列表失败:', error);
762
+ res.status(500).json({ error: error.message });
763
+ }
760
764
  });
761
765
 
762
766
  // 创建模板
763
767
  router.post('/optimization/templates', adminAuthMiddleware, async (req, res) => {
764
- try {
765
- const template = await templateManager.createTemplate(req.body);
766
- res.json(template);
767
- } catch (error) {
768
- logger.error('创建模板失败:', error);
769
- res.status(500).json({ error: error.message });
770
- }
768
+ try {
769
+ const template = await templateManager.createTemplate(req.body);
770
+ res.json(template);
771
+ } catch (error) {
772
+ logger.error('创建模板失败:', error);
773
+ res.status(500).json({ error: error.message });
774
+ }
771
775
  });
772
776
 
773
777
  // 更新模板
774
778
  router.put('/optimization/templates/:id', adminAuthMiddleware, async (req, res) => {
775
- try {
776
- const { id } = req.params;
777
- const template = await templateManager.updateTemplate(id, req.body);
778
- res.json(template);
779
- } catch (error) {
780
- logger.error('更新模板失败:', error);
781
- res.status(500).json({ error: error.message });
782
- }
779
+ try {
780
+ const { id } = req.params;
781
+ const template = await templateManager.updateTemplate(id, req.body);
782
+ res.json(template);
783
+ } catch (error) {
784
+ logger.error('更新模板失败:', error);
785
+ res.status(500).json({ error: error.message });
786
+ }
783
787
  });
784
788
 
785
789
  // 删除模板
786
790
  router.delete('/optimization/templates/:id', adminAuthMiddleware, async (req, res) => {
787
- try {
788
- const { id } = req.params;
789
- await templateManager.deleteTemplate(id);
790
- res.json({ message: '模板删除成功' });
791
- } catch (error) {
792
- logger.error('删除模板失败:', error);
793
- res.status(500).json({ error: error.message });
794
- }
791
+ try {
792
+ const { id } = req.params;
793
+ await templateManager.deleteTemplate(id);
794
+ res.json({ message: '模板删除成功' });
795
+ } catch (error) {
796
+ logger.error('删除模板失败:', error);
797
+ res.status(500).json({ error: error.message });
798
+ }
795
799
  });
796
800
 
797
801
  // ==================== 模型管理路由 ====================
798
802
 
799
803
  // 获取模型提供商列表
800
804
  router.get('/optimization/models/providers', adminAuthMiddleware, async (req, res) => {
801
- try {
802
- const providers = await modelManager.getProviders();
803
- res.json(providers);
804
- } catch (error) {
805
- logger.error('获取模型提供商列表失败:', error);
806
- res.status(500).json({ error: error.message });
807
- }
805
+ try {
806
+ const providers = await modelManager.getProviders();
807
+ res.json(providers);
808
+ } catch (error) {
809
+ logger.error('获取模型提供商列表失败:', error);
810
+ res.status(500).json({ error: error.message });
811
+ }
808
812
  });
809
813
 
810
814
  // 获取模型提供商的默认配置
811
815
  router.get('/optimization/models/providers/:key', adminAuthMiddleware, async (req, res) => {
812
- try {
813
- const { key } = req.params;
814
- const defaults = await modelManager.getProviderDefaults(key);
815
- if (!defaults) {
816
- return res.status(404).json({ error: '提供商不存在' });
817
- }
818
- res.json(defaults);
819
- } catch (error) {
820
- logger.error('获取提供商默认配置失败:', error);
821
- res.status(500).json({ error: error.message });
822
- }
816
+ try {
817
+ const { key } = req.params;
818
+ const defaults = await modelManager.getProviderDefaults(key);
819
+ if (!defaults) {
820
+ return res.status(404).json({ error: '提供商不存在' });
821
+ }
822
+ res.json(defaults);
823
+ } catch (error) {
824
+ logger.error('获取提供商默认配置失败:', error);
825
+ res.status(500).json({ error: error.message });
826
+ }
823
827
  });
824
828
 
825
829
  // 获取所有模型
826
830
  router.get('/optimization/models', adminAuthMiddleware, (req, res) => {
827
- try {
828
- const models = modelManager.getModels();
829
- res.json(models);
830
- } catch (error) {
831
- logger.error('获取模型列表失败:', error);
832
- res.status(500).json({ error: error.message });
833
- }
831
+ try {
832
+ const models = modelManager.getModels();
833
+ res.json(models);
834
+ } catch (error) {
835
+ logger.error('获取模型列表失败:', error);
836
+ res.status(500).json({ error: error.message });
837
+ }
834
838
  });
835
839
 
836
840
  // 创建模型
837
841
  router.post('/optimization/models', adminAuthMiddleware, async (req, res) => {
838
- try {
839
- const model = await modelManager.createModel(req.body);
840
- res.json(model);
841
- } catch (error) {
842
- logger.error('创建模型失败:', error);
843
- res.status(500).json({ error: error.message });
844
- }
842
+ try {
843
+ const model = await modelManager.createModel(req.body);
844
+ res.json(model);
845
+ } catch (error) {
846
+ logger.error('创建模型失败:', error);
847
+ res.status(500).json({ error: error.message });
848
+ }
845
849
  });
846
850
 
847
851
  // 更新模型
848
852
  router.put('/optimization/models/:id', adminAuthMiddleware, async (req, res) => {
849
- try {
850
- const { id } = req.params;
851
- const model = await modelManager.updateModel(id, req.body);
852
- res.json(model);
853
- } catch (error) {
854
- logger.error('更新模型失败:', error);
855
- res.status(500).json({ error: error.message });
856
- }
853
+ try {
854
+ const { id } = req.params;
855
+ const model = await modelManager.updateModel(id, req.body);
856
+ res.json(model);
857
+ } catch (error) {
858
+ logger.error('更新模型失败:', error);
859
+ res.status(500).json({ error: error.message });
860
+ }
857
861
  });
858
862
 
859
863
  // 删除模型
860
864
  router.delete('/optimization/models/:id', adminAuthMiddleware, async (req, res) => {
861
- try {
862
- const { id } = req.params;
863
- await modelManager.deleteModel(id);
864
- res.json({ message: '模型删除成功' });
865
- } catch (error) {
866
- logger.error('删除模型失败:', error);
867
- res.status(500).json({ error: error.message });
868
- }
865
+ try {
866
+ const { id } = req.params;
867
+ await modelManager.deleteModel(id);
868
+ res.json({ message: '模型删除成功' });
869
+ } catch (error) {
870
+ logger.error('删除模型失败:', error);
871
+ res.status(500).json({ error: error.message });
872
+ }
869
873
  });
870
874
 
871
875
  // 测试模型连接
872
876
  router.post('/optimization/models/:id/test', adminAuthMiddleware, async (req, res) => {
873
- try {
874
- const { id } = req.params;
875
- const result = await optimizationService.testModel(id);
876
- res.json(result);
877
- } catch (error) {
878
- logger.error('测试模型连接失败:', error);
879
- res.status(500).json({ error: error.message });
880
- }
877
+ try {
878
+ const { id } = req.params;
879
+ const result = await optimizationService.testModel(id);
880
+ res.json(result);
881
+ } catch (error) {
882
+ logger.error('测试模型连接失败:', error);
883
+ res.status(500).json({ error: error.message });
884
+ }
881
885
  });
882
886
 
883
887
  // ==================== 优化配置路由 ====================
884
888
 
885
889
  // 获取优化配置(预留接口,可用于全局配置)
886
890
  router.get('/optimization/config', adminAuthMiddleware, (req, res) => {
887
- try {
888
- res.json({
889
- maxIterations: 10,
890
- encryptionEnabled: true
891
- });
892
- } catch (error) {
893
- logger.error('获取优化配置失败:', error);
894
- res.status(500).json({ error: error.message });
895
- }
891
+ try {
892
+ res.json({
893
+ maxIterations: 10,
894
+ encryptionEnabled: true
895
+ });
896
+ } catch (error) {
897
+ logger.error('获取优化配置失败:', error);
898
+ res.status(500).json({ error: error.message });
899
+ }
896
900
  });
897
901
 
898
902
  // 更新优化配置(预留接口)
899
903
  router.put('/optimization/config', adminAuthMiddleware, (req, res) => {
900
- try {
901
- res.json({ message: '配置更新成功' });
902
- } catch (error) {
903
- logger.error('更新优化配置失败:', error);
904
- res.status(500).json({ error: error.message });
905
- }
904
+ try {
905
+ res.json({ message: '配置更新成功' });
906
+ } catch (error) {
907
+ logger.error('更新优化配置失败:', error);
908
+ res.status(500).json({ error: error.message });
909
+ }
906
910
  });
907
911
 
908
- export const adminRouter = router;
912
+ export const adminRouter = router;