@becrafter/prompt-manager 0.1.22 → 0.2.2

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 (114) hide show
  1. package/package.json +31 -24
  2. package/packages/resources/tools/agent-browser/README.md +640 -0
  3. package/packages/resources/tools/agent-browser/agent-browser.tool.js +1389 -0
  4. package/packages/resources/tools/thinking/README.md +324 -0
  5. package/packages/resources/tools/thinking/thinking.tool.js +911 -0
  6. package/packages/server/README.md +3 -4
  7. package/packages/server/api/admin.routes.js +668 -664
  8. package/packages/server/api/open.routes.js +68 -67
  9. package/packages/server/api/surge.routes.js +5 -6
  10. package/packages/server/api/tool.routes.js +70 -71
  11. package/packages/server/app.js +70 -73
  12. package/packages/server/configs/authors.json +40 -0
  13. package/packages/server/configs/models/built-in/bigmodel.yaml +6 -6
  14. package/packages/server/configs/models/providers.yaml +4 -4
  15. package/packages/server/configs/templates/built-in/general-iteration.yaml +1 -1
  16. package/packages/server/configs/templates/built-in/general-optimize.yaml +1 -1
  17. package/packages/server/configs/templates/built-in/output-format-optimize.yaml +1 -1
  18. package/packages/server/index.js +3 -9
  19. package/packages/server/mcp/heartbeat-patch.js +1 -3
  20. package/packages/server/mcp/mcp.server.js +64 -134
  21. package/packages/server/mcp/prompt.handler.js +101 -95
  22. package/packages/server/middlewares/auth.middleware.js +31 -31
  23. package/packages/server/server.js +60 -45
  24. package/packages/server/services/TerminalService.js +156 -70
  25. package/packages/server/services/WebSocketService.js +35 -34
  26. package/packages/server/services/author-config.service.js +199 -0
  27. package/packages/server/services/manager.js +66 -60
  28. package/packages/server/services/model.service.js +5 -9
  29. package/packages/server/services/optimization.service.js +25 -22
  30. package/packages/server/services/template.service.js +3 -8
  31. package/packages/server/toolm/author-sync.service.js +97 -0
  32. package/packages/server/toolm/index.js +1 -2
  33. package/packages/server/toolm/package-installer.service.js +47 -50
  34. package/packages/server/toolm/tool-context.service.js +64 -62
  35. package/packages/server/toolm/tool-dependency.service.js +28 -30
  36. package/packages/server/toolm/tool-description-generator-optimized.service.js +55 -55
  37. package/packages/server/toolm/tool-description-generator.service.js +20 -23
  38. package/packages/server/toolm/tool-environment.service.js +45 -44
  39. package/packages/server/toolm/tool-execution.service.js +49 -48
  40. package/packages/server/toolm/tool-loader.service.js +13 -18
  41. package/packages/server/toolm/tool-logger.service.js +33 -39
  42. package/packages/server/toolm/tool-manager.handler.js +17 -15
  43. package/packages/server/toolm/tool-manual-generator.service.js +107 -87
  44. package/packages/server/toolm/tool-mode-handlers.service.js +52 -59
  45. package/packages/server/toolm/tool-storage.service.js +11 -12
  46. package/packages/server/toolm/tool-sync.service.js +36 -39
  47. package/packages/server/toolm/tool-utils.js +0 -1
  48. package/packages/server/toolm/tool-yaml-parser.service.js +12 -11
  49. package/packages/server/toolm/validate-system.js +56 -84
  50. package/packages/server/utils/config.js +97 -12
  51. package/packages/server/utils/logger.js +1 -1
  52. package/packages/server/utils/port-checker.js +8 -8
  53. package/packages/server/utils/util.js +470 -467
  54. package/packages/resources/tools/cognitive-thinking/README.md +0 -284
  55. package/packages/resources/tools/cognitive-thinking/cognitive-thinking.tool.js +0 -837
  56. package/packages/server/mcp/sequential-thinking.handler.js +0 -318
  57. package/packages/server/mcp/think-plan.handler.js +0 -274
  58. package/packages/server/mcp/thinking-toolkit.handler.js +0 -380
  59. package/packages/web/0.d1c5a72339dfc32ad86a.js +0 -1
  60. package/packages/web/112.8807b976372b2b0541a8.js +0 -1
  61. package/packages/web/130.584c7e365da413f5d9be.js +0 -1
  62. package/packages/web/142.72c985bc29720f975cca.js +0 -1
  63. package/packages/web/165.a05fc53bf84d18db36b8.js +0 -2
  64. package/packages/web/165.a05fc53bf84d18db36b8.js.LICENSE.txt +0 -9
  65. package/packages/web/203.724ab9f717b80554c397.js +0 -1
  66. package/packages/web/241.bf941d4f02866795f64a.js +0 -1
  67. package/packages/web/249.54cfb224af63f5f5ec55.js +0 -1
  68. package/packages/web/291.6df35042f8f296fca7cd.js +0 -1
  69. package/packages/web/319.2fab900a31b29873f666.js +0 -1
  70. package/packages/web/32.c78d866281995ec33a7b.js +0 -1
  71. package/packages/web/325.9ca297d0f73f38468ce9.js +0 -1
  72. package/packages/web/366.2f9b48fdbf8eee039e57.js +0 -1
  73. package/packages/web/378.6be08c612cd5a3ef97dc.js +0 -1
  74. package/packages/web/393.7a2f817515c5e90623d7.js +0 -1
  75. package/packages/web/412.062df5f732d5ba203415.js +0 -1
  76. package/packages/web/426.08656fef4918b3fb19ad.js +0 -1
  77. package/packages/web/465.2be8018327130a3bd798.js +0 -1
  78. package/packages/web/48.8ca96fc93667a715e67a.js +0 -1
  79. package/packages/web/480.44c1f1a2927486ac3d4f.js +0 -1
  80. package/packages/web/489.e041a8d0db15dc96d607.js +0 -1
  81. package/packages/web/490.9ffb26c907de020d671b.js +0 -1
  82. package/packages/web/492.58781369e348d91fc06a.js +0 -1
  83. package/packages/web/495.ed63e99791a87167c6b3.js +0 -1
  84. package/packages/web/510.4cc07ab7d30d5c1cd17f.js +0 -1
  85. package/packages/web/543.3af155ed4fa237664308.js +0 -1
  86. package/packages/web/567.f04ab60f8e2c2fb0745a.js +0 -1
  87. package/packages/web/592.f3ad085fa9c1849daa06.js +0 -1
  88. package/packages/web/616.b03fb801b3433b17750f.js +0 -1
  89. package/packages/web/617.d88def54921d2c4dc44c.js +0 -1
  90. package/packages/web/641.d30787d674f548928261.js +0 -1
  91. package/packages/web/672.5269c8399fa42a5af95d.js +0 -1
  92. package/packages/web/731.97cab92b71811c502bda.js +0 -1
  93. package/packages/web/746.3947c6f0235407e420fb.js +0 -1
  94. package/packages/web/756.a53233b3f3913900d5ac.js +0 -1
  95. package/packages/web/77.68801af593a28a631fbf.js +0 -1
  96. package/packages/web/802.53b2bff3cf2a69f7b80c.js +0 -1
  97. package/packages/web/815.b6dfab82265f56c7e046.js +0 -1
  98. package/packages/web/821.f5a13e5c735aac244eb9.js +0 -1
  99. package/packages/web/846.b9bf97d5f559270675ce.js +0 -1
  100. package/packages/web/869.7c10403f500e6201407f.js +0 -1
  101. package/packages/web/885.135050364f99e6924fb5.js +0 -1
  102. package/packages/web/901.fd5aeb9df630609a2b43.js +0 -1
  103. package/packages/web/928.f67e590de3caa4daa3ae.js +0 -1
  104. package/packages/web/955.d833403521ba4dd567ee.js +0 -1
  105. package/packages/web/981.a45cb745cf424044c8c8.js +0 -1
  106. package/packages/web/992.645320b60c74c8787482.js +0 -1
  107. package/packages/web/996.ed9a963dc9e7439eca9a.js +0 -1
  108. package/packages/web/css/codemirror-theme_xq-light.css +0 -43
  109. package/packages/web/css/codemirror.css +0 -344
  110. package/packages/web/css/main.196f434e6a88cd448158.css +0 -7278
  111. package/packages/web/css/terminal-fix.css +0 -571
  112. package/packages/web/index.html +0 -3
  113. package/packages/web/main.dceff50c7307dda04873.js +0 -2
  114. package/packages/web/main.dceff50c7307dda04873.js.LICENSE.txt +0 -3
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * TerminalService - 终端服务管理类
3
- *
3
+ *
4
4
  * 提供跨平台终端会话管理,支持PTY(伪终端)和实时交互
