@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,410 @@
1
+ /**
2
+ * TerminalService 单元测试
3
+ */
4
+
5
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
6
+ import { TerminalService, TerminalSession } from '../../services/TerminalService.js';
7
+ import pty from 'node-pty';
8
+
9
+ describe('TerminalService', () => {
10
+ let terminalService;
11
+
12
+ beforeEach(() => {
13
+ // 重置mock
14
+ vi.clearAllMocks();
15
+
16
+ // 创建新的服务实例
17
+ terminalService = new TerminalService({
18
+ maxSessions: 5,
19
+ timeout: 60000
20
+ });
21
+ });
22
+
23
+ afterEach(async () => {
24
+ // 清理服务
25
+ if (terminalService) {
26
+ await terminalService.shutdown();
27
+ }
28
+ });
29
+
30
+ describe('constructor', () => {
31
+ it('应该使用默认选项初始化', () => {
32
+ const service = new TerminalService();
33
+ expect(service.defaultOptions.maxSessions).toBe(10);
34
+ expect(service.defaultOptions.timeout).toBe(300000);
35
+ expect(service.sessions.size).toBe(0);
36
+ });
37
+
38
+ it('应该使用自定义选项初始化', () => {
39
+ const customOptions = {
40
+ maxSessions: 20,
41
+ timeout: 60000,
42
+ workingDirectory: '/custom/path'
43
+ };
44
+ const service = new TerminalService(customOptions);
45
+ expect(service.defaultOptions.maxSessions).toBe(20);
46
+ expect(service.defaultOptions.timeout).toBe(60000);
47
+ expect(service.defaultOptions.workingDirectory).toBe('/custom/path');
48
+ });
49
+ });
50
+
51
+ describe('createSession', () => {
52
+ it('应该成功创建新的终端会话', async () => {
53
+ // Mock PTY进程
54
+ const mockPty = {
55
+ on: vi.fn(),
56
+ write: vi.fn(),
57
+ resize: vi.fn(),
58
+ kill: vi.fn()
59
+ };
60
+ pty.spawn.mockReturnValue(mockPty);
61
+
62
+ const session = await terminalService.createSession();
63
+
64
+ expect(session).toBeDefined();
65
+ expect(session.id).toBeDefined();
66
+ expect(session.pty).toBe(mockPty);
67
+ expect(terminalService.sessions.has(session.id)).toBe(true);
68
+ expect(pty.spawn).toHaveBeenCalledWith(
69
+ expect.any(String),
70
+ expect.any(Array),
71
+ expect.objectContaining({
72
+ cols: 80,
73
+ rows: 24
74
+ })
75
+ );
76
+ });
77
+
78
+ it('应该使用自定义选项创建会话', async () => {
79
+ const mockPty = {
80
+ on: vi.fn(),
81
+ write: vi.fn(),
82
+ resize: vi.fn(),
83
+ kill: vi.fn()
84
+ };
85
+ pty.spawn.mockReturnValue(mockPty);
86
+
87
+ const options = {
88
+ size: { cols: 120, rows: 30 },
89
+ workingDirectory: '/custom/path',
90
+ shell: '/bin/bash'
91
+ };
92
+
93
+ const session = await terminalService.createSession(options);
94
+
95
+ expect(session.size).toEqual({ cols: 120, rows: 30 });
96
+ expect(session.workingDirectory).toBe('/custom/path');
97
+ expect(pty.spawn).toHaveBeenCalledWith(
98
+ '/bin/bash',
99
+ expect.any(Array),
100
+ expect.objectContaining({
101
+ cols: 120,
102
+ rows: 30,
103
+ cwd: '/custom/path'
104
+ })
105
+ );
106
+ });
107
+
108
+ it('应该在超过最大会话数时抛出错误', async () => {
109
+ const mockPty = {
110
+ on: vi.fn(),
111
+ write: vi.fn(),
112
+ resize: vi.fn(),
113
+ kill: vi.fn()
114
+ };
115
+ pty.spawn.mockReturnValue(mockPty);
116
+
117
+ // 创建最大数量的会话
118
+ for (let i = 0; i < 5; i++) {
119
+ await terminalService.createSession();
120
+ }
121
+
122
+ // 尝试创建超出限制的会话
123
+ await expect(terminalService.createSession()).rejects.toThrow('Maximum sessions limit reached');
124
+ });
125
+
126
+ it('应该在PTY创建失败时抛出错误', async () => {
127
+ pty.spawn.mockImplementation(() => {
128
+ throw new Error('PTY creation failed');
129
+ });
130
+
131
+ await expect(terminalService.createSession()).rejects.toThrow('PTY creation failed');
132
+ });
133
+ });
134
+
135
+ describe('getSession', () => {
136
+ it('应该返回存在的会话', async () => {
137
+ const mockPty = {
138
+ on: vi.fn(),
139
+ write: vi.fn(),
140
+ resize: vi.fn(),
141
+ kill: vi.fn()
142
+ };
143
+ pty.spawn.mockReturnValue(mockPty);
144
+
145
+ const session = await terminalService.createSession();
146
+ const retrievedSession = terminalService.getSession(session.id);
147
+
148
+ expect(retrievedSession).toBe(session);
149
+ });
150
+
151
+ it('应该返回undefined对于不存在的会话', () => {
152
+ const session = terminalService.getSession('non-existent-id');
153
+ expect(session).toBeUndefined();
154
+ });
155
+ });
156
+
157
+ describe('getAllSessions', () => {
158
+ it('应该返回所有会话', async () => {
159
+ const mockPty = {
160
+ on: vi.fn(),
161
+ write: vi.fn(),
162
+ resize: vi.fn(),
163
+ kill: vi.fn()
164
+ };
165
+ pty.spawn.mockReturnValue(mockPty);
166
+
167
+ const session1 = await terminalService.createSession();
168
+ const session2 = await terminalService.createSession();
169
+
170
+ const allSessions = terminalService.getAllSessions();
171
+ expect(allSessions).toHaveLength(2);
172
+ expect(allSessions).toContain(session1);
173
+ expect(allSessions).toContain(session2);
174
+ });
175
+
176
+ it('应该返回空数组当没有会话时', () => {
177
+ const allSessions = terminalService.getAllSessions();
178
+ expect(allSessions).toHaveLength(0);
179
+ });
180
+ });
181
+
182
+ describe('removeSession', () => {
183
+ it('应该成功移除存在的会话', async () => {
184
+ const mockPty = {
185
+ on: vi.fn(),
186
+ write: vi.fn(),
187
+ resize: vi.fn(),
188
+ kill: vi.fn()
189
+ };
190
+ pty.spawn.mockReturnValue(mockPty);
191
+
192
+ const session = await terminalService.createSession();
193
+ const result = await terminalService.removeSession(session.id);
194
+
195
+ expect(result).toBe(true);
196
+ expect(terminalService.sessions.has(session.id)).toBe(false);
197
+ expect(mockPty.kill).toHaveBeenCalled();
198
+ });
199
+
200
+ it('应该返回false对于不存在的会话', async () => {
201
+ const result = await terminalService.removeSession('non-existent-id');
202
+ expect(result).toBe(false);
203
+ });
204
+ });
205
+
206
+ describe('executeCommand', () => {
207
+ it('应该成功执行命令', async () => {
208
+ const result = await terminalService.executeCommand('echo "test"');
209
+
210
+ expect(result).toBeDefined();
211
+ expect(typeof result.exitCode).toBe('number');
212
+ expect(typeof result.stdout).toBe('string');
213
+ expect(typeof result.stderr).toBe('string');
214
+ });
215
+
216
+ it('应该支持自定义工作目录', async () => {
217
+ const options = {
218
+ workingDirectory: '/tmp'
219
+ };
220
+
221
+ // 这里我们只验证调用了正确的参数,实际执行结果取决于系统环境
222
+ await terminalService.executeCommand('pwd', options);
223
+ // 由于使用了真实的spawn,我们主要验证不会抛出错误
224
+ });
225
+
226
+ it('应该支持超时设置', async () => {
227
+ const options = {
228
+ timeout: 1000
229
+ };
230
+
231
+ // 执行一个长时间运行的命令
232
+ const promise = terminalService.executeCommand('sleep 2', options);
233
+
234
+ await expect(promise).rejects.toThrow('Command execution timeout');
235
+ });
236
+ });
237
+
238
+ describe('getStatus', () => {
239
+ it('应该返回正确的服务状态', () => {
240
+ const status = terminalService.getStatus();
241
+
242
+ expect(status).toHaveProperty('totalSessions');
243
+ expect(status).toHaveProperty('activeSessions');
244
+ expect(status).toHaveProperty('maxSessions');
245
+ expect(status).toHaveProperty('uptime');
246
+ expect(status).toHaveProperty('platform');
247
+ expect(status).toHaveProperty('nodeVersion');
248
+ expect(status.totalSessions).toBe(0);
249
+ expect(status.activeSessions).toBe(0);
250
+ expect(status.maxSessions).toBe(5);
251
+ });
252
+ });
253
+
254
+ describe('cleanupInactiveSessions', () => {
255
+ it('应该清理非活跃会话', async () => {
256
+ const mockPty = {
257
+ on: vi.fn(),
258
+ write: vi.fn(),
259
+ resize: vi.fn(),
260
+ kill: vi.fn()
261
+ };
262
+ pty.spawn.mockReturnValue(mockPty);
263
+
264
+ // 创建会话
265
+ const session = await terminalService.createSession();
266
+ expect(terminalService.sessions.size).toBe(1);
267
+
268
+ // 手动设置会话为非活跃状态
269
+ session.isActive = false;
270
+ session.lastActivity = new Date(Date.now() - 40000); // 超过超时时间
271
+
272
+ // 手动调用清理方法
273
+ terminalService.cleanupInactiveSessions();
274
+
275
+ expect(terminalService.sessions.size).toBe(0);
276
+ });
277
+ });
278
+
279
+ describe('shutdown', () => {
280
+ it('应该关闭所有会话并停止服务', async () => {
281
+ const mockPty = {
282
+ on: vi.fn(),
283
+ write: vi.fn(),
284
+ resize: vi.fn(),
285
+ kill: vi.fn()
286
+ };
287
+ pty.spawn.mockReturnValue(mockPty);
288
+
289
+ // 创建多个会话
290
+ await terminalService.createSession();
291
+ await terminalService.createSession();
292
+
293
+ expect(terminalService.sessions.size).toBe(2);
294
+
295
+ await terminalService.shutdown();
296
+
297
+ expect(terminalService.sessions.size).toBe(0);
298
+ expect(mockPty.kill).toHaveBeenCalledTimes(2);
299
+ });
300
+ });
301
+ });
302
+
303
+ describe('TerminalSession', () => {
304
+ let mockPty;
305
+ let session;
306
+
307
+ beforeEach(() => {
308
+ mockPty = {
309
+ on: vi.fn(),
310
+ write: vi.fn(),
311
+ resize: vi.fn(),
312
+ kill: vi.fn()
313
+ };
314
+
315
+ session = new TerminalSession('test-session', mockPty, {
316
+ workingDirectory: '/test/path',
317
+ size: { cols: 100, rows: 25 }
318
+ });
319
+ });
320
+
321
+ afterEach(() => {
322
+ if (session) {
323
+ session.terminate();
324
+ }
325
+ });
326
+
327
+ describe('constructor', () => {
328
+ it('应该正确初始化会话', () => {
329
+ expect(session.id).toBe('test-session');
330
+ expect(session.pty).toBe(mockPty);
331
+ expect(session.workingDirectory).toBe('/test/path');
332
+ expect(session.size).toEqual({ cols: 100, rows: 25 });
333
+ expect(session.isActive).toBe(true);
334
+ expect(mockPty.on).toHaveBeenCalledWith('data', expect.any(Function));
335
+ expect(mockPty.on).toHaveBeenCalledWith('exit', expect.any(Function));
336
+ });
337
+ });
338
+
339
+ describe('write', () => {
340
+ it('应该向PTY写入数据', () => {
341
+ session.write('test command\n');
342
+ expect(mockPty.write).toHaveBeenCalledWith('test command\n');
343
+ });
344
+
345
+ it('应该在非活跃会话时抛出错误', () => {
346
+ session.isActive = false;
347
+ expect(() => session.write('test')).toThrow('Terminal session is not active');
348
+ });
349
+ });
350
+
351
+ describe('resize', () => {
352
+ it('应该调整PTY大小', () => {
353
+ session.resize(120, 30);
354
+ expect(mockPty.resize).toHaveBeenCalledWith(120, 30);
355
+ expect(session.size).toEqual({ cols: 120, rows: 30 });
356
+ });
357
+
358
+ it('应该在非活跃会话时抛出错误', () => {
359
+ session.isActive = false;
360
+ expect(() => session.resize(120, 30)).toThrow('Terminal session is not active');
361
+ });
362
+ });
363
+
364
+ describe('terminate', () => {
365
+ it('应该终止PTY进程', () => {
366
+ session.terminate();
367
+ expect(mockPty.kill).toHaveBeenCalled();
368
+ expect(session.isActive).toBe(false);
369
+ });
370
+ });
371
+
372
+ describe('getInfo', () => {
373
+ it('应该返回会话信息', () => {
374
+ const info = session.getInfo();
375
+
376
+ expect(info).toHaveProperty('id', 'test-session');
377
+ expect(info).toHaveProperty('workingDirectory', '/test/path');
378
+ expect(info).toHaveProperty('size');
379
+ expect(info).toHaveProperty('isActive', true);
380
+ expect(info).toHaveProperty('createdAt');
381
+ expect(info).toHaveProperty('lastActivity');
382
+ });
383
+ });
384
+
385
+ describe('事件处理', () => {
386
+ it('应该处理数据事件', () => {
387
+ const dataCallback = vi.fn();
388
+ session.on('data', dataCallback);
389
+
390
+ // 模拟PTY数据事件
391
+ const dataHandler = mockPty.on.mock.calls.find(call => call[0] === 'data')[1];
392
+ dataHandler('test data');
393
+
394
+ expect(dataCallback).toHaveBeenCalledWith('test data');
395
+ expect(session.lastActivity).toBeInstanceOf(Date);
396
+ });
397
+
398
+ it('应该处理退出事件', () => {
399
+ const exitCallback = vi.fn();
400
+ session.on('exit', exitCallback);
401
+
402
+ // 模拟PTY退出事件
403
+ const exitHandler = mockPty.on.mock.calls.find(call => call[0] === 'exit')[1];
404
+ exitHandler(0, 'SIGTERM');
405
+
406
+ expect(exitCallback).toHaveBeenCalledWith({ exitCode: 0, signal: 'SIGTERM' });
407
+ expect(session.isActive).toBe(false);
408
+ });
409
+ });
410
+ });