@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
@@ -0,0 +1,193 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { pathToFileURL } = require('url');
4
+ const { spawn } = require('child_process');
5
+
6
+ class ModuleLoader {
7
+ constructor(logger, errorHandler) {
8
+ this.logger = logger;
9
+ this.errorHandler = errorHandler;
10
+ this.moduleCache = new Map();
11
+ this.loadingPromises = new Map();
12
+ }
13
+
14
+ async loadServerModule(serverRoot, forceReload = false) {
15
+ const cacheKey = serverRoot;
16
+
17
+ // 如果正在加载,返回现有promise
18
+ if (this.loadingPromises.has(cacheKey) && !forceReload) {
19
+ this.logger.debug('Returning existing module loading promise');
20
+ return this.loadingPromises.get(cacheKey);
21
+ }
22
+
23
+ // 强制重新加载时清理缓存
24
+ if (forceReload) {
25
+ this.logger.debug('Force reloading server module');
26
+ this.moduleCache.delete(cacheKey);
27
+ }
28
+
29
+ // 检查缓存
30
+ if (this.moduleCache.has(cacheKey)) {
31
+ this.logger.debug('Returning cached server module');
32
+ return this.moduleCache.get(cacheKey);
33
+ }
34
+
35
+ const loadingPromise = this._loadModuleInternal(serverRoot);
36
+ this.loadingPromises.set(cacheKey, loadingPromise);
37
+
38
+ try {
39
+ const module = await loadingPromise;
40
+ this.moduleCache.set(cacheKey, module);
41
+ return module;
42
+ } catch (error) {
43
+ this.logger.error('Failed to load server module', error);
44
+ throw error;
45
+ } finally {
46
+ this.loadingPromises.delete(cacheKey);
47
+ }
48
+ }
49
+
50
+ async _loadModuleInternal(serverRoot) {
51
+ this.logger.info('Loading server module', { serverRoot });
52
+
53
+ const serverEntry = path.join(serverRoot, 'packages', 'server', 'server.js');
54
+
55
+ // 验证入口文件存在
56
+ await this._validateServerEntry(serverEntry);
57
+
58
+ // 生成带版本号的URL
59
+ const entryUrl = pathToFileURL(serverEntry);
60
+ entryUrl.searchParams.set('v', Date.now().toString());
61
+
62
+ this.logger.debug('Importing server module', { entryUrl: entryUrl.href });
63
+
64
+ try {
65
+ const module = await import(entryUrl.href);
66
+
67
+ // 验证模块结构
68
+ this._validateServerModule(module);
69
+
70
+ this.logger.info('Server module loaded successfully');
71
+ return module;
72
+ } catch (error) {
73
+ this.logger.error('Failed to import server module', error);
74
+ throw new Error(`Failed to load server module: ${error.message}`);
75
+ }
76
+ }
77
+
78
+ async _validateServerEntry(serverEntry) {
79
+ try {
80
+ await fs.promises.access(serverEntry, fs.constants.F_OK);
81
+ this.logger.debug('Server entry file exists', { serverEntry });
82
+ } catch (error) {
83
+ this.logger.error('Server entry file does not exist', error);
84
+ throw new Error(`Server entry file not found: ${serverEntry}`);
85
+ }
86
+ }
87
+
88
+ _validateServerModule(module) {
89
+ if (!module || typeof module.startServer !== 'function') {
90
+ throw new Error('Invalid server module: missing startServer function');
91
+ }
92
+
93
+ this.logger.debug('Server module validation passed');
94
+ }
95
+
96
+ async installDependencies(targetDir) {
97
+ this.logger.info('Installing server dependencies', { targetDir });
98
+
99
+ // 验证 package.json 存在
100
+ await this._validatePackageJson(targetDir);
101
+
102
+ // 检查并添加缺失的依赖
103
+ await this._ensureRequiredDependencies(targetDir);
104
+
105
+ return new Promise((resolve, reject) => {
106
+ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
107
+ const args = ['install', '--omit=dev', '--no-audit', '--no-fund'];
108
+
109
+ this.logger.debug('Running npm install', { command: npmCommand, args });
110
+
111
+ const child = spawn(npmCommand, args, {
112
+ cwd: targetDir,
113
+ stdio: ['ignore', 'pipe', 'pipe']
114
+ });
115
+
116
+ let stdout = '';
117
+ let stderr = '';
118
+
119
+ child.stdout.on('data', (data) => {
120
+ const output = data.toString().trim();
121
+ stdout += output;
122
+ this.logger.debug(`[npm stdout] ${output}`);
123
+ });
124
+
125
+ child.stderr.on('data', (data) => {
126
+ const output = data.toString().trim();
127
+ stderr += output;
128
+ this.logger.warn(`[npm stderr] ${output}`);
129
+ });
130
+
131
+ child.on('error', (error) => {
132
+ this.logger.error('npm process error', error);
133
+ reject(new Error(`Failed to start npm process: ${error.message}`));
134
+ });
135
+
136
+ child.on('close', (code) => {
137
+ this.logger.debug('npm process exited', { code });
138
+
139
+ if (code === 0) {
140
+ this.logger.info('Dependencies installed successfully');
141
+ resolve();
142
+ } else {
143
+ const errorMsg = `npm install failed with exit code ${code}`;
144
+ this.logger.error(errorMsg, new Error(stderr));
145
+ reject(new Error(errorMsg));
146
+ }
147
+ });
148
+ });
149
+ }
150
+
151
+ async _validatePackageJson(targetDir) {
152
+ const pkgPath = path.join(targetDir, 'package.json');
153
+
154
+ try {
155
+ await fs.promises.access(pkgPath, fs.constants.F_OK);
156
+ this.logger.debug('package.json found in target directory');
157
+ } catch (error) {
158
+ this.logger.error('package.json not found in target directory', { pkgPath });
159
+ throw new Error(`package.json not found in ${targetDir}`);
160
+ }
161
+ }
162
+
163
+ async _ensureRequiredDependencies(targetDir) {
164
+ const pkgPath = path.join(targetDir, 'package.json');
165
+
166
+ try {
167
+ const pkgContent = await fs.promises.readFile(pkgPath, 'utf8');
168
+ const pkg = JSON.parse(pkgContent);
169
+
170
+ pkg.dependencies = pkg.dependencies || {};
171
+
172
+ // 检查并添加 @modelcontextprotocol/sdk
173
+ if (!pkg.dependencies['@modelcontextprotocol/sdk']) {
174
+ pkg.dependencies['@modelcontextprotocol/sdk'] = '^1.20.2';
175
+ await fs.promises.writeFile(pkgPath, JSON.stringify(pkg, null, 2), 'utf8');
176
+ this.logger.info('Added @modelcontextprotocol/sdk to dependencies');
177
+ }
178
+ } catch (error) {
179
+ this.logger.error('Error checking/adding dependencies', error);
180
+ throw error;
181
+ }
182
+ }
183
+
184
+ clearCache(serverRoot) {
185
+ const cacheKey = serverRoot;
186
+ if (this.moduleCache.has(cacheKey)) {
187
+ this.moduleCache.delete(cacheKey);
188
+ this.logger.debug('Cleared module cache', { serverRoot });
189
+ }
190
+ }
191
+ }
192
+
193
+ module.exports = ModuleLoader;
@@ -0,0 +1,152 @@
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
+ this.isPackaged = app.isPackaged;
11
+ }
12
+
13
+ async ensureRuntimeEnvironment() {
14
+ if (this.runtimeRoot) {
15
+ this.logger.debug('Using cached runtime root', { path: this.runtimeRoot });
16
+ return this.runtimeRoot;
17
+ }
18
+
19
+ try {
20
+ if (this.isPackaged) {
21
+ this.runtimeRoot = await this._setupPackagedEnvironment();
22
+ } else {
23
+ this.runtimeRoot = await this._setupDevelopmentEnvironment();
24
+ }
25
+
26
+ this.logger.info('Runtime environment ensured', {
27
+ root: this.runtimeRoot,
28
+ isPackaged: this.isPackaged
29
+ });
30
+
31
+ return this.runtimeRoot;
32
+ } catch (error) {
33
+ this.logger.error('Failed to ensure runtime environment', error);
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ async _setupDevelopmentEnvironment() {
39
+ this.logger.info('Setting up development environment');
40
+
41
+ // Go from app/desktop/src/services -> project root
42
+ const devRoot = path.resolve(__dirname, '..', '..', '..', '..');
43
+
44
+ // 验证开发环境
45
+ await this._validateDevelopmentEnvironment(devRoot);
46
+
47
+ this.runtimeRoot = devRoot;
48
+ return devRoot;
49
+ }
50
+
51
+ async _setupPackagedEnvironment() {
52
+ this.logger.info('Setting up packaged environment');
53
+
54
+ const packagedRoot = path.join(process.resourcesPath, 'prompt-manager');
55
+ const runtimeRoot = path.join(app.getPath('userData'), 'prompt-manager');
56
+
57
+ this.logger.debug('Environment paths', { packagedRoot, runtimeRoot });
58
+
59
+ // 验证打包资源
60
+ await this._validatePackagedResources(packagedRoot);
61
+
62
+ // 设置运行时目录
63
+ await this._setupRuntimeDirectory(packagedRoot, runtimeRoot);
64
+
65
+ this.runtimeRoot = runtimeRoot;
66
+ return runtimeRoot;
67
+ }
68
+
69
+ async _validateDevelopmentEnvironment(devRoot) {
70
+ const requiredPaths = [
71
+ path.join(devRoot, 'package.json'),
72
+ path.join(devRoot, 'packages', 'server', 'server.js')
73
+ ];
74
+
75
+ for (const requiredPath of requiredPaths) {
76
+ try {
77
+ await fs.promises.access(requiredPath, fs.constants.F_OK);
78
+ } catch (error) {
79
+ throw new Error(`Development environment validation failed: ${requiredPath} not found`);
80
+ }
81
+ }
82
+
83
+ this.logger.debug('Development environment validation passed');
84
+ }
85
+
86
+ async _validatePackagedResources(packagedRoot) {
87
+ try {
88
+ await fs.promises.access(packagedRoot, fs.constants.F_OK);
89
+ this.logger.debug('Packaged root exists', { path: packagedRoot });
90
+ } catch (error) {
91
+ throw new Error(`Packaged resources not found: ${packagedRoot}`);
92
+ }
93
+ }
94
+
95
+ async _setupRuntimeDirectory(packagedRoot, runtimeRoot) {
96
+ try {
97
+ await fs.promises.access(runtimeRoot, fs.constants.F_OK);
98
+ this.logger.debug('Runtime root already exists');
99
+ } catch (error) {
100
+ this.logger.info('Creating runtime directory', { path: runtimeRoot });
101
+ await fs.promises.mkdir(runtimeRoot, { recursive: true });
102
+
103
+ this.logger.info('Copying packaged resources to runtime directory');
104
+ await fs.promises.cp(packagedRoot, runtimeRoot, { recursive: true });
105
+ }
106
+ }
107
+
108
+ async _installDependencies(runtimeRoot) {
109
+ this.logger.info('Installing dependencies in runtime directory');
110
+
111
+ const ModuleLoader = require('./module-loader');
112
+ const moduleLoader = new ModuleLoader(this.logger, this.errorHandler);
113
+
114
+ try {
115
+ await moduleLoader.installDependencies(runtimeRoot);
116
+ this.logger.info('Dependencies installed successfully');
117
+ } catch (error) {
118
+ this.logger.error('Failed to install dependencies', error);
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ getServerRoot() {
124
+ if (!this.runtimeRoot) {
125
+ throw new Error('Runtime environment not initialized');
126
+ }
127
+ return this.runtimeRoot;
128
+ }
129
+
130
+ getPackageInfo() {
131
+ if (!this.runtimeRoot) {
132
+ throw new Error('Runtime environment not initialized');
133
+ }
134
+
135
+ const packagePath = path.join(this.runtimeRoot, 'package.json');
136
+
137
+ try {
138
+ const packageContent = fs.readFileSync(packagePath, 'utf8');
139
+ return JSON.parse(packageContent);
140
+ } catch (error) {
141
+ this.logger.error('Failed to read package info', error);
142
+ return { version: 'unknown' };
143
+ }
144
+ }
145
+
146
+ async cleanup() {
147
+ this.logger.info('Cleaning up runtime environment');
148
+ this.runtimeRoot = null;
149
+ }
150
+ }
151
+
152
+ module.exports = RuntimeManager;
@@ -0,0 +1,169 @@
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;