@becrafter/prompt-manager 0.0.18 → 0.1.1
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/IFLOW.md +175 -0
- package/README.md +145 -234
- package/app/desktop/assets/app.1.png +0 -0
- package/app/desktop/assets/app.png +0 -0
- package/app/desktop/assets/icons/icon.icns +0 -0
- package/app/desktop/assets/icons/icon.ico +0 -0
- package/app/desktop/assets/icons/icon.png +0 -0
- package/app/desktop/assets/icons/tray.png +0 -0
- package/app/desktop/assets/templates/about.html +147 -0
- package/app/desktop/assets/tray.png +0 -0
- package/app/desktop/main.js +187 -732
- package/app/desktop/package-lock.json +723 -522
- package/app/desktop/package.json +54 -25
- package/app/desktop/preload.js +7 -0
- package/app/desktop/src/core/error-handler.js +108 -0
- package/app/desktop/src/core/event-emitter.js +84 -0
- package/app/desktop/src/core/logger.js +108 -0
- package/app/desktop/src/core/state-manager.js +125 -0
- package/app/desktop/src/services/module-loader.js +214 -0
- package/app/desktop/src/services/runtime-manager.js +301 -0
- package/app/desktop/src/services/service-manager.js +169 -0
- package/app/desktop/src/services/update-manager.js +268 -0
- package/app/desktop/src/ui/about-dialog-manager.js +208 -0
- package/app/desktop/src/ui/admin-window-manager.js +757 -0
- package/app/desktop/src/ui/splash-manager.js +253 -0
- package/app/desktop/src/ui/tray-manager.js +186 -0
- package/app/desktop/src/utils/icon-manager.js +133 -0
- package/app/desktop/src/utils/path-utils.js +58 -0
- package/app/desktop/src/utils/resource-paths.js +49 -0
- package/app/desktop/src/utils/resource-sync.js +260 -0
- package/app/desktop/src/utils/runtime-sync.js +241 -0
- package/app/desktop/src/utils/template-renderer.js +284 -0
- package/app/desktop/src/utils/version-utils.js +59 -0
- package/examples/prompts/engineer/engineer-professional.yaml +92 -0
- package/examples/prompts/engineer/laowang-engineer.yaml +132 -0
- package/examples/prompts/engineer/nekomata-engineer.yaml +123 -0
- package/examples/prompts/engineer/ojousama-engineer.yaml +124 -0
- package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +105 -0
- package/examples/prompts/workflow/sixstep-workflow.yaml +192 -0
- package/package.json +18 -9
- package/packages/admin-ui/.babelrc +3 -0
- package/packages/admin-ui/admin.html +237 -4784
- package/packages/admin-ui/css/main.css +2592 -0
- package/packages/admin-ui/css/recommended-prompts.css +610 -0
- package/packages/admin-ui/package-lock.json +6981 -0
- package/packages/admin-ui/package.json +36 -0
- package/packages/admin-ui/src/codemirror.js +53 -0
- package/packages/admin-ui/src/index.js +3188 -0
- package/packages/admin-ui/webpack.config.js +76 -0
- package/packages/resources/tools/chrome-devtools/README.md +310 -0
- package/packages/resources/tools/chrome-devtools/chrome-devtools.tool.js +1703 -0
- package/packages/resources/tools/file-reader/README.md +289 -0
- package/packages/resources/tools/file-reader/file-reader.tool.js +1545 -0
- package/packages/resources/tools/filesystem/README.md +359 -0
- package/packages/resources/tools/filesystem/filesystem.tool.js +538 -0
- package/packages/resources/tools/ollama-remote/README.md +192 -0
- package/packages/resources/tools/ollama-remote/ollama-remote.tool.js +421 -0
- package/packages/resources/tools/pdf-reader/README.md +236 -0
- package/packages/resources/tools/pdf-reader/pdf-reader.tool.js +565 -0
- package/packages/resources/tools/playwright/README.md +306 -0
- package/packages/resources/tools/playwright/playwright.tool.js +1186 -0
- package/packages/resources/tools/todolist/README.md +394 -0
- package/packages/resources/tools/todolist/todolist.tool.js +1312 -0
- package/packages/server/README.md +142 -0
- package/packages/server/api/admin.routes.js +42 -11
- package/packages/server/api/surge.routes.js +43 -0
- package/packages/server/app.js +119 -14
- package/packages/server/index.js +39 -0
- package/packages/server/mcp/mcp.server.js +346 -28
- package/packages/server/mcp/{mcp.handler.js → prompt.handler.js} +108 -9
- package/packages/server/mcp/sequential-thinking.handler.js +318 -0
- package/packages/server/mcp/think-plan.handler.js +274 -0
- package/packages/server/middlewares/auth.middleware.js +6 -0
- package/packages/server/package.json +51 -0
- package/packages/server/server.js +37 -1
- package/packages/server/toolm/index.js +9 -0
- package/packages/server/toolm/package-installer.service.js +267 -0
- package/packages/server/toolm/test-tools.js +264 -0
- package/packages/server/toolm/tool-context.service.js +334 -0
- package/packages/server/toolm/tool-dependency.service.js +168 -0
- package/packages/server/toolm/tool-description-generator-optimized.service.js +375 -0
- package/packages/server/toolm/tool-description-generator.service.js +312 -0
- package/packages/server/toolm/tool-environment.service.js +200 -0
- package/packages/server/toolm/tool-execution.service.js +277 -0
- package/packages/server/toolm/tool-loader.service.js +219 -0
- package/packages/server/toolm/tool-logger.service.js +223 -0
- package/packages/server/toolm/tool-manager.handler.js +65 -0
- package/packages/server/toolm/tool-manual-generator.service.js +389 -0
- package/packages/server/toolm/tool-mode-handlers.service.js +224 -0
- package/packages/server/toolm/tool-storage.service.js +111 -0
- package/packages/server/toolm/tool-sync.service.js +138 -0
- package/packages/server/toolm/tool-utils.js +20 -0
- package/packages/server/toolm/tool-yaml-parser.service.js +81 -0
- package/packages/server/toolm/validate-system.js +421 -0
- package/packages/server/utils/config.js +49 -5
- package/packages/server/utils/util.js +65 -10
- package/scripts/build-icons.js +135 -0
- package/scripts/build.sh +57 -0
- package/scripts/surge/CNAME +1 -0
- package/scripts/surge/README.md +47 -0
- package/scripts/surge/package-lock.json +34 -0
- package/scripts/surge/package.json +20 -0
- package/scripts/surge/sync-to-surge.js +151 -0
- package/packages/admin-ui/js/closebrackets.min.js +0 -8
- package/packages/admin-ui/js/codemirror.min.js +0 -8
- package/packages/admin-ui/js/js-yaml.min.js +0 -2
- package/packages/admin-ui/js/markdown.min.js +0 -8
- /package/app/desktop/assets/{icon.png → tray.1.png} +0 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 工具系统全面验证脚本
|
|
4
|
+
*
|
|
5
|
+
* 验证内容:
|
|
6
|
+
* 1. 目录结构是否完整
|
|
7
|
+
* 2. 文件是否存在且可读
|
|
8
|
+
* 3. 模块导入是否正常
|
|
9
|
+
* 4. 工具接口是否符合规范
|
|
10
|
+
* 5. MCP服务器集成是否正确
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'fs-extra';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import os from 'os';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import { pathExists } from './tool-utils.js';
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.dirname(__filename);
|
|
21
|
+
|
|
22
|
+
const colors = {
|
|
23
|
+
reset: '\x1b[0m',
|
|
24
|
+
bright: '\x1b[1m',
|
|
25
|
+
green: '\x1b[32m',
|
|
26
|
+
red: '\x1b[31m',
|
|
27
|
+
yellow: '\x1b[33m',
|
|
28
|
+
blue: '\x1b[34m',
|
|
29
|
+
cyan: '\x1b[36m'
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function log(msg, color = 'reset') {
|
|
33
|
+
console.log(`${colors[color]}${msg}${colors.reset}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function success(msg) {
|
|
37
|
+
log(`✓ ${msg}`, 'green');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function error(msg) {
|
|
41
|
+
log(`✗ ${msg}`, 'red');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function warning(msg) {
|
|
45
|
+
log(`⚠ ${msg}`, 'yellow');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function info(msg) {
|
|
49
|
+
log(`ℹ ${msg}`, 'cyan');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function section(title) {
|
|
53
|
+
log(`\n${'='.repeat(60)}`, 'blue');
|
|
54
|
+
log(` ${title}`, 'bright');
|
|
55
|
+
log('='.repeat(60), 'blue');
|
|
56
|
+
console.log();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 验证结果收集
|
|
60
|
+
const results = {
|
|
61
|
+
total: 0,
|
|
62
|
+
passed: 0,
|
|
63
|
+
failed: 0,
|
|
64
|
+
warnings: 0,
|
|
65
|
+
errors: []
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function check(description, test) {
|
|
69
|
+
results.total++;
|
|
70
|
+
try {
|
|
71
|
+
const result = test();
|
|
72
|
+
if (result === true || result === undefined) {
|
|
73
|
+
success(description);
|
|
74
|
+
results.passed++;
|
|
75
|
+
return true;
|
|
76
|
+
} else if (result === 'warning') {
|
|
77
|
+
warning(description);
|
|
78
|
+
results.warnings++;
|
|
79
|
+
return 'warning';
|
|
80
|
+
} else {
|
|
81
|
+
error(description);
|
|
82
|
+
results.failed++;
|
|
83
|
+
results.errors.push(description);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
error(`${description}: ${err.message}`);
|
|
88
|
+
results.failed++;
|
|
89
|
+
results.errors.push(`${description}: ${err.message}`);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function asyncCheck(description, test) {
|
|
95
|
+
results.total++;
|
|
96
|
+
try {
|
|
97
|
+
const result = await test();
|
|
98
|
+
if (result === true || result === undefined) {
|
|
99
|
+
success(description);
|
|
100
|
+
results.passed++;
|
|
101
|
+
return true;
|
|
102
|
+
} else if (result === 'warning') {
|
|
103
|
+
warning(description);
|
|
104
|
+
results.warnings++;
|
|
105
|
+
return 'warning';
|
|
106
|
+
} else {
|
|
107
|
+
error(description);
|
|
108
|
+
results.failed++;
|
|
109
|
+
results.errors.push(description);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
} catch (err) {
|
|
113
|
+
error(`${description}: ${err.message}`);
|
|
114
|
+
results.failed++;
|
|
115
|
+
results.errors.push(`${description}: ${err.message}`);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 1. 验证目录结构
|
|
121
|
+
async function validateDirectoryStructure() {
|
|
122
|
+
section('1. 验证目录结构');
|
|
123
|
+
|
|
124
|
+
const rootDir = path.join(__dirname, '..', '..', '..', '..');
|
|
125
|
+
const paths = {
|
|
126
|
+
'tools目录': path.join(__dirname),
|
|
127
|
+
'系统工具目录': path.join(rootDir, 'packages', 'resources', 'tools'),
|
|
128
|
+
'用户工具目录': path.join(os.homedir(), '.prompt-manager', 'tools'),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
for (const [name, dirPath] of Object.entries(paths)) {
|
|
132
|
+
await asyncCheck(`${name} 存在: ${dirPath}`, async () => {
|
|
133
|
+
const exists = await pathExists(dirPath);
|
|
134
|
+
if (!exists && name === '用户工具目录') {
|
|
135
|
+
// 用户工具目录不存在时创建
|
|
136
|
+
await fs.ensureDir(dirPath);
|
|
137
|
+
info(` 已创建目录: ${dirPath}`);
|
|
138
|
+
return 'warning';
|
|
139
|
+
}
|
|
140
|
+
return exists;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 2. 验证核心文件
|
|
146
|
+
async function validateCoreFiles() {
|
|
147
|
+
section('2. 验证核心文件');
|
|
148
|
+
|
|
149
|
+
const coreFiles = [
|
|
150
|
+
{ name: '工具加载服务', path: path.join(__dirname, 'tool-loader.service.js') },
|
|
151
|
+
{ name: '工具管理处理器', path: path.join(__dirname, 'tool-manager.handler.js') },
|
|
152
|
+
{ name: '工具系统入口', path: path.join(__dirname, 'index.js') },
|
|
153
|
+
{ name: 'MCP服务器', path: path.join(__dirname, '..', 'mcp.server.js') },
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
for (const file of coreFiles) {
|
|
157
|
+
await asyncCheck(`${file.name} 文件存在`, async () => {
|
|
158
|
+
return await pathExists(file.path);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await asyncCheck(`${file.name} 可读`, async () => {
|
|
162
|
+
try {
|
|
163
|
+
await fs.access(file.path, fs.constants.R_OK);
|
|
164
|
+
return true;
|
|
165
|
+
} catch {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 3. 验证工具文件
|
|
173
|
+
async function validateToolFiles() {
|
|
174
|
+
section('3. 验证工具文件');
|
|
175
|
+
|
|
176
|
+
const rootDir = path.join(__dirname, '..', '..', '..', '..');
|
|
177
|
+
const toolsDir = path.join(rootDir, 'packages', 'resources', 'tools');
|
|
178
|
+
|
|
179
|
+
if (!await pathExists(toolsDir)) {
|
|
180
|
+
error(`工具目录不存在: ${toolsDir}`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const toolDirs = await fs.readdir(toolsDir);
|
|
185
|
+
info(`找到 ${toolDirs.length} 个工具目录`);
|
|
186
|
+
|
|
187
|
+
for (const toolDir of toolDirs) {
|
|
188
|
+
const toolPath = path.join(toolsDir, toolDir);
|
|
189
|
+
const stat = await fs.stat(toolPath);
|
|
190
|
+
|
|
191
|
+
if (!stat.isDirectory()) continue;
|
|
192
|
+
|
|
193
|
+
const toolFile = path.join(toolPath, `${toolDir}.tool.js`);
|
|
194
|
+
await asyncCheck(`工具 '${toolDir}' 文件存在`, async () => {
|
|
195
|
+
return await pathExists(toolFile);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 4. 验证模块导入
|
|
201
|
+
async function validateModuleImports() {
|
|
202
|
+
section('4. 验证模块导入');
|
|
203
|
+
|
|
204
|
+
// 验证工具加载服务
|
|
205
|
+
await asyncCheck('导入工具加载服务', async () => {
|
|
206
|
+
const module = await import('./tool-loader.service.js');
|
|
207
|
+
return module.toolLoaderService !== undefined;
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// 验证工具管理处理器
|
|
211
|
+
await asyncCheck('导入工具管理处理器', async () => {
|
|
212
|
+
const module = await import('./tool-manager.handler.js');
|
|
213
|
+
return typeof module.handleToolM === 'function';
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// 验证工具系统入口
|
|
217
|
+
await asyncCheck('导入工具系统入口', async () => {
|
|
218
|
+
const module = await import('./index.js');
|
|
219
|
+
return module.toolLoaderService !== undefined && module.handleToolM !== undefined;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// 5. 验证工具接口规范
|
|
224
|
+
async function validateToolInterfaces() {
|
|
225
|
+
section('5. 验证工具接口规范');
|
|
226
|
+
|
|
227
|
+
const rootDir = path.join(__dirname, '..', '..', '..', '..');
|
|
228
|
+
const toolsDir = path.join(rootDir, 'packages', 'resources', 'tools');
|
|
229
|
+
|
|
230
|
+
if (!await pathExists(toolsDir)) {
|
|
231
|
+
warning('工具目录不存在,跳过接口验证');
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const toolDirs = await fs.readdir(toolsDir);
|
|
236
|
+
|
|
237
|
+
for (const toolDir of toolDirs) {
|
|
238
|
+
const toolPath = path.join(toolsDir, toolDir);
|
|
239
|
+
const stat = await fs.stat(toolPath);
|
|
240
|
+
|
|
241
|
+
if (!stat.isDirectory()) continue;
|
|
242
|
+
|
|
243
|
+
const toolFile = path.join(toolPath, `${toolDir}.tool.js`);
|
|
244
|
+
|
|
245
|
+
if (!await pathExists(toolFile)) continue;
|
|
246
|
+
|
|
247
|
+
await asyncCheck(`工具 '${toolDir}' 符合接口规范`, async () => {
|
|
248
|
+
const toolModule = await import(toolFile);
|
|
249
|
+
const tool = toolModule.default || toolModule;
|
|
250
|
+
|
|
251
|
+
// 必需方法
|
|
252
|
+
if (typeof tool.execute !== 'function') {
|
|
253
|
+
throw new Error('缺少 execute 方法');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 推荐方法
|
|
257
|
+
const recommendedMethods = ['getMetadata', 'getSchema', 'getDependencies', 'getBusinessErrors'];
|
|
258
|
+
const missing = recommendedMethods.filter(method => typeof tool[method] !== 'function');
|
|
259
|
+
|
|
260
|
+
if (missing.length > 0) {
|
|
261
|
+
info(` 缺少推荐方法: ${missing.join(', ')}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return true;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// 6. 验证工具加载器功能
|
|
270
|
+
async function validateToolLoaderFunctionality() {
|
|
271
|
+
section('6. 验证工具加载器功能');
|
|
272
|
+
|
|
273
|
+
const { toolLoaderService } = await import('./tool-loader.service.js');
|
|
274
|
+
|
|
275
|
+
await asyncCheck('初始化工具加载器', async () => {
|
|
276
|
+
await toolLoaderService.initialize();
|
|
277
|
+
return toolLoaderService.initialized === true;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await asyncCheck('获取工具列表', async () => {
|
|
281
|
+
const tools = toolLoaderService.getAllTools();
|
|
282
|
+
info(` 加载了 ${tools.length} 个工具`);
|
|
283
|
+
return Array.isArray(tools);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// 检查 filesystem 工具
|
|
287
|
+
await asyncCheck('filesystem 工具已加载', async () => {
|
|
288
|
+
return toolLoaderService.hasTool('filesystem');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
if (toolLoaderService.hasTool('filesystem')) {
|
|
292
|
+
await asyncCheck('获取 filesystem 工具详情', async () => {
|
|
293
|
+
const tool = toolLoaderService.getTool('filesystem');
|
|
294
|
+
info(` 工具名称: ${tool.metadata.name}`);
|
|
295
|
+
info(` 工具描述: ${tool.metadata.description}`);
|
|
296
|
+
return tool !== undefined;
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
await asyncCheck('生成 filesystem 工具手册', async () => {
|
|
300
|
+
const manual = toolLoaderService.generateManual('filesystem');
|
|
301
|
+
return typeof manual === 'string' && manual.length > 0;
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// 7. 验证工具管理处理器功能
|
|
307
|
+
async function validateToolManagerFunctionality() {
|
|
308
|
+
section('7. 验证工具管理处理器功能');
|
|
309
|
+
|
|
310
|
+
const { handleToolM } = await import('./tool-manager.handler.js');
|
|
311
|
+
|
|
312
|
+
// 测试 manual 模式
|
|
313
|
+
await asyncCheck('手册模式正常工作', async () => {
|
|
314
|
+
const yamlInput = `tool: tool://filesystem
|
|
315
|
+
mode: manual`;
|
|
316
|
+
|
|
317
|
+
const result = await handleToolM({ yaml: yamlInput });
|
|
318
|
+
return result.content && result.content[0].type === 'text';
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// 测试 execute 模式
|
|
322
|
+
await asyncCheck('执行模式正常工作', async () => {
|
|
323
|
+
const yamlInput = `tool: tool://filesystem
|
|
324
|
+
mode: execute
|
|
325
|
+
parameters:
|
|
326
|
+
method: list_allowed_directories`;
|
|
327
|
+
|
|
328
|
+
const result = await handleToolM({ yaml: yamlInput });
|
|
329
|
+
return result.content && result.content[0].type === 'text';
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// 测试错误处理
|
|
333
|
+
await asyncCheck('错误处理正常工作', async () => {
|
|
334
|
+
try {
|
|
335
|
+
const yamlInput = `tool: tool://nonexistent
|
|
336
|
+
mode: execute`;
|
|
337
|
+
await handleToolM({ yaml: yamlInput });
|
|
338
|
+
return false; // 应该抛出错误
|
|
339
|
+
} catch (error) {
|
|
340
|
+
return error.message.includes('不存在');
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 8. 验证 MCP 服务器集成
|
|
346
|
+
async function validateMCPServerIntegration() {
|
|
347
|
+
section('8. 验证 MCP 服务器集成');
|
|
348
|
+
|
|
349
|
+
await asyncCheck('MCP 服务器模块可导入', async () => {
|
|
350
|
+
const module = await import('../mcp.server.js');
|
|
351
|
+
return typeof module.getMcpServer === 'function';
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
await asyncCheck('MCP 服务器包含 toolm 工具', async () => {
|
|
355
|
+
// 这需要实际启动服务器才能验证,这里只检查导入
|
|
356
|
+
info(' 需要启动服务器才能完全验证,当前仅检查模块导入');
|
|
357
|
+
return 'warning';
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 9. 生成报告
|
|
362
|
+
function generateReport() {
|
|
363
|
+
section('验证结果汇总');
|
|
364
|
+
|
|
365
|
+
console.log(`总计测试: ${results.total}`);
|
|
366
|
+
log(`通过: ${results.passed}`, 'green');
|
|
367
|
+
if (results.warnings > 0) {
|
|
368
|
+
log(`警告: ${results.warnings}`, 'yellow');
|
|
369
|
+
}
|
|
370
|
+
if (results.failed > 0) {
|
|
371
|
+
log(`失败: ${results.failed}`, 'red');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const percentage = (results.passed / results.total * 100).toFixed(1);
|
|
375
|
+
console.log(`\n通过率: ${percentage}%`);
|
|
376
|
+
|
|
377
|
+
if (results.errors.length > 0) {
|
|
378
|
+
section('失败的测试');
|
|
379
|
+
results.errors.forEach((err, index) => {
|
|
380
|
+
error(`${index + 1}. ${err}`);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
console.log();
|
|
385
|
+
if (results.failed === 0) {
|
|
386
|
+
log('🎉 所有验证通过!工具系统已准备就绪。', 'green');
|
|
387
|
+
return true;
|
|
388
|
+
} else {
|
|
389
|
+
log('⚠️ 部分验证失败,请检查并修复错误。', 'yellow');
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 主函数
|
|
395
|
+
async function main() {
|
|
396
|
+
log('\n╔════════════════════════════════════════════════════════╗', 'cyan');
|
|
397
|
+
log('║ Prompt Manager 工具系统全面验证 ║', 'cyan');
|
|
398
|
+
log('╚════════════════════════════════════════════════════════╝', 'cyan');
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
await validateDirectoryStructure();
|
|
402
|
+
await validateCoreFiles();
|
|
403
|
+
await validateToolFiles();
|
|
404
|
+
await validateModuleImports();
|
|
405
|
+
await validateToolInterfaces();
|
|
406
|
+
await validateToolLoaderFunctionality();
|
|
407
|
+
await validateToolManagerFunctionality();
|
|
408
|
+
await validateMCPServerIntegration();
|
|
409
|
+
|
|
410
|
+
const success = generateReport();
|
|
411
|
+
process.exit(success ? 0 : 1);
|
|
412
|
+
} catch (error) {
|
|
413
|
+
console.error('\n验证过程中发生致命错误:');
|
|
414
|
+
console.error(error);
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 运行验证
|
|
420
|
+
main();
|
|
421
|
+
|
|
@@ -3,6 +3,27 @@ import path from 'path';
|
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import crypto from 'crypto';
|
|
6
|
+
import dotenv from 'dotenv';
|
|
7
|
+
|
|
8
|
+
// 解析路径中的环境变量和 ~
|
|
9
|
+
function expandPath(inputPath) {
|
|
10
|
+
if (!inputPath) return inputPath;
|
|
11
|
+
|
|
12
|
+
// 展开 ~ 为用户主目录
|
|
13
|
+
if (inputPath.startsWith('~/')) {
|
|
14
|
+
return path.join(os.homedir(), inputPath.slice(2));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 展开环境变量(支持 ${VAR} 和 $VAR 格式)
|
|
18
|
+
return inputPath.replace(/\$(\w+)|\$\{(\w+)\}/g, (match, varName1, varName2) => {
|
|
19
|
+
const varName = varName1 || varName2;
|
|
20
|
+
return process.env[varName] || match; // 如果环境变量不存在,保留原值
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 加载 .env 文件
|
|
25
|
+
const configHome = path.join(os.homedir(), '.prompt-manager');
|
|
26
|
+
dotenv.config({ path: path.join(configHome, '.env') });
|
|
6
27
|
|
|
7
28
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
29
|
const __dirname = path.dirname(__filename);
|
|
@@ -63,11 +84,16 @@ MCP Prompt Server - 智能 Prompt 管理服务器
|
|
|
63
84
|
LOG_LEVEL 日志级别 (默认: info)
|
|
64
85
|
MAX_PROMPTS 最大prompt数量限制 (默认: 1000)
|
|
65
86
|
RECURSIVE_SCAN 是否启用递归扫描子目录 (默认: true)
|
|
87
|
+
ADMIN_ENABLE 是否启用管理员功能 (默认: true)
|
|
88
|
+
ADMIN_REQUIRE_AUTH 是否需要登录认证 (默认: true)
|
|
89
|
+
ADMIN_USERNAME 管理员用户名 (默认: admin)
|
|
90
|
+
ADMIN_PASSWORD 管理员密码 (默认: admin)
|
|
66
91
|
|
|
67
92
|
示例:
|
|
68
93
|
node packages/server/server.js --prompts-dir /path/to/prompts
|
|
69
94
|
node packages/server/server.js -p ./examples/prompts -P 8080
|
|
70
95
|
LOG_LEVEL=debug node packages/server/server.js -p /custom/prompts
|
|
96
|
+
ADMIN_REQUIRE_AUTH=false node packages/server/server.js # 禁用登录认证
|
|
71
97
|
`);
|
|
72
98
|
}
|
|
73
99
|
|
|
@@ -85,8 +111,8 @@ export class Config {
|
|
|
85
111
|
}
|
|
86
112
|
|
|
87
113
|
// 确定prompts目录
|
|
88
|
-
this.promptsDir = cliArgs.promptsDir ||
|
|
89
|
-
process.env.PROMPTS_DIR ||
|
|
114
|
+
this.promptsDir = expandPath(cliArgs.promptsDir) ||
|
|
115
|
+
expandPath(process.env.PROMPTS_DIR) ||
|
|
90
116
|
DEFAULT_PROMPTS_DIR;
|
|
91
117
|
this.configHome = path.dirname(this.promptsDir);
|
|
92
118
|
|
|
@@ -95,15 +121,20 @@ export class Config {
|
|
|
95
121
|
|
|
96
122
|
// 其他配置
|
|
97
123
|
this.serverName = process.env.MCP_SERVER_NAME || 'prompt-manager';
|
|
98
|
-
this.serverVersion = process.env.MCP_SERVER_VERSION || '0.
|
|
124
|
+
this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.1';
|
|
99
125
|
this.logLevel = process.env.LOG_LEVEL || 'info';
|
|
100
126
|
this.maxPrompts = parseInt(process.env.MAX_PROMPTS) || 1000;
|
|
101
127
|
this.recursiveScan = process.env.RECURSIVE_SCAN !== 'false'; // 默认启用递归扫描
|
|
102
128
|
|
|
129
|
+
// Surge 静态资源代理配置
|
|
130
|
+
this.surgeTarget = process.env.SURGE_TARGET || 'https://becrafter.surge.sh';
|
|
131
|
+
|
|
103
132
|
// 管理员配置
|
|
104
133
|
this.adminEnable = process.env.ADMIN_ENABLE !== 'false'; // 默认启用管理员功能
|
|
105
134
|
this.adminPath = process.env.ADMIN_PATH || '/admin';
|
|
106
135
|
this.exportToken = process.env.EXPORT_TOKEN || crypto.randomBytes(32).toString('hex');
|
|
136
|
+
// 是否需要认证(默认需要)
|
|
137
|
+
this.adminRequireAuth = process.env.ADMIN_REQUIRE_AUTH !== 'false';
|
|
107
138
|
|
|
108
139
|
// 管理员账户(从环境变量或默认值)
|
|
109
140
|
const adminUsername = process.env.ADMIN_USERNAME || 'admin';
|
|
@@ -144,12 +175,14 @@ export class Config {
|
|
|
144
175
|
recursiveScan,
|
|
145
176
|
adminEnable,
|
|
146
177
|
adminPath,
|
|
178
|
+
adminRequireAuth,
|
|
147
179
|
admins,
|
|
148
|
-
exportToken
|
|
180
|
+
exportToken,
|
|
181
|
+
surgeTarget
|
|
149
182
|
} = overrides;
|
|
150
183
|
|
|
151
184
|
if (promptsDir) {
|
|
152
|
-
this.promptsDir = promptsDir;
|
|
185
|
+
this.promptsDir = expandPath(promptsDir);
|
|
153
186
|
this.configHome = path.dirname(this.promptsDir);
|
|
154
187
|
}
|
|
155
188
|
if (port) {
|
|
@@ -176,12 +209,18 @@ export class Config {
|
|
|
176
209
|
if (adminPath) {
|
|
177
210
|
this.adminPath = adminPath;
|
|
178
211
|
}
|
|
212
|
+
if (typeof adminRequireAuth === 'boolean') {
|
|
213
|
+
this.adminRequireAuth = adminRequireAuth;
|
|
214
|
+
}
|
|
179
215
|
if (Array.isArray(admins) && admins.length) {
|
|
180
216
|
this.admins = admins;
|
|
181
217
|
}
|
|
182
218
|
if (exportToken) {
|
|
183
219
|
this.exportToken = exportToken;
|
|
184
220
|
}
|
|
221
|
+
if (surgeTarget) {
|
|
222
|
+
this.surgeTarget = surgeTarget;
|
|
223
|
+
}
|
|
185
224
|
}
|
|
186
225
|
|
|
187
226
|
|
|
@@ -276,6 +315,11 @@ export class Config {
|
|
|
276
315
|
process.stderr.write(` 递归扫描: ${this.recursiveScan ? '启用' : '禁用'}\n`);
|
|
277
316
|
process.stderr.write(` Prompts目录: ${this.promptsDir}\n`);
|
|
278
317
|
process.stderr.write(` 最大Prompt数量: ${this.maxPrompts}\n`);
|
|
318
|
+
process.stderr.write(` 管理员功能: ${this.adminEnable ? '启用' : '禁用'}\n`);
|
|
319
|
+
if (this.adminEnable) {
|
|
320
|
+
process.stderr.write(` 登录认证: ${this.adminRequireAuth ? '需要' : '不需要'}\n`);
|
|
321
|
+
}
|
|
322
|
+
process.stderr.write(` Surge代理目标: ${this.surgeTarget}\n`);
|
|
279
323
|
process.stderr.write('======================================================================================\n\n');
|
|
280
324
|
}
|
|
281
325
|
}
|
|
@@ -8,7 +8,8 @@ import { fileURLToPath } from 'url';
|
|
|
8
8
|
import { logger } from './logger.js';
|
|
9
9
|
|
|
10
10
|
export const GROUP_META_FILENAME = '.groupmeta.json';
|
|
11
|
-
|
|
11
|
+
// 允许中文、空格、emoji 等字符,禁止路径分隔符及常见非法文件名字符
|
|
12
|
+
export const GROUP_NAME_REGEX = /^(?![.]{1,2}$)[^\\/:*?"<>|\r\n]{1,64}$/;
|
|
12
13
|
|
|
13
14
|
// 获取当前文件的目录路径
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -206,6 +207,7 @@ export class Util {
|
|
|
206
207
|
* @returns
|
|
207
208
|
*/
|
|
208
209
|
isValidGroupName(name) {
|
|
210
|
+
if (typeof name !== 'string') return false;
|
|
209
211
|
return GROUP_NAME_REGEX.test(name);
|
|
210
212
|
}
|
|
211
213
|
|
|
@@ -334,20 +336,73 @@ export class Util {
|
|
|
334
336
|
return content.trim();
|
|
335
337
|
}
|
|
336
338
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
339
|
+
getWebUiRoot() {
|
|
340
|
+
// 检查是否在 Electron 环境中运行
|
|
341
|
+
const isElectron = typeof process !== 'undefined' &&
|
|
342
|
+
process.versions &&
|
|
343
|
+
process.versions.electron;
|
|
344
|
+
|
|
345
|
+
// 检查是否是打包应用
|
|
346
|
+
if (isElectron && process.resourcesPath) {
|
|
347
|
+
// 检查是否在打包模式(在我们的应用目录下有 app.asar)
|
|
348
|
+
const ourAppAsar = path.join(process.resourcesPath, 'app.asar');
|
|
349
|
+
if (fs.existsSync(ourAppAsar)) {
|
|
350
|
+
// 在打包的 Electron 应用中,web UI 位于 app.asar 内
|
|
351
|
+
return path.join(process.resourcesPath, 'app.asar', 'web');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 在开发环境中,web UI 位于项目目录中的 packages/web
|
|
342
356
|
const __filename = fileURLToPath(import.meta.url);
|
|
343
|
-
const __dirname = path.dirname(
|
|
344
|
-
|
|
357
|
+
const __dirname = path.dirname(__filename);
|
|
358
|
+
const devWebPath = path.join(__dirname, '..', 'web');
|
|
359
|
+
|
|
360
|
+
if (this._pathExistsSync(devWebPath)) {
|
|
361
|
+
return devWebPath;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// 如果上面的路径不存在,尝试从项目根目录查找
|
|
365
|
+
const projectRoot = path.resolve(__dirname, '../../..');
|
|
366
|
+
const altWebPath = path.join(projectRoot, 'packages', 'web');
|
|
367
|
+
if (this._pathExistsSync(altWebPath)) {
|
|
368
|
+
return altWebPath;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// 返回默认路径
|
|
372
|
+
return devWebPath;
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
_pathExistsSync(filePath) {
|
|
376
|
+
try {
|
|
377
|
+
fs.accessSync(filePath, fs.constants.F_OK);
|
|
378
|
+
return true;
|
|
379
|
+
} catch (error) {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
345
382
|
};
|
|
346
383
|
|
|
347
384
|
async getPromptManager() {
|
|
348
385
|
if (!_promptManager) {
|
|
349
|
-
|
|
350
|
-
|
|
386
|
+
try {
|
|
387
|
+
// 首先尝试相对路径导入
|
|
388
|
+
const serviceModule = await import('../services/manager.js');
|
|
389
|
+
_promptManager = serviceModule.promptManager;
|
|
390
|
+
} catch (error) {
|
|
391
|
+
// 如果相对路径导入失败,尝试使用绝对路径
|
|
392
|
+
try {
|
|
393
|
+
const path = await import('path');
|
|
394
|
+
const { fileURLToPath } = await import('url');
|
|
395
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
396
|
+
const __dirname = path.dirname(__filename);
|
|
397
|
+
const managerPath = path.join(__dirname, '..', 'services', 'manager.js');
|
|
398
|
+
const serviceModule = await import(managerPath);
|
|
399
|
+
_promptManager = serviceModule.promptManager;
|
|
400
|
+
} catch (absolutePathError) {
|
|
401
|
+
// 如果绝对路径也失败,记录错误并重新抛出
|
|
402
|
+
console.error('Failed to import promptManager with both relative and absolute paths:', absolutePathError);
|
|
403
|
+
throw absolutePathError;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
351
406
|
}
|
|
352
407
|
return _promptManager;
|
|
353
408
|
}
|