@becrafter/prompt-manager 0.0.19 → 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.
Files changed (103) hide show
  1. package/README.md +145 -234
  2. package/app/desktop/assets/app.1.png +0 -0
  3. package/app/desktop/assets/app.png +0 -0
  4. package/app/desktop/assets/icons/icon.icns +0 -0
  5. package/app/desktop/assets/icons/icon.ico +0 -0
  6. package/app/desktop/assets/icons/icon.png +0 -0
  7. package/app/desktop/assets/icons/tray.png +0 -0
  8. package/app/desktop/assets/tray.1.png +0 -0
  9. package/app/desktop/assets/tray.png +0 -0
  10. package/app/desktop/main.js +27 -0
  11. package/app/desktop/package-lock.json +216 -48
  12. package/app/desktop/package.json +23 -29
  13. package/app/desktop/src/services/module-loader.js +43 -22
  14. package/app/desktop/src/services/runtime-manager.js +172 -23
  15. package/app/desktop/src/ui/admin-window-manager.js +757 -0
  16. package/app/desktop/src/ui/splash-manager.js +253 -0
  17. package/app/desktop/src/ui/tray-manager.js +8 -24
  18. package/app/desktop/src/utils/icon-manager.js +39 -47
  19. package/app/desktop/src/utils/resource-paths.js +0 -23
  20. package/app/desktop/src/utils/resource-sync.js +260 -0
  21. package/app/desktop/src/utils/runtime-sync.js +241 -0
  22. package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +105 -0
  23. package/package.json +16 -13
  24. package/packages/admin-ui/.babelrc +3 -0
  25. package/packages/admin-ui/admin.html +237 -4784
  26. package/packages/admin-ui/css/main.css +2592 -0
  27. package/packages/admin-ui/css/recommended-prompts.css +610 -0
  28. package/packages/admin-ui/package-lock.json +6981 -0
  29. package/packages/admin-ui/package.json +36 -0
  30. package/packages/admin-ui/src/codemirror.js +53 -0
  31. package/packages/admin-ui/src/index.js +3188 -0
  32. package/packages/admin-ui/webpack.config.js +76 -0
  33. package/packages/resources/tools/chrome-devtools/README.md +310 -0
  34. package/packages/resources/tools/chrome-devtools/chrome-devtools.tool.js +1703 -0
  35. package/packages/resources/tools/file-reader/README.md +289 -0
  36. package/packages/resources/tools/file-reader/file-reader.tool.js +1545 -0
  37. package/packages/resources/tools/filesystem/README.md +359 -0
  38. package/packages/resources/tools/filesystem/filesystem.tool.js +514 -160
  39. package/packages/resources/tools/ollama-remote/README.md +192 -0
  40. package/packages/resources/tools/ollama-remote/ollama-remote.tool.js +421 -0
  41. package/packages/resources/tools/pdf-reader/README.md +236 -0
  42. package/packages/resources/tools/pdf-reader/pdf-reader.tool.js +565 -0
  43. package/packages/resources/tools/playwright/README.md +306 -0
  44. package/packages/resources/tools/playwright/playwright.tool.js +1186 -0
  45. package/packages/resources/tools/todolist/README.md +394 -0
  46. package/packages/resources/tools/todolist/todolist.tool.js +1312 -0
  47. package/packages/server/README.md +142 -0
  48. package/packages/server/api/admin.routes.js +42 -11
  49. package/packages/server/api/surge.routes.js +43 -0
  50. package/packages/server/app.js +119 -14
  51. package/packages/server/index.js +39 -0
  52. package/packages/server/mcp/mcp.server.js +324 -105
  53. package/packages/server/mcp/sequential-thinking.handler.js +318 -0
  54. package/packages/server/mcp/think-plan.handler.js +274 -0
  55. package/packages/server/middlewares/auth.middleware.js +6 -0
  56. package/packages/server/package.json +51 -0
  57. package/packages/server/server.js +37 -1
  58. package/packages/server/toolm/index.js +9 -0
  59. package/packages/server/toolm/package-installer.service.js +267 -0
  60. package/packages/server/toolm/test-tools.js +264 -0
  61. package/packages/server/toolm/tool-context.service.js +334 -0
  62. package/packages/server/toolm/tool-dependency.service.js +168 -0
  63. package/packages/server/toolm/tool-description-generator-optimized.service.js +375 -0
  64. package/packages/server/toolm/tool-description-generator.service.js +312 -0
  65. package/packages/server/toolm/tool-environment.service.js +200 -0
  66. package/packages/server/toolm/tool-execution.service.js +277 -0
  67. package/packages/server/toolm/tool-loader.service.js +219 -0
  68. package/packages/server/toolm/tool-logger.service.js +223 -0
  69. package/packages/server/toolm/tool-manager.handler.js +65 -0
  70. package/packages/server/toolm/tool-manual-generator.service.js +389 -0
  71. package/packages/server/toolm/tool-mode-handlers.service.js +224 -0
  72. package/packages/server/toolm/tool-storage.service.js +111 -0
  73. package/packages/server/toolm/tool-sync.service.js +138 -0
  74. package/packages/server/toolm/tool-utils.js +20 -0
  75. package/packages/server/toolm/tool-yaml-parser.service.js +81 -0
  76. package/packages/server/toolm/validate-system.js +421 -0
  77. package/packages/server/utils/config.js +49 -5
  78. package/packages/server/utils/util.js +65 -10
  79. package/scripts/build-icons.js +99 -69
  80. package/scripts/build.sh +57 -0
  81. package/scripts/surge/CNAME +1 -0
  82. package/scripts/surge/README.md +47 -0
  83. package/scripts/surge/package-lock.json +34 -0
  84. package/scripts/surge/package.json +20 -0
  85. package/scripts/surge/sync-to-surge.js +151 -0
  86. package/app/desktop/assets/icons/icon_1024x1024.png +0 -0
  87. package/app/desktop/assets/icons/icon_128x128.png +0 -0
  88. package/app/desktop/assets/icons/icon_16x16.png +0 -0
  89. package/app/desktop/assets/icons/icon_24x24.png +0 -0
  90. package/app/desktop/assets/icons/icon_256x256.png +0 -0
  91. package/app/desktop/assets/icons/icon_32x32.png +0 -0
  92. package/app/desktop/assets/icons/icon_48x48.png +0 -0
  93. package/app/desktop/assets/icons/icon_512x512.png +0 -0
  94. package/app/desktop/assets/icons/icon_64x64.png +0 -0
  95. package/app/desktop/assets/icons/icon_96x96.png +0 -0
  96. package/packages/admin-ui/js/closebrackets.min.js +0 -8
  97. package/packages/admin-ui/js/codemirror.min.js +0 -8
  98. package/packages/admin-ui/js/js-yaml.min.js +0 -2
  99. package/packages/admin-ui/js/markdown.min.js +0 -8
  100. package/packages/resources/tools/index.js +0 -16
  101. package/packages/server/mcp/toolx.handler.js +0 -131
  102. package/scripts/icns-builder/package.json +0 -12
  103. /package/packages/server/mcp/{mcp.handler.js → prompt.handler.js} +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.0.19';
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
- export const GROUP_NAME_REGEX = /^[a-zA-Z0-9-_\u4e00-\u9fa5]{1,64}$/;
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
- * 获取admin-ui目录的绝对路径
339
- * @returns {string} admin-ui目录的绝对路径
340
- */
341
- getAdminUiRoot() {
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(path.dirname(__filename));
344
- return path.join(__dirname, '..', 'admin-ui');
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
- const serviceModule = await import('../services/manager.js');
350
- _promptManager = serviceModule.promptManager;
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
  }