5
5
  * 支持Windows、macOS和Linux系统的原生终端命令
6
6
  */
@@ -39,8 +39,6 @@ async function tryLoadNodePty() {
39
39
  // 尝试自动修复
40
40
  try {
41
41
  const { spawn } = await import('child_process');
42
- const { promisify } = await import('util');
43
- const exec = promisify(spawn);
44
42
 
45
43
  logger.info('正在重新编译 node-pty...');
46
44
  const rebuildProcess = spawn('npm', ['rebuild', 'node-pty'], {
@@ -49,7 +47,7 @@ async function tryLoadNodePty() {
49
47
  });
50
48
 
51
49
  await new Promise((resolve, reject) => {
52
- rebuildProcess.on('close', (code) => {
50
+ rebuildProcess.on('close', code => {
53
51
  if (code === 0) {
54
52
  resolve();
55
53
  } else {
@@ -98,7 +96,7 @@ class TerminalSession {
98
96
  this.environment = options.environment || process.env;
99
97
  this.isActive = true;
100
98
  this.isFallback = options.isFallback || false; // 标记是否使用回退方案
101
-
99
+
102
100
  // 绑定PTY事件
103
101
  this.setupPtyEvents();
104
102
  }
@@ -125,7 +123,7 @@ class TerminalSession {
125
123
  setupPtyEvents() {
126
124
  if (!this.pty) return;
127
125
 
128
- this.pty.on('data', (data) => {
126
+ this.pty.on('data', data => {
129
127
  this.lastActivity = new Date();
130
128
  this.emit('data', data);
131
129
  });
@@ -228,18 +226,18 @@ export class TerminalService {
228
226
  maxSessions: 10, // 最大会话数
229
227
  ...options
230
228
  };
231
-
229
+
232
230
  // 定期清理非活跃会话
233
231
  this.cleanupInterval = setInterval(() => {
234
232
  this.cleanupInactiveSessions();
235
233
  }, 60000); // 每分钟检查一次
236
-
234
+
237
235
  logger.info('TerminalService initialized');
238
-
236
+
239
237
  // 修复 node-pty 二进制文件权限
240
238
  this.fixNodePtyPermissions();
241
239
  }
242
-
240
+
243
241
  /**
244
242
  * 修复 node-pty 二进制文件权限
245
243
  * 这是解决 posix_spawnp failed 错误的关键
@@ -248,38 +246,54 @@ export class TerminalService {
248
246
  try {
249
247
  const { execSync } = await import('child_process');
250
248
  const platform = process.platform;
251
-
249
+
252
250
  // 只在 Unix-like 系统上修复权限(macOS, Linux)
253
251
  if (platform !== 'win32') {
254
252
  logger.info('🔧 检查并修复 node-pty 二进制文件权限...');
255
-
253
+
256
254
  // 尝试多个可能的 node-pty 路径
257
255
  const possiblePaths = [
258
256
  // 路径1: 在包的 node_modules 中(开发环境)
259
- path.join(path.dirname(path.dirname(new URL(import.meta.url).pathname)), 'node_modules', 'node-pty', 'prebuilds'),
257
+ path.join(
258
+ path.dirname(path.dirname(new URL(import.meta.url).pathname)),
259
+ 'node_modules',
260
+ 'node-pty',
261
+ 'prebuilds'
262
+ ),
260
263
  // 路径2: 在根 node_modules 中(npm 安装环境)
261
264
  path.join(process.cwd(), 'node_modules', 'node-pty', 'prebuilds'),
262
265
  // 路径3: 相对于当前工作目录
263
- path.join(process.cwd(), 'node_modules', '@becrafter', 'prompt-manager', 'node_modules', 'node-pty', 'prebuilds')
266
+ path.join(
267
+ process.cwd(),
268
+ 'node_modules',
269
+ '@becrafter',
270
+ 'prompt-manager',
271
+ 'node_modules',
272
+ 'node-pty',
273
+ 'prebuilds'
274
+ )
264
275
  ];
265
-
276
+
266
277
  let ptyPath = null;
267
278
  const fs = await import('fs');
268
-
279
+
269
280
  for (const possiblePath of possiblePaths) {
270
281
  if (fs.existsSync(possiblePath)) {
271
282
  ptyPath = possiblePath;
272
283
  break;
273
284
  }
274
285
  }
275
-
286
+
276
287
  if (ptyPath) {
277
288
  try {
278
289
  // 添加执行权限 - 使用 find 命令来处理所有平台
279
- execSync(`find ${ptyPath} -type f -name "*.node" -o -name "spawn-helper" | xargs chmod +x 2>/dev/null || true`, {
280
- stdio: 'pipe',
281
- timeout: 5000
282
- });
290
+ execSync(
291
+ `find ${ptyPath} -type f -name "*.node" -o -name "spawn-helper" | xargs chmod +x 2>/dev/null || true`,
292
+ {
293
+ stdio: 'pipe',
294
+ timeout: 5000
295
+ }
296
+ );
283
297
  logger.info('✅ node-pty 权限修复完成');
284
298
  } catch (error) {
285
299
  // 静默失败,不影响服务启动
@@ -306,12 +320,14 @@ export class TerminalService {
306
320
 
307
321
  // 检查PTY是否可用
308
322
  if (!PTY_AVAILABLE) {
309
- throw new Error('Terminal functionality is disabled - node-pty module is not available. Run "npm rebuild node-pty" to fix this.');
323
+ throw new Error(
324
+ 'Terminal functionality is disabled - node-pty module is not available. Run "npm rebuild node-pty" to fix this.'
325
+ );
310
326
  }
311
327
 
312
328
  const sessionId = options.id || randomUUID();
313
329
  const sessionOptions = { ...this.defaultOptions, ...options };
314
-
330
+
315
331
  // 检查会话数限制
316
332
  if (this.sessions.size >= sessionOptions.maxSessions) {
317
333
  throw new Error(`Maximum sessions limit reached: ${sessionOptions.maxSessions}`);
@@ -325,19 +341,19 @@ export class TerminalService {
325
341
  try {
326
342
  const ptyProcess = await this.createPtyProcess(sessionOptions);
327
343
  const session = new TerminalSession(sessionId, ptyProcess, sessionOptions);
328
-
344
+
329
345
  // 添加事件监听
330
- session.on('data', (data) => {
346
+ session.on('data', data => {
331
347
  this.handleSessionData(sessionId, data);
332
348
  });
333
-
334
- session.on('exit', (info) => {
349
+
350
+ session.on('exit', info => {
335
351
  this.handleSessionExit(sessionId, info);
336
352
  });
337
-
353
+
338
354
  // 存储会话
339
355
  this.sessions.set(sessionId, session);
340
-
356
+
341
357
  logger.info(`Terminal session created: ${sessionId}`);
342
358
  return session;
343
359
  } catch (error) {
@@ -354,6 +370,74 @@ export class TerminalService {
354
370
  const args = this.getShellArgs(shell);
355
371
  const cwd = options.workingDirectory || os.homedir();
356
372
 
373
+ // 构建优化的 PATH 环境变量
374
+ const buildOptimizedPath = () => {
375
+ const platform = process.platform;
376
+ const existingPaths = process.env.PATH ? process.env.PATH.split(':') : [];
377
+ const pathSet = new Set(existingPaths);
378
+
379
+ // 添加常见的系统工具路径(按优先级排序)
380
+ const systemPaths = [];
381
+
382
+ if (platform === 'darwin') {
383
+ // macOS 特定路径
384
+ systemPaths.push(
385
+ '/opt/homebrew/bin', // Apple Silicon Homebrew
386
+ '/opt/homebrew/sbin',
387
+ '/usr/local/bin', // Intel Homebrew
388
+ '/usr/local/sbin',
389
+ '/usr/bin',
390
+ '/usr/sbin',
391
+ '/bin',
392
+ '/sbin',
393
+ '/Library/Apple/usr/bin', // Apple 系统工具
394
+ '/usr/local/MacGPG2/bin', // GPG 工具
395
+ '~/.opencode/bin',
396
+ '~/.local/bin', // 用户本地工具
397
+ '~/bin' // 用户 bin 目录
398
+ );
399
+ } else if (platform === 'linux') {
400
+ // Linux 特定路径
401
+ systemPaths.push(
402
+ '/usr/local/bin',
403
+ '/usr/local/sbin',
404
+ '/usr/bin',
405
+ '/usr/sbin',
406
+ '/bin',
407
+ '/sbin',
408
+ '/snap/bin', // Snap 应用
409
+ '~/.local/bin',
410
+ '~/bin'
411
+ );
412
+ } else if (platform === 'win32') {
413
+ // Windows 特定路径(使用分号分隔)
414
+ const winPaths = [
415
+ `${process.env.ProgramFiles}\\Git\\bin`,
416
+ `${process.env.ProgramFiles}\\Git\\usr\\bin`,
417
+ `${process.env.ProgramFiles}\\nodejs`,
418
+ `${process.env['ProgramFiles(x86)']}\\Git\\bin`,
419
+ `${process.env['ProgramFiles(x86)']}\\Git\\usr\\bin`,
420
+ `${process.env['ProgramFiles(x86)']}\\nodejs`,
421
+ `${process.env.LOCALAPPDATA}\\Programs\\Git\\bin`,
422
+ `${process.env.APPDATA}\\npm`,
423
+ `${process.env.LOCALAPPDATA}\\Programs\\Microsoft VS Code\\bin`,
424
+ `${process.env.ProgramFiles}\\Microsoft VS Code\\bin`
425
+ ].filter(Boolean);
426
+ return `${winPaths.join(';')};${process.env.PATH || ''}`;
427
+ }
428
+
429
+ // 添加路径到集合(保持优先级顺序)
430
+ systemPaths.forEach(path => {
431
+ if (!pathSet.has(path)) {
432
+ pathSet.add(path);
433
+ }
434
+ });
435
+
436
+ // 合并所有路径,保持原有 PATH 的顺序,但优先添加系统路径
437
+ const optimizedPaths = [...pathSet];
438
+ return optimizedPaths.join(':');
439
+ };
440
+
357
441
  // 确保环境变量正确,特别是 PATH
358
442
  const env = {
359
443
  ...process.env,
@@ -365,11 +449,14 @@ export class TerminalService {
365
449
  LC_ALL: process.env.LC_ALL || process.env.LANG || 'en_US.UTF-8',
366
450
  LC_CTYPE: process.env.LC_CTYPE || process.env.LANG || 'en_US.UTF-8',
367
451
  // 确保 TERM 变量设置
368
- TERM: process.env.TERM || 'xterm-256color'
452
+ TERM: process.env.TERM || 'xterm-256color',
453
+ // 设置优化的 PATH
454
+ PATH: buildOptimizedPath()
369
455
  };
370
456
 
371
457
  logger.info(`🔧 创建终端会话 - Shell: ${shell}, Args: [${args.join(', ')}], CWD: ${cwd}`);
372
458
  logger.info(`🔧 环境变量 - SHELL: ${env.SHELL}, TERM: ${env.TERM}, LANG: ${env.LANG}`);
459
+ logger.info(`🔧 PATH 已优化,包含 ${env.PATH.split(':').length} 个路径`);
373
460
  logger.info(`🔧 Shell 可执行性检查: ${shell} ${args.join(' ')}`);
374
461
 
375
462
  // 检查 shell 是否可执行
@@ -390,27 +477,27 @@ export class TerminalService {
390
477
 
391
478
  logger.info(`✅ Shell 验证通过: ${shell}`);
392
479
  } catch (error) {
393
- logger.error(`❌ Shell 验证失败:`, error.message);
480
+ logger.error('❌ Shell 验证失败:', error.message);
394
481
  throw error;
395
482
  }
396
483
 
397
484
  // 创建 PTY 进程 - 使用多级回退机制
398
- logger.info(`🔧 尝试创建 PTY 进程...`);
485
+ logger.info('🔧 尝试创建 PTY 进程...');
399
486
 
400
487
  // 定义尝试策略的优先级
401
488
  const strategies = [
402
489
  // 策略 1: 使用用户指定的 shell 和 xterm-256color
403
490
  {
404
491
  name: 'User shell with xterm-256color',
405
- shell: shell,
406
- args: args,
492
+ shell,
493
+ args,
407
494
  term: 'xterm-256color'
408
495
  },
409
496
  // 策略 2: 使用用户指定的 shell 和 xterm
410
497
  {
411
498
  name: 'User shell with xterm',
412
- shell: shell,
413
- args: args,
499
+ shell,
500
+ args,
414
501
  term: 'xterm'
415
502
  },
416
503
  // 策略 3: 使用 /bin/sh 和 xterm-256color
@@ -440,15 +527,15 @@ export class TerminalService {
440
527
 
441
528
  for (let i = 0; i < strategies.length; i++) {
442
529
  const strategy = strategies[i];
443
-
530
+
444
531
  try {
445
532
  logger.info(`🔄 尝试策略 ${i + 1}/${strategies.length}: ${strategy.name}`);
446
-
533
+
447
534
  const ptyProcess = pty.default.spawn(strategy.shell, strategy.args, {
448
535
  name: strategy.term,
449
536
  cols: options.size.cols,
450
537
  rows: options.size.rows,
451
- cwd: cwd,
538
+ cwd,
452
539
  env: {
453
540
  ...env,
454
541
  TERM: strategy.term,
@@ -458,23 +545,22 @@ export class TerminalService {
458
545
 
459
546
  logger.info(`✅ PTY 进程创建成功,PID: ${ptyProcess.pid}`);
460
547
  logger.info(`✅ 使用策略: ${strategy.name}`);
461
-
548
+
462
549
  // 更新会话选项以反映实际使用的 shell
463
550
  options.shell = strategy.shell;
464
-
465
- return ptyProcess;
466
551
 
552
+ return ptyProcess;
467
553
  } catch (error) {
468
554
  lastError = error;
469
555
  logger.warn(`❌ 策略 ${i + 1} 失败: ${error.message}`);
470
-
556
+
471
557
  // 继续尝试下一个策略
472
558
  continue;
473
559
  }
474
560
  }
475
561
 
476
562
  // 所有策略都失败了
477
- logger.error(`❌ 所有 PTY 创建策略都失败了`);
563
+ logger.error('❌ 所有 PTY 创建策略都失败了');
478
564
  logger.error(`❌ 最后一个错误: ${lastError?.message}`);
479
565
  logger.error(`❌ 系统信息 - 平台: ${process.platform}, Node: ${process.version}`);
480
566
  logger.error(`❌ 环境信息 - SHELL: ${env.SHELL}, TERM: ${env.TERM}`);
@@ -483,14 +569,14 @@ export class TerminalService {
483
569
 
484
570
  // 提供用户友好的错误信息
485
571
  const error = new Error(
486
- `终端创建失败:所有 PTY 创建策略都失败了。\n` +
487
- `最后一个错误: ${lastError?.message}\n` +
488
- `建议解决方案:\n` +
489
- `1. 运行: npm rebuild node-pty\n` +
490
- `2. 检查系统权限和 macOS 安全设置\n` +
491
- `3. 确认 shell 路径正确: ${shell}\n` +
492
- `4. 重启系统后再试\n` +
493
- `5. 检查是否有其他进程占用了 PTY 资源`
572
+ '终端创建失败:所有 PTY 创建策略都失败了。\n' +
573
+ `最后一个错误: ${lastError?.message}\n` +
574
+ '建议解决方案:\n' +
575
+ '1. 运行: npm rebuild node-pty\n' +
576
+ '2. 检查系统权限和 macOS 安全设置\n' +
577
+ `3. 确认 shell 路径正确: ${shell}\n` +
578
+ '4. 重启系统后再试\n' +
579
+ '5. 检查是否有其他进程占用了 PTY 资源'
494
580
  );
495
581
  error.code = 'TERMINAL_CREATION_FAILED';
496
582
  error.originalError = lastError;
@@ -585,11 +671,11 @@ export class TerminalService {
585
671
  cleanupInactiveSessions() {
586
672
  const now = new Date();
587
673
  const timeoutMs = this.defaultOptions.timeout;
588
-
589
- for (const [sessionId, session] of this.sessions) {
590
- if (!session.isActive || (now - session.lastActivity) > timeoutMs) {
591
- logger.info(`Cleaning up inactive session: ${sessionId}`);
592
- this.removeSession(sessionId);
674
+
675
+ for (const session of this.sessions.values()) {
676
+ if (!session.isActive || now - session.lastActivity > timeoutMs) {
677
+ logger.info(`Cleaning up inactive session: ${session.sessionId}`);
678
+ this.removeSession(session.sessionId);
593
679
  }
594
680
  }
595
681
  }
@@ -602,9 +688,9 @@ export class TerminalService {
602
688
  const shell = this.getDefaultShellForPlatform();
603
689
  const args = process.platform === 'win32' ? ['/c', command] : ['-c', command];
604
690
  const cwd = options.workingDirectory || this.defaultOptions.workingDirectory;
605
-
691
+
606
692
  const child = spawn(shell, args, {
607
- cwd: cwd,
693
+ cwd,
608
694
  env: { ...process.env, ...options.environment },
609
695
  stdio: ['pipe', 'pipe', 'pipe']
610
696
  });
@@ -612,23 +698,23 @@ export class TerminalService {
612
698
  let stdout = '';
613
699
  let stderr = '';
614
700
 
615
- child.stdout?.on('data', (data) => {
701
+ child.stdout?.on('data', data => {
616
702
  stdout += data.toString();
617
703
  });
618
704
 
619
- child.stderr?.on('data', (data) => {
705
+ child.stderr?.on('data', data => {
620
706
  stderr += data.toString();
621
707
  });
622
708
 
623
- child.on('close', (code) => {
709
+ child.on('close', code => {
624
710
  resolve({
625
711
  exitCode: code,
626
- stdout: stdout,
627
- stderr: stderr
712
+ stdout,
713
+ stderr
628
714
  });
629
715
  });
630
716
 
631
- child.on('error', (error) => {
717
+ child.on('error', error => {
632
718
  reject(error);
633
719
  });
634
720
 
@@ -650,7 +736,7 @@ export class TerminalService {
650
736
  if (session) {
651
737
  return session.workingDirectory;
652
738
  }
653
-
739
+
654
740
  // 如果没有会话,返回默认工作目录
655
741
  return this.defaultOptions.workingDirectory;
656
742
  }
@@ -689,16 +775,16 @@ export class TerminalService {
689
775
  */
690
776
  async shutdown() {
691
777
  // 清理所有会话
692
- for (const [sessionId, session] of this.sessions) {
778
+ for (const session of this.sessions.values()) {
693
779
  session.terminate();
694
780
  }
695
781
  this.sessions.clear();
696
-
782
+
697
783
  // 清理定时器
698
784
  if (this.cleanupInterval) {
699
785
  clearInterval(this.cleanupInterval);
700
786
  }
701
-
787
+
702
788
  logger.info('TerminalService shutdown');
703
789
  }
704
790
  }
@@ -729,4 +815,4 @@ export async function reloadPty() {
729
815
  export const terminalService = new TerminalService();
730
816
 
731
817
  // 导出类型定义
732
- export { TerminalSession };
818
+ export { TerminalSession };
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * WebSocketService - WebSocket服务管理类
3
- *
3
+ *
4
4
  * 提供实时双向通信服务,支持终端会话的实时数据传输
5
5
  * 处理客户端连接、消息路由和会话管理
6
6
  */
@@ -22,7 +22,7 @@ class WebSocketConnection {
22
22
  this.sessionId = null;
23
23
  this.isAuthenticated = false;
24
24
  this.userInfo = null;
25
-
25
+
26
26
  this.setupWebSocketEvents();
27
27
  }
28
28
 
@@ -30,7 +30,7 @@ class WebSocketConnection {
30
30
  * 设置WebSocket事件监听
31
31
  */
32
32
  setupWebSocketEvents() {
33
- this.ws.on('message', (data) => {
33
+ this.ws.on('message', data => {
34
34
  this.handleMessage(data);
35
35
  });
36
36
 
@@ -38,7 +38,7 @@ class WebSocketConnection {
38
38
  this.handleClose(code, reason);
39
39
  });
40
40
 
41
- this.ws.on('error', (error) => {
41
+ this.ws.on('error', error => {
42
42
  this.handleError(error);
43
43
  });
44
44
 
@@ -54,9 +54,9 @@ class WebSocketConnection {
54
54
  try {
55
55
  this.lastActivity = new Date();
56
56
  const message = JSON.parse(data.toString());
57
-
57
+
58
58
  logger.debug(`Received message from client ${this.clientId}:`, message.type);
59
-
59
+
60
60
  // 根据消息类型处理
61
61
  switch (message.type) {
62
62
  case 'terminal.create':
@@ -100,14 +100,14 @@ class WebSocketConnection {
100
100
  this.sessionId = session.id;
101
101
 
102
102
  // 监听会话数据
103
- session.on('data', (data) => {
103
+ session.on('data', data => {
104
104
  this.send('terminal.data', {
105
105
  sessionId: session.id,
106
- data: data
106
+ data
107
107
  });
108
108
  });
109
109
 
110
- session.on('exit', (info) => {
110
+ session.on('exit', info => {
111
111
  this.send('terminal.exit', {
112
112
  sessionId: session.id,
113
113
  exitCode: info.exitCode,
@@ -175,7 +175,7 @@ class WebSocketConnection {
175
175
  /**
176
176
  * 处理终端关闭
177
177
  */
178
- async handleTerminalClose(message) {
178
+ async handleTerminalClose(_message) {
179
179
  if (this.sessionId) {
180
180
  try {
181
181
  await terminalService.removeSession(this.sessionId);
@@ -192,7 +192,7 @@ class WebSocketConnection {
192
192
  /**
193
193
  * 处理ping
194
194
  */
195
- handlePing(message) {
195
+ handlePing(_message) {
196
196
  this.send('pong', {
197
197
  timestamp: Date.now(),
198
198
  clientId: this.clientId
@@ -204,7 +204,7 @@ class WebSocketConnection {
204
204
  */
205
205
  handleClose(code, reason) {
206
206
  logger.info(`Client ${this.clientId} disconnected: ${code} - ${reason}`);
207
-
207
+
208
208
  // 清理关联的终端会话
209
209
  if (this.sessionId) {
210
210
  terminalService.removeSession(this.sessionId);
@@ -224,12 +224,12 @@ class WebSocketConnection {
224
224
  send(type, data) {
225
225
  if (this.ws.readyState === this.ws.OPEN) {
226
226
  const message = {
227
- type: type,
227
+ type,
228
228
  timestamp: Date.now(),
229
229
  clientId: this.clientId,
230
230
  ...data
231
231
  };
232
-
232
+
233
233
  this.ws.send(JSON.stringify(message));
234
234
  }
235
235
  }
@@ -239,8 +239,8 @@ class WebSocketConnection {
239
239
  */
240
240
  sendError(message, details = null) {
241
241
  this.send('error', {
242
- message: message,
243
- details: details
242
+ message,
243
+ details
244
244
  });
245
245
  }
246
246
 
@@ -274,33 +274,38 @@ class WebSocketConnection {
274
274
  export class WebSocketService {
275
275
  constructor(options = {}) {
276
276
  this.options = {
277
- port: options.port || 0, // 0 表示让系统自动分配端口,或使用外部指定的端口
277
+ port: options.port !== undefined ? options.port : 0, // 0 表示让系统自动分配端口
278
278
  host: '0.0.0.0',
279
279
  maxConnections: 100,
280
280
  heartbeatInterval: 30000, // 30秒心跳
281
281
  connectionTimeout: 300000, // 5分钟超时
282
282
  ...options
283
283
  };
284
-
284
+
285
285
  this.wss = null;
286
286
  this.connections = new Map();
287
287
  this.isRunning = false;
288
-
288
+
289
289
  logger.info('WebSocketService initialized');
290
290
  }
291
291
 
292
292
  /**
293
293
  * 启动WebSocket服务
294
+ * @param {Object} options - 可选配置
295
+ * @param {number} options.port - WebSocket 端口(会覆盖构造函数中的配置)
294
296
  */
295
- async start() {
297
+ async start(options = {}) {
296
298
  if (this.isRunning) {
297
299
  throw new Error('WebSocket service is already running');
298
300
  }
299
301
 
302
+ // 合并传入的端口配置
303
+ const port = options.port || this.options.port;
304
+
300
305
  return new Promise((resolve, reject) => {
301
306
  try {
302
307
  this.wss = new WebSocketServer({
303
- port: this.options.port,
308
+ port,
304
309
  host: this.options.host,
305
310
  maxConnections: this.options.maxConnections
306
311
  });
@@ -309,7 +314,7 @@ export class WebSocketService {
309
314
  this.handleConnection(ws, request);
310
315
  });
311
316
 
312
- this.wss.on('error', (error) => {
317
+ this.wss.on('error', error => {
313
318
  logger.error('WebSocket server error:', error);
314
319
  if (!this.isRunning) {
315
320
  reject(error);
@@ -328,7 +333,6 @@ export class WebSocketService {
328
333
 
329
334
  resolve();
330
335
  });
331
-
332
336
  } catch (error) {
333
337
  reject(error);
334
338
  }
@@ -344,7 +348,7 @@ export class WebSocketService {
344
348
  }
345
349
 
346
350
  // 关闭所有连接
347
- for (const [clientId, connection] of this.connections) {
351
+ for (const connection of this.connections.values()) {
348
352
  connection.close(1001, 'Server shutdown');
349
353
  }
350
354
  this.connections.clear();
@@ -369,7 +373,7 @@ export class WebSocketService {
369
373
  */
370
374
  handleConnection(ws, request) {
371
375
  const clientId = this.generateClientId();
372
-
376
+
373
377
  // 检查连接数限制
374
378
  if (this.connections.size >= this.options.maxConnections) {
375
379
  ws.close(1013, 'Server overload');
@@ -379,12 +383,12 @@ export class WebSocketService {
379
383
  try {
380
384
  const connection = new WebSocketConnection(ws, clientId);
381
385
  this.connections.set(clientId, connection);
382
-
386
+
383
387
  logger.info(`New client connected: ${clientId} from ${request.socket.remoteAddress}`);
384
-
388
+
385
389
  // 发送欢迎消息
386
390
  connection.send('welcome', {
387
- clientId: clientId,
391
+ clientId,
388
392
  serverInfo: {
389
393
  version: '1.0.0',
390
394
  platform: process.platform,
@@ -396,7 +400,6 @@ export class WebSocketService {
396
400
  ws.on('close', () => {
397
401
  this.connections.delete(clientId);
398
402
  });
399
-
400
403
  } catch (error) {
401
404
  logger.error(`Failed to handle connection for client ${clientId}:`, error);
402
405
  ws.close(1011, 'Internal error');
@@ -416,7 +419,7 @@ export class WebSocketService {
416
419
  startHeartbeat() {
417
420
  this.heartbeatInterval = setInterval(() => {
418
421
  const now = Date.now();
419
-
422
+
420
423
  for (const [clientId, connection] of this.connections) {
421
424
  // 检查连接超时
422
425
  if (now - connection.lastActivity > this.options.connectionTimeout) {
@@ -471,9 +474,7 @@ export class WebSocketService {
471
474
  * 获取服务状态
472
475
  */
473
476
  getStatus() {
474
- const activeConnections = this.getAllConnections().filter(
475
- conn => conn.ws.readyState === conn.ws.OPEN
476
- );
477
+ const activeConnections = this.getAllConnections().filter(conn => conn.ws.readyState === conn.ws.OPEN);
477
478
 
478
479
  return {
479
480
  isRunning: this.isRunning,
@@ -491,4 +492,4 @@ export class WebSocketService {
491
492
  export const webSocketService = new WebSocketService();
492
493
 
493
494
  // 导出类型定义
494
- export { WebSocketConnection };
495
+ export { WebSocketConnection };