@becrafter/prompt-manager 0.1.2 → 0.1.9

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 (110) hide show
  1. package/README.md +304 -121
  2. package/app/cli/commands/start.js +65 -4
  3. package/app/cli/support/argv.js +6 -0
  4. package/env.example +32 -0
  5. package/package.json +36 -7
  6. package/packages/server/api/admin.routes.js +409 -1
  7. package/packages/server/api/open.routes.js +7 -2
  8. package/packages/server/api/tool.routes.js +479 -0
  9. package/packages/server/app.js +97 -25
  10. package/packages/server/configs/models/built-in/bigmodel.yaml +6 -0
  11. package/packages/server/configs/models/providers.yaml +50 -0
  12. package/packages/server/configs/templates/built-in/general-iteration.yaml +60 -0
  13. package/packages/server/configs/templates/built-in/general-optimize.yaml +63 -0
  14. package/packages/server/configs/templates/built-in/output-format-optimize.yaml +95 -0
  15. package/packages/server/mcp/heartbeat-patch.js +73 -0
  16. package/packages/server/mcp/mcp.server.js +63 -314
  17. package/packages/server/mcp/prompt.handler.js +26 -0
  18. package/packages/server/mcp/thinking-toolkit.handler.js +380 -0
  19. package/packages/server/package.json +35 -3
  20. package/packages/server/server.js +114 -12
  21. package/packages/server/services/TerminalService.js +498 -0
  22. package/packages/server/services/WebSocketService.js +484 -0
  23. package/packages/server/services/manager.js +38 -7
  24. package/packages/server/services/model.service.js +473 -0
  25. package/packages/server/services/optimization.service.js +457 -0
  26. package/packages/server/services/template.service.js +333 -0
  27. package/packages/server/toolm/tool-description-generator-optimized.service.js +5 -2
  28. package/packages/server/toolm/tool-sync.service.js +47 -3
  29. package/packages/server/utils/config.js +8 -1
  30. package/packages/server/utils/port-checker.js +63 -0
  31. package/packages/server/utils/util.js +27 -0
  32. package/IFLOW.md +0 -175
  33. package/app/desktop/assets/app.1.png +0 -0
  34. package/app/desktop/assets/app.png +0 -0
  35. package/app/desktop/assets/icons/icon.icns +0 -0
  36. package/app/desktop/assets/icons/icon.ico +0 -0
  37. package/app/desktop/assets/icons/icon.png +0 -0
  38. package/app/desktop/assets/icons/tray.png +0 -0
  39. package/app/desktop/assets/templates/about.html +0 -147
  40. package/app/desktop/assets/tray.1.png +0 -0
  41. package/app/desktop/assets/tray.png +0 -0
  42. package/app/desktop/main.js +0 -241
  43. package/app/desktop/package-lock.json +0 -5026
  44. package/app/desktop/package.json +0 -100
  45. package/app/desktop/preload.js +0 -7
  46. package/app/desktop/src/core/error-handler.js +0 -108
  47. package/app/desktop/src/core/event-emitter.js +0 -84
  48. package/app/desktop/src/core/logger.js +0 -108
  49. package/app/desktop/src/core/state-manager.js +0 -125
  50. package/app/desktop/src/services/module-loader.js +0 -214
  51. package/app/desktop/src/services/runtime-manager.js +0 -301
  52. package/app/desktop/src/services/service-manager.js +0 -169
  53. package/app/desktop/src/services/update-manager.js +0 -267
  54. package/app/desktop/src/ui/about-dialog-manager.js +0 -208
  55. package/app/desktop/src/ui/admin-window-manager.js +0 -757
  56. package/app/desktop/src/ui/splash-manager.js +0 -253
  57. package/app/desktop/src/ui/tray-manager.js +0 -186
  58. package/app/desktop/src/utils/icon-manager.js +0 -133
  59. package/app/desktop/src/utils/path-utils.js +0 -58
  60. package/app/desktop/src/utils/resource-paths.js +0 -49
  61. package/app/desktop/src/utils/resource-sync.js +0 -260
  62. package/app/desktop/src/utils/runtime-sync.js +0 -241
  63. package/app/desktop/src/utils/template-renderer.js +0 -284
  64. package/app/desktop/src/utils/version-utils.js +0 -59
  65. package/examples/prompts/developer/code-review.yaml +0 -32
  66. package/examples/prompts/developer/code_refactoring.yaml +0 -31
  67. package/examples/prompts/developer/doc-generator.yaml +0 -36
  68. package/examples/prompts/developer/error-code-fixer.yaml +0 -35
  69. package/examples/prompts/engineer/engineer-professional.yaml +0 -92
  70. package/examples/prompts/engineer/laowang-engineer.yaml +0 -132
  71. package/examples/prompts/engineer/nekomata-engineer.yaml +0 -123
  72. package/examples/prompts/engineer/ojousama-engineer.yaml +0 -124
  73. package/examples/prompts/generator/gen_3d_edu_webpage_html.yaml +0 -117
  74. package/examples/prompts/generator/gen_3d_webpage_html.yaml +0 -75
  75. package/examples/prompts/generator/gen_bento_grid_html.yaml +0 -112
  76. package/examples/prompts/generator/gen_html_web_page.yaml +0 -88
  77. package/examples/prompts/generator/gen_knowledge_card_html.yaml +0 -83
  78. package/examples/prompts/generator/gen_magazine_card_html.yaml +0 -82
  79. package/examples/prompts/generator/gen_mimeng_headline_title.yaml +0 -71
  80. package/examples/prompts/generator/gen_podcast_script.yaml +0 -69
  81. package/examples/prompts/generator/gen_prd_prototype_html.yaml +0 -175
  82. package/examples/prompts/generator/gen_summarize.yaml +0 -157
  83. package/examples/prompts/generator/gen_title.yaml +0 -119
  84. package/examples/prompts/generator/others/api_documentation.yaml +0 -32
  85. package/examples/prompts/generator/others/build_mcp_server.yaml +0 -26
  86. package/examples/prompts/generator/others/project_architecture.yaml +0 -31
  87. package/examples/prompts/generator/others/test_case_generator.yaml +0 -30
  88. package/examples/prompts/generator/others/writing_assistant.yaml +0 -72
  89. package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +0 -105
  90. package/examples/prompts/workflow/sixstep-workflow.yaml +0 -192
  91. package/packages/admin-ui/.babelrc +0 -3
  92. package/packages/admin-ui/admin.html +0 -412
  93. package/packages/admin-ui/css/codemirror-theme_xq-light.css +0 -43
  94. package/packages/admin-ui/css/codemirror.css +0 -344
  95. package/packages/admin-ui/css/main.css +0 -2592
  96. package/packages/admin-ui/css/recommended-prompts.css +0 -610
  97. package/packages/admin-ui/package-lock.json +0 -6973
  98. package/packages/admin-ui/package.json +0 -36
  99. package/packages/admin-ui/src/codemirror.js +0 -53
  100. package/packages/admin-ui/src/index.js +0 -3188
  101. package/packages/admin-ui/webpack.config.js +0 -76
  102. package/packages/server/toolm/test-tools.js +0 -264
  103. package/scripts/build-icons.js +0 -135
  104. package/scripts/build.sh +0 -57
  105. package/scripts/postinstall.js +0 -34
  106. package/scripts/surge/CNAME +0 -1
  107. package/scripts/surge/README.md +0 -47
  108. package/scripts/surge/package-lock.json +0 -34
  109. package/scripts/surge/package.json +0 -20
  110. package/scripts/surge/sync-to-surge.js +0 -151
