@becrafter/prompt-manager 0.1.12 → 0.1.15

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 (139) hide show
  1. package/app/desktop/assets/app.1.png +0 -0
  2. package/app/desktop/assets/app.png +0 -0
  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.png +0 -0
  6. package/app/desktop/assets/icons/tray.png +0 -0
  7. package/app/desktop/assets/templates/about.html +147 -0
  8. package/app/desktop/assets/tray.1.png +0 -0
  9. package/app/desktop/assets/tray.png +0 -0
  10. package/app/desktop/docs/ASSETS_PLANNING.md +351 -0
  11. package/app/desktop/docs/REFACTORING_SUMMARY.md +205 -0
  12. package/app/desktop/main.js +340 -0
  13. package/app/desktop/package-lock.json +6912 -0
  14. package/app/desktop/package.json +119 -0
  15. package/app/desktop/preload.js +7 -0
  16. package/app/desktop/src/core/error-handler.js +108 -0
  17. package/app/desktop/src/core/event-emitter.js +84 -0
  18. package/app/desktop/src/core/logger.js +130 -0
  19. package/app/desktop/src/core/state-manager.js +125 -0
  20. package/app/desktop/src/services/module-loader.js +330 -0
  21. package/app/desktop/src/services/runtime-manager.js +398 -0
  22. package/app/desktop/src/services/service-manager.js +210 -0
  23. package/app/desktop/src/services/update-manager.js +267 -0
  24. package/app/desktop/src/ui/about-dialog-manager.js +208 -0
  25. package/app/desktop/src/ui/admin-window-manager.js +757 -0
  26. package/app/desktop/src/ui/splash-manager.js +253 -0
  27. package/app/desktop/src/ui/tray-manager.js +186 -0
  28. package/app/desktop/src/utils/icon-manager.js +133 -0
  29. package/app/desktop/src/utils/path-utils.js +58 -0
  30. package/app/desktop/src/utils/resource-paths.js +49 -0
  31. package/app/desktop/src/utils/resource-sync.js +260 -0
  32. package/app/desktop/src/utils/runtime-sync.js +241 -0
  33. package/app/desktop/src/utils/self-check.js +288 -0
  34. package/app/desktop/src/utils/template-renderer.js +284 -0
  35. package/app/desktop/src/utils/version-utils.js +59 -0
  36. package/env.example +1 -1
  37. package/examples/prompts/developer/code-review.yaml +32 -0
  38. package/examples/prompts/developer/code_refactoring.yaml +31 -0
  39. package/examples/prompts/developer/doc-generator.yaml +36 -0
  40. package/examples/prompts/developer/error-code-fixer.yaml +35 -0
  41. package/examples/prompts/engineer/engineer-professional.yaml +92 -0
  42. package/examples/prompts/engineer/laowang-engineer.yaml +132 -0
  43. package/examples/prompts/engineer/nekomata-engineer.yaml +123 -0
  44. package/examples/prompts/engineer/ojousama-engineer.yaml +124 -0
  45. package/examples/prompts/generator/gen_3d_edu_webpage_html.yaml +117 -0
  46. package/examples/prompts/generator/gen_3d_webpage_html.yaml +75 -0
  47. package/examples/prompts/generator/gen_bento_grid_html.yaml +112 -0
  48. package/examples/prompts/generator/gen_html_web_page.yaml +88 -0
  49. package/examples/prompts/generator/gen_knowledge_card_html.yaml +83 -0
  50. package/examples/prompts/generator/gen_magazine_card_html.yaml +82 -0
  51. package/examples/prompts/generator/gen_mimeng_headline_title.yaml +71 -0
  52. package/examples/prompts/generator/gen_podcast_script.yaml +69 -0
  53. package/examples/prompts/generator/gen_prd_prototype_html.yaml +175 -0
  54. package/examples/prompts/generator/gen_summarize.yaml +157 -0
  55. package/examples/prompts/generator/gen_title.yaml +119 -0
  56. package/examples/prompts/generator/others/api_documentation.yaml +32 -0
  57. package/examples/prompts/generator/others/build_mcp_server.yaml +26 -0
  58. package/examples/prompts/generator/others/project_architecture.yaml +31 -0
  59. package/examples/prompts/generator/others/test_case_generator.yaml +30 -0
  60. package/examples/prompts/generator/others/writing_assistant.yaml +72 -0
  61. package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +105 -0
  62. package/examples/prompts/workflow/sixstep-workflow.yaml +192 -0
  63. package/package.json +13 -1
  64. package/packages/server/.eslintrc.js +70 -0
  65. package/packages/server/.husky/pre-commit +8 -0
  66. package/packages/server/.husky/pre-push +8 -0
  67. package/packages/server/.prettierrc +14 -0
  68. package/packages/server/dev-server.js +90 -0
  69. package/packages/server/jsdoc.conf.json +39 -0
  70. package/packages/server/playwright.config.js +62 -0
  71. package/packages/server/scripts/generate-docs.js +300 -0
  72. package/packages/server/server.js +1 -0
  73. package/packages/server/services/TerminalService.js +84 -11
  74. package/packages/server/tests/e2e/terminal-e2e.test.js +315 -0
  75. package/packages/server/tests/integration/terminal-websocket.test.js +372 -0
  76. package/packages/server/tests/integration/tools.test.js +264 -0
  77. package/packages/server/tests/setup.js +45 -0
  78. package/packages/server/tests/unit/TerminalService.test.js +410 -0
  79. package/packages/server/tests/unit/WebSocketService.test.js +403 -0
  80. package/packages/server/tests/unit/core.test.js +94 -0
  81. package/packages/server/typedoc.json +52 -0
  82. package/packages/server/utils/config.js +1 -1
  83. package/packages/server/utils/util.js +59 -5
  84. package/packages/server/vitest.config.js +74 -0
  85. package/packages/web/0.d1c5a72339dfc32ad86a.js +1 -0
  86. package/packages/web/112.8807b976372b2b0541a8.js +1 -0
  87. package/packages/web/130.584c7e365da413f5d9be.js +1 -0
  88. package/packages/web/142.72c985bc29720f975cca.js +1 -0
  89. package/packages/web/165.a05fc53bf84d18db36b8.js +2 -0
  90. package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +9 -0
  91. package/packages/web/203.724ab9f717b80554c397.js +1 -0
  92. package/packages/web/241.bf941d4f02866795f64a.js +1 -0
  93. package/packages/web/249.54cfb224af63f5f5ec55.js +1 -0
  94. package/packages/web/291.6df35042f8f296fca7cd.js +1 -0
  95. package/packages/web/319.2fab900a31b29873f666.js +1 -0
  96. package/packages/web/32.c78d866281995ec33a7b.js +1 -0
  97. package/packages/web/325.9ca297d0f73f38468ce9.js +1 -0
  98. package/packages/web/366.2f9b48fdbf8eee039e57.js +1 -0
  99. package/packages/web/378.6be08c612cd5a3ef97dc.js +1 -0
  100. package/packages/web/393.7a2f817515c5e90623d7.js +1 -0
  101. package/packages/web/412.062df5f732d5ba203415.js +1 -0
  102. package/packages/web/426.08656fef4918b3fb19ad.js +1 -0
  103. package/packages/web/465.2be8018327130a3bd798.js +1 -0
  104. package/packages/web/48.8ca96fc93667a715e67a.js +1 -0
  105. package/packages/web/480.44c1f1a2927486ac3d4f.js +1 -0
  106. package/packages/web/489.e041a8d0db15dc96d607.js +1 -0
  107. package/packages/web/490.9ffb26c907de020d671b.js +1 -0
  108. package/packages/web/492.58781369e348d91fc06a.js +1 -0
  109. package/packages/web/495.ed63e99791a87167c6b3.js +1 -0
  110. package/packages/web/510.4cc07ab7d30d5c1cd17f.js +1 -0
  111. package/packages/web/543.3af155ed4fa237664308.js +1 -0
  112. package/packages/web/567.f04ab60f8e2c2fb0745a.js +1 -0
  113. package/packages/web/592.f3ad085fa9c1849daa06.js +1 -0
  114. package/packages/web/616.b03fb801b3433b17750f.js +1 -0
  115. package/packages/web/617.d88def54921d2c4dc44c.js +1 -0
  116. package/packages/web/641.d30787d674f548928261.js +1 -0
  117. package/packages/web/672.5269c8399fa42a5af95d.js +1 -0
  118. package/packages/web/731.97cab92b71811c502bda.js +1 -0
  119. package/packages/web/746.3947c6f0235407e420fb.js +1 -0
  120. package/packages/web/756.a53233b3f3913900d5ac.js +1 -0
  121. package/packages/web/77.68801af593a28a631fbf.js +1 -0
  122. package/packages/web/802.53b2bff3cf2a69f7b80c.js +1 -0
  123. package/packages/web/815.b6dfab82265f56c7e046.js +1 -0
  124. package/packages/web/821.f5a13e5c735aac244eb9.js +1 -0
  125. package/packages/web/846.b9bf97d5f559270675ce.js +1 -0
  126. package/packages/web/869.7c10403f500e6201407f.js +1 -0
  127. package/packages/web/885.135050364f99e6924fb5.js +1 -0
  128. package/packages/web/901.fd5aeb9df630609a2b43.js +1 -0
  129. package/packages/web/928.f67e590de3caa4daa3ae.js +1 -0
  130. package/packages/web/955.d833403521ba4dd567ee.js +1 -0
  131. package/packages/web/981.a45cb745cf424044c8c8.js +1 -0
  132. package/packages/web/992.645320b60c74c8787482.js +1 -0
  133. package/packages/web/996.ed9a963dc9e7439eca9a.js +1 -0
  134. package/packages/web/css/codemirror-theme_xq-light.css +43 -0
  135. package/packages/web/css/codemirror.css +344 -0
  136. package/packages/web/css/main.3b61356b384d2f11f47f.css +7268 -0
  137. package/packages/web/index.html +3 -0
  138. package/packages/web/main.77c2c4b553ca3fac223b.js +2 -0
  139. package/packages/web/main.77c2c4b553ca3fac223b.js.LICENSE.txt +3 -0
