@becrafter/prompt-manager 0.1.20 → 0.1.21
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/env.example +4 -8
- package/package.json +1 -3
- package/packages/resources/tools/cognitive-thinking/README.md +284 -0
- package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +837 -0
- package/packages/server/api/admin.routes.js +19 -0
- package/packages/server/mcp/mcp.server.js +6 -6
- package/packages/server/server.js +4 -3
- package/packages/server/services/WebSocketService.js +15 -5
- package/packages/server/utils/config.js +24 -6
- package/packages/server/utils/util.js +63 -18
- package/packages/web/css/terminal-fix.css +571 -0
- package/packages/web/index.html +1 -1
- package/packages/web/{main.b427a9e6f77a32a2f87f.js → main.dceff50c7307dda04873.js} +2 -2
- /package/packages/web/{main.b427a9e6f77a32a2f87f.js.LICENSE.txt → main.dceff50c7307dda04873.js.LICENSE.txt} +0 -0
|
@@ -16,6 +16,7 @@ import {adminAuthMiddleware} from '../middlewares/auth.middleware.js'
|
|
|
16
16
|
import { templateManager } from '../services/template.service.js';
|
|
17
17
|
import { modelManager } from '../services/model.service.js';
|
|
18
18
|
import { optimizationService } from '../services/optimization.service.js';
|
|
19
|
+
import { webSocketService } from '../services/WebSocketService.js';
|
|
19
20
|
|
|
20
21
|
const router = express.Router();
|
|
21
22
|
|
|
@@ -36,6 +37,24 @@ router.get('/config', (req, res) => {
|
|
|
36
37
|
});
|
|
37
38
|
});
|
|
38
39
|
|
|
40
|
+
// 获取公开配置端点(无需认证)
|
|
41
|
+
router.get('/config/public', (req, res) => {
|
|
42
|
+
const publicConfig = config.getPublicConfig();
|
|
43
|
+
|
|
44
|
+
// 如果 WebSocket 服务已启动,使用实际分配的端口
|
|
45
|
+
if (webSocketService.isRunning) {
|
|
46
|
+
publicConfig.websocketPort = webSocketService.getPort();
|
|
47
|
+
} else {
|
|
48
|
+
// 如果 WebSocket 服务未启动,返回 null 表示尚未确定
|
|
49
|
+
publicConfig.websocketPort = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
res.json({
|
|
53
|
+
success: true,
|
|
54
|
+
data: publicConfig
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
39
58
|
// 登录端点
|
|
40
59
|
router.post('/login', (req, res) => {
|
|
41
60
|
// 检查是否启用了管理员功能
|
|
@@ -130,12 +130,12 @@ export const getMcpServer = async () => {
|
|
|
130
130
|
return handleToolM(args);
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
|
-
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
133
|
+
// {
|
|
134
|
+
// name: 'thinking',
|
|
135
|
+
// description: `🧭 **智能思考工具箱**\n\n【规范名称】promptmanager_thinking\n【调用说明】在提示词中使用 promptmanager_thinking,实际调用时自动映射到 mcp__[server]__action\n\n⚠️ **务必先读说明**:每次首次使用某个 scenario 时,先发送仅包含 \`{"scenario":"..."}\` 的请求获取完整描述,确认理解适用场景与参数要求后,再携带 payload 调用。跳过此步骤易导致字段缺失或流程误用。\n\n## 核心特性\n\n- **双模式思考** - 提供顺序思考(exploratory)和思考规划(execution)两种模式\n- **智能引导** - 通过场景参数自动匹配合适的思考策略\n- **结构化流程** - 支持多轮思考追踪和分支管理\n- **错误预防** - 强制预读说明,避免参数配置错误\n- **灵活扩展** - 支持修订、分支和会话管理\n\n## 何时使用 Thinking Toolkit\n\n### 快速决策(IF-THEN 规则):\n- IF 需要探索性思考、诊断问题、发散推理 → 使用 scenario: "exploratory"\n- IF 需要结构化规划、制定执行步骤 → 使用 scenario: "execution"\n- IF 看到 scenario 参数 → 使用 thinking_toolkit 调用\n- IF 不确定场景用法 → 先用仅包含 scenario 的请求查看说明\n\n### 首次使用任何场景\n⚠️ **必须先发送仅包含 scenario 的请求** 阅读场景完整描述\n⚠️ 示例:thinking_toolkit with scenario: "exploratory" (无payload)\n\n## 如何使用 Thinking Toolkit\n\n### 模式 1:查看场景说明(首次使用)\n\n\`\`\`javascript\nmcp_mcp-router_thinking_toolkit({\n scenario: "exploratory"\n})\n\`\`\`\n\n**重要**:每次使用新场景前必须先执行此步骤,了解场景的具体参数要求和使用方法。\n\n### 模式 2:执行顺序思考\n\n\`\`\`javascript\nmcp_mcp-router_thinking_toolkit({\n scenario: "exploratory",\n payload: {\n thought: "分析性能下降的可能原因",\n totalThoughts: 5,\n nextThoughtNeeded: true\n }\n})\n\`\`\`\n\n### 模式 3:执行思考规划\n\n\`\`\`javascript\nmcp_mcp-router_thinking_toolkit({\n scenario: "execution",\n payload: {\n thought: "需要上线新版本",\n plan: "1. 备份 2. 部署 3. 验证",\n action: "先执行备份脚本",\n thoughtNumber: "TP-001"\n }\n})\n\`\`\`\n\n## 关键规则\n\n### ✅ 正确格式\n- 先发送 \`{"scenario": "..."}\` 获取场景说明\n- 根据说明确认参数要求后,再携带 payload 调用\n- scenario 必填:exploratory(顺序思考)或 execution(思考规划)\n- payload 根据场景填写对应字段\n\n### ❌ 常见错误\n- 不要跳过场景说明,直接携带 payload 调用(易导致参数错误)\n- 不要混用不同场景的参数字段\n- 不要在首次使用场景时直接执行 payload\n\n## 支持的思考场景\n\n### Exploratory(顺序思考)\n适合探索、诊断、发散推理场景,支持多轮思考追踪和分支管理。\n\n### Execution(思考规划)\n适合结构化计划制定和行动追踪,按步骤执行任务规划。\n\n更多场景正在开发中...`,
|
|
136
|
+
// inputSchema: thinkingToolkitInputSchema,
|
|
137
|
+
// handler: async (args) => handleThinkingToolkit(args)
|
|
138
|
+
// }
|
|
139
139
|
// {
|
|
140
140
|
// name: 'reload_prompts',
|
|
141
141
|
// description: 'Force a reload of all preset prompts to overwrite the cache.',
|
|
@@ -150,10 +150,11 @@ export async function startServer(options = {}) {
|
|
|
150
150
|
// 设置服务器实例
|
|
151
151
|
serverInstance = server;
|
|
152
152
|
|
|
153
|
-
// 启动WebSocket
|
|
153
|
+
// 启动WebSocket服务,传入 HTTP 服务器端口
|
|
154
154
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
await webSocketService.start({ port: config.getPort() });
|
|
156
|
+
const wsPort = webSocketService.getPort();
|
|
157
|
+
logger.info(`WebSocket服务启动成功,端口: ${wsPort}`);
|
|
157
158
|
} catch (wsError) {
|
|
158
159
|
logger.error('WebSocket服务启动失败:', wsError.message);
|
|
159
160
|
// WebSocket服务失败不影响主服务器运行
|
|
@@ -274,7 +274,7 @@ class WebSocketConnection {
|
|
|
274
274
|
export class WebSocketService {
|
|
275
275
|
constructor(options = {}) {
|
|
276
276
|
this.options = {
|
|
277
|
-
port:
|
|
277
|
+
port: options.port || 0, // 0 表示让系统自动分配端口,或使用外部指定的端口
|
|
278
278
|
host: '0.0.0.0',
|
|
279
279
|
maxConnections: 100,
|
|
280
280
|
heartbeatInterval: 30000, // 30秒心跳
|
|
@@ -318,11 +318,14 @@ export class WebSocketService {
|
|
|
318
318
|
|
|
319
319
|
this.wss.on('listening', () => {
|
|
320
320
|
this.isRunning = true;
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// 获取实际分配的端口
|
|
322
|
+
const address = this.wss.address();
|
|
323
|
+
this.actualPort = typeof address === 'string' ? parseInt(address) : address.port;
|
|
324
|
+
logger.info(`WebSocket server listening on ${this.options.host}:${this.actualPort}`);
|
|
325
|
+
|
|
323
326
|
// 启动心跳检测
|
|
324
327
|
this.startHeartbeat();
|
|
325
|
-
|
|
328
|
+
|
|
326
329
|
resolve();
|
|
327
330
|
});
|
|
328
331
|
|
|
@@ -457,6 +460,13 @@ export class WebSocketService {
|
|
|
457
460
|
return Array.from(this.connections.values());
|
|
458
461
|
}
|
|
459
462
|
|
|
463
|
+
/**
|
|
464
|
+
* 获取实际分配的端口
|
|
465
|
+
*/
|
|
466
|
+
getPort() {
|
|
467
|
+
return this.actualPort || this.options.port;
|
|
468
|
+
}
|
|
469
|
+
|
|
460
470
|
/**
|
|
461
471
|
* 获取服务状态
|
|
462
472
|
*/
|
|
@@ -467,7 +477,7 @@ export class WebSocketService {
|
|
|
467
477
|
|
|
468
478
|
return {
|
|
469
479
|
isRunning: this.isRunning,
|
|
470
|
-
port: this.
|
|
480
|
+
port: this.getPort(),
|
|
471
481
|
host: this.options.host,
|
|
472
482
|
totalConnections: this.connections.size,
|
|
473
483
|
activeConnections: activeConnections.length,
|
|
@@ -77,14 +77,12 @@ MCP Prompt Server - 智能 Prompt 管理服务器
|
|
|
77
77
|
-v, --version 显示版本信息
|
|
78
78
|
|
|
79
79
|
环境变量:
|
|
80
|
-
MCP_SERVER_NAME 服务器名称 (默认: prompt-manager)
|
|
81
80
|
SERVER_PORT 服务器端口 (默认: 5621)
|
|
82
81
|
PROMPTS_DIR Prompts目录路径
|
|
83
|
-
MCP_SERVER_VERSION 服务器版本
|
|
84
82
|
LOG_LEVEL 日志级别 (默认: info)
|
|
85
83
|
MAX_PROMPTS 最大prompt数量限制 (默认: 1000)
|
|
86
84
|
RECURSIVE_SCAN 是否启用递归扫描子目录 (默认: true)
|
|
87
|
-
ADMIN_ENABLE
|
|
85
|
+
ADMIN_ENABLE 是否启用管理界面 (默认: true)
|
|
88
86
|
ADMIN_REQUIRE_AUTH 是否需要登录认证 (默认: true)
|
|
89
87
|
ADMIN_USERNAME 管理员用户名 (默认: admin)
|
|
90
88
|
ADMIN_PASSWORD 管理员密码 (默认: admin)
|
|
@@ -120,8 +118,8 @@ export class Config {
|
|
|
120
118
|
this.port = cliArgs.port || process.env.SERVER_PORT || 5621;
|
|
121
119
|
|
|
122
120
|
// 其他配置
|
|
123
|
-
this.serverName =
|
|
124
|
-
this.serverVersion =
|
|
121
|
+
this.serverName = 'prompt-manager';
|
|
122
|
+
this.serverVersion = '0.1.20';
|
|
125
123
|
this.logLevel = process.env.LOG_LEVEL || 'info';
|
|
126
124
|
this.maxPrompts = parseInt(process.env.MAX_PROMPTS) || 1000;
|
|
127
125
|
this.recursiveScan = process.env.RECURSIVE_SCAN !== 'false'; // 默认启用递归扫描
|
|
@@ -310,6 +308,26 @@ export class Config {
|
|
|
310
308
|
}
|
|
311
309
|
}
|
|
312
310
|
|
|
311
|
+
/**
|
|
312
|
+
* 获取公开配置(前端可访问的配置信息)
|
|
313
|
+
*/
|
|
314
|
+
getPublicConfig() {
|
|
315
|
+
return {
|
|
316
|
+
serverName: this.serverName,
|
|
317
|
+
serverVersion: this.serverVersion,
|
|
318
|
+
port: this.port,
|
|
319
|
+
adminEnable: this.adminEnable,
|
|
320
|
+
adminPath: this.adminPath,
|
|
321
|
+
websocketPort: null, // 这个会在 admin.routes.js 中动态设置
|
|
322
|
+
features: {
|
|
323
|
+
terminal: true,
|
|
324
|
+
optimization: true,
|
|
325
|
+
templates: true,
|
|
326
|
+
models: true
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
313
331
|
/**
|
|
314
332
|
* 显示当前配置(输出到 stderr,不干扰 MCP 通信)
|
|
315
333
|
*/
|
|
@@ -322,7 +340,7 @@ export class Config {
|
|
|
322
340
|
process.stderr.write(` 递归扫描: ${this.recursiveScan ? '启用' : '禁用'}\n`);
|
|
323
341
|
process.stderr.write(` Prompts目录: ${this.promptsDir}\n`);
|
|
324
342
|
process.stderr.write(` 最大Prompt数量: ${this.maxPrompts}\n`);
|
|
325
|
-
process.stderr.write(`
|
|
343
|
+
process.stderr.write(` 管理界面: ${this.adminEnable ? '启用' : '禁用'}\n`);
|
|
326
344
|
if (this.adminEnable) {
|
|
327
345
|
process.stderr.write(` 登录认证: ${this.adminRequireAuth ? '需要' : '不需要'}\n`);
|
|
328
346
|
}
|
|
@@ -385,39 +385,84 @@ export class Util {
|
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
getWebUiRoot() {
|
|
388
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
389
|
+
const __dirname = path.dirname(__filename);
|
|
390
|
+
|
|
391
|
+
console.log('🔍 getWebUiRoot() called from:', __dirname);
|
|
392
|
+
|
|
388
393
|
// 检查是否在 Electron 环境中运行
|
|
389
|
-
const isElectron = typeof process !== 'undefined' &&
|
|
390
|
-
process.versions &&
|
|
394
|
+
const isElectron = typeof process !== 'undefined' &&
|
|
395
|
+
process.versions &&
|
|
391
396
|
process.versions.electron;
|
|
392
|
-
|
|
397
|
+
|
|
393
398
|
// 检查是否是打包应用
|
|
394
399
|
if (isElectron && process.resourcesPath) {
|
|
395
|
-
// 检查是否在打包模式(在我们的应用目录下有 app.asar)
|
|
396
400
|
const ourAppAsar = path.join(process.resourcesPath, 'app.asar');
|
|
397
401
|
if (fs.existsSync(ourAppAsar)) {
|
|
398
|
-
|
|
399
|
-
|
|
402
|
+
const asarPath = path.join(process.resourcesPath, 'app.asar', 'web');
|
|
403
|
+
console.log('📦 Using Electron ASAR path:', asarPath);
|
|
404
|
+
return asarPath;
|
|
400
405
|
}
|
|
401
406
|
}
|
|
402
|
-
|
|
403
|
-
// 在开发环境中,web UI 位于项目目录中的 packages/web
|
|
404
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
405
|
-
const __dirname = path.dirname(__filename);
|
|
406
|
-
const devWebPath = path.join(__dirname, '..', 'web');
|
|
407
407
|
|
|
408
|
+
// 在开发环境中,web UI 位于项目目录中的 packages/web
|
|
409
|
+
const devWebPath = path.join(__dirname, '..', '..', 'web');
|
|
410
|
+
console.log('🔍 Checking dev path:', devWebPath);
|
|
408
411
|
if (this._pathExistsSync(devWebPath)) {
|
|
412
|
+
console.log('✅ Using dev environment path:', devWebPath);
|
|
409
413
|
return devWebPath;
|
|
410
414
|
}
|
|
411
415
|
|
|
412
|
-
// 在 npm
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
416
|
+
// 在 npm 包环境中,查找 packages/web
|
|
417
|
+
// 从当前文件位置向上查找可能的包根目录
|
|
418
|
+
let currentDir = __dirname;
|
|
419
|
+
let searchDepth = 0;
|
|
420
|
+
const maxDepth = 5;
|
|
421
|
+
|
|
422
|
+
while (searchDepth < maxDepth) {
|
|
423
|
+
// 检查 packages/web
|
|
424
|
+
const webPath = path.join(currentDir, 'packages', 'web');
|
|
425
|
+
console.log('🔍 Checking npm package path:', webPath);
|
|
426
|
+
if (this._pathExistsSync(webPath)) {
|
|
427
|
+
console.log('✅ Found web UI in npm package:', webPath);
|
|
428
|
+
return webPath;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// 检查直接的 web 目录(某些打包场景)
|
|
432
|
+
const altWebPath = path.join(currentDir, 'web');
|
|
433
|
+
console.log('🔍 Checking alternative path:', altWebPath);
|
|
434
|
+
if (this._pathExistsSync(altWebPath)) {
|
|
435
|
+
console.log('✅ Found web UI in alternative path:', altWebPath);
|
|
436
|
+
return altWebPath;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// 向上查找
|
|
440
|
+
const parentDir = path.dirname(currentDir);
|
|
441
|
+
if (parentDir === currentDir) {
|
|
442
|
+
// 已经到达根目录
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
currentDir = parentDir;
|
|
446
|
+
searchDepth++;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// 如果都找不到,使用当前工作目录作为最后尝试
|
|
450
|
+
const cwdWebPath = path.join(process.cwd(), 'packages', 'web');
|
|
451
|
+
console.log('🔍 Checking CWD path:', cwdWebPath);
|
|
452
|
+
if (this._pathExistsSync(cwdWebPath)) {
|
|
453
|
+
console.log('✅ Found web UI in CWD:', cwdWebPath);
|
|
454
|
+
return cwdWebPath;
|
|
417
455
|
}
|
|
418
456
|
|
|
419
|
-
//
|
|
420
|
-
|
|
457
|
+
// 最后的fallback
|
|
458
|
+
console.error('❌ Web UI not found in any location. This will cause blank pages.');
|
|
459
|
+
console.error('Current directory:', __dirname);
|
|
460
|
+
console.error('Working directory:', process.cwd());
|
|
461
|
+
console.error('Checked paths:');
|
|
462
|
+
console.error(' - Dev path:', devWebPath);
|
|
463
|
+
console.error(' - CWD path:', cwdWebPath);
|
|
464
|
+
|
|
465
|
+
return devWebPath; // 返回开发路径作为fallback,虽然它不存在
|
|
421
466
|
};
|
|
422
467
|
|
|
423
468
|
/**
|