@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.
- package/package.json +31 -24
- package/packages/resources/tools/agent-browser/README.md +640 -0
- package/packages/resources/tools/agent-browser/agent-browser.tool.js +1389 -0
- package/packages/resources/tools/thinking/README.md +324 -0
- package/packages/resources/tools/thinking/thinking.tool.js +911 -0
- package/packages/server/README.md +3 -4
- package/packages/server/api/admin.routes.js +668 -664
- package/packages/server/api/open.routes.js +68 -67
- package/packages/server/api/surge.routes.js +5 -6
- package/packages/server/api/tool.routes.js +70 -71
- package/packages/server/app.js +70 -73
- package/packages/server/configs/authors.json +40 -0
- package/packages/server/configs/models/built-in/bigmodel.yaml +6 -6
- package/packages/server/configs/models/providers.yaml +4 -4
- package/packages/server/configs/templates/built-in/general-iteration.yaml +1 -1
- package/packages/server/configs/templates/built-in/general-optimize.yaml +1 -1
- package/packages/server/configs/templates/built-in/output-format-optimize.yaml +1 -1
- package/packages/server/index.js +3 -9
- package/packages/server/mcp/heartbeat-patch.js +1 -3
- package/packages/server/mcp/mcp.server.js +64 -134
- package/packages/server/mcp/prompt.handler.js +101 -95
- package/packages/server/middlewares/auth.middleware.js +31 -31
- package/packages/server/server.js +60 -45
- package/packages/server/services/TerminalService.js +156 -70
- package/packages/server/services/WebSocketService.js +35 -34
- package/packages/server/services/author-config.service.js +199 -0
- package/packages/server/services/manager.js +66 -60
- package/packages/server/services/model.service.js +5 -9
- package/packages/server/services/optimization.service.js +25 -22
- package/packages/server/services/template.service.js +3 -8
- package/packages/server/toolm/author-sync.service.js +97 -0
- package/packages/server/toolm/index.js +1 -2
- package/packages/server/toolm/package-installer.service.js +47 -50
- package/packages/server/toolm/tool-context.service.js +64 -62
- package/packages/server/toolm/tool-dependency.service.js +28 -30
- package/packages/server/toolm/tool-description-generator-optimized.service.js +55 -55
- package/packages/server/toolm/tool-description-generator.service.js +20 -23
- package/packages/server/toolm/tool-environment.service.js +45 -44
- package/packages/server/toolm/tool-execution.service.js +49 -48
- package/packages/server/toolm/tool-loader.service.js +13 -18
- package/packages/server/toolm/tool-logger.service.js +33 -39
- package/packages/server/toolm/tool-manager.handler.js +17 -15
- package/packages/server/toolm/tool-manual-generator.service.js +107 -87
- package/packages/server/toolm/tool-mode-handlers.service.js +52 -59
- package/packages/server/toolm/tool-storage.service.js +11 -12
- package/packages/server/toolm/tool-sync.service.js +36 -39
- package/packages/server/toolm/tool-utils.js +0 -1
- package/packages/server/toolm/tool-yaml-parser.service.js +12 -11
- package/packages/server/toolm/validate-system.js +56 -84
- package/packages/server/utils/config.js +97 -12
- package/packages/server/utils/logger.js +1 -1
- package/packages/server/utils/port-checker.js +8 -8
- package/packages/server/utils/util.js +470 -467
- package/packages/resources/tools/cognitive-thinking/README.md +0 -284
- package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +0 -837
- package/packages/server/mcp/sequential-thinking.handler.js +0 -318
- package/packages/server/mcp/think-plan.handler.js +0 -274
- package/packages/server/mcp/thinking-toolkit.handler.js +0 -380
- package/packages/web/0.d1c5a72339dfc32ad86a.js +0 -1
- package/packages/web/112.8807b976372b2b0541a8.js +0 -1
- package/packages/web/130.584c7e365da413f5d9be.js +0 -1
- package/packages/web/142.72c985bc29720f975cca.js +0 -1
- package/packages/web/165.a05fc53bf84d18db36b8.js +0 -2
- package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +0 -9
- package/packages/web/203.724ab9f717b80554c397.js +0 -1
- package/packages/web/241.bf941d4f02866795f64a.js +0 -1
- package/packages/web/249.54cfb224af63f5f5ec55.js +0 -1
- package/packages/web/291.6df35042f8f296fca7cd.js +0 -1
- package/packages/web/319.2fab900a31b29873f666.js +0 -1
- package/packages/web/32.c78d866281995ec33a7b.js +0 -1
- package/packages/web/325.9ca297d0f73f38468ce9.js +0 -1
- package/packages/web/366.2f9b48fdbf8eee039e57.js +0 -1
- package/packages/web/378.6be08c612cd5a3ef97dc.js +0 -1
- package/packages/web/393.7a2f817515c5e90623d7.js +0 -1
- package/packages/web/412.062df5f732d5ba203415.js +0 -1
- package/packages/web/426.08656fef4918b3fb19ad.js +0 -1
- package/packages/web/465.2be8018327130a3bd798.js +0 -1
- package/packages/web/48.8ca96fc93667a715e67a.js +0 -1
- package/packages/web/480.44c1f1a2927486ac3d4f.js +0 -1
- package/packages/web/489.e041a8d0db15dc96d607.js +0 -1
- package/packages/web/490.9ffb26c907de020d671b.js +0 -1
- package/packages/web/492.58781369e348d91fc06a.js +0 -1
- package/packages/web/495.ed63e99791a87167c6b3.js +0 -1
- package/packages/web/510.4cc07ab7d30d5c1cd17f.js +0 -1
- package/packages/web/543.3af155ed4fa237664308.js +0 -1
- package/packages/web/567.f04ab60f8e2c2fb0745a.js +0 -1
- package/packages/web/592.f3ad085fa9c1849daa06.js +0 -1
- package/packages/web/616.b03fb801b3433b17750f.js +0 -1
- package/packages/web/617.d88def54921d2c4dc44c.js +0 -1
- package/packages/web/641.d30787d674f548928261.js +0 -1
- package/packages/web/672.5269c8399fa42a5af95d.js +0 -1
- package/packages/web/731.97cab92b71811c502bda.js +0 -1
- package/packages/web/746.3947c6f0235407e420fb.js +0 -1
- package/packages/web/756.a53233b3f3913900d5ac.js +0 -1
- package/packages/web/77.68801af593a28a631fbf.js +0 -1
- package/packages/web/802.53b2bff3cf2a69f7b80c.js +0 -1
- package/packages/web/815.b6dfab82265f56c7e046.js +0 -1
- package/packages/web/821.f5a13e5c735aac244eb9.js +0 -1
- package/packages/web/846.b9bf97d5f559270675ce.js +0 -1
- package/packages/web/869.7c10403f500e6201407f.js +0 -1
- package/packages/web/885.135050364f99e6924fb5.js +0 -1
- package/packages/web/901.fd5aeb9df630609a2b43.js +0 -1
- package/packages/web/928.f67e590de3caa4daa3ae.js +0 -1
- package/packages/web/955.d833403521ba4dd567ee.js +0 -1
- package/packages/web/981.a45cb745cf424044c8c8.js +0 -1
- package/packages/web/992.645320b60c74c8787482.js +0 -1
- package/packages/web/996.ed9a963dc9e7439eca9a.js +0 -1
- package/packages/web/css/codemirror-theme_xq-light.css +0 -43
- package/packages/web/css/codemirror.css +0 -344
- package/packages/web/css/main.196f434e6a88cd448158.css +0 -7278
- package/packages/web/css/terminal-fix.css +0 -571
- package/packages/web/index.html +0 -3
- package/packages/web/main.dceff50c7307dda04873.js +0 -2
- package/packages/web/main.dceff50c7307dda04873.js.LICENSE.txt +0 -3
|
@@ -7,82 +7,88 @@ import { util } from '../utils/util.js';
|
|
|
7
7
|
export async function handleGetPrompt(args) {
|
|
8
8
|
// 注意:这里为了兼容性,我们同时支持prompt_id和name参数
|
|
9
9
|
const promptId = args.prompt_id || args.name;
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
if (!promptId) {
|
|
12
|
-
throw new Error(
|
|
12
|
+
throw new Error('缺少必需参数: prompt_id');
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
const promptManager = await util.getPromptManager();
|
|
16
16
|
const prompt = promptManager.getPrompt(promptId);
|
|
17
17
|
if (!prompt) {
|
|
18
18
|
throw new Error(`未找到ID为 "${promptId}" 的prompt`);
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// 返回完整的prompt信息
|
|
22
22
|
const promptInfo = {
|
|
23
|
-
id: prompt.uniqueId,
|
|
23
|
+
id: prompt.uniqueId, // 使用基于文件路径的唯一ID
|
|
24
24
|
name: prompt.name,
|
|
25
25
|
description: prompt.description || `Prompt: ${prompt.name}`,
|
|
26
26
|
messages: prompt.messages || [],
|
|
27
27
|
arguments: prompt.arguments || [],
|
|
28
|
-
filePath: prompt.relativePath
|
|
28
|
+
filePath: prompt.relativePath // 添加文件路径信息
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
if (config.getLogLevel() === 'debug') {
|
|
32
32
|
promptInfo.metadata = {
|
|
33
33
|
uniqueId: prompt.uniqueId,
|
|
34
34
|
fileName: prompt.fileName,
|
|
35
|
-
fullPath: prompt.filePath
|
|
35
|
+
fullPath: prompt.filePath
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
return convertToText(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
return convertToText(
|
|
40
|
+
{
|
|
41
|
+
success: true,
|
|
42
|
+
prompt: promptInfo
|
|
43
|
+
},
|
|
44
|
+
'detail'
|
|
45
|
+
);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
// 处理 search_prompts 工具调用
|
|
46
49
|
export async function handleSearchPrompts(args) {
|
|
47
50
|
// 注意:这里为了兼容性,我们同时支持title和name参数
|
|
48
51
|
const searchTerm = args.title || args.name;
|
|
49
|
-
|
|
52
|
+
|
|
50
53
|
const logLevel = config.getLogLevel();
|
|
51
54
|
const promptManager = await util.getPromptManager();
|
|
52
|
-
|
|
55
|
+
const allPrompts = (await promptManager.loadPrompts()).prompts || [];
|
|
53
56
|
|
|
54
57
|
// 如果搜索词为空,则返回所有提示词
|
|
55
58
|
if (!searchTerm) {
|
|
56
|
-
|
|
59
|
+
const simplifiedPrompts = formatResults(allPrompts);
|
|
57
60
|
|
|
58
|
-
return convertToText(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
return convertToText(
|
|
62
|
+
{
|
|
63
|
+
success: true,
|
|
64
|
+
query: searchTerm || '',
|
|
65
|
+
count: simplifiedPrompts.length,
|
|
66
|
+
results: simplifiedPrompts
|
|
67
|
+
},
|
|
68
|
+
'list'
|
|
69
|
+
);
|
|
64
70
|
}
|
|
65
|
-
|
|
71
|
+
|
|
66
72
|
// 实现相似度匹配算法
|
|
67
|
-
const searchResults = allPrompts
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const searchResults = allPrompts
|
|
74
|
+
.map(prompt => {
|
|
75
|
+
prompt.description = prompt.description || `Prompt: ${prompt.name}`;
|
|
76
|
+
prompt.arguments = prompt.arguments || [];
|
|
77
|
+
prompt.hasArguments = prompt.arguments && prompt.arguments.length > 0;
|
|
78
|
+
return {
|
|
79
|
+
prompt,
|
|
80
|
+
score: util.calculateSimilarityScore(searchTerm, prompt)
|
|
81
|
+
};
|
|
82
|
+
})
|
|
83
|
+
.filter(result => result.score > 0) // 只返回有匹配的结果
|
|
84
|
+
.sort((a, b) => b.score - a.score); // 按相似度得分降序排列
|
|
79
85
|
|
|
80
|
-
|
|
86
|
+
const result = {
|
|
81
87
|
success: true,
|
|
82
88
|
query: searchTerm || '',
|
|
83
89
|
count: searchResults.length,
|
|
84
|
-
results: formatResults(searchResults)
|
|
85
|
-
}
|
|
90
|
+
results: formatResults(searchResults)
|
|
91
|
+
};
|
|
86
92
|
|
|
87
93
|
if (logLevel === 'debug') {
|
|
88
94
|
result.debug = {
|
|
@@ -90,9 +96,9 @@ export async function handleSearchPrompts(args) {
|
|
|
90
96
|
id: result.prompt.id,
|
|
91
97
|
name: result.prompt.name,
|
|
92
98
|
score: result.score,
|
|
93
|
-
fullPath: result.prompt.filePath
|
|
99
|
+
fullPath: result.prompt.filePath
|
|
94
100
|
}))
|
|
95
|
-
}
|
|
101
|
+
};
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
return convertToText(result, 'list');
|
|
@@ -101,21 +107,25 @@ export async function handleSearchPrompts(args) {
|
|
|
101
107
|
/**
|
|
102
108
|
* 处理 reload_prompts 工具调用
|
|
103
109
|
*/
|
|
104
|
-
export async function handleReloadPrompts(
|
|
110
|
+
export async function handleReloadPrompts(_args) {
|
|
105
111
|
logger.info('重新加载prompts...');
|
|
106
|
-
|
|
112
|
+
|
|
107
113
|
const promptManager = await util.getPromptManager();
|
|
108
114
|
const result = await promptManager.reloadPrompts();
|
|
109
|
-
|
|
115
|
+
|
|
110
116
|
return {
|
|
111
117
|
content: [
|
|
112
118
|
{
|
|
113
|
-
type:
|
|
114
|
-
text: JSON.stringify(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
type: 'text',
|
|
120
|
+
text: JSON.stringify(
|
|
121
|
+
{
|
|
122
|
+
success: true,
|
|
123
|
+
message: `重新加载完成: 成功 ${result.success} 个, 失败 ${result.errorCount} 个`,
|
|
124
|
+
result: formatResults(result.prompts)
|
|
125
|
+
},
|
|
126
|
+
null,
|
|
127
|
+
2
|
|
128
|
+
)
|
|
119
129
|
}
|
|
120
130
|
]
|
|
121
131
|
};
|
|
@@ -123,8 +133,8 @@ export async function handleReloadPrompts(args) {
|
|
|
123
133
|
|
|
124
134
|
/**
|
|
125
135
|
* 格式化搜索结果
|
|
126
|
-
* @param {*} results
|
|
127
|
-
* @returns
|
|
136
|
+
* @param {*} results
|
|
137
|
+
* @returns
|
|
128
138
|
*/
|
|
129
139
|
function formatResults(results = []) {
|
|
130
140
|
if (!Array.isArray(results)) return [];
|
|
@@ -151,23 +161,23 @@ function formatResults(results = []) {
|
|
|
151
161
|
|
|
152
162
|
/**
|
|
153
163
|
* 处理列表格式输出
|
|
154
|
-
* @param {*} result
|
|
155
|
-
* @returns
|
|
164
|
+
* @param {*} result
|
|
165
|
+
* @returns
|
|
156
166
|
*/
|
|
157
167
|
function formatListOutput(result) {
|
|
158
168
|
// 生成当前时间戳
|
|
159
169
|
const now = new Date();
|
|
160
170
|
const formattedDate = `${now.getFullYear()}/${(now.getMonth() + 1).toString().padStart(2, '0')}/${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
|
161
|
-
|
|
171
|
+
|
|
162
172
|
// 构建新的输出格式
|
|
163
|
-
let output =
|
|
164
|
-
output +=
|
|
165
|
-
output +=
|
|
173
|
+
let output = '';
|
|
174
|
+
output += '[PROMPT_HEADER_AREA]\n';
|
|
175
|
+
output += '🎭 **PromptManager 提示词清单**\n';
|
|
166
176
|
output += `📅 ${formattedDate}\n\n`;
|
|
167
|
-
output +=
|
|
168
|
-
output +=
|
|
177
|
+
output += '--------------------------------------------------\n';
|
|
178
|
+
output += '[PROMPT_LIST_AREA]\n\n';
|
|
169
179
|
output += `📦 **提示词列表** (${result.count}个)\n`;
|
|
170
|
-
|
|
180
|
+
|
|
171
181
|
// 添加提示词列表
|
|
172
182
|
if (result.results && Array.isArray(result.results) && result.results.length > 0) {
|
|
173
183
|
result.results.forEach(prompt => {
|
|
@@ -175,75 +185,71 @@ function formatListOutput(result) {
|
|
|
175
185
|
output += ` - ${prompt.description}\n`;
|
|
176
186
|
});
|
|
177
187
|
} else {
|
|
178
|
-
output +=
|
|
188
|
+
output += '(无提示词)\n';
|
|
179
189
|
}
|
|
180
|
-
|
|
181
|
-
output +=
|
|
182
|
-
output +=
|
|
183
|
-
output +=
|
|
184
|
-
|
|
190
|
+
|
|
191
|
+
output += '\n--------------------------------------------------\n';
|
|
192
|
+
output += '[STATE_AREA]\n';
|
|
193
|
+
output += '📍 **当前状态**:prompts_completed\n';
|
|
194
|
+
|
|
185
195
|
// 返回格式化文本
|
|
186
196
|
return output;
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
/**
|
|
190
200
|
* 处理详情格式输出
|
|
191
|
-
* @param {*} result
|
|
201
|
+
* @param {*} result
|
|
192
202
|
* @returns string
|
|
193
203
|
*/
|
|
194
204
|
function formatDetailOutput(result) {
|
|
195
205
|
const prompt = result.prompt;
|
|
196
|
-
|
|
197
|
-
// 生成当前时间戳
|
|
198
|
-
const now = new Date();
|
|
199
|
-
const formattedDate = `${now.getFullYear()}/${(now.getMonth() + 1).toString().padStart(2, '0')}/${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
|
200
|
-
|
|
206
|
+
|
|
201
207
|
// 构建新的输出格式
|
|
202
|
-
let output =
|
|
203
|
-
output +=
|
|
204
|
-
output +=
|
|
208
|
+
let output = '';
|
|
209
|
+
output += '--------------------------------------------------\n';
|
|
210
|
+
output += '[PROMPT_HEADER_AREA]\n';
|
|
205
211
|
output += `- id: ${prompt.id}\n`;
|
|
206
212
|
output += `- name: ${prompt.name}\n`;
|
|
207
213
|
output += `- description: ${prompt.description}\n`;
|
|
208
214
|
output += `- filepath: ${prompt.filePath}\n\n`;
|
|
209
|
-
output +=
|
|
210
|
-
output +=
|
|
211
|
-
|
|
215
|
+
output += '--------------------------------------------------\n';
|
|
216
|
+
output += '[PROMPT_PARAMS_AREA]\n';
|
|
217
|
+
|
|
212
218
|
// 添加参数信息
|
|
213
219
|
if (prompt.arguments && Array.isArray(prompt.arguments) && prompt.arguments.length > 0) {
|
|
214
220
|
prompt.arguments.forEach(param => {
|
|
215
|
-
const requiredText = param.required ?
|
|
221
|
+
const requiredText = param.required ? '必填' : '非必填';
|
|
216
222
|
output += `- ${param.name}: ${param.type}; ${requiredText}; ${param.description}\n`;
|
|
217
223
|
});
|
|
218
224
|
} else {
|
|
219
|
-
output +=
|
|
225
|
+
output += '(无参数)\n';
|
|
220
226
|
}
|
|
221
|
-
|
|
222
|
-
output +=
|
|
223
|
-
output +=
|
|
224
|
-
|
|
227
|
+
|
|
228
|
+
output += '\n--------------------------------------------------\n';
|
|
229
|
+
output += '[PROMPT_CONTENT_AREA]\n';
|
|
230
|
+
|
|
225
231
|
// 添加消息内容
|
|
226
232
|
if (prompt.messages && Array.isArray(prompt.messages)) {
|
|
227
|
-
const userMessages = prompt.messages.filter(msg => msg.role !==
|
|
233
|
+
const userMessages = prompt.messages.filter(msg => msg.role !== '');
|
|
228
234
|
if (userMessages.length > 0 && userMessages[0].content && userMessages[0].content.text) {
|
|
229
|
-
output += userMessages[0].content.text
|
|
235
|
+
output += `${userMessages[0].content.text}\n`;
|
|
230
236
|
}
|
|
231
237
|
}
|
|
232
|
-
|
|
233
|
-
output +=
|
|
234
|
-
output +=
|
|
235
|
-
|
|
238
|
+
|
|
239
|
+
output += '\n[STATE_AREA]\n';
|
|
240
|
+
output += '📍 **当前状态**:prompt_loaded\n';
|
|
241
|
+
|
|
236
242
|
return output;
|
|
237
243
|
}
|
|
238
244
|
|
|
239
245
|
/**
|
|
240
246
|
* 将对象转换为格式化的text类型输出
|
|
241
|
-
* @param {*} result
|
|
247
|
+
* @param {*} result
|
|
242
248
|
* @param {string} format - 输出格式类型: 'list' 或 'detail'
|
|
243
|
-
* @returns
|
|
249
|
+
* @returns
|
|
244
250
|
*/
|
|
245
251
|
function convertToText(result, format) {
|
|
246
|
-
let ret =
|
|
252
|
+
let ret = '';
|
|
247
253
|
switch (format) {
|
|
248
254
|
case 'list':
|
|
249
255
|
ret = formatListOutput(result);
|
|
@@ -252,12 +258,12 @@ function convertToText(result, format) {
|
|
|
252
258
|
ret = formatDetailOutput(result);
|
|
253
259
|
break;
|
|
254
260
|
default:
|
|
255
|
-
ret =JSON.stringify(result, null, 2);
|
|
261
|
+
ret = JSON.stringify(result, null, 2);
|
|
256
262
|
}
|
|
257
263
|
return {
|
|
258
264
|
content: [
|
|
259
265
|
{
|
|
260
|
-
type:
|
|
266
|
+
type: 'text',
|
|
261
267
|
text: ret
|
|
262
268
|
}
|
|
263
269
|
]
|
|
@@ -272,7 +278,7 @@ export async function handlePrompts(args) {
|
|
|
272
278
|
const { action, query } = args;
|
|
273
279
|
|
|
274
280
|
if (!action) {
|
|
275
|
-
throw new Error(
|
|
281
|
+
throw new Error('缺少必需参数: action (search 或 get)');
|
|
276
282
|
}
|
|
277
283
|
|
|
278
284
|
switch (action) {
|
|
@@ -281,7 +287,7 @@ export async function handlePrompts(args) {
|
|
|
281
287
|
|
|
282
288
|
case 'get':
|
|
283
289
|
if (!query) {
|
|
284
|
-
throw new Error(
|
|
290
|
+
throw new Error('get操作需要提供query参数指定提示词ID或名称');
|
|
285
291
|
}
|
|
286
292
|
return handleGetPrompt({ prompt_id: query });
|
|
287
293
|
|
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
import { config } from '../utils/config.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
* 管理员API中间件
|
|
5
|
+
* @param {*} req
|
|
6
|
+
* @param {*} res
|
|
7
|
+
* @param {*} next
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
10
|
export function adminAuthMiddleware(req, res, next) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// 检查是否启用了管理员功能
|
|
12
|
+
if (!config.adminEnable) {
|
|
13
|
+
return res.status(404).json({ error: 'Admin功能未启用' });
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
// 如果不需要认证,直接通过
|
|
17
|
+
if (!config.adminRequireAuth) {
|
|
18
|
+
next();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
// 检查Authorization请求头是否存在且格式正确
|
|
23
|
+
const authHeader = req.headers.authorization;
|
|
24
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
25
|
+
return res.status(401).json({ error: '未提供认证令牌' });
|
|
26
|
+
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// 提取Bearer token
|
|
29
|
+
const token = authHeader.substring(7);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
// 验证令牌是否在配置的管理员列表中
|
|
32
|
+
const admin = config.admins.find(a => a.token === token);
|
|
33
|
+
if (!admin) {
|
|
34
|
+
return res.status(401).json({ error: '无效的认证令牌' });
|
|
35
|
+
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
37
|
+
// 将管理员信息附加到请求对象,供后续中间件使用
|
|
38
|
+
req.admin = admin;
|
|
39
|
+
next();
|
|
40
|
+
}
|
|
@@ -4,9 +4,10 @@ import { config } from './utils/config.js';
|
|
|
4
4
|
import { logger } from './utils/logger.js';
|
|
5
5
|
import { util } from './utils/util.js';
|
|
6
6
|
import { syncSystemTools } from './toolm/tool-sync.service.js';
|
|
7
|
+
import { syncAuthorConfig } from './toolm/author-sync.service.js';
|
|
7
8
|
import { startLogCleanupTask } from './toolm/tool-logger.service.js';
|
|
8
9
|
import { webSocketService } from './services/WebSocketService.js';
|
|
9
|
-
import { checkPortAvailable
|
|
10
|
+
import { checkPortAvailable } from './utils/port-checker.js';
|
|
10
11
|
|
|
11
12
|
// 动态导入 promptManager,以处理 Electron 打包后的路径问题
|
|
12
13
|
let promptManager;
|
|
@@ -33,34 +34,39 @@ export async function isServerRunning() {
|
|
|
33
34
|
if (!serverInstance) {
|
|
34
35
|
return false;
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
// 实际验证服务器是否在监听
|
|
38
|
-
return new Promise(
|
|
39
|
-
import('http')
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
return new Promise(resolve => {
|
|
40
|
+
import('http')
|
|
41
|
+
.then(http => {
|
|
42
|
+
// 设置超时以避免长时间等待
|
|
43
|
+
const req = http.request(
|
|
44
|
+
{
|
|
45
|
+
hostname: 'localhost',
|
|
46
|
+
port: config.getPort(),
|
|
47
|
+
path: '/health',
|
|
48
|
+
method: 'GET',
|
|
49
|
+
timeout: 2000
|
|
50
|
+
},
|
|
51
|
+
_res => {
|
|
52
|
+
resolve(true);
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
req.on('error', () => {
|
|
57
|
+
resolve(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
req.on('timeout', () => {
|
|
61
|
+
req.destroy();
|
|
62
|
+
resolve(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
req.end();
|
|
66
|
+
})
|
|
67
|
+
.catch(() => {
|
|
57
68
|
resolve(false);
|
|
58
69
|
});
|
|
59
|
-
|
|
60
|
-
req.end();
|
|
61
|
-
}).catch(() => {
|
|
62
|
-
resolve(false);
|
|
63
|
-
});
|
|
64
70
|
});
|
|
65
71
|
}
|
|
66
72
|
|
|
@@ -86,19 +92,19 @@ export async function startServer(options = {}) {
|
|
|
86
92
|
serverStartingPromise = (async () => {
|
|
87
93
|
try {
|
|
88
94
|
await _handleConfig(options);
|
|
89
|
-
|
|
95
|
+
|
|
90
96
|
// 检查端口可用性
|
|
91
97
|
const port = config.getPort();
|
|
92
98
|
const isPortAvailable = await checkPortAvailable(port);
|
|
93
|
-
|
|
99
|
+
|
|
94
100
|
if (!isPortAvailable) {
|
|
95
101
|
const errorMsg = `端口 ${port} 已被占用,请检查是否有其他服务在使用该端口,或手动指定其他端口`;
|
|
96
102
|
logger.error(errorMsg);
|
|
97
103
|
throw new Error(errorMsg);
|
|
98
104
|
}
|
|
99
|
-
|
|
105
|
+
|
|
100
106
|
await promptManager.loadPrompts();
|
|
101
|
-
|
|
107
|
+
|
|
102
108
|
// 加载优化模板和模型
|
|
103
109
|
try {
|
|
104
110
|
const { templateManager } = await import('./services/template.service.js');
|
|
@@ -115,17 +121,24 @@ export async function startServer(options = {}) {
|
|
|
115
121
|
} catch (error) {
|
|
116
122
|
logger.warn('加载优化模型失败,继续启动服务', { error: error.message });
|
|
117
123
|
}
|
|
118
|
-
|
|
124
|
+
|
|
119
125
|
// 同步系统工具到沙箱环境
|
|
120
126
|
try {
|
|
121
127
|
await syncSystemTools();
|
|
122
128
|
} catch (error) {
|
|
123
129
|
logger.error('同步系统工具失败,继续启动服务', { error: error.message });
|
|
124
130
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
|
|
132
|
+
// 同步作者配置到沙箱环境
|
|
133
|
+
try {
|
|
134
|
+
await syncAuthorConfig();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.error('同步作者配置失败,继续启动服务', { error: error.message });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MCP 长连接可能长时间空闲(IDE 侧保持会话),若沿用 Node 默认超时(requestTimeout 5 分钟、keepAliveTimeout 5 秒、headersTimeout 60 秒)
|
|
140
|
+
// 会导致连接被动关闭。这里将相关超时调高/关闭以避免 IDE 定期断开。
|
|
141
|
+
const MCP_LONG_TIMEOUT = 24 * 60 * 60 * 1000; // 24h
|
|
129
142
|
|
|
130
143
|
// 启动日志清理任务
|
|
131
144
|
startLogCleanupTask();
|
|
@@ -137,7 +150,9 @@ export async function startServer(options = {}) {
|
|
|
137
150
|
logger.info(`MCP服务启动成功 http://localhost:${port}/mcp`);
|
|
138
151
|
if (config.adminEnable) {
|
|
139
152
|
logger.info(`管理员界面可通过 http://localhost:${port}${config.adminPath} 访问`);
|
|
140
|
-
process.stderr.write(
|
|
153
|
+
process.stderr.write(
|
|
154
|
+
'\n======================================================================================\n'
|
|
155
|
+
);
|
|
141
156
|
}
|
|
142
157
|
|
|
143
158
|
// 放宽 HTTP 服务器超时,防止 MCP 流式会话被意外回收
|
|
@@ -149,17 +164,17 @@ export async function startServer(options = {}) {
|
|
|
149
164
|
|
|
150
165
|
// 设置服务器实例
|
|
151
166
|
serverInstance = server;
|
|
152
|
-
|
|
153
|
-
// 启动WebSocket服务,传入 HTTP 服务器端口
|
|
167
|
+
|
|
154
168
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
// WebSocket服务使用动态端口(端口0,由系统自动分配)
|
|
170
|
+
await webSocketService.start();
|
|
171
|
+
const wsPort = webSocketService.getPort();
|
|
172
|
+
logger.info(`WebSocket服务启动成功,端口: ${wsPort}`);
|
|
158
173
|
} catch (wsError) {
|
|
159
174
|
logger.error('WebSocket服务启动失败:', wsError.message);
|
|
160
175
|
// WebSocket服务失败不影响主服务器运行
|
|
161
176
|
}
|
|
162
|
-
|
|
177
|
+
|
|
163
178
|
resolve(server);
|
|
164
179
|
} catch (error) {
|
|
165
180
|
logger.error('服务器启动后处理失败:', error.message);
|
|
@@ -168,7 +183,7 @@ export async function startServer(options = {}) {
|
|
|
168
183
|
}
|
|
169
184
|
});
|
|
170
185
|
|
|
171
|
-
server.on('error',
|
|
186
|
+
server.on('error', err => {
|
|
172
187
|
logger.error('服务器启动失败:', err.message);
|
|
173
188
|
if (err.code === 'EADDRINUSE') {
|
|
174
189
|
logger.error(`端口 ${port} 已被占用,请检查是否有其他服务在使用该端口`);
|
|
@@ -220,7 +235,7 @@ export async function stopServer() {
|
|
|
220
235
|
}
|
|
221
236
|
|
|
222
237
|
await new Promise((resolve, reject) => {
|
|
223
|
-
serverInstance.close(
|
|
238
|
+
serverInstance.close(err => {
|
|
224
239
|
if (err) {
|
|
225
240
|
logger.error('停止服务器失败:', err.message);
|
|
226
241
|
reject(err);
|
|
@@ -255,7 +270,7 @@ const isDirectRun = (() => {
|
|
|
255
270
|
})();
|
|
256
271
|
|
|
257
272
|
if (isDirectRun) {
|
|
258
|
-
startServer().catch(
|
|
273
|
+
startServer().catch(error => {
|
|
259
274
|
logger.error('服务器启动失败:', error.message);
|
|
260
275
|
process.exit(1);
|
|
261
276
|
});
|