aico-cli 0.4.6 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ import { join as join$1 } from 'node:path';
13
13
  import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.4.6";
16
+ const version = "0.4.9";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
package/dist/cli.mjs CHANGED
@@ -53,26 +53,13 @@ class ProcessManager extends EventEmitter {
53
53
  async spawn(command, args = [], options = {}) {
54
54
  const startTime = Date.now();
55
55
  const processName = options.name || command;
56
- const isWindows = process.platform === "win32";
57
56
  this.log(`\u542F\u52A8\u8FDB\u7A0B: ${processName}`, "info");
58
57
  try {
59
- let finalCommand = command;
60
- let finalArgs = args;
61
- if (isWindows) {
62
- if (command === "npx") {
63
- finalCommand = "npx.cmd";
64
- } else if (command === "claude") {
65
- finalCommand = "claude.cmd";
66
- }
67
- }
68
- const child = spawn(finalCommand, finalArgs, {
58
+ const child = spawn(command, args, {
69
59
  cwd: options.cwd || process.cwd(),
70
60
  env: { ...process.env, ...options.env },
71
61
  stdio: options.stdio || "pipe",
72
- shell: false,
73
- // 禁用shell模式,避免进程泄漏
74
- windowsHide: isWindows
75
- // Windows上隐藏子进程窗口
62
+ shell: options.shell || process.platform === "win32"
76
63
  });
77
64
  this.registerProcess(child, processName);
78
65
  let timeoutId;
@@ -259,20 +246,14 @@ class ProcessManager extends EventEmitter {
259
246
  * 清理所有进程
260
247
  */
261
248
  cleanup() {
262
- const isWindows = process.platform === "win32";
263
- if (isWindows) {
264
- this.cleanupWindowsProcesses();
265
- }
266
249
  for (const [pid, info] of this.processes) {
267
250
  if (info.status === "running") {
268
251
  try {
269
- const signal = isWindows ? "SIGTERM" : "SIGKILL";
270
- info.process.kill(signal);
252
+ info.process.kill("SIGKILL");
271
253
  } catch {
272
254
  }
273
255
  }
274
256
  }
275
- this.cleanupZombieProcesses();
276
257
  this.processes.clear();
277
258
  }
278
259
  /**
@@ -354,18 +335,9 @@ class ProcessManager extends EventEmitter {
354
335
  cleanupZombieProcesses() {
355
336
  let cleanedCount = 0;
356
337
  const runningProcesses = this.getRunningProcessList();
357
- const isWindows = process.platform === "win32";
358
- this.log(`\u5F00\u59CB\u6E05\u7406\u50F5\u5C38\u8FDB\u7A0B\uFF0C\u5F53\u524D\u8FD0\u884C\u4E2D\u8FDB\u7A0B\u6570: ${runningProcesses.length}`, "info");
359
338
  for (const process2 of runningProcesses) {
360
339
  try {
361
340
  process2.process.kill(0);
362
- if (isWindows) {
363
- if (process2.process.exitCode !== null) {
364
- this.log(`\u6E05\u7406Windows\u50F5\u5C38\u8FDB\u7A0B: ${process2.name} (PID: ${process2.pid})`, "warning");
365
- this.unregisterProcess(process2.pid);
366
- cleanedCount++;
367
- }
368
- }
369
341
  } catch (error) {
370
342
  this.log(`\u6E05\u7406\u50F5\u5C38\u8FDB\u7A0B: ${process2.name} (PID: ${process2.pid})`, "warning");
371
343
  this.unregisterProcess(process2.pid);
@@ -377,56 +349,6 @@ class ProcessManager extends EventEmitter {
377
349
  }
378
350
  return cleanedCount;
379
351
  }
380
- /**
381
- * 深度清理进程,包括可能的残留进程
382
- */
383
- deepCleanup() {
384
- const isWindows = process.platform === "win32";
385
- let totalCleaned = 0;
386
- this.log("\u5F00\u59CB\u6DF1\u5EA6\u6E05\u7406\u8FDB\u7A0B...", "info");
387
- totalCleaned += this.cleanupZombieProcesses();
388
- if (isWindows) {
389
- totalCleaned += this.cleanupWindowsProcesses();
390
- }
391
- const remainingProcesses = this.getProcessCount();
392
- if (remainingProcesses > 0) {
393
- this.log(`\u5F3A\u5236\u6E05\u7406\u5269\u4F59\u7684 ${remainingProcesses} \u4E2A\u8FDB\u7A0B`, "warning");
394
- this.cleanup();
395
- totalCleaned += remainingProcesses;
396
- }
397
- this.log(`\u6DF1\u5EA6\u6E05\u7406\u5B8C\u6210\uFF0C\u603B\u5171\u6E05\u7406\u4E86 ${totalCleaned} \u4E2A\u8FDB\u7A0B`, "info");
398
- return totalCleaned;
399
- }
400
- /**
401
- * Windows平台特定的进程清理
402
- * 针对Windows的进程管理特点进行优化
403
- */
404
- cleanupWindowsProcesses() {
405
- const isWindows = process.platform === "win32";
406
- if (!isWindows) {
407
- return 0;
408
- }
409
- let cleanedCount = 0;
410
- const runningProcesses = this.getRunningProcessList();
411
- this.log("\u6267\u884CWindows\u5E73\u53F0\u7279\u5B9A\u8FDB\u7A0B\u6E05\u7406...", "info");
412
- for (const process2 of runningProcesses) {
413
- try {
414
- if (process2.process.exitCode !== null) {
415
- this.log(`\u6E05\u7406Windows\u8FDB\u7A0B: ${process2.name} (PID: ${process2.pid})`, "warning");
416
- this.unregisterProcess(process2.pid);
417
- cleanedCount++;
418
- }
419
- } catch (error) {
420
- this.log(`\u5F3A\u5236\u6E05\u7406Windows\u8FDB\u7A0B: ${process2.name} (PID: ${process2.pid})`, "error");
421
- this.unregisterProcess(process2.pid);
422
- cleanedCount++;
423
- }
424
- }
425
- if (cleanedCount > 0) {
426
- this.log(`Windows\u5E73\u53F0\u6E05\u7406\u4E86 ${cleanedCount} \u4E2A\u8FDB\u7A0B`, "info");
427
- }
428
- return cleanedCount;
429
- }
430
352
  /**
431
353
  * 添加进程到列表(用于测试)
432
354
  */
@@ -439,59 +361,33 @@ class ProcessManager extends EventEmitter {
439
361
  */
440
362
  async replaceProcess(command, args = [], options = {}) {
441
363
  const processName = options.name || command;
442
- const isWindows = process.platform === "win32";
443
364
  try {
365
+ this.log(`\u6E05\u7406 ${this.processes.size} \u4E2A\u7BA1\u7406\u8FDB\u7A0B...`, "info");
444
366
  this.cleanup();
445
367
  const { spawn: spawn2 } = await import('node:child_process');
446
- let finalCommand = command;
447
- let finalArgs = args;
448
- if (isWindows) {
449
- if (command === "npx") {
450
- finalCommand = "npx.cmd";
451
- } else if (command === "claude") {
452
- finalCommand = "claude.cmd";
453
- }
454
- }
455
- const child = spawn2(finalCommand, finalArgs, {
368
+ const child = spawn2(command, args, {
456
369
  stdio: "inherit",
457
370
  // 继承所有 stdio
458
371
  cwd: options.cwd || process.cwd(),
459
372
  env: { ...process.env, ...options.env },
460
- shell: false,
461
- // 禁用shell模式,避免进程泄漏
462
- // Windows上使用更严格的进程控制
463
- windowsHide: isWindows
464
- // Windows上隐藏子进程窗口
373
+ shell: options.shell || process.platform === "win32"
374
+ // 移除 detached: true,避免子进程脱离管理
375
+ // detached: false 是默认值,子进程会随着父进程退出而退出
465
376
  });
466
377
  child.on("error", (error) => {
467
378
  this.log(`\u8FDB\u7A0B\u66FF\u6362\u5931\u8D25: ${error}`, "error");
468
- this.cleanup();
469
379
  process.exit(1);
470
380
  });
471
381
  child.on("exit", (code) => {
472
382
  this.log(`\u66FF\u6362\u8FDB\u7A0B\u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${code}`, "info");
473
- this.cleanup();
474
383
  process.exit(code || 0);
475
384
  });
476
385
  this.registerProcess(child, processName);
477
- if (isWindows) {
478
- const checkInterval = setInterval(() => {
479
- if (child.exitCode !== null) {
480
- clearInterval(checkInterval);
481
- this.cleanup();
482
- process.exit(child.exitCode || 0);
483
- }
484
- }, 1e3);
485
- child.on("exit", () => {
486
- clearInterval(checkInterval);
487
- });
488
- }
489
386
  await new Promise(() => {
490
387
  });
491
388
  process.exit(0);
492
389
  } catch (error) {
493
390
  this.log(`\u8FDB\u7A0B\u66FF\u6362\u5931\u8D25: ${error}`, "error");
494
- this.cleanup();
495
391
  process.exit(1);
496
392
  }
497
393
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aico-cli",
3
- "version": "0.4.6",
3
+ "version": "0.4.9",
4
4
  "packageManager": "pnpm@9.15.9",
5
5
  "description": "AI CLI",
6
6
  "repository": {