flex-mcp 1.1.5 → 1.1.6
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/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +135 -84
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +25 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +261 -0
- package/dist/daemon.js.map +1 -0
- package/dist/index.js +35 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/tool-sync.d.ts.map +1 -1
- package/dist/mcp/tool-sync.js +0 -1
- package/dist/mcp/tool-sync.js.map +1 -1
- package/dist/web/assets/{Blank-BX2hzrSo.js → Blank-BAn70pKV.js} +1 -1
- package/dist/web/assets/{Configs-DGpyzfgE.js → Configs-C6QxaALX.js} +1 -1
- package/dist/web/assets/{Dashboard-Dk-7JVrJ.js → Dashboard-CC6Oo381.js} +2 -2
- package/dist/web/assets/{InitScriptEditor-CJfq5ewu.js → InitScriptEditor-DzzTB5Qk.js} +2 -2
- package/dist/web/assets/{Layout-CbJQ0_wa.js → Layout-BOxnvITD.js} +1 -1
- package/dist/web/assets/{Layout-D8dTPthK.js → Layout-CNq36nXL.js} +1 -1
- package/dist/web/assets/{Login-Apd8mOT7.js → Login-BxCS6qf-.js} +1 -1
- package/dist/web/assets/{Login-CPVVdjS9.js → Login-zgQ_fCXm.js} +1 -1
- package/dist/web/assets/{Users-Dfo1A39a.js → Users-68dlwZ5K.js} +1 -1
- package/dist/web/assets/{index-Ku_MdnLs.js → index-DAOSS2K-.js} +2 -2
- package/dist/web/assets/{style-COdYV8kW.css → style-C2LUa6XO.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -1
package/dist/cli.d.ts
CHANGED
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
package/dist/cli.js
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* 命令行入口
|
|
4
4
|
* 支持作为 npm 包直接启动服务、初始化、部署等
|
|
5
5
|
*/
|
|
6
|
-
import 'dotenv/config';
|
|
7
6
|
import * as fs from 'fs';
|
|
8
7
|
import * as path from 'path';
|
|
9
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { config } from 'dotenv';
|
|
10
|
+
import { Command } from 'commander';
|
|
10
11
|
import { serve } from '@hono/node-server';
|
|
11
12
|
import { Hono } from 'hono';
|
|
12
13
|
import { cors } from 'hono/cors';
|
|
@@ -15,11 +16,141 @@ import { apiRouter } from './api/index.js';
|
|
|
15
16
|
import { mcpRouter } from './mcp/index.js';
|
|
16
17
|
import { hasWebFiles, readStaticFile, getMimeType } from './static.js';
|
|
17
18
|
import { reportStartup } from './utils/telemetry.js';
|
|
19
|
+
import { startDaemon, stopDaemon, restartDaemon, statusDaemon, } from './daemon.js';
|
|
18
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
21
|
const __dirname = path.dirname(__filename);
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// 先加载 .env 文件(提供默认值)
|
|
23
|
+
config();
|
|
24
|
+
// 创建 Commander 程序实例
|
|
25
|
+
const program = new Command();
|
|
26
|
+
// 定义全局选项(所有命令都可以使用)
|
|
27
|
+
// 注意:commander 会将选项名规范化,支持 --port 或 --PORT(大小写不敏感)
|
|
28
|
+
program
|
|
29
|
+
.option('--port <port>', '服务器端口', process.env.PORT || '3000')
|
|
30
|
+
.option('--host <host>', '服务器地址', process.env.HOST || '0.0.0.0')
|
|
31
|
+
.option('--cors-origin <origin>', 'CORS 来源', process.env.CORS_ORIGIN || '*')
|
|
32
|
+
.option('--admin-username <username>', '超级管理员用户名', process.env.ADMIN_USERNAME || 'admin')
|
|
33
|
+
.option('--admin-password <password>', '超级管理员密码', process.env.ADMIN_PASSWORD || '123456')
|
|
34
|
+
.option('--data-dir <dir>', '数据目录', process.env.DATA_DIR || './.data')
|
|
35
|
+
.option('--database-url <url>', '数据库路径', process.env.DATABASE_URL)
|
|
36
|
+
.option('--jwt-secret <secret>', 'JWT 密钥', process.env.JWT_SECRET)
|
|
37
|
+
.allowUnknownOption(); // 允许未知选项(支持 --PORT 等大写格式)
|
|
38
|
+
// 定义命令
|
|
39
|
+
program
|
|
40
|
+
.name('flex-mcp')
|
|
41
|
+
.description('可运营 MCP Node 服务 - 支持多用户管理、MCP 协议、脚本执行')
|
|
42
|
+
.version('1.1.4');
|
|
43
|
+
program
|
|
44
|
+
.command('init')
|
|
45
|
+
.description('初始化项目(创建 .env 文件,初始化数据库)')
|
|
46
|
+
.action(async () => {
|
|
47
|
+
await init();
|
|
48
|
+
});
|
|
49
|
+
program
|
|
50
|
+
.command('start')
|
|
51
|
+
.description('启动服务器(守护进程模式,后台运行)')
|
|
52
|
+
.action(async () => {
|
|
53
|
+
// 将命令行选项应用到环境变量(优先级最高,覆盖 .env 中的值)
|
|
54
|
+
const options = program.opts();
|
|
55
|
+
// commander 会将选项名规范化:--port -> port, --cors-origin -> corsOrigin
|
|
56
|
+
const optionMap = {
|
|
57
|
+
port: 'PORT',
|
|
58
|
+
host: 'HOST',
|
|
59
|
+
corsOrigin: 'CORS_ORIGIN',
|
|
60
|
+
adminUsername: 'ADMIN_USERNAME',
|
|
61
|
+
adminPassword: 'ADMIN_PASSWORD',
|
|
62
|
+
dataDir: 'DATA_DIR',
|
|
63
|
+
databaseUrl: 'DATABASE_URL',
|
|
64
|
+
jwtSecret: 'JWT_SECRET',
|
|
65
|
+
};
|
|
66
|
+
// 处理 commander 解析的选项
|
|
67
|
+
for (const [key, value] of Object.entries(options)) {
|
|
68
|
+
if (value !== undefined) {
|
|
69
|
+
const envKey = optionMap[key] || key.toUpperCase().replace(/-/g, '_');
|
|
70
|
+
process.env[envKey] = String(value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 手动解析剩余参数,支持 --PORT 等大写格式
|
|
74
|
+
const args = process.argv.slice(2);
|
|
75
|
+
let i = 1; // 跳过命令名
|
|
76
|
+
while (i < args.length) {
|
|
77
|
+
const arg = args[i];
|
|
78
|
+
if (arg.startsWith('--')) {
|
|
79
|
+
const [key, value] = arg.includes('=')
|
|
80
|
+
? arg.substring(2).split('=', 2)
|
|
81
|
+
: [arg.substring(2), args[i + 1]];
|
|
82
|
+
if (key && value && !value.startsWith('--')) {
|
|
83
|
+
// 将键转换为环境变量格式(大写,下划线分隔)
|
|
84
|
+
const envKey = key.toUpperCase().replace(/-/g, '_');
|
|
85
|
+
process.env[envKey] = value;
|
|
86
|
+
i += arg.includes('=') ? 1 : 2;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
i++;
|
|
91
|
+
}
|
|
92
|
+
// 检查是否以守护进程模式运行
|
|
93
|
+
if (process.env.DAEMON_MODE === 'true') {
|
|
94
|
+
// 守护进程模式:直接启动服务器
|
|
95
|
+
await start();
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// 前台模式:启动守护进程
|
|
99
|
+
await startDaemon();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
program
|
|
103
|
+
.command('stop')
|
|
104
|
+
.description('停止服务器')
|
|
105
|
+
.action(async () => {
|
|
106
|
+
await stopDaemon();
|
|
107
|
+
});
|
|
108
|
+
program
|
|
109
|
+
.command('restart')
|
|
110
|
+
.description('重启服务器')
|
|
111
|
+
.action(async () => {
|
|
112
|
+
await restartDaemon();
|
|
113
|
+
});
|
|
114
|
+
program
|
|
115
|
+
.command('status')
|
|
116
|
+
.description('查看服务器状态')
|
|
117
|
+
.action(async () => {
|
|
118
|
+
await statusDaemon();
|
|
119
|
+
});
|
|
120
|
+
program
|
|
121
|
+
.command('deploy')
|
|
122
|
+
.description('一键部署(初始化 + 启动)')
|
|
123
|
+
.action(async () => {
|
|
124
|
+
await deploy();
|
|
125
|
+
});
|
|
126
|
+
// 添加示例说明到帮助信息
|
|
127
|
+
program.addHelpText('after', `
|
|
128
|
+
示例:
|
|
129
|
+
flex-mcp init # 初始化项目
|
|
130
|
+
flex-mcp start # 启动服务器(守护进程模式)
|
|
131
|
+
flex-mcp start --PORT 12345 # 启动服务器,指定端口为 12345
|
|
132
|
+
flex-mcp start --PORT=12345 --HOST=0.0.0.0 # 使用等号格式指定多个参数
|
|
133
|
+
flex-mcp stop # 停止服务器
|
|
134
|
+
flex-mcp restart # 重启服务器
|
|
135
|
+
flex-mcp status # 查看服务器状态
|
|
136
|
+
flex-mcp deploy # 一键部署
|
|
137
|
+
|
|
138
|
+
环境变量优先级(从高到低):
|
|
139
|
+
1. 命令行参数(--KEY VALUE 或 --KEY=VALUE)
|
|
140
|
+
2. .env 文件中的变量
|
|
141
|
+
3. 默认值
|
|
142
|
+
|
|
143
|
+
更多信息: https://github.com/LeeLejia/meta-mcp
|
|
144
|
+
`);
|
|
145
|
+
// 解析命令行参数并执行对应的 action
|
|
146
|
+
// commander 会自动处理错误和帮助信息
|
|
147
|
+
try {
|
|
148
|
+
program.parse();
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error('❌ 错误:', error.message || error);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
23
154
|
// 环境变量模板
|
|
24
155
|
const ENV_TEMPLATE = `# flex-mcp 环境配置
|
|
25
156
|
|
|
@@ -193,9 +324,6 @@ async function start() {
|
|
|
193
324
|
else {
|
|
194
325
|
console.log(`💡 Web UI: 未构建,请先构建前端或使用开发模式`);
|
|
195
326
|
}
|
|
196
|
-
console.log(`\n💡 从 Cursor 连接:`);
|
|
197
|
-
console.log(` URL: http://${host}:${port}/mcp/request?email=YOUR_EMAIL&apiKey=YOUR_API_KEY`);
|
|
198
|
-
console.log(` SSE: http://${host}:${port}/mcp/sse?email=YOUR_EMAIL&apiKey=YOUR_API_KEY`);
|
|
199
327
|
// 上报服务器启动统计(延迟执行,不阻塞启动)
|
|
200
328
|
reportStartup();
|
|
201
329
|
}
|
|
@@ -208,81 +336,4 @@ async function deploy() {
|
|
|
208
336
|
console.log('\n📦 启动服务器...\n');
|
|
209
337
|
await start();
|
|
210
338
|
}
|
|
211
|
-
/**
|
|
212
|
-
* 显示帮助信息
|
|
213
|
-
*/
|
|
214
|
-
function showHelp() {
|
|
215
|
-
console.log(`
|
|
216
|
-
flex-mcp - 可运营 MCP Node 服务
|
|
217
|
-
|
|
218
|
-
用法:
|
|
219
|
-
flex-mcp <command> [options]
|
|
220
|
-
|
|
221
|
-
命令:
|
|
222
|
-
init 初始化项目(创建 .env 文件,初始化数据库)
|
|
223
|
-
start 启动服务器
|
|
224
|
-
deploy 一键部署(初始化 + 启动)
|
|
225
|
-
help 显示帮助信息
|
|
226
|
-
|
|
227
|
-
示例:
|
|
228
|
-
flex-mcp init # 初始化项目
|
|
229
|
-
flex-mcp start # 启动服务器
|
|
230
|
-
flex-mcp deploy # 一键部署
|
|
231
|
-
|
|
232
|
-
环境变量:
|
|
233
|
-
通过 .env 文件配置,或使用环境变量:
|
|
234
|
-
- PORT: 服务器端口(默认: 3000)
|
|
235
|
-
- HOST: 服务器地址(默认: 0.0.0.0)
|
|
236
|
-
- ADMIN_USERNAME: 超级管理员用户名(默认: admin)
|
|
237
|
-
- ADMIN_PASSWORD: 超级管理员密码(默认: 123456)
|
|
238
|
-
- DATA_DIR: 数据目录(默认: ./.data)
|
|
239
|
-
|
|
240
|
-
更多信息: https://github.com/LeeLejia/meta-mcp
|
|
241
|
-
`);
|
|
242
|
-
}
|
|
243
|
-
// 主函数
|
|
244
|
-
async function main() {
|
|
245
|
-
try {
|
|
246
|
-
switch (command) {
|
|
247
|
-
case 'init':
|
|
248
|
-
await init();
|
|
249
|
-
break;
|
|
250
|
-
case 'start':
|
|
251
|
-
await start();
|
|
252
|
-
break;
|
|
253
|
-
case 'deploy':
|
|
254
|
-
await deploy();
|
|
255
|
-
break;
|
|
256
|
-
case 'help':
|
|
257
|
-
case '--help':
|
|
258
|
-
case '-h':
|
|
259
|
-
showHelp();
|
|
260
|
-
break;
|
|
261
|
-
default:
|
|
262
|
-
if (command.startsWith('-')) {
|
|
263
|
-
showHelp();
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
console.error(`❌ 未知命令: ${command}`);
|
|
267
|
-
console.log('运行 "flex-mcp help" 查看帮助信息');
|
|
268
|
-
process.exit(1);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
catch (error) {
|
|
273
|
-
console.error('❌ 错误:', error.message || error);
|
|
274
|
-
process.exit(1);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
// 如果直接运行此文件,执行主函数
|
|
278
|
-
// 检查是否是直接运行(不是被导入)
|
|
279
|
-
// 在 ESM 模块中,如果文件被直接执行,import.meta.url 会匹配 process.argv[1]
|
|
280
|
-
// 或者通过 npm bin 链接运行时,argv[1] 会包含 cli.js 或 flex-mcp
|
|
281
|
-
const isMainModule = import.meta.url === `file://${process.argv[1]}` ||
|
|
282
|
-
process.argv[1]?.includes('cli.js') ||
|
|
283
|
-
process.argv[1]?.includes('flex-mcp') ||
|
|
284
|
-
// 如果没有任何参数且是直接运行,也执行
|
|
285
|
-
(process.argv.length === 2 && import.meta.url.endsWith('cli.js'));
|
|
286
|
-
// 总是执行主函数(因为这是 CLI 入口文件)
|
|
287
|
-
main();
|
|
288
339
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 守护进程管理模块
|
|
3
|
+
* 实现类似 whistle w2 的进程管理功能
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 获取 PID 文件路径
|
|
7
|
+
*/
|
|
8
|
+
export declare function getPidFile(): string;
|
|
9
|
+
/**
|
|
10
|
+
* 启动守护进程
|
|
11
|
+
*/
|
|
12
|
+
export declare function startDaemon(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* 停止守护进程
|
|
15
|
+
*/
|
|
16
|
+
export declare function stopDaemon(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* 重启守护进程
|
|
19
|
+
*/
|
|
20
|
+
export declare function restartDaemon(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* 查看守护进程状态
|
|
23
|
+
*/
|
|
24
|
+
export declare function statusDaemon(): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AA8ED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAiFjD;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAqDhD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAKnD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CA8BlD"}
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 守护进程管理模块
|
|
3
|
+
* 实现类似 whistle w2 的进程管理功能
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import { getDataDir } from './config.js';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
// PID 文件路径(存储在数据目录)
|
|
13
|
+
const PID_FILE = path.join(getDataDir(), 'flex-mcp.pid');
|
|
14
|
+
const LOG_FILE = path.join(getDataDir(), 'flex-mcp.log');
|
|
15
|
+
/**
|
|
16
|
+
* 获取 PID 文件路径
|
|
17
|
+
*/
|
|
18
|
+
export function getPidFile() {
|
|
19
|
+
return PID_FILE;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 读取 PID 文件
|
|
23
|
+
*/
|
|
24
|
+
function readPid() {
|
|
25
|
+
try {
|
|
26
|
+
if (!fs.existsSync(PID_FILE)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const pidStr = fs.readFileSync(PID_FILE, 'utf-8').trim();
|
|
30
|
+
const pid = parseInt(pidStr, 10);
|
|
31
|
+
return isNaN(pid) ? null : pid;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 写入 PID 文件
|
|
39
|
+
*/
|
|
40
|
+
function writePid(pid) {
|
|
41
|
+
try {
|
|
42
|
+
fs.writeFileSync(PID_FILE, pid.toString(), 'utf-8');
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('❌ 无法写入 PID 文件:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 删除 PID 文件
|
|
50
|
+
*/
|
|
51
|
+
function removePid() {
|
|
52
|
+
try {
|
|
53
|
+
if (fs.existsSync(PID_FILE)) {
|
|
54
|
+
fs.unlinkSync(PID_FILE);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// 忽略错误
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 检查进程是否正在运行
|
|
63
|
+
*/
|
|
64
|
+
function isProcessRunning(pid) {
|
|
65
|
+
try {
|
|
66
|
+
// 发送信号 0 来检查进程是否存在(不会实际发送信号)
|
|
67
|
+
process.kill(pid, 0);
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// ESRCH 表示进程不存在
|
|
72
|
+
if (error.code === 'ESRCH') {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
// 其他错误(如权限问题)也认为进程不存在
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 获取服务器启动脚本路径
|
|
81
|
+
*/
|
|
82
|
+
function getServerScriptPath() {
|
|
83
|
+
// 如果是开发环境,使用 tsx 运行源文件
|
|
84
|
+
// 如果是生产环境,使用编译后的 dist/index.js
|
|
85
|
+
const distPath = path.join(__dirname, 'index.js');
|
|
86
|
+
const srcPath = path.join(__dirname, '..', 'src', 'index.ts');
|
|
87
|
+
// 检查编译后的文件是否存在
|
|
88
|
+
if (fs.existsSync(distPath)) {
|
|
89
|
+
return distPath;
|
|
90
|
+
}
|
|
91
|
+
// 否则使用源文件(开发环境)
|
|
92
|
+
return srcPath;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 启动守护进程
|
|
96
|
+
*/
|
|
97
|
+
export async function startDaemon() {
|
|
98
|
+
// 检查是否已经运行
|
|
99
|
+
const existingPid = readPid();
|
|
100
|
+
if (existingPid !== null && isProcessRunning(existingPid)) {
|
|
101
|
+
console.log(`⚠️ 服务已在运行中 (PID: ${existingPid})`);
|
|
102
|
+
console.log(` 使用 "flex-mcp stop" 停止服务`);
|
|
103
|
+
console.log(` 使用 "flex-mcp status" 查看状态`);
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
// 清理旧的 PID 文件(如果存在但进程已停止)
|
|
107
|
+
if (existingPid !== null) {
|
|
108
|
+
removePid();
|
|
109
|
+
}
|
|
110
|
+
console.log('🚀 启动 flex-mcp 守护进程...');
|
|
111
|
+
// 获取服务器脚本路径
|
|
112
|
+
const serverScript = getServerScriptPath();
|
|
113
|
+
const isDev = serverScript.endsWith('.ts');
|
|
114
|
+
// 准备启动命令
|
|
115
|
+
let command;
|
|
116
|
+
let args;
|
|
117
|
+
if (isDev) {
|
|
118
|
+
// 开发环境:使用 tsx
|
|
119
|
+
command = 'npx';
|
|
120
|
+
args = ['tsx', serverScript];
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// 生产环境:使用 node
|
|
124
|
+
command = 'node';
|
|
125
|
+
args = [serverScript];
|
|
126
|
+
}
|
|
127
|
+
// 创建日志文件流
|
|
128
|
+
const logStream = fs.createWriteStream(LOG_FILE, { flags: 'a' });
|
|
129
|
+
const logDate = new Date().toISOString();
|
|
130
|
+
logStream.write(`\n=== flex-mcp started at ${logDate} ===\n`);
|
|
131
|
+
// 启动子进程
|
|
132
|
+
const child = spawn(command, args, {
|
|
133
|
+
detached: true,
|
|
134
|
+
stdio: ['ignore', logStream, logStream],
|
|
135
|
+
env: {
|
|
136
|
+
...process.env,
|
|
137
|
+
// 标记为守护进程模式,避免无限递归
|
|
138
|
+
DAEMON_MODE: 'true',
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
// 监听错误
|
|
142
|
+
child.on('error', (error) => {
|
|
143
|
+
console.error('❌ 启动失败:', error);
|
|
144
|
+
logStream.end();
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|
|
147
|
+
// 等待一下确保进程启动成功
|
|
148
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
149
|
+
// 检查进程是否还在运行
|
|
150
|
+
if (child.pid && isProcessRunning(child.pid)) {
|
|
151
|
+
// 写入 PID 文件
|
|
152
|
+
writePid(child.pid);
|
|
153
|
+
// 解除父子进程关系,让子进程成为独立的守护进程
|
|
154
|
+
child.unref();
|
|
155
|
+
console.log(`✅ 守护进程已启动 (PID: ${child.pid})`);
|
|
156
|
+
console.log(`📝 日志文件: ${LOG_FILE}`);
|
|
157
|
+
console.log(`\n💡 管理命令:`);
|
|
158
|
+
console.log(` flex-mcp stop # 停止服务`);
|
|
159
|
+
console.log(` flex-mcp restart # 重启服务`);
|
|
160
|
+
console.log(` flex-mcp status # 查看状态`);
|
|
161
|
+
console.log(` tail -f ${LOG_FILE} # 查看日志`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.error('❌ 进程启动失败,请查看日志:', LOG_FILE);
|
|
165
|
+
logStream.end();
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* 停止守护进程
|
|
171
|
+
*/
|
|
172
|
+
export async function stopDaemon() {
|
|
173
|
+
const pid = readPid();
|
|
174
|
+
if (pid === null) {
|
|
175
|
+
console.log('ℹ️ 服务未运行');
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
if (!isProcessRunning(pid)) {
|
|
179
|
+
console.log('ℹ️ 服务未运行(PID 文件存在但进程已停止)');
|
|
180
|
+
removePid();
|
|
181
|
+
process.exit(0);
|
|
182
|
+
}
|
|
183
|
+
console.log(`🛑 正在停止服务 (PID: ${pid})...`);
|
|
184
|
+
try {
|
|
185
|
+
// 发送 SIGTERM 信号(优雅关闭)
|
|
186
|
+
process.kill(pid, 'SIGTERM');
|
|
187
|
+
// 等待进程退出(最多等待 5 秒)
|
|
188
|
+
let waited = 0;
|
|
189
|
+
const maxWait = 5000;
|
|
190
|
+
const interval = 100;
|
|
191
|
+
while (waited < maxWait) {
|
|
192
|
+
if (!isProcessRunning(pid)) {
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
196
|
+
waited += interval;
|
|
197
|
+
}
|
|
198
|
+
// 如果还在运行,强制杀死
|
|
199
|
+
if (isProcessRunning(pid)) {
|
|
200
|
+
console.log('⚠️ 进程未响应,强制终止...');
|
|
201
|
+
process.kill(pid, 'SIGKILL');
|
|
202
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
203
|
+
}
|
|
204
|
+
// 删除 PID 文件
|
|
205
|
+
removePid();
|
|
206
|
+
console.log('✅ 服务已停止');
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error.code === 'ESRCH') {
|
|
210
|
+
// 进程不存在
|
|
211
|
+
console.log('ℹ️ 进程已停止');
|
|
212
|
+
removePid();
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.error('❌ 停止服务失败:', error.message);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* 重启守护进程
|
|
222
|
+
*/
|
|
223
|
+
export async function restartDaemon() {
|
|
224
|
+
console.log('🔄 重启服务...\n');
|
|
225
|
+
await stopDaemon();
|
|
226
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
227
|
+
await startDaemon();
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 查看守护进程状态
|
|
231
|
+
*/
|
|
232
|
+
export async function statusDaemon() {
|
|
233
|
+
const pid = readPid();
|
|
234
|
+
if (pid === null) {
|
|
235
|
+
console.log('ℹ️ 状态: 未运行');
|
|
236
|
+
console.log(` 使用 "flex-mcp start" 启动服务`);
|
|
237
|
+
process.exit(0);
|
|
238
|
+
}
|
|
239
|
+
const isRunning = isProcessRunning(pid);
|
|
240
|
+
if (isRunning) {
|
|
241
|
+
console.log(`✅ 状态: 运行中`);
|
|
242
|
+
console.log(` PID: ${pid}`);
|
|
243
|
+
console.log(` PID 文件: ${PID_FILE}`);
|
|
244
|
+
console.log(` 日志文件: ${LOG_FILE}`);
|
|
245
|
+
console.log(`\n💡 管理命令:`);
|
|
246
|
+
console.log(` flex-mcp stop # 停止服务`);
|
|
247
|
+
console.log(` flex-mcp restart # 重启服务`);
|
|
248
|
+
console.log(` tail -f ${LOG_FILE} # 查看日志`);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
console.log(`⚠️ 状态: 已停止(PID 文件存在但进程不存在)`);
|
|
252
|
+
console.log(` PID 文件: ${PID_FILE}`);
|
|
253
|
+
console.log(`\n💡 清理 PID 文件:`);
|
|
254
|
+
console.log(` rm ${PID_FILE}`);
|
|
255
|
+
console.log(`\n💡 启动服务:`);
|
|
256
|
+
console.log(` flex-mcp start`);
|
|
257
|
+
// 清理无效的 PID 文件
|
|
258
|
+
removePid();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -122,12 +122,13 @@ else {
|
|
|
122
122
|
// 启动服务器
|
|
123
123
|
const port = parseInt(process.env.PORT || '3000');
|
|
124
124
|
const host = process.env.HOST || 'localhost';
|
|
125
|
+
let server = null;
|
|
125
126
|
async function start() {
|
|
126
127
|
// 初始化数据库
|
|
127
128
|
await initDatabase();
|
|
128
129
|
// 启动服务器
|
|
129
|
-
serve({
|
|
130
|
-
fetch: app.fetch,
|
|
130
|
+
server = serve({
|
|
131
|
+
fetch: app.fetch, // 类型兼容性修复
|
|
131
132
|
port,
|
|
132
133
|
hostname: host,
|
|
133
134
|
});
|
|
@@ -146,6 +147,38 @@ async function start() {
|
|
|
146
147
|
// 上报服务器启动统计(延迟执行,不阻塞启动)
|
|
147
148
|
reportStartup();
|
|
148
149
|
}
|
|
150
|
+
// 优雅关闭处理
|
|
151
|
+
async function gracefulShutdown(signal) {
|
|
152
|
+
console.log(`\n收到 ${signal} 信号,正在优雅关闭...`);
|
|
153
|
+
if (server) {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
// @hono/node-server 的 serve 返回的是 http.Server
|
|
156
|
+
const httpServer = server;
|
|
157
|
+
httpServer.close(() => {
|
|
158
|
+
console.log('✅ 服务器已关闭');
|
|
159
|
+
resolve();
|
|
160
|
+
});
|
|
161
|
+
// 10 秒后强制退出
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
console.log('⚠️ 强制退出');
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}, 10000);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
process.exit(0);
|
|
169
|
+
}
|
|
170
|
+
// 注册信号处理器
|
|
171
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
172
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
173
|
+
// 处理未捕获的异常
|
|
174
|
+
process.on('uncaughtException', (error) => {
|
|
175
|
+
console.error('❌ 未捕获的异常:', error);
|
|
176
|
+
gracefulShutdown('uncaughtException').then(() => process.exit(1));
|
|
177
|
+
});
|
|
178
|
+
process.on('unhandledRejection', (reason, _) => {
|
|
179
|
+
console.error('❌ 未处理的 Promise 拒绝:', reason);
|
|
180
|
+
gracefulShutdown('unhandledRejection').then(() => process.exit(1));
|
|
181
|
+
});
|
|
149
182
|
start().catch((error) => {
|
|
150
183
|
console.error('Failed to start server:', error);
|
|
151
184
|
process.exit(1);
|