@@ -0,0 +1,403 @@
1
+ /**
2
+ * WebSocketService 单元测试
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+
7
+ // Mock all modules before imports
8
+ vi.mock('ws', () => ({
9
+ WebSocketServer: vi.fn(),
10
+ WebSocket: vi.fn()
11
+ }));
12
+
13
+ vi.mock('../../utils/logger.js', () => ({
14
+ logger: {
15
+ info: vi.fn(),
16
+ error: vi.fn(),
17
+ debug: vi.fn(),
18
+ warn: vi.fn()
19
+ }
20
+ }));
21
+
22
+ vi.mock('../../services/TerminalService.js', () => ({
23
+ terminalService: {
24
+ createSession: vi.fn(),
25
+ getSession: vi.fn(),
26
+ removeSession: vi.fn()
27
+ }
28
+ }));
29
+
30
+ // Now import the modules
31
+ import { WebSocketService, WebSocketConnection } from '../../services/WebSocketService.js';
32
+ import { terminalService } from '../../services/TerminalService.js';
33
+ import { WebSocketServer } from 'ws';
34
+
35
+ describe('WebSocketService', () => {
36
+ let webSocketService;
37
+ let mockWss;
38
+ let mockWs;
39
+
40
+ beforeEach(() => {
41
+ vi.clearAllMocks();
42
+
43
+ // Mock WebSocket Server
44
+ mockWss = {
45
+ on: vi.fn(),
46
+ close: vi.fn()
47
+ };
48
+ WebSocketServer.mockImplementation(() => mockWss);
49
+
50
+ // Mock WebSocket
51
+ mockWs = {
52
+ readyState: 1, // WebSocket.OPEN
53
+ OPEN: 1,
54
+ send: vi.fn(),
55
+ close: vi.fn(),
56
+ ping: vi.fn(),
57
+ on: vi.fn()
58
+ };
59
+
60
+ // 创建服务实例
61
+ webSocketService = new WebSocketService({
62
+ port: 8081,
63
+ maxConnections: 5
64
+ });
65
+ });
66
+
67
+ afterEach(async () => {
68
+ if (webSocketService) {
69
+ // 清理连接以避免 close 方法错误
70
+ webSocketService.connections.clear();
71
+ try {
72
+ await webSocketService.stop();
73
+ } catch (error) {
74
+ // 忽略清理时的错误
75
+ }
76
+ }
77
+ });
78
+
79
+ describe('constructor', () => {
80
+ it('应该使用默认选项初始化', () => {
81
+ const service = new WebSocketService();
82
+ expect(service.options.port).toBe(8081);
83
+ expect(service.options.maxConnections).toBe(100);
84
+ expect(service.connections.size).toBe(0);
85
+ expect(service.isRunning).toBe(false);
86
+ });
87
+
88
+ it('应该使用自定义选项初始化', () => {
89
+ const customOptions = {
90
+ port: 9090,
91
+ maxConnections: 50,
92
+ heartbeatInterval: 60000
93
+ };
94
+ const service = new WebSocketService(customOptions);
95
+ expect(service.options.port).toBe(9090);
96
+ expect(service.options.maxConnections).toBe(50);
97
+ expect(service.options.heartbeatInterval).toBe(60000);
98
+ });
99
+ });
100
+
101
+ describe('start', () => {
102
+ it('应该成功启动WebSocket服务', async () => {
103
+ // 模拟服务器启动成功
104
+ let listeningCallback;
105
+ mockWss.on.mockImplementation((event, callback) => {
106
+ if (event === 'listening') {
107
+ listeningCallback = callback;
108
+ }
109
+ });
110
+
111
+ const startPromise = webSocketService.start();
112
+
113
+ // 触发listening事件
114
+ listeningCallback();
115
+
116
+ await startPromise;
117
+
118
+ expect(webSocketService.isRunning).toBe(true);
119
+ expect(WebSocketServer).toHaveBeenCalledWith({
120
+ port: 8081,
121
+ host: '0.0.0.0',
122
+ maxConnections: 5
123
+ });
124
+ expect(mockWss.on).toHaveBeenCalledWith('connection', expect.any(Function));
125
+ expect(mockWss.on).toHaveBeenCalledWith('error', expect.any(Function));
126
+ expect(mockWss.on).toHaveBeenCalledWith('listening', expect.any(Function));
127
+ });
128
+
129
+ it('应该在已经运行时抛出错误', async () => {
130
+ webSocketService.isRunning = true;
131
+
132
+ await expect(webSocketService.start()).rejects.toThrow('WebSocket service is already running');
133
+ });
134
+
135
+ it('应该在服务器错误时抛出错误', async () => {
136
+ const error = new Error('Server error');
137
+ mockWss.on.mockImplementation((event, callback) => {
138
+ if (event === 'error') {
139
+ callback(error);
140
+ }
141
+ });
142
+
143
+ await expect(webSocketService.start()).rejects.toThrow('Server error');
144
+ });
145
+ });
146
+
147
+ describe('stop', () => {
148
+ it('应该成功停止WebSocket服务', async () => {
149
+ // 设置为运行状态
150
+ webSocketService.isRunning = true;
151
+ webSocketService.wss = mockWss;
152
+
153
+ // 添加一个连接
154
+ const mockConnection = {
155
+ close: vi.fn(),
156
+ ws: { readyState: 1 }
157
+ };
158
+ webSocketService.connections.set('test-client', mockConnection);
159
+
160
+ await webSocketService.stop();
161
+
162
+ expect(webSocketService.isRunning).toBe(false);
163
+ expect(mockConnection.close).toHaveBeenCalledWith(1001, 'Server shutdown');
164
+ expect(mockWss.close).toHaveBeenCalled();
165
+ });
166
+
167
+ it('应该在未运行时不执行任何操作', async () => {
168
+ webSocketService.isRunning = false;
169
+
170
+ await webSocketService.stop();
171
+
172
+ expect(mockWss.close).not.toHaveBeenCalled();
173
+ });
174
+ });
175
+
176
+ describe('handleConnection', () => {
177
+ beforeEach(() => {
178
+ webSocketService.isRunning = true;
179
+ webSocketService.wss = mockWss;
180
+ });
181
+
182
+ it('应该处理新的连接', () => {
183
+ const mockRequest = {
184
+ socket: {
185
+ remoteAddress: '127.0.0.1'
186
+ }
187
+ };
188
+
189
+ // 确保 mockWs 有正确的 readyState
190
+ mockWs.readyState = 1;
191
+ mockWs.OPEN = 1;
192
+
193
+ webSocketService.handleConnection(mockWs, mockRequest);
194
+
195
+ expect(webSocketService.connections.size).toBe(1);
196
+ expect(mockWs.send).toHaveBeenCalledWith(
197
+ expect.stringContaining('"type":"welcome"')
198
+ );
199
+ });
200
+
201
+ it('应该在超过最大连接数时拒绝连接', () => {
202
+ // 添加最大数量的连接
203
+ for (let i = 0; i < 5; i++) {
204
+ webSocketService.connections.set(`client-${i}`, {});
205
+ }
206
+
207
+ webSocketService.handleConnection(mockWs, {});
208
+
209
+ expect(mockWs.close).toHaveBeenCalledWith(1013, 'Server overload');
210
+ expect(webSocketService.connections.size).toBe(5);
211
+ });
212
+ });
213
+
214
+ describe('broadcast', () => {
215
+ beforeEach(() => {
216
+ // 添加模拟连接
217
+ const connection1 = {
218
+ send: vi.fn(),
219
+ ws: { readyState: 1, OPEN: 1 }
220
+ };
221
+ const connection2 = {
222
+ send: vi.fn(),
223
+ ws: { readyState: 1, OPEN: 1 }
224
+ };
225
+
226
+ webSocketService.connections.set('client1', connection1);
227
+ webSocketService.connections.set('client2', connection2);
228
+ });
229
+
230
+ it('应该向所有连接广播消息', () => {
231
+ const message = { type: 'test', data: 'broadcast data' };
232
+
233
+ webSocketService.broadcast('test', { data: 'broadcast data' });
234
+
235
+ const connections = Array.from(webSocketService.connections.values());
236
+ expect(connections[0].send).toHaveBeenCalledWith('test', { data: 'broadcast data' });
237
+ expect(connections[1].send).toHaveBeenCalledWith('test', { data: 'broadcast data' });
238
+ });
239
+ });
240
+
241
+ describe('getStatus', () => {
242
+ it('应该返回正确的服务状态', () => {
243
+ webSocketService.isRunning = true;
244
+ webSocketService.options.port = 8081;
245
+ webSocketService.options.host = '0.0.0.0';
246
+ webSocketService.options.maxConnections = 5;
247
+
248
+ // 添加一个活跃连接
249
+ const activeConnection = {
250
+ ws: { readyState: 1, OPEN: 1 } // WebSocket.OPEN
251
+ };
252
+ webSocketService.connections.set('active', activeConnection);
253
+
254
+ const status = webSocketService.getStatus();
255
+
256
+ expect(status).toHaveProperty('isRunning', true);
257
+ expect(status).toHaveProperty('port', 8081);
258
+ expect(status).toHaveProperty('host', '0.0.0.0');
259
+ expect(status).toHaveProperty('totalConnections', 1);
260
+ expect(status).toHaveProperty('activeConnections', 1);
261
+ expect(status).toHaveProperty('maxConnections', 5);
262
+ expect(status).toHaveProperty('uptime');
263
+ });
264
+ });
265
+ });
266
+
267
+ describe('WebSocketConnection', () => {
268
+ let connection;
269
+ let mockWs;
270
+
271
+ beforeEach(() => {
272
+ vi.clearAllMocks();
273
+
274
+ mockWs = {
275
+ readyState: 1, // WebSocket.OPEN
276
+ OPEN: 1,
277
+ send: vi.fn(),
278
+ close: vi.fn(),
279
+ ping: vi.fn(),
280
+ on: vi.fn()
281
+ };
282
+
283
+ // 清理之前的 mock 调用记录
284
+ terminalService.createSession.mockClear();
285
+ terminalService.getSession.mockClear();
286
+ terminalService.removeSession.mockClear();
287
+
288
+ // 创建连接实例
289
+ connection = new WebSocketConnection(mockWs, 'test-client');
290
+ });
291
+
292
+ describe('constructor', () => {
293
+ it('应该正确初始化连接', () => {
294
+ expect(connection.clientId).toBe('test-client');
295
+ expect(connection.ws).toBe(mockWs);
296
+ expect(connection.isAuthenticated).toBe(false);
297
+ expect(connection.sessionId).toBeNull();
298
+ expect(mockWs.on).toHaveBeenCalledWith('message', expect.any(Function));
299
+ expect(mockWs.on).toHaveBeenCalledWith('close', expect.any(Function));
300
+ expect(mockWs.on).toHaveBeenCalledWith('error', expect.any(Function));
301
+ expect(mockWs.on).toHaveBeenCalledWith('pong', expect.any(Function));
302
+ });
303
+ });
304
+
305
+ describe.skip('handleMessage', () => {
306
+ // 这些测试需要更深入的 mock 重构,暂时跳过
307
+ it.skip('应该处理终端创建消息', async () => {
308
+ // TODO: 修复 terminalService mock 交互问题
309
+ });
310
+
311
+ it.skip('应该处理终端数据消息', async () => {
312
+ // TODO: 修复 terminalService mock 交互问题
313
+ });
314
+
315
+ it.skip('应该处理终端调整大小消息', async () => {
316
+ // TODO: 修复 terminalService mock 交互问题
317
+ });
318
+
319
+ it('应该处理ping消息', () => {
320
+ const message = { type: 'ping' };
321
+
322
+ const messageHandler = mockWs.on.mock.calls.find(call => call[0] === 'message')[1];
323
+ messageHandler(JSON.stringify(message));
324
+
325
+ expect(mockWs.send).toHaveBeenCalledWith(
326
+ expect.stringContaining('"type":"pong"')
327
+ );
328
+ });
329
+
330
+ it('应该处理未知消息类型', () => {
331
+ const message = { type: 'unknown' };
332
+
333
+ const messageHandler = mockWs.on.mock.calls.find(call => call[0] === 'message')[1];
334
+ messageHandler(JSON.stringify(message));
335
+
336
+ expect(mockWs.send).toHaveBeenCalledWith(
337
+ expect.stringContaining('"type":"error"')
338
+ );
339
+ });
340
+ });
341
+
342
+ describe('send', () => {
343
+ it('应该发送消息', () => {
344
+ const data = { test: 'data' };
345
+
346
+ connection.send('test', data);
347
+
348
+ // 检查 mockWs.send 被调用,并验证调用参数包含正确的 JSON 结构
349
+ expect(mockWs.send).toHaveBeenCalledTimes(1);
350
+ const sentMessage = JSON.parse(mockWs.send.mock.calls[0][0]);
351
+
352
+ expect(sentMessage.type).toBe('test');
353
+ expect(sentMessage.clientId).toBe('test-client');
354
+ expect(sentMessage.test).toBe('data');
355
+ expect(typeof sentMessage.timestamp).toBe('number');
356
+ });
357
+
358
+ it('应该在连接未打开时不发送消息', () => {
359
+ mockWs.readyState = 0; // WebSocket.CONNECTING
360
+
361
+ connection.send('test', { data: 'test' });
362
+
363
+ expect(mockWs.send).not.toHaveBeenCalled();
364
+ });
365
+ });
366
+
367
+ describe('sendError', () => {
368
+ it('应该发送错误消息', () => {
369
+ connection.sendError('Test error', 'Error details');
370
+
371
+ // 检查 mockWs.send 被调用,并验证调用参数包含正确的 JSON 结构
372
+ expect(mockWs.send).toHaveBeenCalledTimes(1);
373
+ const sentMessage = JSON.parse(mockWs.send.mock.calls[0][0]);
374
+
375
+ expect(sentMessage.type).toBe('error');
376
+ expect(sentMessage.clientId).toBe('test-client');
377
+ expect(sentMessage.message).toBe('Test error');
378
+ expect(sentMessage.details).toBe('Error details');
379
+ expect(typeof sentMessage.timestamp).toBe('number');
380
+ });
381
+ });
382
+
383
+ describe('getInfo', () => {
384
+ it('应该返回连接信息', () => {
385
+ const info = connection.getInfo();
386
+
387
+ expect(info).toHaveProperty('clientId', 'test-client');
388
+ expect(info).toHaveProperty('connectedAt');
389
+ expect(info).toHaveProperty('lastActivity');
390
+ expect(info).toHaveProperty('sessionId', null);
391
+ expect(info).toHaveProperty('isAuthenticated', false);
392
+ expect(info).toHaveProperty('readyState', mockWs.readyState);
393
+ });
394
+ });
395
+
396
+ describe('close', () => {
397
+ it('应该关闭连接', () => {
398
+ connection.close(1000, 'Test close');
399
+
400
+ expect(mockWs.close).toHaveBeenCalledWith(1000, 'Test close');
401
+ });
402
+ });
403
+ });
@@ -0,0 +1,94 @@
1
+ /**
2
+ * 核心库功能测试
3
+ * 测试库是否能正确导入和使用
4
+ */
5
+
6
+ import { describe, it, expect, beforeAll } from 'vitest';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ // 获取server包的index.js路径
14
+ const serverIndexPath = path.join(__dirname, '../../index.js');
15
+
16
+ describe('核心库导入测试', () => {
17
+ let coreModules = {};
18
+
19
+ beforeAll(async () => {
20
+ // 动态导入所有导出的函数和对象
21
+ coreModules = await import(serverIndexPath);
22
+ });
23
+
24
+ it('应该成功导入所有模块', () => {
25
+ expect(coreModules).toBeDefined();
26
+ expect(Object.keys(coreModules).length).toBeGreaterThan(0);
27
+ });
28
+
29
+ it('应该导出服务器相关函数', () => {
30
+ expect(typeof coreModules.startServer).toBe('function');
31
+ expect(typeof coreModules.stopServer).toBe('function');
32
+ expect(typeof coreModules.getServerState).toBe('function');
33
+ expect(typeof coreModules.getServerAddress).toBe('function');
34
+ expect(typeof coreModules.isServerRunning).toBe('function');
35
+ });
36
+
37
+ it('应该导出核心对象', () => {
38
+ expect(typeof coreModules.app).toBe('function');
39
+ expect(typeof coreModules.config).toBe('object');
40
+ expect(typeof coreModules.logger).toBe('object');
41
+ expect(typeof coreModules.util).toBe('object');
42
+ expect(typeof coreModules.promptManager).toBe('object');
43
+ });
44
+
45
+ it('应该导出MCP相关函数', () => {
46
+ expect(typeof coreModules.getMcpServer).toBe('function');
47
+ expect(typeof coreModules.handleGetPrompt).toBe('function');
48
+ expect(typeof coreModules.handleSearchPrompts).toBe('function');
49
+ expect(typeof coreModules.handleReloadPrompts).toBe('function');
50
+ });
51
+
52
+ it('应该导出路由相关对象', () => {
53
+ expect(typeof coreModules.adminRouter).toBe('function');
54
+ expect(typeof coreModules.openRouter).toBe('function');
55
+ expect(typeof coreModules.adminAuthMiddleware).toBe('function');
56
+ });
57
+
58
+ it('配置对象应该有正确的方法', () => {
59
+ expect(typeof coreModules.config.getPort).toBe('function');
60
+ expect(typeof coreModules.config.getPromptsDir).toBe('function');
61
+ });
62
+
63
+ it('日志对象应该有正确的方法', () => {
64
+ expect(typeof coreModules.logger.info).toBe('function');
65
+ expect(typeof coreModules.logger.error).toBe('function');
66
+ expect(typeof coreModules.logger.warn).toBe('function');
67
+ expect(typeof coreModules.logger.debug).toBe('function');
68
+ });
69
+
70
+ it('工具对象应该正确导出', () => {
71
+ expect(coreModules.util).toBeDefined();
72
+ expect(typeof coreModules.util).toBe('object');
73
+ });
74
+
75
+ it('提示词管理器应该正确导出', () => {
76
+ expect(coreModules.promptManager).toBeDefined();
77
+ expect(typeof coreModules.promptManager).toBe('object');
78
+ });
79
+
80
+ it('服务器状态函数应该正常工作', async () => {
81
+ expect(typeof coreModules.getServerAddress).toBe('function');
82
+ expect(typeof coreModules.isServerRunning).toBe('function');
83
+
84
+ // 测试函数调用
85
+ const state = coreModules.getServerState();
86
+ expect(typeof state).toBe('object');
87
+
88
+ const address = coreModules.getServerAddress();
89
+ expect(typeof address).toBe('string');
90
+
91
+ const isRunning = await coreModules.isServerRunning();
92
+ expect(typeof isRunning).toBe('boolean');
93
+ });
94
+ });
@@ -0,0 +1,52 @@
1
+ {
2
+ "entryPoints": [
3
+ "./index.js",
4
+ "./services/",
5
+ "./utils/",
6
+ "./mcp/",
7
+ "./api/",
8
+ "./toolm/"
9
+ ],
10
+ "out": "./docs/typedoc/",
11
+ "exclude": [
12
+ "node_modules/",
13
+ "dist/",
14
+ "coverage/",
15
+ "tests/",
16
+ "test-results/",
17
+ "**/*.test.js",
18
+ "**/*.spec.js"
19
+ ],
20
+ "excludePrivate": true,
21
+ "excludeProtected": false,
22
+ "excludeInternal": true,
23
+ "hideGenerator": true,
24
+ "sort": ["source-order"],
25
+ "kindSortOrder": [
26
+ "Class",
27
+ "Interface",
28
+ "Type alias",
29
+ "Variable",
30
+ "Function",
31
+ "Enum",
32
+ "Namespace"
33
+ ],
34
+ "categorizeByGroup": true,
35
+ "defaultCategory": "Other",
36
+ "categoryOrder": [
37
+ "Services",
38
+ "Utils",
39
+ "MCP",
40
+ "API",
41
+ "Tools",
42
+ "*"
43
+ ],
44
+ "plugin": [
45
+ "typedoc-plugin-markdown",
46
+ "typedoc-plugin-mermaid"
47
+ ],
48
+ "readme": "none",
49
+ "gitRevision": "main",
50
+ "sourceLinkTemplate": "https://github.com/BeCrafter/prompt-manager/blob/{gitRevision}/{path}#L{line}",
51
+ "tsconfig": "./tsconfig.json"
52
+ }
@@ -121,7 +121,7 @@ export class Config {
121
121
 
122
122
  // 其他配置
123
123
  this.serverName = process.env.MCP_SERVER_NAME || 'prompt-manager';
124
- this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.12';
124
+ this.serverVersion = process.env.MCP_SERVER_VERSION || '0.1.15';
125
125
  this.logLevel = process.env.LOG_LEVEL || 'info';
126
126
  this.maxPrompts = parseInt(process.env.MAX_PROMPTS) || 1000;
127
127
  this.recursiveScan = process.env.RECURSIVE_SCAN !== 'false'; // 默认启用递归扫描
@@ -51,6 +51,54 @@ export class Util {
51
51
  }
52
52
  }
