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.
- package/dist/chunks/simple-config.mjs +1 -1
- package/dist/cli.mjs +8 -112
- package/package.json +1 -1
|
@@ -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.
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
461
|
-
//
|
|
462
|
-
//
|
|
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
|
}
|