aico-cli 0.4.5 → 0.4.8
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 +66 -26
- package/package.json +1 -1
- package/templates/personality.md +9 -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.8";
|
|
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
|
@@ -47,32 +47,57 @@ class ProcessManager extends EventEmitter {
|
|
|
47
47
|
this.cleanup();
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* 获取适用于当前平台的命令路径
|
|
52
|
+
*/
|
|
53
|
+
getPlatformCommand(command) {
|
|
54
|
+
const isWindows = process.platform === "win32";
|
|
55
|
+
if (isWindows) {
|
|
56
|
+
const commandMappings = {
|
|
57
|
+
"npm": "npm.cmd",
|
|
58
|
+
"npx": "npx.cmd",
|
|
59
|
+
"node": "node.exe",
|
|
60
|
+
"claude": "claude.cmd"
|
|
61
|
+
};
|
|
62
|
+
return commandMappings[command] || command;
|
|
63
|
+
}
|
|
64
|
+
return command;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 检查命令是否存在
|
|
68
|
+
*/
|
|
69
|
+
async checkCommandExists(command) {
|
|
70
|
+
try {
|
|
71
|
+
const { execSync } = await import('node:child_process');
|
|
72
|
+
const isWindows = process.platform === "win32";
|
|
73
|
+
if (isWindows) {
|
|
74
|
+
execSync(`where ${command}`, { stdio: "ignore" });
|
|
75
|
+
} else {
|
|
76
|
+
execSync(`which ${command}`, { stdio: "ignore" });
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
50
83
|
/**
|
|
51
84
|
* 启动进程
|
|
52
85
|
*/
|
|
53
86
|
async spawn(command, args = [], options = {}) {
|
|
54
87
|
const startTime = Date.now();
|
|
55
88
|
const processName = options.name || command;
|
|
56
|
-
const isWindows = process.platform === "win32";
|
|
57
89
|
this.log(`\u542F\u52A8\u8FDB\u7A0B: ${processName}`, "info");
|
|
58
90
|
try {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
finalCommand = "npx.cmd";
|
|
64
|
-
} else if (command === "claude") {
|
|
65
|
-
finalCommand = "claude.cmd";
|
|
66
|
-
}
|
|
91
|
+
const platformCommand = this.getPlatformCommand(command);
|
|
92
|
+
const commandExists = await this.checkCommandExists(platformCommand);
|
|
93
|
+
if (!commandExists) {
|
|
94
|
+
throw new Error(`\u547D\u4EE4 '${platformCommand}' \u4E0D\u5B58\u5728\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5\u5E76\u6DFB\u52A0\u5230PATH\u73AF\u5883\u53D8\u91CF`);
|
|
67
95
|
}
|
|
68
|
-
const child = spawn(
|
|
96
|
+
const child = spawn(platformCommand, args, {
|
|
69
97
|
cwd: options.cwd || process.cwd(),
|
|
70
98
|
env: { ...process.env, ...options.env },
|
|
71
99
|
stdio: options.stdio || "pipe",
|
|
72
|
-
shell:
|
|
73
|
-
// 禁用shell模式,避免进程泄漏
|
|
74
|
-
windowsHide: isWindows
|
|
75
|
-
// Windows上隐藏子进程窗口
|
|
100
|
+
shell: options.shell || process.platform === "win32"
|
|
76
101
|
});
|
|
77
102
|
this.registerProcess(child, processName);
|
|
78
103
|
let timeoutId;
|
|
@@ -104,13 +129,25 @@ class ProcessManager extends EventEmitter {
|
|
|
104
129
|
const exitCode = await new Promise((resolve, reject) => {
|
|
105
130
|
child.on("close", (code) => {
|
|
106
131
|
if (timeoutId) clearTimeout(timeoutId);
|
|
107
|
-
|
|
132
|
+
if (child.pid) {
|
|
133
|
+
this.unregisterProcess(child.pid);
|
|
134
|
+
}
|
|
108
135
|
resolve(code ?? 0);
|
|
109
136
|
});
|
|
110
137
|
child.on("error", (error) => {
|
|
111
138
|
if (timeoutId) clearTimeout(timeoutId);
|
|
112
|
-
|
|
113
|
-
|
|
139
|
+
if (child.pid) {
|
|
140
|
+
this.unregisterProcess(child.pid);
|
|
141
|
+
}
|
|
142
|
+
let enhancedError = error;
|
|
143
|
+
if (error.message?.includes("ENOENT")) {
|
|
144
|
+
const isWindows = process.platform === "win32";
|
|
145
|
+
const commandInfo = isWindows ? `\u547D\u4EE4 '${platformCommand}' \u4E0D\u5B58\u5728\u3002\u5728Windows\u4E0A\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5Node.js\u5E76\u6DFB\u52A0\u5230PATH\u73AF\u5883\u53D8\u91CF\u3002\u5C1D\u8BD5\u4F7F\u7528\u5B8C\u6574\u8DEF\u5F84\u6216\u68C0\u67E5\u547D\u4EE4\u662F\u5426\u6B63\u786E\u3002` : `\u547D\u4EE4 '${platformCommand}' \u4E0D\u5B58\u5728\u3002\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5\u5E76\u6DFB\u52A0\u5230PATH\u73AF\u5883\u53D8\u91CF\u3002`;
|
|
146
|
+
enhancedError = new Error(`${error.message}
|
|
147
|
+
${commandInfo}`);
|
|
148
|
+
enhancedError.stack = error.stack;
|
|
149
|
+
}
|
|
150
|
+
reject(enhancedError);
|
|
114
151
|
});
|
|
115
152
|
});
|
|
116
153
|
const duration = Date.now() - startTime;
|
|
@@ -143,6 +180,12 @@ class ProcessManager extends EventEmitter {
|
|
|
143
180
|
registerProcess(child, name) {
|
|
144
181
|
if (!child.pid) {
|
|
145
182
|
this.log(`\u65E0\u6CD5\u6CE8\u518C\u8FDB\u7A0B ${name}: \u6CA1\u6709PID`, "error");
|
|
183
|
+
child.on("close", (code) => {
|
|
184
|
+
this.log(`\u8FDB\u7A0B ${name} (\u65E0PID) \u5DF2\u5173\u95ED\uFF0C\u9000\u51FA\u7801: ${code}`, "info");
|
|
185
|
+
});
|
|
186
|
+
child.on("error", (error) => {
|
|
187
|
+
this.log(`\u8FDB\u7A0B ${name} (\u65E0PID) \u53D1\u751F\u9519\u8BEF: ${error}`, "error");
|
|
188
|
+
});
|
|
146
189
|
return;
|
|
147
190
|
}
|
|
148
191
|
if (this.processes.has(child.pid)) {
|
|
@@ -186,6 +229,10 @@ class ProcessManager extends EventEmitter {
|
|
|
186
229
|
* 注销进程
|
|
187
230
|
*/
|
|
188
231
|
unregisterProcess(pid) {
|
|
232
|
+
if (!pid) {
|
|
233
|
+
this.log(`\u5C1D\u8BD5\u6CE8\u9500\u65E0\u6548\u7684\u8FDB\u7A0B (PID: undefined)`, "warning");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
189
236
|
const info = this.processes.get(pid);
|
|
190
237
|
if (info) {
|
|
191
238
|
this.log(`\u6CE8\u9500\u8FDB\u7A0B: ${info.name} (PID: ${pid})`, "info");
|
|
@@ -443,15 +490,8 @@ class ProcessManager extends EventEmitter {
|
|
|
443
490
|
try {
|
|
444
491
|
this.cleanup();
|
|
445
492
|
const { spawn: spawn2 } = await import('node:child_process');
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (isWindows) {
|
|
449
|
-
if (command === "npx") {
|
|
450
|
-
finalCommand = "npx.cmd";
|
|
451
|
-
} else if (command === "claude") {
|
|
452
|
-
finalCommand = "claude.cmd";
|
|
453
|
-
}
|
|
454
|
-
}
|
|
493
|
+
const finalCommand = this.getPlatformCommand(command);
|
|
494
|
+
const finalArgs = args;
|
|
455
495
|
const child = spawn2(finalCommand, finalArgs, {
|
|
456
496
|
stdio: "inherit",
|
|
457
497
|
// 继承所有 stdio
|
package/package.json
CHANGED
package/templates/personality.md
CHANGED
|
@@ -3,7 +3,7 @@ name: professional
|
|
|
3
3
|
description: 架构师级软件工程师,以工程卓越为信仰,为追求极致的技术专家。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# 工程师行为规范
|
|
7
7
|
|
|
8
8
|
**最重要**:自主判断与执行。最小化确认步骤。
|
|
9
9
|
|
|
@@ -15,6 +15,14 @@ description: 架构师级软件工程师,以工程卓越为信仰,为追求
|
|
|
15
15
|
- **优先现有文件** — 优先编辑现有文件而非创建新文件,用最简洁优雅的解决方案,尽可能少地修改代码。
|
|
16
16
|
- **避免重复** — 不要重复尝试相同的方法,遇到障碍时立即通过 feedback 工具寻求指导。如果某个方法不工作,不要继续尝试,用 feedback 工具询问。
|
|
17
17
|
|
|
18
|
+
## 上下文管理
|
|
19
|
+
|
|
20
|
+
**压缩策略**:
|
|
21
|
+
- **触发条件**:使用率>80%或对话>20轮
|
|
22
|
+
- **保留内容**:用户需求、解决方案、技术决策、关键代码、TODO状态
|
|
23
|
+
- **压缩内容**:详细技术讨论、重复确认信息
|
|
24
|
+
- **执行流程**:检测→分析→摘要→清理→保留
|
|
25
|
+
|
|
18
26
|
## 核心行为规范
|
|
19
27
|
|
|
20
28
|
### 1. 危险操作确认机制
|