@@ -1,214 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { pathToFileURL } = require('url');
4
- const { spawn } = require('child_process');
5
- const { constants } = require('fs');
6
-
7
- class ModuleLoader {
8
- constructor(logger, errorHandler) {
9
- this.logger = logger;
10
- this.errorHandler = errorHandler;
11
- this.moduleCache = new Map();
12
- this.loadingPromises = new Map();
13
- }
14
-
15
- async loadServerModule(serverRoot, forceReload = false) {
16
- const cacheKey = serverRoot;
17
-
18
- // 如果正在加载,返回现有promise
19
- if (this.loadingPromises.has(cacheKey) && !forceReload) {
20
- this.logger.debug('Returning existing module loading promise');
21
- return this.loadingPromises.get(cacheKey);
22
- }
23
-
24
- // 强制重新加载时清理缓存
25
- if (forceReload) {
26
- this.logger.debug('Force reloading server module');
27
- this.moduleCache.delete(cacheKey);
28
- }
29
-
30
- // 检查缓存
31
- if (this.moduleCache.has(cacheKey)) {
32
- this.logger.debug('Returning cached server module');
33
- return this.moduleCache.get(cacheKey);
34
- }
35
-
36
- const loadingPromise = this._loadModuleInternal(serverRoot);
37
- this.loadingPromises.set(cacheKey, loadingPromise);
38
-
39
- try {
40
- const module = await loadingPromise;
41
- this.moduleCache.set(cacheKey, module);
42
- return module;
43
- } catch (error) {
44
- this.logger.error('Failed to load server module', error);
45
- throw error;
46
- } finally {
47
- this.loadingPromises.delete(cacheKey);
48
- }
49
- }
50
-
51
- async _loadModuleInternal(serverRoot) {
52
- this.logger.info('Loading server module', { serverRoot });
53
-
54
- // 简化路径查找逻辑,优先查找 app.asar 包中的核心库
55
- const pathsToCheck = [
56
- // 1. 优先从 app.asar 包中的 node_modules 加载(打包应用中)
57
- path.join(process.resourcesPath, 'app.asar', 'node_modules', '@becrafter', 'prompt-manager-core', 'index.js'),
58
- // 2. 尝试从 serverRoot 的 packages/server 加载(开发环境)
59
- path.join(serverRoot, 'packages', 'server', 'index.js'),
60
- // 3. 尝试从 serverRoot 的 node_modules 加载
61
- path.join(serverRoot, 'node_modules', '@becrafter', 'prompt-manager-core', 'index.js'),
62
- ];
63
-
64
- for (const libPath of pathsToCheck) {
65
- if (await this._pathExists(libPath)) {
66
- const entryUrl = pathToFileURL(libPath);
67
- // 添加版本参数以防止缓存
68
- entryUrl.searchParams.set('v', Date.now().toString());
69
-
70
- const module = await import(entryUrl.href);
71
- this._validateServerModule(module);
72
- this.logger.info('Server module loaded successfully');
73
- return module;
74
- }
75
- }
76
-
77
- // 如果所有路径都没有找到,抛出错误
78
- throw new Error(`Could not find core library in any of the expected paths: ${pathsToCheck.join(', ')}`);
79
- }
80
-
81
- async _pathExists(targetPath) {
82
- try {
83
- await fs.promises.access(targetPath, constants.F_OK);
84
- return true;
85
- } catch (error) {
86
- return false;
87
- }
88
- }
89
-
90
- async _validateServerEntry(serverEntry) {
91
- try {
92
- // 验证库的 package.json 存在
93
- const packageJsonPath = path.join(serverEntry, 'package.json');
94
- await fs.promises.access(packageJsonPath, fs.constants.F_OK);
95
- this.logger.debug('Server module package.json exists', { serverEntry });
96
- } catch (error) {
97
- this.logger.error('Server module not found', error);
98
- throw new Error(`Server module not found: ${serverEntry}`);
99
- }
100
- }
101
-
102
- _validateServerModule(module) {
103
- if (!module || typeof module.startServer !== 'function') {
104
- throw new Error('Invalid server module: missing startServer function');
105
- }
106
-
107
- this.logger.debug('Server module validation passed');
108
- }
109
-
110
- async installDependencies(targetDir) {
111
- this.logger.info('Installing server dependencies', { targetDir });
112
-
113
- // 验证 package.json 存在
114
- await this._validatePackageJson(targetDir);
115
-
116
- // 检查并添加缺失的依赖
117
- await this._ensureRequiredDependencies(targetDir);
118
-
119
- return new Promise((resolve, reject) => {
120
- const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
121
- const args = ['install', '--omit=dev', '--no-audit', '--no-fund'];
122
-
123
- this.logger.debug('Running npm install', { command: npmCommand, args });
124
-
125
- const child = spawn(npmCommand, args, {
126
- cwd: targetDir,
127
- stdio: ['ignore', 'pipe', 'pipe']
128
- });
129
-
130
- let stdout = '';
131
- let stderr = '';
132
-
133
- child.stdout.on('data', (data) => {
134
- const output = data.toString().trim();
135
- stdout += output;
136
- this.logger.debug(`[npm stdout] ${output}`);
137
- });
138
-
139
- child.stderr.on('data', (data) => {
140
- const output = data.toString().trim();
141
- stderr += output;
142
- this.logger.warn(`[npm stderr] ${output}`);
143
- });
144
-
145
- child.on('error', (error) => {
146
- this.logger.error('npm process error', error);
147
- reject(new Error(`Failed to start npm process: ${error.message}`));
148
- });
149
-
150
- child.on('close', (code) => {
151
- this.logger.debug('npm process exited', { code });
152
-
153
- if (code === 0) {
154
- this.logger.info('Dependencies installed successfully');
155
- resolve();
156
- } else {
157
- const errorMsg = `npm install failed with exit code ${code}`;
158
- this.logger.error(errorMsg, new Error(stderr));
159
- reject(new Error(errorMsg));
160
- }
161
- });
162
- });
163
- }
164
-
165
- async _validatePackageJson(targetDir) {
166
- const pkgPath = path.join(targetDir, 'package.json');
167
-
168
- try {
169
- await fs.promises.access(pkgPath, fs.constants.F_OK);
170
- this.logger.debug('package.json found in target directory');
171
- } catch (error) {
172
- this.logger.error('package.json not found in target directory', { pkgPath });
173
- throw new Error(`package.json not found in ${targetDir}`);
174
- }
175
- }
176
-
177
- async _ensureRequiredDependencies(targetDir) {
178
- const pkgPath = path.join(targetDir, 'package.json');
179
-
180
- try {
181
- const pkgContent = await fs.promises.readFile(pkgPath, 'utf8');
182
- const pkg = JSON.parse(pkgContent);
183
-
184
- pkg.dependencies = pkg.dependencies || {};
185
-
186
- // 确保 @becrafter/prompt-manager-core 依赖存在
187
- if (!pkg.dependencies['@becrafter/prompt-manager-core']) {
188
- pkg.dependencies['@becrafter/prompt-manager-core'] = '^0.0.19';
189
- await fs.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
190
- this.logger.info('Added @becrafter/prompt-manager-core to dependencies');
191
- }
192
-
193
- // 检查并添加 @modelcontextprotocol/sdk
194
- if (!pkg.dependencies['@modelcontextprotocol/sdk']) {
195
- pkg.dependencies['@modelcontextprotocol/sdk'] = '^1.20.2';
196
- await fs.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
197
- this.logger.info('Added @modelcontextprotocol/sdk to dependencies');
198
- }
199
- } catch (error) {
200
- this.logger.error('Error checking/adding dependencies', error);
201
- throw error;
202
- }
203
- }
204
-
205
- clearCache(serverRoot) {
206
- const cacheKey = serverRoot;
207
- if (this.moduleCache.has(cacheKey)) {
208
- this.moduleCache.delete(cacheKey);
209
- this.logger.debug('Cleared module cache', { serverRoot });
210
- }
211
- }
212
- }
213
-
214
- module.exports = ModuleLoader;
@@ -1,301 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { app } = require('electron');
4
-
5
- class RuntimeManager {
6
- constructor(logger, errorHandler) {
7
- this.logger = logger;
8
- this.errorHandler = errorHandler;
9
- this.runtimeRoot = null;
10
- // 更准确地判断是否为打包应用
11
- // 在开发模式下,即使 app.isPackaged 为 true,我们的项目目录结构也不同于打包应用
12
- this.isPackaged = this._checkIfActuallyPackaged();
13
- }
14
-
15
- _checkIfActuallyPackaged() {
16
- // 简化环境检测逻辑
17
- const appPath = app.getAppPath();
18
- const isDev = appPath.includes('node_modules/electron') ||
19
- process.env.NODE_ENV === 'development' ||
20
- process.defaultApp;
21
-
22
- return !isDev && app.isPackaged;
23
- }
24
-
25
- async ensureRuntimeEnvironment() {
26
- if (this.runtimeRoot) {
27
- this.logger.debug('Using cached runtime root', { path: this.runtimeRoot });
28
- return this.runtimeRoot;
29
- }
30
-
31
- try {
32
- if (this.isPackaged) {
33
- this.runtimeRoot = await this._setupPackagedEnvironment();
34
- } else {
35
- this.runtimeRoot = await this._setupDevelopmentEnvironment();
36
- }
37
-
38
- this.logger.info('Runtime environment ensured', {
39
- root: this.runtimeRoot,
40
- isPackaged: this.isPackaged
41
- });
42
-
43
- return this.runtimeRoot;
44
- } catch (error) {
45
- this.logger.error('Failed to ensure runtime environment', error);
46
- throw error;
47
- }
48
- }
49
-
50
- async _setupDevelopmentEnvironment() {
51
- this.logger.info('Setting up development environment');
52
-
53
- // Go from app/desktop/src/services -> project root
54
- const devRoot = path.resolve(__dirname, '..', '..', '..', '..');
55
-
56
- // 验证开发环境
57
- await this._validateDevelopmentEnvironment(devRoot);
58
-
59
- this.runtimeRoot = devRoot;
60
- return devRoot;
61
- }
62
-
63
- async _setupPackagedEnvironment() {
64
- this.logger.info('Setting up packaged environment');
65
-
66
- // 在打包的 Electron 应用中,资源文件位于 app.asar 中
67
- const packagedRoot = path.join(process.resourcesPath, 'app.asar');
68
- const runtimeRoot = path.join(app.getPath('userData'), 'prompt-manager');
69
-
70
- this.logger.debug('Environment paths', {
71
- packagedRoot,
72
- runtimeRoot,
73
- resourcesPath: process.resourcesPath,
74
- isMountedVolume: process.resourcesPath.includes('/Volumes/')
75
- });
76
-
77
- // 简化逻辑:仅检查是否是挂载卷
78
- const isFromMountedVolume = process.resourcesPath.includes('/Volumes/');
79
-
80
- if (isFromMountedVolume) {
81
- this.logger.debug('Detected mounted volume, attempting to find appropriate path');
82
-
83
- // 尝试主要路径
84
- try {
85
- await this._validatePackagedResources(packagedRoot);
86
- this.logger.debug('Validated packaged resources from mounted volume path', { path: packagedRoot });
87
- } catch (error) {
88
- // 在挂载卷中,即使验证失败,我们也要继续执行
89
- // 因为文件可能存在于挂载卷中,但由于权限问题无法验证
90
- this.logger.warn('Could not validate packaged resources from mounted volume, continuing anyway', {
91
- error: error.message
92
- });
93
- }
94
- } else {
95
- // 非挂载卷,使用正常验证流程
96
- await this._validatePackagedResources(packagedRoot);
97
- }
98
-
99
- // 设置运行时目录(仅复制必要的文件,不包括 ASAR 包)
100
- await this._setupRuntimeDirectory(packagedRoot, runtimeRoot);
101
-
102
- this.runtimeRoot = runtimeRoot;
103
- return runtimeRoot;
104
- }
105
-
106
- async _validateDevelopmentEnvironment(devRoot) {
107
- const requiredPaths = [
108
- path.join(devRoot, 'package.json')
109
- ];
110
-
111
- for (const requiredPath of requiredPaths) {
112
- try {
113
- await fs.promises.access(requiredPath, fs.constants.F_OK);
114
- } catch (error) {
115
- throw new Error(`Development environment validation failed: ${requiredPath} not found`);
116
- }
117
- }
118
-
119
- // 检查 @becrafter/prompt-manager-core 在 node_modules 中是否存在
120
- const coreLibPath = path.join(devRoot, 'node_modules', '@becrafter', 'prompt-manager-core', 'index.js');
121
- try {
122
- await fs.promises.access(coreLibPath, fs.constants.F_OK);
123
- } catch (error) {
124
- this.logger.debug('Core library not found in node_modules, checking for local packages/server');
125
- // 如果 node_modules 中不存在,检查 local packages/server 目录
126
- const localServerPath = path.join(devRoot, 'packages', 'server', 'server.js');
127
- try {
128
- await fs.promises.access(localServerPath, fs.constants.F_OK);
129
- } catch (localError) {
130
- throw new Error(`Development environment validation failed: neither core library nor local server found (${coreLibPath}, ${localServerPath})`);
131
- }
132
- }
133
-
134
- this.logger.debug('Development environment validation passed');
135
- }
136
-
137
- async _validatePackagedResources(packagedRoot) {
138
- this.logger.debug('Validating packaged resources', { packagedRoot });
139
-
140
- // 检查 app.asar 文件是否存在
141
- if (packagedRoot.endsWith('.asar')) {
142
- // 在 Electron 中,当代码在 ASAR 包内运行时,对 ASAR 文件的访问方式不同
143
- // 我们需要检查文件是否存在,但不能依赖 stats.isFile()
144
- try {
145
- // 首先尝试使用 fs.access 来检查文件是否存在和可访问
146
- await fs.promises.access(packagedRoot, fs.constants.F_OK);
147
- this.logger.debug('Packaged ASAR is accessible via fs.access', { path: packagedRoot });
148
- return; // Found ASAR file, validation passed
149
- } catch (accessError) {
150
- // 如果 fs.access 失败,尝试使用 fs.stat 并检查错误类型
151
- try {
152
- const stats = await fs.promises.stat(packagedRoot);
153
- // 在 ASAR 环境中,即使文件存在,stats.isFile() 也可能返回 false
154
- // 我们只检查是否存在错误,而不检查文件类型
155
- this.logger.debug('Packaged ASAR exists via fs.stat', {
156
- path: packagedRoot,
157
- isFile: stats.isFile(),
158
- isDirectory: stats.isDirectory()
159
- });
160
- return; // Found ASAR file, validation passed
161
- } catch (statError) {
162
- // 如果两种方法都失败,记录详细信息然后抛出错误
163
- this.logger.error('Failed to validate packaged resources', {
164
- path: packagedRoot,
165
- accessError: accessError.message,
166
- accessCode: accessError.code,
167
- statError: statError.message,
168
- statCode: statError.code,
169
- processResourcesPath: process.resourcesPath,
170
- appPath: app.getAppPath()
171
- });
172
- throw new Error(`Packaged resources not found: ${packagedRoot} (access: ${accessError.message}, stat: ${statError.message})`);
173
- }
174
- }
175
- } else {
176
- try {
177
- const stats = await fs.promises.stat(packagedRoot);
178
- if (stats.isDirectory() || stats.isFile()) {
179
- this.logger.debug('Packaged root exists', { path: packagedRoot });
180
- }
181
- } catch (error) {
182
- this.logger.error('Packaged root not found or not accessible', { packagedRoot, error: error.message });
183
- throw new Error(`Packaged resources not found: ${packagedRoot}`);
184
- }
185
- }
186
- }
187
-
188
- // 移除了无用的 _generateVolumePaths 方法
189
-
190
- async _setupRuntimeDirectory(packagedRoot, runtimeRoot) {
191
- try {
192
- await fs.promises.access(runtimeRoot, fs.constants.F_OK);
193
- this.logger.debug('Runtime root already exists');
194
- } catch (error) {
195
- this.logger.info('Creating runtime directory', { path: runtimeRoot });
196
- await fs.promises.mkdir(runtimeRoot, { recursive: true });
197
-
198
- this.logger.info('Copying packaged resources to runtime directory');
199
-
200
- // 检查是否是 ASAR 文件
201
- if (packagedRoot.endsWith('.asar')) {
202
- // 对于 ASAR 文件,我们不需要解压整个包,只需要复制它
203
- // 但我们需要确保文件存在且可访问
204
- try {
205
- await fs.promises.access(packagedRoot, fs.constants.F_OK);
206
- this.logger.debug('ASAR file exists, copying to runtime directory');
207
-
208
- // 复制 ASAR 文件到运行时目录
209
- const targetAsarPath = path.join(runtimeRoot, 'app.asar');
210
- await fs.promises.copyFile(packagedRoot, targetAsarPath);
211
- this.logger.debug('Copied ASAR file to runtime directory', { source: packagedRoot, target: targetAsarPath });
212
- } catch (copyError) {
213
- this.logger.error('Failed to copy ASAR file to runtime directory', {
214
- source: packagedRoot,
215
- error: copyError.message
216
- });
217
-
218
- // 如果复制失败,记录错误但继续执行
219
- // 应用程序可能仍然可以运行,因为它可以直接从原始位置访问 ASAR 文件
220
- this.logger.warn('Continuing without copying ASAR file to runtime directory');
221
- }
222
- } else {
223
- // 如果是普通目录,直接复制
224
- await fs.promises.cp(packagedRoot, runtimeRoot, { recursive: true });
225
- }
226
- }
227
- }
228
-
229
- async _installDependencies(runtimeRoot) {
230
- this.logger.info('Installing dependencies in runtime directory');
231
-
232
- const ModuleLoader = require('./module-loader');
233
- const moduleLoader = new ModuleLoader(this.logger, this.errorHandler);
234
-
235
- try {
236
- await moduleLoader.installDependencies(runtimeRoot);
237
- this.logger.info('Dependencies installed successfully');
238
- } catch (error) {
239
- this.logger.error('Failed to install dependencies', error);
240
- throw error;
241
- }
242
- }
243
-
244
- getServerRoot() {
245
- if (!this.runtimeRoot) {
246
- throw new Error('Runtime environment not initialized');
247
- }
248
- return this.runtimeRoot;
249
- }
250
-
251
- getPackageInfo() {
252
- // 优先从 app.asar 压缩包中读取 package.json
253
- const asarPackagePath = path.join(process.resourcesPath, 'app.asar', 'package.json');
254
-
255
- // 尝试从 app.asar 中读取
256
- try {
257
- const packageContent = fs.readFileSync(asarPackagePath, 'utf8');
258
- this.logger.debug('Read package.json from app.asar', { path: asarPackagePath });
259
- return JSON.parse(packageContent);
260
- } catch (asarError) {
261
- // 如果从 app.asar 读取失败,尝试从 app.getAppPath() 读取(开发环境或备用方案)
262
- try {
263
- const appPathPackagePath = path.join(app.getAppPath(), 'package.json');
264
- const packageContent = fs.readFileSync(appPathPackagePath, 'utf8');
265
- this.logger.debug('Read package.json from app path', { path: appPathPackagePath });
266
- return JSON.parse(packageContent);
267
- } catch (appPathError) {
268
- // 最后尝试从 runtimeRoot 读取(向后兼容)
269
- if (this.runtimeRoot) {
270
- try {
271
- const runtimePackagePath = path.join(this.runtimeRoot, 'package.json');
272
- const packageContent = fs.readFileSync(runtimePackagePath, 'utf8');
273
- this.logger.debug('Read package.json from runtime root', { path: runtimePackagePath });
274
- return JSON.parse(packageContent);
275
- } catch (runtimeError) {
276
- this.logger.error('Failed to read package info from all locations', {
277
- asarError: asarError.message,
278
- appPathError: appPathError.message,
279
- runtimeError: runtimeError.message
280
- });
281
- }
282
- } else {
283
- this.logger.error('Failed to read package info from app.asar and app path', {
284
- asarError: asarError.message,
285
- appPathError: appPathError.message
286
- });
287
- }
288
- }
289
- }
290
-
291
- // 所有尝试都失败,返回默认值
292
- return { version: 'unknown' };
293
- }
294
-
295
- async cleanup() {
296
- this.logger.info('Cleaning up runtime environment');
297
- this.runtimeRoot = null;
298
- }
299
- }
300
-
301
- module.exports = RuntimeManager;
@@ -1,169 +0,0 @@
1
- const { dialog, shell } = require('electron');
2
- const EventEmitter = require('../core/event-emitter');
3
-
4
- class ServiceManager extends EventEmitter {
5
- constructor(logger, errorHandler, moduleLoader) {
6
- super();
7
- this.logger = logger;
8
- this.errorHandler = errorHandler;
9
- this.moduleLoader = moduleLoader;
10
- this.currentModule = null;
11
- this.serverState = null;
12
- }
13
-
14
- async startService(serverRoot, stateManager) {
15
- this.logger.info('Starting service', { serverRoot });
16
-
17
- try {
18
- // 验证服务状态
19
- if (!stateManager.canStartService()) {
20
- this.logger.warn('Service cannot be started in current state', {
21
- currentState: stateManager.get('service')
22
- });
23
- return false;
24
- }
25
-
26
- // 更新状态
27
- stateManager.set('service', 'starting');
28
- this.emitStatusUpdate(stateManager);
29
-
30
- // 加载服务器模块
31
- const module = await this.moduleLoader.loadServerModule(serverRoot, true);
32
-
33
- // 停止现有服务实例
34
- await this.stopExistingService(module);
35
-
36
- // 启动新服务
37
- await module.startServer();
38
-
39
- // 获取服务器状态
40
- this.serverState = module.getServerState();
41
- this.currentModule = module;
42
-
43
- // 更新状态
44
- stateManager.set({
45
- service: 'running',
46
- server: this.serverState,
47
- module: module
48
- });
49
- stateManager.resetFailureCount();
50
-
51
- this.logger.info('Service started successfully', { serverState: this.serverState });
52
- this.emitStatusUpdate(stateManager);
53
-
54
- return true;
55
-
56
- } catch (error) {
57
- this.logger.error('Failed to start service', error);
58
-
59
- // 更新状态
60
- stateManager.set('service', 'error');
61
- const failureCount = stateManager.incrementFailureCount();
62
-
63
- // 处理错误
64
- const shouldRestart = await this.errorHandler.handleServiceStartError(
65
- error,
66
- failureCount,
67
- this.logger.getLogFilePath()
68
- );
69
-
70
- if (shouldRestart) {
71
- this.logger.info('User requested application restart');
72
- this.emitRestartRequested();
73
- }
74
-
75
- this.emitStatusUpdate(stateManager);
76
- return false;
77
- }
78
- }
79
-
80
- async stopService(stateManager) {
81
- this.logger.info('Stopping service');
82
-
83
- try {
84
- // 验证服务状态
85
- if (!stateManager.canStopService()) {
86
- this.logger.warn('Service cannot be stopped in current state', {
87
- currentState: stateManager.get('service')
88
- });
89
- return false;
90
- }
91
-
92
- // 更新状态
93
- stateManager.set('service', 'stopping');
94
- this.emitStatusUpdate(stateManager);
95
-
96
- // 停止服务
97
- if (this.currentModule && typeof this.currentModule.stopServer === 'function') {
98
- await this.currentModule.stopServer();
99
- this.logger.info('Server stopped successfully');
100
- }
101
-
102
- // 清理状态
103
- this.currentModule = null;
104
- this.serverState = null;
105
-
106
- // 更新状态
107
- stateManager.set({
108
- service: 'stopped',
109
- server: null,
110
- module: null
111
- });
112
-
113
- // 清理模块缓存
114
- const serverRoot = stateManager.get('runtimeRoot');
115
- if (serverRoot) {
116
- this.moduleLoader.clearCache(serverRoot);
117
- }
118
-
119
- this.logger.info('Service stopped successfully');
120
- this.emitStatusUpdate(stateManager);
121
-
122
- return true;
123
-
124
- } catch (error) {
125
- this.logger.error('Failed to stop service', error);
126
-
127
- // 更新状态
128
- stateManager.set('service', 'error');
129
- this.errorHandler.handleError('SERVICE_STOP_FAILED', error);
130
- this.emitStatusUpdate(stateManager);
131
-
132
- return false;
133
- }
134
- }
135
-
136
- async stopExistingService(module) {
137
- if (!module || typeof module.stopServer !== 'function') {
138
- this.logger.debug('No existing service to stop');
139
- return;
140
- }
141
-
142
- try {
143
- this.logger.debug('Stopping existing service instance');
144
- await module.stopServer();
145
- this.logger.info('Existing service instance stopped');
146
- } catch (error) {
147
- this.logger.warn('Failed to stop existing service instance', error);
148
- // 不抛出错误,继续启动新服务
149
- }
150
- }
151
-
152
- getServiceStatus() {
153
- return {
154
- state: this.serverState,
155
- module: this.currentModule,
156
- isRunning: this.currentModule !== null
157
- };
158
- }
159
-
160
- emitStatusUpdate(stateManager) {
161
- this.emit('status-update', stateManager.getServiceStatus());
162
- }
163
-
164
- emitRestartRequested() {
165
- this.emit('restart-requested');
166
- }
167
- }
168
-
169
- module.exports = ServiceManager;