@becrafter/prompt-manager 0.0.16 → 0.0.19

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 (60) hide show
  1. package/IFLOW.md +175 -0
  2. package/README.md +66 -80
  3. package/app/desktop/assets/icons/icon.icns +0 -0
  4. package/app/desktop/assets/icons/icon.ico +0 -0
  5. package/app/desktop/assets/icons/icon_1024x1024.png +0 -0
  6. package/app/desktop/assets/icons/icon_128x128.png +0 -0
  7. package/app/desktop/assets/icons/icon_16x16.png +0 -0
  8. package/app/desktop/assets/icons/icon_24x24.png +0 -0
  9. package/app/desktop/assets/icons/icon_256x256.png +0 -0
  10. package/app/desktop/assets/icons/icon_32x32.png +0 -0
  11. package/app/desktop/assets/icons/icon_48x48.png +0 -0
  12. package/app/desktop/assets/icons/icon_512x512.png +0 -0
  13. package/app/desktop/assets/icons/icon_64x64.png +0 -0
  14. package/app/desktop/assets/icons/icon_96x96.png +0 -0
  15. package/app/desktop/assets/templates/about.html +147 -0
  16. package/app/desktop/main.js +178 -460
  17. package/app/desktop/package-lock.json +1150 -412
  18. package/app/desktop/package.json +54 -11
  19. package/app/desktop/preload.js +7 -0
  20. package/app/desktop/src/core/error-handler.js +108 -0
  21. package/app/desktop/src/core/event-emitter.js +84 -0
  22. package/app/desktop/src/core/logger.js +108 -0
  23. package/app/desktop/src/core/state-manager.js +125 -0
  24. package/app/desktop/src/services/module-loader.js +193 -0
  25. package/app/desktop/src/services/runtime-manager.js +152 -0
  26. package/app/desktop/src/services/service-manager.js +169 -0
  27. package/app/desktop/src/services/update-manager.js +268 -0
  28. package/app/desktop/src/ui/about-dialog-manager.js +208 -0
  29. package/app/desktop/src/ui/tray-manager.js +202 -0
  30. package/app/desktop/src/utils/icon-manager.js +141 -0
  31. package/app/desktop/src/utils/path-utils.js +58 -0
  32. package/app/desktop/src/utils/resource-paths.js +72 -0
  33. package/app/desktop/src/utils/template-renderer.js +284 -0
  34. package/app/desktop/src/utils/version-utils.js +59 -0
  35. package/examples/prompts/engineer/engineer-professional.yaml +92 -0
  36. package/examples/prompts/engineer/laowang-engineer.yaml +132 -0
  37. package/examples/prompts/engineer/nekomata-engineer.yaml +123 -0
  38. package/examples/prompts/engineer/ojousama-engineer.yaml +124 -0
  39. package/examples/prompts/workflow/sixstep-workflow.yaml +192 -0
  40. package/package.json +10 -3
  41. package/packages/admin-ui/admin.html +2 -2
  42. package/packages/resources/tools/filesystem/filesystem.tool.js +184 -0
  43. package/packages/resources/tools/index.js +16 -0
  44. package/packages/server/api/admin.routes.js +450 -0
  45. package/packages/server/api/open.routes.js +89 -0
  46. package/packages/server/app.js +163 -0
  47. package/packages/server/mcp/mcp.handler.js +265 -0
  48. package/packages/server/mcp/mcp.server.js +181 -0
  49. package/packages/server/mcp/toolx.handler.js +131 -0
  50. package/packages/server/middlewares/auth.middleware.js +34 -0
  51. package/packages/server/server.js +42 -908
  52. package/packages/server/{manager.js → services/manager.js} +13 -5
  53. package/packages/server/{config.js → utils/config.js} +27 -27
  54. package/packages/server/utils/util.js +356 -0
  55. package/scripts/build-icons.js +105 -0
  56. package/scripts/icns-builder/package.json +12 -0
  57. package/packages/server/mcp.js +0 -234
  58. package/packages/server/mcpManager.js +0 -205
  59. /package/app/desktop/assets/{icon.png → icons/icon.png} +0 -0
  60. /package/packages/server/{logger.js → utils/logger.js} +0 -0