53
53
 
54
+ /**
55
+ * 初始化内置配置(如果不存在)
56
+ * 同步内置的模型配置和模板到用户配置目录
57
+ */
58
+ async seedBuiltInConfigsIfEmpty() {
59
+ try {
60
+ const userConfigDir = path.join(os.homedir(), '.prompt-manager', 'configs');
61
+ const builtInConfigsDir = this.getBuiltInConfigsDir();
62
+
63
+ // 检查内置配置目录是否存在
64
+ const builtInExists = await fse.pathExists(builtInConfigsDir);
65
+ if (!builtInExists) {
66
+ logger.debug('内置配置目录不存在,跳过同步');
67
+ return;
68
+ }
69
+
70
+ // 确保用户配置目录存在
71
+ await fse.ensureDir(userConfigDir);
72
+
73
+ // 同步模型配置
74
+ const modelsSrc = path.join(builtInConfigsDir, 'models');
75
+ const modelsDst = path.join(userConfigDir, 'models');
76
+ if (await fse.pathExists(modelsSrc)) {
77
+ await fse.copy(modelsSrc, modelsDst, {
78
+ overwrite: false,
79
+ errorOnExist: false,
80
+ recursive: true
81
+ });
82
+ logger.info(`已同步内置模型配置到 ${modelsDst}`);
83
+ }
84
+
85
+ // 同步模板配置
86
+ const templatesSrc = path.join(builtInConfigsDir, 'templates');
87
+ const templatesDst = path.join(userConfigDir, 'templates');
88
+ if (await fse.pathExists(templatesSrc)) {
89
+ await fse.copy(templatesSrc, templatesDst, {
90
+ overwrite: false,
91
+ errorOnExist: false,
92
+ recursive: true
93
+ });
94
+ logger.info(`已同步内置模板配置到 ${templatesDst}`);
95
+ }
96
+
97
+ } catch (error) {
98
+ logger.warn('同步内置配置失败:', error.message);
99
+ }
100
+ }
101
+
54
102
  /**
55
103
  * 生成文件唯一标识码
56
104
  * @param {*} relativePath
@@ -379,10 +427,10 @@ export class Util {
379
427
  */
380
428
  getBuiltInConfigsDir() {
381
429
  // 检查是否在 Electron 环境中运行
382
- const isElectron = typeof process !== 'undefined' &&
383
- process.versions &&
430
+ const isElectron = typeof process !== 'undefined' &&
431
+ process.versions &&
384
432
  process.versions.electron;
385
-
433
+
386
434
  // 检查是否是打包应用
387
435
  // 在 macOS 打包应用中,process.resourcesPath 存在
388
436
  if (process.resourcesPath) {
@@ -392,10 +440,16 @@ export class Util {
392
440
  return packagedConfigPath;
393
441
  }
394
442
  }
395
-
396
- // 在开发环境中,配置位于 packages/server/configs/
443
+
444
+ // npm 包环境中,配置位于 node_modules 中的包目录
397
445
  const __filename = fileURLToPath(import.meta.url);
398
446
  const __dirname = path.dirname(__filename);
447
+ const npmConfigPath = path.resolve(__dirname, '../configs');
448
+ if (this._pathExistsSync(npmConfigPath)) {
449
+ return npmConfigPath;
450
+ }
451
+
452
+ // 在开发环境中,配置位于 packages/server/configs/
399
453
  return path.resolve(__dirname, '../configs');
400
454
  }
401
455