@becrafter/prompt-manager 0.0.16 → 0.0.18
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/README.md +66 -80
- package/app/desktop/main.js +321 -31
- package/app/desktop/package-lock.json +784 -79
- package/app/desktop/package.json +11 -3
- package/package.json +2 -1
- package/packages/admin-ui/admin.html +1 -1
- package/packages/server/api/admin.routes.js +450 -0
- package/packages/server/api/open.routes.js +89 -0
- package/packages/server/app.js +163 -0
- package/packages/server/{mcp.js → mcp/mcp.handler.js} +11 -79
- package/packages/server/mcp/mcp.server.js +82 -0
- package/packages/server/middlewares/auth.middleware.js +34 -0
- package/packages/server/server.js +42 -908
- package/packages/server/{manager.js → services/manager.js} +13 -5
- package/packages/server/{config.js → utils/config.js} +27 -27
- package/packages/server/utils/util.js +356 -0
- package/packages/server/mcpManager.js +0 -205
- /package/packages/server/{logger.js → utils/logger.js} +0 -0
package/app/desktop/main.js
CHANGED
|
@@ -7,6 +7,59 @@ const { pathToFileURL } = require('url');
|
|
|
7
7
|
const tar = require('tar');
|
|
8
8
|
const { spawn } = require('child_process');
|
|
9
9
|
|
|
10
|
+
// 设置日志文件
|
|
11
|
+
const logFilePath = path.join(app.getPath('userData'), 'prompt-manager-desktop.log');
|
|
12
|
+
let logStream;
|
|
13
|
+
|
|
14
|
+
// 初始化日志流
|
|
15
|
+
function initLogStream() {
|
|
16
|
+
try {
|
|
17
|
+
// 确保日志目录存在
|
|
18
|
+
const logDir = path.dirname(logFilePath);
|
|
19
|
+
if (!fs.existsSync(logDir)) {
|
|
20
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// 创建或追加到日志文件
|
|
24
|
+
logStream = fs.createWriteStream(logFilePath, { flags: 'a' });
|
|
25
|
+
console.log = function(...args) {
|
|
26
|
+
const message = `[${new Date().toISOString()}] [INFO] ${args.join(' ')}\n`;
|
|
27
|
+
process.stdout.write(message);
|
|
28
|
+
if (logStream) {
|
|
29
|
+
logStream.write(message);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
console.error = function(...args) {
|
|
34
|
+
const message = `[${new Date().toISOString()}] [ERROR] ${args.join(' ')}\n`;
|
|
35
|
+
process.stderr.write(message);
|
|
36
|
+
if (logStream) {
|
|
37
|
+
logStream.write(message);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
console.warn = function(...args) {
|
|
42
|
+
const message = `[${new Date().toISOString()}] [WARN] ${args.join(' ')}\n`;
|
|
43
|
+
process.stdout.write(message);
|
|
44
|
+
if (logStream) {
|
|
45
|
+
logStream.write(message);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
console.debug = function(...args) {
|
|
50
|
+
const message = `[${new Date().toISOString()}] [DEBUG] ${args.join(' ')}\n`;
|
|
51
|
+
process.stdout.write(message);
|
|
52
|
+
if (logStream) {
|
|
53
|
+
logStream.write(message);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
console.log(`Logging initialized. Log file: ${logFilePath}`);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error('Failed to initialize logging:', error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
10
63
|
let tray = null;
|
|
11
64
|
let adminWindow = null;
|
|
12
65
|
let serviceState = 'stopped';
|
|
@@ -16,6 +69,7 @@ let serverModuleVersion = 0;
|
|
|
16
69
|
let serverModuleLoading = null;
|
|
17
70
|
let isQuitting = false;
|
|
18
71
|
let runtimeServerRoot = null;
|
|
72
|
+
let startFailureCount = 0;
|
|
19
73
|
|
|
20
74
|
const desktopPackageJson = JSON.parse(
|
|
21
75
|
fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')
|
|
@@ -27,55 +81,153 @@ function resolveBaseServerRoot() {
|
|
|
27
81
|
|
|
28
82
|
async function ensureRuntimeServerRoot() {
|
|
29
83
|
if (runtimeServerRoot) {
|
|
84
|
+
console.log('Using cached runtimeServerRoot:', runtimeServerRoot);
|
|
30
85
|
return runtimeServerRoot;
|
|
31
86
|
}
|
|
32
87
|
|
|
33
88
|
if (!app.isPackaged) {
|
|
89
|
+
console.log('App is not packaged, using development server root');
|
|
34
90
|
runtimeServerRoot = resolveBaseServerRoot();
|
|
91
|
+
console.log('Development server root:', runtimeServerRoot);
|
|
35
92
|
return runtimeServerRoot;
|
|
36
93
|
}
|
|
37
94
|
|
|
95
|
+
console.log('App is packaged, setting up runtime server root');
|
|
96
|
+
console.log('process.resourcesPath:', process.resourcesPath);
|
|
97
|
+
console.log('app.getPath("userData"):', app.getPath('userData'));
|
|
98
|
+
|
|
38
99
|
const packagedRoot = path.join(process.resourcesPath, 'prompt-manager');
|
|
39
100
|
const runtimeRoot = path.join(app.getPath('userData'), 'prompt-manager');
|
|
101
|
+
|
|
102
|
+
console.log('packagedRoot:', packagedRoot);
|
|
103
|
+
console.log('runtimeRoot:', runtimeRoot);
|
|
40
104
|
|
|
41
105
|
try {
|
|
42
|
-
|
|
106
|
+
// 检查打包的资源目录是否存在
|
|
107
|
+
try {
|
|
108
|
+
await fs.promises.access(packagedRoot, fs.constants.F_OK);
|
|
109
|
+
console.log('Packaged root exists');
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error('Packaged root does not exist:', packagedRoot);
|
|
112
|
+
throw new Error(`Packaged root not found: ${packagedRoot}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 检查运行时目录是否存在
|
|
116
|
+
let needsInstall = false;
|
|
117
|
+
try {
|
|
118
|
+
await fs.promises.access(runtimeRoot, fs.constants.F_OK);
|
|
119
|
+
console.log('Runtime root already exists');
|
|
120
|
+
|
|
121
|
+
// 检查是否需要安装依赖
|
|
122
|
+
try {
|
|
123
|
+
await fs.promises.access(path.join(runtimeRoot, 'node_modules'), fs.constants.F_OK);
|
|
124
|
+
console.log('node_modules already exists in runtime root');
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.log('node_modules not found in runtime root, will install dependencies');
|
|
127
|
+
needsInstall = true;
|
|
128
|
+
}
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.log('Runtime root does not exist, creating and copying files');
|
|
131
|
+
await fs.promises.mkdir(runtimeRoot, { recursive: true });
|
|
132
|
+
console.log('Created runtime root directory');
|
|
133
|
+
|
|
134
|
+
// 复制文件并显示进度
|
|
135
|
+
console.log('Copying files from packaged root to runtime root...');
|
|
136
|
+
await fs.promises.cp(packagedRoot, runtimeRoot, { recursive: true });
|
|
137
|
+
console.log('File copy completed');
|
|
138
|
+
needsInstall = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 如果需要安装依赖
|
|
142
|
+
if (needsInstall) {
|
|
143
|
+
console.log('Installing dependencies in runtime root');
|
|
144
|
+
try {
|
|
145
|
+
await installServerDependencies(runtimeRoot);
|
|
146
|
+
console.log('Dependencies installed successfully');
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('Failed to install dependencies:', error);
|
|
149
|
+
dialog.showErrorBox('依赖安装失败', `无法安装服务器依赖: ${error.message}\n\n请查看日志文件: ${logFilePath}`);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
43
153
|
} catch (error) {
|
|
44
|
-
|
|
45
|
-
|
|
154
|
+
console.error('Error in ensureRuntimeServerRoot:', error);
|
|
155
|
+
dialog.showErrorBox('服务器初始化失败', `无法设置服务器运行环境: ${error.message}\n\n请查看日志文件: ${logFilePath}`);
|
|
156
|
+
throw error;
|
|
46
157
|
}
|
|
47
158
|
|
|
48
159
|
runtimeServerRoot = runtimeRoot;
|
|
160
|
+
console.log('Final runtimeServerRoot:', runtimeServerRoot);
|
|
49
161
|
return runtimeServerRoot;
|
|
50
162
|
}
|
|
51
163
|
|
|
52
164
|
async function loadServerModule(options = {}) {
|
|
53
|
-
|
|
165
|
+
console.log('loadServerModule called with options:', options);
|
|
166
|
+
console.log('Current serviceState:', serviceState);
|
|
167
|
+
console.log('serverModule exists:', !!serverModule);
|
|
168
|
+
console.log('serverModuleLoading exists:', !!serverModuleLoading);
|
|
169
|
+
|
|
170
|
+
// 如果强制重新加载或服务状态异常,则清理缓存
|
|
171
|
+
if (options.forceReload || serviceState === 'error') {
|
|
172
|
+
console.log('Forcing module reload, clearing cache');
|
|
54
173
|
serverModule = null;
|
|
55
174
|
serverModuleVersion += 1;
|
|
175
|
+
serverModuleLoading = null;
|
|
56
176
|
}
|
|
57
177
|
|
|
58
178
|
if (serverModule) {
|
|
179
|
+
console.log('Returning cached server module');
|
|
59
180
|
return serverModule;
|
|
60
181
|
}
|
|
61
182
|
|
|
62
183
|
if (serverModuleLoading) {
|
|
184
|
+
console.log('Module loading in progress, returning promise');
|
|
63
185
|
return serverModuleLoading;
|
|
64
186
|
}
|
|
65
187
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
})
|
|
78
|
-
|
|
188
|
+
try {
|
|
189
|
+
const serverRoot = await ensureRuntimeServerRoot();
|
|
190
|
+
console.log('Server root resolved to:', serverRoot);
|
|
191
|
+
|
|
192
|
+
const serverEntry = path.join(serverRoot, 'packages', 'server', 'server.js');
|
|
193
|
+
console.log('Server entry file:', serverEntry);
|
|
194
|
+
|
|
195
|
+
// 检查入口文件是否存在
|
|
196
|
+
try {
|
|
197
|
+
await fs.promises.access(serverEntry, fs.constants.F_OK);
|
|
198
|
+
console.log('Server entry file exists');
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error('Server entry file does not exist:', serverEntry);
|
|
201
|
+
throw new Error(`Server entry file not found: ${serverEntry}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const entryUrl = pathToFileURL(serverEntry);
|
|
205
|
+
entryUrl.searchParams.set('v', String(serverModuleVersion));
|
|
206
|
+
console.log('Entry URL:', entryUrl.href);
|
|
207
|
+
|
|
208
|
+
serverModuleLoading = import(entryUrl.href)
|
|
209
|
+
.then((mod) => {
|
|
210
|
+
console.log('Module loaded successfully');
|
|
211
|
+
serverModule = mod;
|
|
212
|
+
return mod;
|
|
213
|
+
})
|
|
214
|
+
.catch((error) => {
|
|
215
|
+
console.error('Module loading failed:', error);
|
|
216
|
+
// 清理加载状态,以便下次重试
|
|
217
|
+
serverModuleLoading = null;
|
|
218
|
+
serverModule = null;
|
|
219
|
+
throw new Error(`Failed to load server module: ${error.message}`);
|
|
220
|
+
})
|
|
221
|
+
.finally(() => {
|
|
222
|
+
serverModuleLoading = null;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return serverModuleLoading;
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error('Error in loadServerModule:', error);
|
|
228
|
+
dialog.showErrorBox('模块加载失败', error.message);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
79
231
|
}
|
|
80
232
|
|
|
81
233
|
function getServerStatusLabel() {
|
|
@@ -94,29 +246,57 @@ function getServerStatusLabel() {
|
|
|
94
246
|
}
|
|
95
247
|
|
|
96
248
|
async function startService() {
|
|
249
|
+
console.log('startService called');
|
|
250
|
+
// 如果正在运行或正在启动,直接返回
|
|
97
251
|
if (serviceState === 'running' || serviceState === 'starting') {
|
|
252
|
+
console.log('Service is already running or starting, returning');
|
|
98
253
|
return;
|
|
99
254
|
}
|
|
100
255
|
|
|
101
256
|
serviceState = 'starting';
|
|
257
|
+
console.log('Service state set to starting');
|
|
102
258
|
refreshTrayMenu();
|
|
103
259
|
|
|
104
260
|
try {
|
|
105
|
-
|
|
261
|
+
console.log('Loading server module with force reload');
|
|
262
|
+
// 强制重新加载模块以确保获取最新状态
|
|
263
|
+
const module = await loadServerModule({ forceReload: true });
|
|
264
|
+
console.log('Server module loaded, starting server');
|
|
265
|
+
|
|
266
|
+
if (!module || typeof module.startServer !== 'function') {
|
|
267
|
+
throw new Error('Invalid server module or missing startServer function');
|
|
268
|
+
}
|
|
269
|
+
|
|
106
270
|
await module.startServer();
|
|
271
|
+
console.log('Server started successfully');
|
|
107
272
|
currentServerState = module.getServerState();
|
|
108
273
|
serviceState = 'running';
|
|
274
|
+
startFailureCount = 0; // 重置失败计数
|
|
275
|
+
console.log('Service state set to running');
|
|
109
276
|
} catch (error) {
|
|
110
277
|
serviceState = 'error';
|
|
111
278
|
currentServerState = null;
|
|
112
|
-
|
|
279
|
+
startFailureCount++;
|
|
280
|
+
|
|
281
|
+
console.error('服务启动失败:', error);
|
|
282
|
+
console.error('Error stack:', error.stack);
|
|
283
|
+
|
|
284
|
+
// 如果连续失败3次,提示用户重启应用
|
|
285
|
+
if (startFailureCount >= 3) {
|
|
286
|
+
console.log('Too many start failures, prompting for restart');
|
|
287
|
+
await promptForRestart();
|
|
288
|
+
} else {
|
|
289
|
+
dialog.showErrorBox('服务启动失败', `${error?.message || String(error)}\n\n请查看控制台日志获取更多信息。`);
|
|
290
|
+
}
|
|
113
291
|
} finally {
|
|
292
|
+
console.log('Refreshing tray menu');
|
|
114
293
|
refreshTrayMenu();
|
|
115
294
|
}
|
|
116
295
|
}
|
|
117
296
|
|
|
118
297
|
async function stopService() {
|
|
119
|
-
|
|
298
|
+
// 如果服务未运行或正在停止,直接返回
|
|
299
|
+
if (serviceState !== 'running' && serviceState !== 'error') {
|
|
120
300
|
return;
|
|
121
301
|
}
|
|
122
302
|
|
|
@@ -125,10 +305,16 @@ async function stopService() {
|
|
|
125
305
|
|
|
126
306
|
try {
|
|
127
307
|
const module = await loadServerModule();
|
|
128
|
-
|
|
308
|
+
if (module && typeof module.stopServer === 'function') {
|
|
309
|
+
await module.stopServer();
|
|
310
|
+
}
|
|
129
311
|
currentServerState = null;
|
|
130
312
|
serviceState = 'stopped';
|
|
313
|
+
|
|
314
|
+
// 清理MCP会话和传输
|
|
315
|
+
console.log('Clearing MCP sessions and transports');
|
|
131
316
|
} catch (error) {
|
|
317
|
+
console.error('停止服务失败:', error);
|
|
132
318
|
dialog.showErrorBox('停止服务失败', error?.message || String(error));
|
|
133
319
|
serviceState = 'error';
|
|
134
320
|
} finally {
|
|
@@ -228,6 +414,16 @@ function refreshTrayMenu() {
|
|
|
228
414
|
click: () => openAdminWindow(adminUrl)
|
|
229
415
|
},
|
|
230
416
|
{ type: 'separator' },
|
|
417
|
+
{
|
|
418
|
+
label: '查看日志文件',
|
|
419
|
+
click: () => {
|
|
420
|
+
try {
|
|
421
|
+
shell.openPath(logFilePath);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
dialog.showErrorBox('打开日志文件失败', error.message);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
},
|
|
231
427
|
{
|
|
232
428
|
label: '检查更新',
|
|
233
429
|
click: () => checkForUpdates()
|
|
@@ -242,6 +438,9 @@ function refreshTrayMenu() {
|
|
|
242
438
|
click: async () => {
|
|
243
439
|
isQuitting = true;
|
|
244
440
|
await stopService();
|
|
441
|
+
if (logStream) {
|
|
442
|
+
logStream.end();
|
|
443
|
+
}
|
|
245
444
|
app.quit();
|
|
246
445
|
}
|
|
247
446
|
}
|
|
@@ -358,43 +557,63 @@ async function checkForUpdates() {
|
|
|
358
557
|
}
|
|
359
558
|
|
|
360
559
|
async function performInPlaceUpgrade(version) {
|
|
560
|
+
console.log('Performing in-place upgrade to version:', version);
|
|
361
561
|
const tarballUrl = `https://registry.npmjs.org/@becrafter/prompt-manager/-/@becrafter/prompt-manager-${version}.tgz`;
|
|
362
562
|
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'prompt-manager-upgrade-'));
|
|
363
563
|
const tarballPath = path.join(tmpDir, `${version}.tgz`);
|
|
564
|
+
|
|
565
|
+
console.log('Temporary directory:', tmpDir);
|
|
364
566
|
|
|
365
567
|
try {
|
|
568
|
+
console.log('Downloading tarball from:', tarballUrl);
|
|
366
569
|
const response = await fetch(tarballUrl);
|
|
367
570
|
if (!response.ok) {
|
|
368
|
-
throw new Error(
|
|
571
|
+
throw new Error(`Failed to download tarball: ${response.status} ${response.statusText}`);
|
|
369
572
|
}
|
|
370
573
|
|
|
371
574
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
372
575
|
await fs.promises.writeFile(tarballPath, buffer);
|
|
576
|
+
console.log('Tarball downloaded to:', tarballPath);
|
|
373
577
|
|
|
374
578
|
await tar.x({ file: tarballPath, cwd: tmpDir });
|
|
375
579
|
const extractedPath = path.join(tmpDir, 'package');
|
|
580
|
+
console.log('Tarball extracted to:', extractedPath);
|
|
376
581
|
|
|
377
582
|
const serverRoot = await ensureRuntimeServerRoot();
|
|
378
583
|
const examplesDir = path.join(serverRoot, 'examples', 'prompts');
|
|
379
584
|
const examplesBackup = path.join(tmpDir, 'examples-prompts');
|
|
380
585
|
|
|
381
586
|
if (await pathExists(examplesDir)) {
|
|
587
|
+
console.log('Backing up examples directory');
|
|
382
588
|
await fs.promises.cp(examplesDir, examplesBackup, { recursive: true });
|
|
383
589
|
}
|
|
384
590
|
|
|
591
|
+
console.log('Removing old server root');
|
|
385
592
|
await fs.promises.rm(serverRoot, { recursive: true, force: true });
|
|
386
593
|
await fs.promises.mkdir(serverRoot, { recursive: true });
|
|
594
|
+
|
|
595
|
+
console.log('Copying extracted package to server root');
|
|
387
596
|
await fs.promises.cp(extractedPath, serverRoot, { recursive: true });
|
|
388
597
|
|
|
389
598
|
if (await pathExists(examplesBackup)) {
|
|
599
|
+
console.log('Restoring examples directory');
|
|
390
600
|
const targetExamples = path.join(serverRoot, 'examples', 'prompts');
|
|
391
601
|
await fs.promises.mkdir(path.dirname(targetExamples), { recursive: true });
|
|
392
602
|
await fs.promises.cp(examplesBackup, targetExamples, { recursive: true });
|
|
393
603
|
}
|
|
394
604
|
|
|
605
|
+
console.log('Installing server dependencies');
|
|
395
606
|
await installServerDependencies(serverRoot);
|
|
607
|
+
|
|
608
|
+
console.log('Reloading server module');
|
|
396
609
|
await loadServerModule({ forceReload: true });
|
|
610
|
+
|
|
611
|
+
console.log('Upgrade completed successfully');
|
|
612
|
+
} catch (error) {
|
|
613
|
+
console.error('Upgrade failed:', error);
|
|
614
|
+
throw error;
|
|
397
615
|
} finally {
|
|
616
|
+
console.log('Cleaning up temporary directory');
|
|
398
617
|
await fs.promises.rm(tmpDir, { recursive: true, force: true });
|
|
399
618
|
}
|
|
400
619
|
}
|
|
@@ -409,8 +628,36 @@ async function pathExists(targetPath) {
|
|
|
409
628
|
}
|
|
410
629
|
|
|
411
630
|
async function installServerDependencies(targetDir) {
|
|
631
|
+
console.log('Installing server dependencies in:', targetDir);
|
|
632
|
+
|
|
633
|
+
// 检查 targetDir 是否存在 package.json
|
|
634
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
635
|
+
try {
|
|
636
|
+
await fs.promises.access(pkgPath, fs.constants.F_OK);
|
|
637
|
+
console.log('package.json found in target directory');
|
|
638
|
+
} catch (error) {
|
|
639
|
+
console.error('package.json not found in target directory:', pkgPath);
|
|
640
|
+
throw new Error(`package.json not found in ${targetDir}`);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// 检查 @modelcontextprotocol/sdk 是否在 dependencies 中
|
|
644
|
+
try {
|
|
645
|
+
const pkgContent = await fs.promises.readFile(pkgPath, 'utf8');
|
|
646
|
+
const pkg = JSON.parse(pkgContent);
|
|
647
|
+
if (!pkg.dependencies || !pkg.dependencies['@modelcontextprotocol/sdk']) {
|
|
648
|
+
console.warn('@modelcontextprotocol/sdk not found in dependencies, adding it');
|
|
649
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
650
|
+
pkg.dependencies['@modelcontextprotocol/sdk'] = '^1.20.2';
|
|
651
|
+
await fs.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
|
|
652
|
+
}
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error('Error checking/adding @modelcontextprotocol/sdk to package.json:', error);
|
|
655
|
+
}
|
|
656
|
+
|
|
412
657
|
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
413
|
-
const args = ['install', '--omit=dev'];
|
|
658
|
+
const args = ['install', '--omit=dev', '--no-audit', '--no-fund'];
|
|
659
|
+
|
|
660
|
+
console.log('Running npm install with args:', args);
|
|
414
661
|
|
|
415
662
|
await new Promise((resolve, reject) => {
|
|
416
663
|
const child = spawn(npmCommand, args, {
|
|
@@ -418,29 +665,56 @@ async function installServerDependencies(targetDir) {
|
|
|
418
665
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
419
666
|
});
|
|
420
667
|
|
|
668
|
+
let stdout = '';
|
|
421
669
|
let stderr = '';
|
|
670
|
+
|
|
422
671
|
child.stdout.on('data', (data) => {
|
|
423
|
-
|
|
672
|
+
const output = data.toString().trim();
|
|
673
|
+
stdout += output;
|
|
674
|
+
console.log(`[npm stdout] ${output}`);
|
|
424
675
|
});
|
|
676
|
+
|
|
425
677
|
child.stderr.on('data', (data) => {
|
|
426
|
-
|
|
427
|
-
|
|
678
|
+
const output = data.toString().trim();
|
|
679
|
+
stderr += output;
|
|
680
|
+
console.error(`[npm stderr] ${output}`);
|
|
428
681
|
});
|
|
429
682
|
|
|
430
683
|
child.on('error', (error) => {
|
|
431
|
-
|
|
684
|
+
console.error('npm process error:', error);
|
|
685
|
+
reject(new Error(`Failed to start npm process: ${error.message}`));
|
|
432
686
|
});
|
|
433
687
|
|
|
434
688
|
child.on('close', (code) => {
|
|
689
|
+
console.log('npm process exited with code:', code);
|
|
435
690
|
if (code === 0) {
|
|
691
|
+
console.log('npm install completed successfully');
|
|
436
692
|
resolve();
|
|
437
693
|
} else {
|
|
438
|
-
|
|
694
|
+
const errorMsg = `npm install failed with exit code ${code}: ${stderr}`;
|
|
695
|
+
console.error(errorMsg);
|
|
696
|
+
reject(new Error(errorMsg));
|
|
439
697
|
}
|
|
440
698
|
});
|
|
441
699
|
});
|
|
442
700
|
}
|
|
443
701
|
|
|
702
|
+
async function promptForRestart() {
|
|
703
|
+
const { response } = await dialog.showMessageBox({
|
|
704
|
+
type: 'error',
|
|
705
|
+
buttons: ['重启应用', '取消'],
|
|
706
|
+
defaultId: 0,
|
|
707
|
+
cancelId: 1,
|
|
708
|
+
message: '服务启动失败',
|
|
709
|
+
detail: '多次尝试启动服务均失败,建议重启应用以恢复正常状态。'
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
if (response === 0) {
|
|
713
|
+
app.relaunch();
|
|
714
|
+
app.exit(0);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
444
718
|
async function showAboutDialog() {
|
|
445
719
|
const serviceVersion = await getCurrentServiceVersion();
|
|
446
720
|
const lines = [
|
|
@@ -460,19 +734,32 @@ async function showAboutDialog() {
|
|
|
460
734
|
}
|
|
461
735
|
|
|
462
736
|
app.whenReady().then(async () => {
|
|
737
|
+
// 初始化日志
|
|
738
|
+
initLogStream();
|
|
463
739
|
console.log('App is packaged:', app.isPackaged);
|
|
464
740
|
console.log('App data path:', app.getPath('userData'));
|
|
465
741
|
console.log('Resources path:', process.resourcesPath);
|
|
466
742
|
console.log('__dirname:', __dirname);
|
|
743
|
+
console.log('Process platform:', process.platform);
|
|
744
|
+
console.log('Process version:', process.version);
|
|
745
|
+
console.log('Electron version:', process.versions.electron);
|
|
467
746
|
|
|
468
747
|
Menu.setApplicationMenu(null);
|
|
469
748
|
if (process.platform === 'darwin') {
|
|
470
749
|
app.dock.hide();
|
|
471
750
|
}
|
|
472
751
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
752
|
+
try {
|
|
753
|
+
await ensureRuntimeServerRoot();
|
|
754
|
+
console.log('Runtime server root ensured successfully');
|
|
755
|
+
ensureTray();
|
|
756
|
+
console.log('System tray ensured successfully');
|
|
757
|
+
await startService();
|
|
758
|
+
console.log('Service started successfully');
|
|
759
|
+
} catch (error) {
|
|
760
|
+
console.error('Error during app initialization:', error);
|
|
761
|
+
dialog.showErrorBox('应用初始化失败', `启动过程中发生错误: ${error.message}\n\n请查看日志文件: ${logFilePath}`);
|
|
762
|
+
}
|
|
476
763
|
});
|
|
477
764
|
|
|
478
765
|
app.on('window-all-closed', (event) => {
|
|
@@ -486,6 +773,9 @@ app.on('before-quit', async (event) => {
|
|
|
486
773
|
event.preventDefault();
|
|
487
774
|
isQuitting = true;
|
|
488
775
|
await stopService();
|
|
776
|
+
if (logStream) {
|
|
777
|
+
logStream.end();
|
|
778
|
+
}
|
|
489
779
|
app.quit();
|
|
490
780
|
});
|
|
491
781
|
|