@@ -1,496 +1,214 @@
1
- const electron = require('electron');
2
- const { app, BrowserWindow, Tray, Menu, clipboard, dialog, nativeImage, shell } = electron;
3
- const path = require('path');
4
- const fs = require('fs');
5
- const os = require('os');
6
- const { pathToFileURL } = require('url');
7
- const tar = require('tar');
8
- const { spawn } = require('child_process');
9
-
10
- let tray = null;
11
- let adminWindow = null;
12
- let serviceState = 'stopped';
13
- let currentServerState = null;
14
- let serverModule = null;
15
- let serverModuleVersion = 0;
16
- let serverModuleLoading = null;
17
- let isQuitting = false;
18
- let runtimeServerRoot = null;
19
-
20
- const desktopPackageJson = JSON.parse(
21
- fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')
22
- );
23
-
24
- function resolveBaseServerRoot() {
25
- return path.resolve(__dirname, '..', '..');
26
- }
27
-
28
- async function ensureRuntimeServerRoot() {
29
- if (runtimeServerRoot) {
30
- return runtimeServerRoot;
31
- }
32
-
33
- if (!app.isPackaged) {
34
- runtimeServerRoot = resolveBaseServerRoot();
35
- return runtimeServerRoot;
36
- }
37
-
38
- const packagedRoot = path.join(process.resourcesPath, 'prompt-manager');
39
- const runtimeRoot = path.join(app.getPath('userData'), 'prompt-manager');
40
-
41
- try {
42
- await fs.promises.access(runtimeRoot, fs.constants.F_OK);
43
- } catch (error) {
44
- await fs.promises.mkdir(runtimeRoot, { recursive: true });
45
- await fs.promises.cp(packagedRoot, runtimeRoot, { recursive: true });
46
- }
47
-
48
- runtimeServerRoot = runtimeRoot;
49
- return runtimeServerRoot;
50
- }
51
-
52
- async function loadServerModule(options = {}) {
53
- if (options.forceReload) {
54
- serverModule = null;
55
- serverModuleVersion += 1;
56
- }
1
+ /**
2
+ * 应用主入口
3
+ * 重构后的主程序,遵循SRP、KISS、DRY、YAGNI原则
4
+ */
57
5
 
58
- if (serverModule) {
59
- return serverModule;
60
- }
6
+ const { app, BrowserWindow, ipcMain } = require('electron');
7
+ const path = require('path');
61
8
 
62
- if (serverModuleLoading) {
63
- return serverModuleLoading;
9
+ // 导入管理器模块
10
+ const AppState = require('./src/core/state-manager');
11
+ const Logger = require('./src/core/logger');
12
+ const ErrorHandler = require('./src/core/error-handler');
13
+ const RuntimeManager = require('./src/services/runtime-manager');
14
+ const ModuleLoader = require('./src/services/module-loader');
15
+ const ServiceManager = require('./src/services/service-manager');
16
+ const TrayManager = require('./src/ui/tray-manager');
17
+ const UpdateManager = require('./src/services/update-manager');
18
+ const AboutDialogManager = require('./src/ui/about-dialog-manager');
19
+ const IconManager = require('./src/utils/icon-manager');
20
+
21
+ class PromptManagerApp {
22
+ constructor() {
23
+ this.stateManager = new AppState();
24
+ this.logger = new Logger({ debugEnabled: false });
25
+ this.errorHandler = new ErrorHandler(this.logger);
26
+ this.runtimeManager = new RuntimeManager(this.logger, this.errorHandler);
27
+ this.moduleLoader = new ModuleLoader(this.logger, this.errorHandler);
28
+ this.iconManager = new IconManager();
29
+ this.serviceManager = new ServiceManager(this.logger, this.errorHandler, this.moduleLoader);
30
+ this.updateManager = new UpdateManager(this.logger, this.errorHandler, this.runtimeManager);
31
+ this.aboutDialogManager = new AboutDialogManager(this.logger, this.runtimeManager, this.iconManager);
32
+ this.trayManager = new TrayManager(this.logger, this.errorHandler, this.iconManager);
33
+
34
+ this.isInitialized = false;
35
+ }
36
+
37
+ async initialize() {
38
+ if (this.isInitialized) return;
39
+
40
+ try {
41
+ this.logger.info('Initializing Prompt Manager Desktop Application');
42
+
43
+ // 初始化日志系统
44
+ await this.logger.initialize();
45
+
46
+ // 设置应用菜单
47
+ this.setupApplicationMenu();
48
+
49
+ // 初始化系统托盘
50
+ await this.trayManager.initialize(this.stateManager);
51
+
52
+ // 设置事件监听
53
+ this.setupEventListeners();
54
+
55
+ // 确保运行时环境
56
+ const serverRoot = await this.runtimeManager.ensureRuntimeEnvironment();
57
+ this.stateManager.set('runtimeRoot', serverRoot);
58
+
59
+ // 启动服务
60
+ await this.startService();
61
+
62
+ this.isInitialized = true;
63
+ this.logger.info('Application initialized successfully');
64
+
65
+ } catch (error) {
66
+ this.logger.error('Application initialization failed', error);
67
+ this.errorHandler.handleError('APP_INIT_FAILED', error, {
68
+ logFilePath: this.logger.getLogFilePath()
69
+ });
70
+
71
+ throw error;
72
+ }
64
73
  }
65
74
 
66
- const serverRoot = await ensureRuntimeServerRoot();
67
- const serverEntry = path.join(serverRoot, 'packages', 'server', 'server.js');
68
- const entryUrl = pathToFileURL(serverEntry);
69
- entryUrl.searchParams.set('v', String(serverModuleVersion));
70
- serverModuleLoading = import(entryUrl.href)
71
- .then((mod) => {
72
- serverModule = mod;
73
- return mod;
74
- })
75
- .finally(() => {
76
- serverModuleLoading = null;
75
+ setupApplicationMenu() {
76
+ if (process.platform === 'darwin') {
77
+ app.dock.hide();
78
+ }
79
+
80
+ // 隐藏默认应用菜单
81
+ const { Menu } = require('electron');
82
+ Menu.setApplicationMenu(null);
83
+ }
84
+
85
+ setupEventListeners() {
86
+ // 托盘事件
87
+ this.trayManager.on('service-start-requested', () => this.startService());
88
+ this.trayManager.on('service-stop-requested', () => this.stopService());
89
+ this.trayManager.on('update-check-requested', () => this.checkForUpdates());
90
+ this.trayManager.on('about-dialog-requested', () => this.showAboutDialog());
91
+ this.trayManager.on('quit-requested', () => this.quitApplication());
92
+
93
+ // 服务管理器事件
94
+ this.serviceManager.on('status-update', () => this.trayManager.updateMenu());
95
+ this.serviceManager.on('restart-requested', () => this.restartApplication());
96
+
97
+ // IPC事件
98
+ ipcMain.on('about-window-click', (event, data) => {
99
+ this.aboutDialogManager.handleAboutWindowClick(data);
100
+ });
101
+
102
+ // 应用事件
103
+ app.on('window-all-closed', (event) => {
104
+ event.preventDefault(); // 防止应用退出
105
+ });
106
+
107
+ app.on('before-quit', async (event) => {
108
+ if (this.stateManager.get('isQuitting')) return;
109
+
110
+ event.preventDefault();
111
+ await this.quitApplication();
112
+ });
113
+
114
+ app.on('activate', () => {
115
+ if (!this.trayManager.tray) {
116
+ this.trayManager.initialize(this.stateManager);
117
+ }
77
118
  });
78
- return serverModuleLoading;
79
- }
80
-
81
- function getServerStatusLabel() {
82
- switch (serviceState) {
83
- case 'running':
84
- return '运行中';
85
- case 'starting':
86
- return '启动中';
87
- case 'stopping':
88
- return '停止中';
89
- case 'error':
90
- return '启动失败';
91
- default:
92
- return '已停止';
93
- }
94
- }
95
-
96
- async function startService() {
97
- if (serviceState === 'running' || serviceState === 'starting') {
98
- return;
99
- }
100
-
101
- serviceState = 'starting';
102
- refreshTrayMenu();
103
-
104
- try {
105
- const module = await loadServerModule();
106
- await module.startServer();
107
- currentServerState = module.getServerState();
108
- serviceState = 'running';
109
- } catch (error) {
110
- serviceState = 'error';
111
- currentServerState = null;
112
- dialog.showErrorBox('服务启动失败', error?.message || String(error));
113
- } finally {
114
- refreshTrayMenu();
115
- }
116
- }
117
-
118
- async function stopService() {
119
- if (serviceState !== 'running') {
120
- return;
121
- }
122
-
123
- serviceState = 'stopping';
124
- refreshTrayMenu();
125
-
126
- try {
127
- const module = await loadServerModule();
128
- await module.stopServer();
129
- currentServerState = null;
130
- serviceState = 'stopped';
131
- } catch (error) {
132
- dialog.showErrorBox('停止服务失败', error?.message || String(error));
133
- serviceState = 'error';
134
- } finally {
135
- refreshTrayMenu();
136
- }
137
- }
138
-
139
- function ensureTray() {
140
- if (tray) {
141
- return tray;
142
119
  }
143
120
 
144
- // 尝试多种可能的图标路径
145
- const possiblePaths = [
146
- path.join(__dirname, 'assets', 'icon.png'),
147
- path.join(process.resourcesPath, 'assets', 'icon.png'),
148
- path.join(__dirname, '..', 'assets', 'icon.png')
149
- ];
150
-
151
- let iconPath = null;
152
- let icon = null;
153
-
154
- console.log('App is packaged:', app.isPackaged);
155
- console.log('__dirname:', __dirname);
156
- console.log('process.resourcesPath:', process.resourcesPath);
157
-
158
- for (const possiblePath of possiblePaths) {
159
- console.log('Checking icon path:', possiblePath);
160
- console.log('File exists:', fs.existsSync(possiblePath));
161
- if (fs.existsSync(possiblePath)) {
162
- iconPath = possiblePath;
163
- break;
121
+ async startService() {
122
+ const serverRoot = this.stateManager.get('runtimeRoot');
123
+ if (!serverRoot) {
124
+ this.logger.error('Cannot start service: runtime root not set');
125
+ return false;
164
126
  }
165
- }
166
-
167
- if (!iconPath) {
168
- console.error('Icon file not found in any of the expected locations');
169
- // 创建一个简单的文本托盘作为后备
170
- tray = new Tray(nativeImage.createEmpty());
171
- tray.setToolTip('Prompt Server - Icon Missing');
172
- refreshTrayMenu();
173
- return tray;
174
- }
175
-
176
- console.log('Attempting to load icon from:', iconPath);
177
-
178
- try {
179
- icon = nativeImage.createFromPath(iconPath);
180
- console.log('Icon loaded successfully');
181
- console.log('Icon is empty:', icon.isEmpty());
182
- console.log('Icon size:', icon.getSize());
183
127
 
184
- if (process.platform === 'darwin') {
185
- icon = icon.resize({ width: 18, height: 18 });
186
- icon.setTemplateImage(true);
187
- console.log('Icon resized and set as template image');
188
- }
189
-
190
- tray = new Tray(icon);
191
- tray.setToolTip('Prompt Server');
192
- console.log('Tray created successfully');
193
- refreshTrayMenu();
194
- return tray;
195
- } catch (error) {
196
- console.error('Failed to create tray:', error);
197
- // 创建一个简单的文本托盘作为后备
198
- tray = new Tray(nativeImage.createEmpty());
199
- tray.setToolTip('Prompt Server - Error');
200
- refreshTrayMenu();
201
- return tray;
128
+ return await this.serviceManager.startService(serverRoot, this.stateManager);
202
129
  }
203
- }
204
130
 
205
- function refreshTrayMenu() {
206
- if (!tray) {
207
- return;
131
+ async stopService() {
132
+ return await this.serviceManager.stopService(this.stateManager);
208
133
  }
209
134
 
210
- const address = currentServerState?.address ?? 'http://127.0.0.1:5621';
211
- const adminUrl = currentServerState?.adminPath ? `${address}${currentServerState.adminPath}` : `${address}/admin`;
212
-
213
- const template = [
214
- { label: `状态:${getServerStatusLabel()}`, enabled: false },
215
- { type: 'separator' },
216
- {
217
- label: serviceState === 'running' ? '停止服务' : '启动服务',
218
- click: () => (serviceState === 'running' ? stopService() : startService())
219
- },
220
- {
221
- label: '复制服务地址',
222
- enabled: serviceState === 'running',
223
- click: () => clipboard.writeText(`${address}/mcp`)
224
- },
225
- {
226
- label: '打开管理后台',
227
- enabled: serviceState === 'running',
228
- click: () => openAdminWindow(adminUrl)
229
- },
230
- { type: 'separator' },
231
- {
232
- label: '检查更新',
233
- click: () => checkForUpdates()
234
- },
235
- {
236
- label: '关于服务',
237
- click: () => showAboutDialog()
238
- },
239
- { type: 'separator' },
240
- {
241
- label: '退出服务',
242
- click: async () => {
243
- isQuitting = true;
244
- await stopService();
245
- app.quit();
246
- }
135
+ async checkForUpdates() {
136
+ try {
137
+ await this.updateManager.checkForUpdates();
138
+ } catch (error) {
139
+ this.logger.error('Update check failed', error);
247
140
  }
248
- ];
249
-
250
- const menu = Menu.buildFromTemplate(template);
251
- tray.setContextMenu(menu);
252
- }
253
-
254
- function openAdminWindow(url) {
255
- if (adminWindow) {
256
- adminWindow.focus();
257
- return;
258
141
  }
259
142
 
260
- adminWindow = new BrowserWindow({
261
- width: 1200,
262
- height: 800,
263
- title: 'Prompt Server 管理后台',
264
- webPreferences: {
265
- contextIsolation: true,
266
- preload: undefined
267
- }
268
- });
269
-
270
- adminWindow.loadURL(url);
271
- adminWindow.on('closed', () => {
272
- adminWindow = null;
273
- });
274
- }
275
-
276
- async function getCurrentServiceVersion() {
277
- try {
278
- const serverRoot = await ensureRuntimeServerRoot();
279
- const pkgRaw = await fs.promises.readFile(path.join(serverRoot, 'package.json'), 'utf8');
280
- const pkg = JSON.parse(pkgRaw);
281
- return pkg.version;
282
- } catch (error) {
283
- return 'unknown';
143
+ showAboutDialog() {
144
+ this.aboutDialogManager.showAboutDialog();
284
145
  }
285
- }
286
-
287
- function compareVersions(a, b) {
288
- const toNumbers = (value = '') => value.split('.').map((part) => parseInt(part, 10) || 0);
289
- const [a1, a2, a3] = toNumbers(a);
290
- const [b1, b2, b3] = toNumbers(b);
291
- if (a1 !== b1) return a1 - b1;
292
- if (a2 !== b2) return a2 - b2;
293
- return a3 - b3;
294
- }
295
146
 
296
- async function checkForUpdates() {
297
- try {
298
- const currentVersion = await getCurrentServiceVersion();
299
-
300
- const response = await fetch('https://registry.npmjs.org/@becrafter/prompt-manager');
301
- if (!response.ok) {
302
- throw new Error('无法获取最新版本信息');
303
- }
304
-
305
- const metadata = await response.json();
306
- const latestVersion = metadata?.['dist-tags']?.latest;
307
-
308
- if (!latestVersion) {
309
- throw new Error('未能解析最新版本号');
310
- }
311
-
312
- if (compareVersions(latestVersion, currentVersion) <= 0) {
313
- await dialog.showMessageBox({
314
- type: 'info',
315
- message: '已是最新版本',
316
- detail: `服务当前版本:${currentVersion}`
317
- });
318
- return;
319
- }
320
-
321
- const { response: action } = await dialog.showMessageBox({
322
- type: 'question',
323
- buttons: ['立即升级', '打开发布页', '取消'],
324
- defaultId: 0,
325
- cancelId: 2,
326
- message: `发现新版本 ${latestVersion}`,
327
- detail: '升级期间服务会短暂停止,是否继续?'
328
- });
329
-
330
- if (action === 1) {
331
- shell.openExternal('https://github.com/BeCrafter/prompt-manager/releases/latest');
332
- return;
333
- }
334
-
335
- if (action !== 0) {
336
- return;
337
- }
338
-
339
- const wasRunning = serviceState === 'running';
340
- if (wasRunning) {
341
- await stopService();
342
- }
343
-
344
- await performInPlaceUpgrade(latestVersion);
345
-
346
- await dialog.showMessageBox({
347
- type: 'info',
348
- message: '升级成功',
349
- detail: `服务已升级到 ${latestVersion}`
350
- });
351
-
352
- if (wasRunning) {
353
- await startService();
354
- }
355
- } catch (error) {
356
- dialog.showErrorBox('检查更新失败', error?.message || String(error));
147
+ handleAboutWindowClick(data) {
148
+ // 委托给AboutDialogManager处理
149
+ this.aboutDialogManager.handleAboutWindowClick(data);
357
150
  }
358
- }
359
-
360
- async function performInPlaceUpgrade(version) {
361
- const tarballUrl = `https://registry.npmjs.org/@becrafter/prompt-manager/-/@becrafter/prompt-manager-${version}.tgz`;
362
- const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'prompt-manager-upgrade-'));
363
- const tarballPath = path.join(tmpDir, `${version}.tgz`);
364
-
365
- try {
366
- const response = await fetch(tarballUrl);
367
- if (!response.ok) {
368
- throw new Error('无法下载升级包');
369
- }
370
-
371
- const buffer = Buffer.from(await response.arrayBuffer());
372
- await fs.promises.writeFile(tarballPath, buffer);
373
-
374
- await tar.x({ file: tarballPath, cwd: tmpDir });
375
- const extractedPath = path.join(tmpDir, 'package');
376
-
377
- const serverRoot = await ensureRuntimeServerRoot();
378
- const examplesDir = path.join(serverRoot, 'examples', 'prompts');
379
- const examplesBackup = path.join(tmpDir, 'examples-prompts');
380
151
 
381
- if (await pathExists(examplesDir)) {
382
- await fs.promises.cp(examplesDir, examplesBackup, { recursive: true });
383
- }
384
-
385
- await fs.promises.rm(serverRoot, { recursive: true, force: true });
386
- await fs.promises.mkdir(serverRoot, { recursive: true });
387
- await fs.promises.cp(extractedPath, serverRoot, { recursive: true });
388
-
389
- if (await pathExists(examplesBackup)) {
390
- const targetExamples = path.join(serverRoot, 'examples', 'prompts');
391
- await fs.promises.mkdir(path.dirname(targetExamples), { recursive: true });
392
- await fs.promises.cp(examplesBackup, targetExamples, { recursive: true });
152
+ async restartApplication() {
153
+ this.logger.info('Restarting application');
154
+
155
+ try {
156
+ await this.stopService();
157
+ app.relaunch();
158
+ app.exit(0);
159
+ } catch (error) {
160
+ this.logger.error('Failed to restart application', error);
393
161
  }
394
-
395
- await installServerDependencies(serverRoot);
396
- await loadServerModule({ forceReload: true });
397
- } finally {
398
- await fs.promises.rm(tmpDir, { recursive: true, force: true });
399
162
  }
400
- }
401
163
 
402
- async function pathExists(targetPath) {
403
- try {
404
- await fs.promises.access(targetPath, fs.constants.F_OK);
405
- return true;
406
- } catch (error) {
407
- return false;
164
+ async quitApplication() {
165
+ this.logger.info('Quitting application');
166
+
167
+ try {
168
+ this.stateManager.set('isQuitting', true);
169
+
170
+ // 停止服务
171
+ await this.stopService();
172
+
173
+ // 清理资源
174
+ await this.aboutDialogManager.closeAboutDialog();
175
+
176
+ this.trayManager.destroy();
177
+ await this.logger.close();
178
+ await this.runtimeManager.cleanup();
179
+
180
+ app.quit();
181
+ } catch (error) {
182
+ this.logger.error('Error during application shutdown', error);
183
+ app.quit(); // 强制退出
184
+ }
408
185
  }
409
186
  }
410
187
 
411
- async function installServerDependencies(targetDir) {
412
- const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
413
- const args = ['install', '--omit=dev'];
414
-
415
- await new Promise((resolve, reject) => {
416
- const child = spawn(npmCommand, args, {
417
- cwd: targetDir,
418
- stdio: ['ignore', 'pipe', 'pipe']
419
- });
420
-
421
- let stderr = '';
422
- child.stdout.on('data', (data) => {
423
- console.log(`[npm] ${data.toString().trim()}`);
424
- });
425
- child.stderr.on('data', (data) => {
426
- stderr += data.toString();
427
- console.error(`[npm] ${data.toString().trim()}`);
428
- });
429
-
430
- child.on('error', (error) => {
431
- reject(error);
432
- });
433
-
434
- child.on('close', (code) => {
435
- if (code === 0) {
436
- resolve();
437
- } else {
438
- reject(new Error(`npm install failed with exit code ${code}: ${stderr}`));
439
- }
440
- });
441
- });
442
- }
443
-
444
- async function showAboutDialog() {
445
- const serviceVersion = await getCurrentServiceVersion();
446
- const lines = [
447
- // `桌面应用版本:${desktopPackageJson.version}`,
448
- `服务版本:${serviceVersion}`,
449
- `Electron:${process.versions.electron}`,
450
- // `Chromium:${process.versions.chrome}`,
451
- `Node.js:${process.versions.node}`
452
- ];
453
-
454
- await dialog.showMessageBox({
455
- type: 'info',
456
- title: '关于 Prompt Server',
457
- message: '组件版本信息',
458
- detail: lines.join('\n')
459
- });
460
- }
188
+ // 应用启动
189
+ const promptManagerApp = new PromptManagerApp();
461
190
 
462
191
  app.whenReady().then(async () => {
463
- console.log('App is packaged:', app.isPackaged);
464
- console.log('App data path:', app.getPath('userData'));
465
- console.log('Resources path:', process.resourcesPath);
466
- console.log('__dirname:', __dirname);
467
-
468
- Menu.setApplicationMenu(null);
469
- if (process.platform === 'darwin') {
470
- app.dock.hide();
192
+ try {
193
+ await promptManagerApp.initialize();
194
+ } catch (error) {
195
+ console.error('Failed to start application:', error);
196
+ app.quit();
471
197
  }
472
-
473
- await ensureRuntimeServerRoot();
474
- ensureTray();
475
- await startService();
476
- });
477
-
478
- app.on('window-all-closed', (event) => {
479
- event.preventDefault();
480
198
  });
481
199
 
482
- app.on('before-quit', async (event) => {
483
- if (isQuitting) {
484
- return;
200
+ // 异常处理
201
+ process.on('uncaughtException', (error) => {
202
+ console.error('Uncaught Exception:', error);
203
+ if (promptManagerApp.logger) {
204
+ promptManagerApp.logger.error('Uncaught Exception', error);
485
205
  }
486
- event.preventDefault();
487
- isQuitting = true;
488
- await stopService();
489
206
  app.quit();
490
207
  });
491
208
 
492
- app.on('activate', () => {
493
- if (!tray) {
494
- ensureTray();
209
+ process.on('unhandledRejection', (reason, promise) => {
210
+ console.error('Unhandled Rejection at:', promise, 'reason:', reason);
211
+ if (promptManagerApp.logger) {
212
+ promptManagerApp.logger.error('Unhandled Rejection', reason);
495
213
  }
496
- });
214
+ });