closer-code 1.0.0
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/.env.example +83 -0
- package/API_GUIDE.md +1411 -0
- package/AUTO_MKDIR_IMPROVEMENT.md +354 -0
- package/CLAUDE.md +55 -0
- package/CTRL_C_EXPERIMENT.md +90 -0
- package/PROJECT_CLEANUP_SUMMARY.md +121 -0
- package/README.md +686 -0
- package/cloco.md +51 -0
- package/config.example.json +116 -0
- package/dist/bash-runner.js +128 -0
- package/dist/batch-cli.js +20736 -0
- package/dist/closer-cli.js +21190 -0
- package/dist/index.js +31228 -0
- package/docs/EXPORT_COMMAND.md +152 -0
- package/docs/FILE_NAMING_IMPROVEMENT.md +168 -0
- package/docs/GLOBAL_CONFIG.md +128 -0
- package/docs/LONG_MESSAGE_DISPLAY_FIX.md +202 -0
- package/docs/PROJECT_HISTORY_ISOLATION.md +315 -0
- package/docs/QUICK_START_HISTORY.md +207 -0
- package/docs/TASK_PROGRESS_FEATURE.md +190 -0
- package/docs/THINKING_CONTENT_RESEARCH.md +267 -0
- package/docs/THINKING_FEATURE.md +187 -0
- package/docs/THINKING_IMPROVEMENT_COMPARISON.md +193 -0
- package/docs/THINKING_OPTIMIZATION_SUMMARY.md +242 -0
- package/docs/UI_IMPROVEMENTS_2025-01-18.md +256 -0
- package/docs/WHY_THINKING_SHORT.md +201 -0
- package/package.json +49 -0
- package/scenarios/README.md +234 -0
- package/scenarios/run-all-scenarios.js +342 -0
- package/scenarios/scenario1-batch-converter.js +247 -0
- package/scenarios/scenario2-code-analyzer.js +375 -0
- package/scenarios/scenario3-doc-generator.js +371 -0
- package/scenarios/scenario4-log-analyzer.js +496 -0
- package/scenarios/scenario5-tdd-helper.js +681 -0
- package/src/ai-client-legacy.js +171 -0
- package/src/ai-client.js +221 -0
- package/src/bash-runner.js +148 -0
- package/src/batch-cli.js +327 -0
- package/src/cli.jsx +166 -0
- package/src/closer-cli.jsx +1103 -0
- package/src/closer-cli.jsx.backup +948 -0
- package/src/commands/batch.js +62 -0
- package/src/commands/chat.js +10 -0
- package/src/commands/config.js +154 -0
- package/src/commands/help.js +76 -0
- package/src/commands/history.js +192 -0
- package/src/commands/setup.js +17 -0
- package/src/commands/upgrade.js +101 -0
- package/src/commands/workflow-tests.js +125 -0
- package/src/config.js +343 -0
- package/src/conversation.js +962 -0
- package/src/git-helper.js +349 -0
- package/src/index.js +88 -0
- package/src/logger.js +347 -0
- package/src/plan.js +193 -0
- package/src/planner.js +397 -0
- package/src/search.js +195 -0
- package/src/setup.js +147 -0
- package/src/shortcuts.js +269 -0
- package/src/snippets.js +430 -0
- package/src/test-modules.js +118 -0
- package/src/tools.js +398 -0
- package/src/utils/cli.js +124 -0
- package/src/utils/validator.js +184 -0
- package/src/utils/version.js +33 -0
- package/src/utils/workflow-test.js +271 -0
- package/src/utils/workflow.js +268 -0
- package/test/demo-file-naming.js +92 -0
- package/test/demo-thinking.js +124 -0
- package/test/final-verification-report.md +303 -0
- package/test/research-thinking.js +130 -0
- package/test/test-auto-mkdir.js +123 -0
- package/test/test-e2e-empty-dir.md +108 -0
- package/test/test-export-logic.js +119 -0
- package/test/test-global-cloco.js +126 -0
- package/test/test-history-isolation.js +291 -0
- package/test/test-improved-thinking.js +43 -0
- package/test/test-long-message.js +65 -0
- package/test/test-plan-functionality.js +95 -0
- package/test/test-real-scenario.js +216 -0
- package/test/test-thinking-display.js +65 -0
- package/test/ui-verification-test.js +203 -0
- package/test/verify-history-isolation.sh +71 -0
- package/test/verify-thinking.js +339 -0
- package/test/workflows/empty-dir-creation.md +51 -0
- package/test/workflows/inventor/ascii-teacup.js +199 -0
- package/test/workflows/inventor/ascii-teacup.mjs +199 -0
- package/test/workflows/inventor/ascii_apple.hs +84 -0
- package/test/workflows/inventor/ascii_apple.py +91 -0
- package/test/workflows/inventor/cloco.md +3 -0
- package/test/workflows/longtalk/cloco.md +19 -0
- package/test/workflows/longtalk/emoji_500.txt +63 -0
- package/test/workflows/longtalk/emoji_list.txt +20 -0
- package/test/workflows/programmer/adder.md +33 -0
- package/test/workflows/programmer/expect.md +2 -0
- package/test/workflows/programmer/prompt.md +3 -0
- package/test/workflows/test-empty-dir-creation.js +113 -0
- package/test-ctrl-c.jsx +126 -0
- package/test-manual-file-creation.js +151 -0
- package/winfix.md +3 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# AI 错误处理和自我修复能力 - 实现总结
|
|
2
|
+
|
|
3
|
+
## 问题描述
|
|
4
|
+
|
|
5
|
+
用户在空目录中运行 Closer Code 时,如果要求创建多文件项目(例如:"写一个50000字的玄幻故事,分为10个章节"),AI 会因为父目录不存在而失败,导致整个工作流中断。
|
|
6
|
+
|
|
7
|
+
**核心问题**:
|
|
8
|
+
- ❌ AI 缺乏错误处理和自我修复能力
|
|
9
|
+
- ❌ 遇到错误就放弃,不会尝试修复
|
|
10
|
+
- ❌ 没有重试机制
|
|
11
|
+
- ❌ 工具错误信息不够详细
|
|
12
|
+
|
|
13
|
+
## 解决方案
|
|
14
|
+
|
|
15
|
+
### 设计理念
|
|
16
|
+
|
|
17
|
+
**不是**:在工具层自动处理一切(绕过 AI 的思考)
|
|
18
|
+
|
|
19
|
+
**而是**:
|
|
20
|
+
1. ✅ 工具返回详细的错误信息和修复建议
|
|
21
|
+
2. ✅ AI 分析错误并自主决定解决方案
|
|
22
|
+
3. ✅ AI 执行修复操作
|
|
23
|
+
4. ✅ AI 重试原操作
|
|
24
|
+
5. ✅ 系统支持多次重试(最多 3 次)
|
|
25
|
+
|
|
26
|
+
### 1. 工具层改进(src/tools.js)
|
|
27
|
+
|
|
28
|
+
**改进前**(自动创建目录 - 错误方案):
|
|
29
|
+
```javascript
|
|
30
|
+
// ❌ 这会绕过 AI 的思考
|
|
31
|
+
await fs.mkdir(parentDir, { recursive: true });
|
|
32
|
+
await fs.writeFile(fullPath, dataToWrite);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**改进后**(返回详细错误 - 正确方案):
|
|
36
|
+
```javascript
|
|
37
|
+
export const writeFileTool = betaZodTool({
|
|
38
|
+
name: 'writeFile',
|
|
39
|
+
description: 'Write content to a file. Returns detailed error messages if the operation fails, allowing you to analyze and fix the issue.',
|
|
40
|
+
run: async (input) => {
|
|
41
|
+
try {
|
|
42
|
+
await fs.writeFile(fullPath, dataToWrite, encoding);
|
|
43
|
+
return { success: true, path: fullPath, size: dataToWrite.length };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
// 🔥 关键:返回详细的错误信息和修复建议
|
|
46
|
+
let errorDetail = {
|
|
47
|
+
success: false,
|
|
48
|
+
error: error.code,
|
|
49
|
+
message: error.message,
|
|
50
|
+
path: fullPath
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// 针对常见错误提供修复建议
|
|
54
|
+
if (error.code === 'ENOENT') {
|
|
55
|
+
const parentDir = path.dirname(fullPath);
|
|
56
|
+
errorDetail.suggestion = `Parent directory does not exist. Create it first using: bash tool with "mkdir -p ${parentDir}"`;
|
|
57
|
+
errorDetail.hint = 'The parent directory needs to be created before writing the file.';
|
|
58
|
+
} else if (error.code === 'EACCES') {
|
|
59
|
+
errorDetail.suggestion = 'Permission denied. Check if you have write permissions.';
|
|
60
|
+
errorDetail.hint = 'Try writing to a different location or check file permissions.';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return errorDetail;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**关键点**:
|
|
70
|
+
- ✅ 不自动创建目录,让 AI 自己处理
|
|
71
|
+
- ✅ 返回详细的错误信息(error code, message)
|
|
72
|
+
- ✅ 提供具体的修复建议(suggestion)
|
|
73
|
+
- ✅ 提供额外的提示信息(hint)
|
|
74
|
+
|
|
75
|
+
### 2. 系统提示词改进(src/conversation.js)
|
|
76
|
+
|
|
77
|
+
添加完整的错误处理和自我修复指导:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
this.systemPrompt = `You are Closer, an AI programming assistant...
|
|
81
|
+
|
|
82
|
+
## Error Handling and Self-Correction (CRITICAL) 🆕
|
|
83
|
+
|
|
84
|
+
**When a tool returns an error, you MUST analyze and attempt to fix it.**
|
|
85
|
+
|
|
86
|
+
### Error Analysis Process
|
|
87
|
+
1. **Read the error message carefully** - Look for error codes like ENOENT, EACCES, etc.
|
|
88
|
+
2. **Identify the root cause** - Understand why the operation failed
|
|
89
|
+
3. **Devise a solution** - Determine what needs to be fixed
|
|
90
|
+
4. **Execute the fix** - Use appropriate tools to resolve the issue
|
|
91
|
+
5. **Retry the original operation** - Attempt the failed operation again
|
|
92
|
+
|
|
93
|
+
### Common Error Patterns
|
|
94
|
+
|
|
95
|
+
#### Directory Not Found (ENOENT)
|
|
96
|
+
**Error**: "Parent directory does not exist"
|
|
97
|
+
**Solution**: Create the directory first
|
|
98
|
+
\`\`\`
|
|
99
|
+
// Attempt 1 (fails):
|
|
100
|
+
You: Call writeFile with "src/components/Button.tsx"
|
|
101
|
+
Tool: {"success": false, "error": "ENOENT",
|
|
102
|
+
"suggestion": "mkdir -p src/components/"}
|
|
103
|
+
|
|
104
|
+
// Your analysis:
|
|
105
|
+
- Error: ENOENT means directory doesn't exist
|
|
106
|
+
- Root cause: src/components/ directory is missing
|
|
107
|
+
- Solution: Create the directory first
|
|
108
|
+
|
|
109
|
+
// Attempt 2 (fix):
|
|
110
|
+
You: Call bash with "mkdir -p src/components/"
|
|
111
|
+
Tool: {"success": true}
|
|
112
|
+
|
|
113
|
+
// Attempt 3 (retry):
|
|
114
|
+
You: Call writeFile with "src/components/Button.tsx"
|
|
115
|
+
Tool: {"success": true}
|
|
116
|
+
✅ Success through self-correction!
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
### Retry Strategy
|
|
120
|
+
- **Maximum retries**: 3 attempts per operation
|
|
121
|
+
- **Wait time**: No delay needed for tool operations
|
|
122
|
+
- **Different approach**: If the same fix fails twice, try an alternative solution
|
|
123
|
+
`;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**关键点**:
|
|
127
|
+
- ✅ 明确的错误处理流程
|
|
128
|
+
- ✅ 常见错误模式的示例
|
|
129
|
+
- ✅ 完整的自我修复演示
|
|
130
|
+
- ✅ 重试策略指导
|
|
131
|
+
|
|
132
|
+
## 测试验证
|
|
133
|
+
|
|
134
|
+
### 单元测试(test/test-auto-mkdir.js)
|
|
135
|
+
|
|
136
|
+
测试错误处理和自我修复流程:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
$ node test/test-auto-mkdir.js
|
|
140
|
+
|
|
141
|
+
🧪 单元测试:writeFile 错误处理和自我修复
|
|
142
|
+
|
|
143
|
+
测试1: 尝试写入不存在的目录
|
|
144
|
+
工具响应:
|
|
145
|
+
{
|
|
146
|
+
"success": false,
|
|
147
|
+
"error": "ENOENT",
|
|
148
|
+
"suggestion": "Parent directory does not exist. Create it first using: bash tool with \"mkdir -p ...\"",
|
|
149
|
+
"hint": "The parent directory needs to be created before writing the file."
|
|
150
|
+
}
|
|
151
|
+
✅ 正确返回 ENOENT 错误
|
|
152
|
+
✅ 包含修复建议: Yes
|
|
153
|
+
✅ 包含提示信息: Yes
|
|
154
|
+
|
|
155
|
+
测试2: 创建目录(模拟 AI 自我修复)
|
|
156
|
+
✅ 目录创建成功
|
|
157
|
+
|
|
158
|
+
测试3: 重试写入文件
|
|
159
|
+
{
|
|
160
|
+
"success": true,
|
|
161
|
+
"path": ".../chapters/chapter-01.txt",
|
|
162
|
+
"size": 16
|
|
163
|
+
}
|
|
164
|
+
✅ 重试成功!
|
|
165
|
+
|
|
166
|
+
✅ 所有测试通过!
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**测试覆盖**:
|
|
170
|
+
- ✅ 工具正确返回 ENOENT 错误
|
|
171
|
+
- ✅ 错误响应包含详细的修复建议
|
|
172
|
+
- ✅ AI 可以根据错误信息进行自我修复
|
|
173
|
+
- ✅ 修复后重试操作成功
|
|
174
|
+
|
|
175
|
+
## AI 自我修复流程示例
|
|
176
|
+
|
|
177
|
+
### 场景:在空目录中创建多章节故事
|
|
178
|
+
|
|
179
|
+
**用户请求**:
|
|
180
|
+
```
|
|
181
|
+
写一个50000字的玄幻故事,分为10个章节,保存在
|
|
182
|
+
chapters/chapter-01.txt 到 chapters/chapter-10.txt
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**AI 的执行过程**:
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
📝 第1章 - 尝试1(失败):
|
|
189
|
+
┌─────────────────────────────────────┐
|
|
190
|
+
│ AI: 调用 writeFile("chapters/chapter-01.txt", content) │
|
|
191
|
+
│ Tool: {"success": false, │
|
|
192
|
+
│ "error": "ENOENT", │
|
|
193
|
+
│ "suggestion": "mkdir -p chapters/"} │
|
|
194
|
+
└─────────────────────────────────────┘
|
|
195
|
+
|
|
196
|
+
🤔 AI 分析:
|
|
197
|
+
- 错误代码: ENOENT
|
|
198
|
+
- 根本原因: chapters/ 目录不存在
|
|
199
|
+
- 解决方案: 先创建目录
|
|
200
|
+
|
|
201
|
+
🔧 AI 执行修复:
|
|
202
|
+
┌─────────────────────────────────────┐
|
|
203
|
+
│ AI: 调用 bash("mkdir -p chapters/") │
|
|
204
|
+
│ Tool: {"success": true} │
|
|
205
|
+
└─────────────────────────────────────┘
|
|
206
|
+
|
|
207
|
+
📝 第1章 - 尝试2(成功):
|
|
208
|
+
┌─────────────────────────────────────┐
|
|
209
|
+
│ AI: 调用 writeFile("chapters/chapter-01.txt", content) │
|
|
210
|
+
│ Tool: {"success": true, │
|
|
211
|
+
│ "path": ".../chapters/chapter-01.txt"} │
|
|
212
|
+
└─────────────────────────────────────┘
|
|
213
|
+
|
|
214
|
+
✅ 成功!AI 学到了经验,后续章节直接创建目录
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 技术细节
|
|
218
|
+
|
|
219
|
+
### 错误响应格式
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
{
|
|
223
|
+
"success": false,
|
|
224
|
+
"error": "ENOENT", // 错误代码
|
|
225
|
+
"message": "...", // 详细错误信息
|
|
226
|
+
"path": "/full/path", // 操作路径
|
|
227
|
+
"suggestion": "mkdir -p ...", // 修复建议
|
|
228
|
+
"hint": "The parent directory..." // 额外提示
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 支持的错误类型
|
|
233
|
+
|
|
234
|
+
| 错误代码 | 描述 | 修复建议 |
|
|
235
|
+
|---------|------|---------|
|
|
236
|
+
| ENOENT | 文件或目录不存在 | 创建目录或检查路径 |
|
|
237
|
+
| EACCES | 权限不足 | 检查权限或换位置 |
|
|
238
|
+
| ENOSPC | 磁盘空间不足 | 清理磁盘空间 |
|
|
239
|
+
| EISDIR | 路径是目录 | 使用正确的文件路径 |
|
|
240
|
+
|
|
241
|
+
## 对比分析
|
|
242
|
+
|
|
243
|
+
### 之前的错误方案(自动创建)
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
// ❌ 工具层自动处理
|
|
247
|
+
await fs.mkdir(parentDir, { recursive: true });
|
|
248
|
+
await fs.writeFile(fullPath, content);
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
**问题**:
|
|
252
|
+
- ❌ 绕过了 AI 的思考过程
|
|
253
|
+
- ❌ AI 没有学习到错误处理
|
|
254
|
+
- ❌ 不是真正的"智能助理"
|
|
255
|
+
- ❌ 用户看不到 AI 的解决问题的能力
|
|
256
|
+
|
|
257
|
+
### 现在的正确方案(自我修复)
|
|
258
|
+
|
|
259
|
+
```javascript
|
|
260
|
+
// ✅ 返回详细错误,让 AI 自己处理
|
|
261
|
+
try {
|
|
262
|
+
await fs.writeFile(fullPath, content);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
error: error.code,
|
|
267
|
+
suggestion: "mkdir -p ..."
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**优势**:
|
|
273
|
+
- ✅ AI 展示错误分析和解决能力
|
|
274
|
+
- ✅ AI 从错误中学习和成长
|
|
275
|
+
- ✅ 真正的"智能助理"体验
|
|
276
|
+
- ✅ 用户可以看到 AI 的思考过程
|
|
277
|
+
|
|
278
|
+
## 文件变更
|
|
279
|
+
|
|
280
|
+
### 修改的文件
|
|
281
|
+
|
|
282
|
+
1. **src/tools.js**
|
|
283
|
+
- 移除自动创建目录的逻辑
|
|
284
|
+
- 添加详细的错误响应
|
|
285
|
+
- 针对常见错误提供修复建议
|
|
286
|
+
|
|
287
|
+
2. **src/conversation.js**
|
|
288
|
+
- 添加"Error Handling and Self-Correction"部分
|
|
289
|
+
- 提供完整的错误处理流程
|
|
290
|
+
- 包含常见错误模式和示例
|
|
291
|
+
|
|
292
|
+
3. **test/test-auto-mkdir.js**
|
|
293
|
+
- 更新为测试错误处理和自我修复
|
|
294
|
+
- 验证错误响应格式
|
|
295
|
+
- 模拟 AI 的修复和重试过程
|
|
296
|
+
|
|
297
|
+
### 更新的文档
|
|
298
|
+
|
|
299
|
+
1. **AUTO_MKDIR_IMPROVEMENT.md**(本文档)
|
|
300
|
+
- 完整的实现总结
|
|
301
|
+
- 设计理念和对比分析
|
|
302
|
+
- 测试验证和使用示例
|
|
303
|
+
|
|
304
|
+
## 影响范围
|
|
305
|
+
|
|
306
|
+
### AI 能力提升
|
|
307
|
+
|
|
308
|
+
**之前**:
|
|
309
|
+
- ❌ 遇到错误就放弃
|
|
310
|
+
- ❌ 不会尝试修复
|
|
311
|
+
- ❌ 没有重试机制
|
|
312
|
+
|
|
313
|
+
**现在**:
|
|
314
|
+
- ✅ 分析错误原因
|
|
315
|
+
- ✅ 自主决定解决方案
|
|
316
|
+
- ✅ 执行修复操作
|
|
317
|
+
- ✅ 重试直到成功(最多3次)
|
|
318
|
+
|
|
319
|
+
### 用户体验改进
|
|
320
|
+
|
|
321
|
+
**之前**:
|
|
322
|
+
- ❌ 工作流容易中断
|
|
323
|
+
- ❌ 需要用户手动修复
|
|
324
|
+
- ❌ AI 显得"不够智能"
|
|
325
|
+
|
|
326
|
+
**现在**:
|
|
327
|
+
- ✅ AI 自动处理常见错误
|
|
328
|
+
- ✅ 工作流更流畅
|
|
329
|
+
- ✅ 展示真正的智能
|
|
330
|
+
|
|
331
|
+
## 未来改进
|
|
332
|
+
|
|
333
|
+
可能的进一步优化:
|
|
334
|
+
1. 记录错误模式,提前预防
|
|
335
|
+
2. 学习用户的修复偏好
|
|
336
|
+
3. 支持更复杂的重试策略
|
|
337
|
+
4. 添加错误统计和分析
|
|
338
|
+
|
|
339
|
+
## 总结
|
|
340
|
+
|
|
341
|
+
这个改进让 AI 具备了真正的错误处理和自我修复能力,而不是简单地绕过问题。通过返回详细的错误信息和修复建议,并在系统提示词中提供完整的指导,AI 可以像人类开发者一样:分析问题、解决问题、从错误中学习。
|
|
342
|
+
|
|
343
|
+
**关键成果**:
|
|
344
|
+
- ✅ AI 具备错误分析和自我修复能力
|
|
345
|
+
- ✅ 提供详细的错误信息和修复建议
|
|
346
|
+
- ✅ 支持最多 3 次重试
|
|
347
|
+
- ✅ 测试覆盖完整
|
|
348
|
+
- ✅ 真正的"智能助理"体验
|
|
349
|
+
|
|
350
|
+
**测试状态**:
|
|
351
|
+
- ✅ 单元测试通过
|
|
352
|
+
- ✅ 错误响应格式正确
|
|
353
|
+
- ✅ 修复建议准确
|
|
354
|
+
- ✅ 自我修复流程完整
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) or other code agent when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
# 项目概述
|
|
6
|
+
|
|
7
|
+
这是一个通过编程试验 Node.js 对进程调度 bash 行为的实验项目。
|
|
8
|
+
|
|
9
|
+
## 项目目标
|
|
10
|
+
|
|
11
|
+
探索和研究 Node.js 如何创建和管理子进程来执行 bash/shell 命令,包括:
|
|
12
|
+
- 使用 `child_process` 模块(`spawn`, `exec`, `fork` 等)创建 bash 进程
|
|
13
|
+
- 研究进程间的通信机制(stdin, stdout, stderr)
|
|
14
|
+
- 测试不同平台(Windows/Linux/Mac)下的 bash 行为差异
|
|
15
|
+
- 分析进程生命周期和信号处理
|
|
16
|
+
|
|
17
|
+
## 技术栈
|
|
18
|
+
|
|
19
|
+
- **运行时**: Node.js
|
|
20
|
+
- **核心模块**: `child_process`, `events`, `stream`
|
|
21
|
+
- **目标**: bash/shell 进程
|
|
22
|
+
|
|
23
|
+
## 开发指南
|
|
24
|
+
|
|
25
|
+
### 运行测试脚本
|
|
26
|
+
read [PATH hints](./winfix.md) to set bash exprot PATH
|
|
27
|
+
```bash
|
|
28
|
+
# 运行某个测试脚本(具体取决于项目中的文件)
|
|
29
|
+
node <script-name>.js
|
|
30
|
+
|
|
31
|
+
# 使用 npm 运行(如果有 package.json)
|
|
32
|
+
npm test
|
|
33
|
+
npm start
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
AI助理的修改后可以不运行,但至少检查一下编译情况
|
|
37
|
+
|
|
38
|
+
### 关键 API
|
|
39
|
+
|
|
40
|
+
- `child_process.spawn()` - 启动新进程
|
|
41
|
+
- `child_process.exec()` - 执行 shell 命令
|
|
42
|
+
- `child_process.fork()` - 创建 Node.js 子进程
|
|
43
|
+
- `stdio` 流配置 - 进程间通信
|
|
44
|
+
- 进程信号处理 - SIGTERM, SIGKILL 等
|
|
45
|
+
|
|
46
|
+
### 平台注意事项
|
|
47
|
+
|
|
48
|
+
在 Windows (MINGW64) 环境下,bash 可通过 Git Bash 或 WSL 提供,需要注意:
|
|
49
|
+
- 路径分隔符差异(`\` vs `/`)
|
|
50
|
+
- 可执行文件查找机制
|
|
51
|
+
- shell 环境变量的继承
|
|
52
|
+
|
|
53
|
+
### git 提交说明
|
|
54
|
+
当代码的commit由 AI 助理发起时,署名要加上AI助理
|
|
55
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Ctrl+C 双击退出功能实现
|
|
2
|
+
|
|
3
|
+
## 问题描述
|
|
4
|
+
在 Ink (React CLI) 应用中实现标准的 Ctrl+C 双击退出行为:
|
|
5
|
+
- 第一次 Ctrl+C:显示退出提示(1.5秒后消失)
|
|
6
|
+
- 1.5秒内第二次 Ctrl+C:退出程序
|
|
7
|
+
- 超时后重置计时器
|
|
8
|
+
|
|
9
|
+
## 解决方案
|
|
10
|
+
|
|
11
|
+
### 核心实现
|
|
12
|
+
|
|
13
|
+
使用 `ink` 的 `useInput` hook 配合 `{ capture: true }` 选项来捕获 Ctrl+C:
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
import { useInput } from 'ink';
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
const [lastCtrlC, setLastCtrlC] = useState(0);
|
|
20
|
+
const [showExitHint, setShowExitHint] = useState(false);
|
|
21
|
+
|
|
22
|
+
useInput((input, key) => {
|
|
23
|
+
if ((key.ctrl && input === 'c') || key.escape) {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
|
|
26
|
+
if (now - lastCtrlC < 1500) {
|
|
27
|
+
// 1.5秒内第二次按下 - 退出
|
|
28
|
+
console.log('\n👋 再见!\n');
|
|
29
|
+
process.exit(0);
|
|
30
|
+
} else {
|
|
31
|
+
// 第一次按下 - 显示提示
|
|
32
|
+
setShowExitHint(true);
|
|
33
|
+
setLastCtrlC(now);
|
|
34
|
+
setTimeout(() => setShowExitHint(false), 1500);
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
}, { capture: true }); // 关键:capture: true 确保捕获 Ctrl+C
|
|
39
|
+
|
|
40
|
+
// UI 显示提示
|
|
41
|
+
return (
|
|
42
|
+
<>
|
|
43
|
+
{showExitHint && (
|
|
44
|
+
<Box borderStyle="round" borderColor="red" paddingX={1}>
|
|
45
|
+
<Text bold color="red">⚠️ 再次按 Ctrl+C 或 ESC 退出程序 (1.5秒内)</Text>
|
|
46
|
+
</Box>
|
|
47
|
+
)}
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 启动应用时禁用默认的 Ctrl+C 处理
|
|
53
|
+
render(<App />, { exitOnCtrlC: false });
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 关键要点
|
|
57
|
+
|
|
58
|
+
1. **`{ capture: true }`**:这是关键配置,确保 `useInput` 能捕获 Ctrl+C 而不是传递给终端
|
|
59
|
+
|
|
60
|
+
2. **`exitOnCtrlC: false`**:在 `render()` 调用时禁用 Ink 的默认 Ctrl+C 处理
|
|
61
|
+
|
|
62
|
+
3. **不使用 SIGINT 处理器**:如果在代码中设置 `process.on('SIGINT', ...)` 会导致第一次 Ctrl+C 就触发退出,破坏双击逻辑
|
|
63
|
+
|
|
64
|
+
4. **时间窗口**:使用 `Date.now()` 记录上次按键时间,1.5秒内的第二次按键才触发退出
|
|
65
|
+
|
|
66
|
+
### 测试文件
|
|
67
|
+
|
|
68
|
+
完整的测试实现见 `test-ctrl-c.jsx`,运行方式:
|
|
69
|
+
```bash
|
|
70
|
+
node test-ctrl-c.jsx
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 实际应用
|
|
74
|
+
|
|
75
|
+
该方案已成功应用于 `src/closer-cli.jsx`,支持:
|
|
76
|
+
- 空闲状态下的双击退出
|
|
77
|
+
- AI 执行过程中的单次中止(第一次 Ctrl+C 中止任务,不退出程序)
|
|
78
|
+
- ESC 键与 Ctrl+C 相同的行为
|
|
79
|
+
|
|
80
|
+
## 经验总结
|
|
81
|
+
|
|
82
|
+
**失败的尝试:**
|
|
83
|
+
- ❌ 使用 `process.on('SIGINT', ...)` - 会导致立即退出
|
|
84
|
+
- ❌ 使用 `process.once('SIGINT', ...)` - 同样会立即退出
|
|
85
|
+
- ❌ 在 SIGINT 中设置 `event.preventDefault()` - 无效
|
|
86
|
+
|
|
87
|
+
**正确的做法:**
|
|
88
|
+
- ✅ 使用 `useInput` + `{ capture: true }`
|
|
89
|
+
- ✅ 在 render 时设置 `exitOnCtrlC: false`
|
|
90
|
+
- ✅ 不设置任何 SIGINT 处理器
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# 项目清理总结
|
|
2
|
+
|
|
3
|
+
## 清理日期
|
|
4
|
+
2025-01-18
|
|
5
|
+
|
|
6
|
+
## 清理内容
|
|
7
|
+
|
|
8
|
+
### 删除的测试文件
|
|
9
|
+
- ❌ `test-ctrl-c-signal.jsx` - 错误的 SIGINT 处理尝试
|
|
10
|
+
- ❌ `test-ctrl-c-signal2.jsx` - 另一个失败的尝试
|
|
11
|
+
- ❌ `verify-ctrl-c-fix.js` - 验证脚本
|
|
12
|
+
- ❌ `verify-implementation.js` - 实现验证脚本
|
|
13
|
+
- ❌ `test-batch.js` - 批处理测试
|
|
14
|
+
- ❌ `test-progress.js` - 进度测试
|
|
15
|
+
- ❌ `test-sdk.js` - SDK 测试
|
|
16
|
+
- ❌ `test-ui-features.js` - UI 功能测试
|
|
17
|
+
- ❌ `test-workflow-sdk.js` - 工作流测试
|
|
18
|
+
- ❌ `test.js` - 通用测试
|
|
19
|
+
- ❌ `nul` - 无用文件
|
|
20
|
+
- ❌ `test-ctrl-c.jsx~` - 备份文件
|
|
21
|
+
|
|
22
|
+
### 删除的文档文件
|
|
23
|
+
- ❌ `CTRL+C_FIX_SUMMARY.md` - 修复总结(已过时)
|
|
24
|
+
- ❌ `CTRL_C_CAPTURE_FIX.md` - 捕获修复说明(已过时)
|
|
25
|
+
- ❌ `CTRL_C_SOLUTIONS.md` - 解决方案文档(已过时)
|
|
26
|
+
- ❌ `FINAL_SUMMARY.md` - 最终总结(已过时)
|
|
27
|
+
- ❌ `IMPLEMENTATION_PLAN.md` - 实现计划(已过时)
|
|
28
|
+
- ❌ `IMPLEMENTATION_SUMMARY.md` - 实现总结(已过时)
|
|
29
|
+
- ❌ `PROGRESS_SUMMARY.md` - 进度总结(已过时)
|
|
30
|
+
- ❌ `TEST_CTRL_C_GUIDE.md` - 测试指南(已过时)
|
|
31
|
+
- ❌ `TEST_REPORT.md` - 测试报告(已过时)
|
|
32
|
+
- ❌ `USAGE_GUIDE.md` - 使用指南(已过时)
|
|
33
|
+
- ❌ `VERIFICATION_CHECKLIST.md` - 验证清单(已过时)
|
|
34
|
+
- ❌ `VERIFICATION_REPORT.md` - 验证报告(已过时)
|
|
35
|
+
- ❌ `API_GUIDE.md` - API 指南(已过时)
|
|
36
|
+
- ❌ `BATCH_MODE.md` - 批处理模式文档(已过时)
|
|
37
|
+
- ❌ `SDK_MIGRATION.md` - SDK 迁移指南(已过时)
|
|
38
|
+
- ❌ `docs/NAMING_IMPROVEMENT_SUMMARY.md` - 命名改进总结(已过时)
|
|
39
|
+
- ❌ `.closer_plan/` - 整个计划目录(临时文件)
|
|
40
|
+
|
|
41
|
+
### 保留的核心文件
|
|
42
|
+
- ✅ `README.md` - 项目主文档(已更新实验记录链接)
|
|
43
|
+
- ✅ `CLAUDE.md` - AI 助手指南
|
|
44
|
+
- ✅ `cloco.md` - 项目行为指南
|
|
45
|
+
- ✅ `winfix.md` - Windows 环境修复说明
|
|
46
|
+
- ✅ `CTRL_C_EXPERIMENT.md` - Ctrl+C 实验记录(新建)
|
|
47
|
+
- ✅ `test-ctrl-c.jsx` - Ctrl+C 功能测试(正确实现)
|
|
48
|
+
- ✅ `src/closer-cli.jsx` - 主 CLI(已应用正确方案)
|
|
49
|
+
- ✅ `docs/PROJECT_HISTORY_ISOLATION.md` - 项目历史隔离文档
|
|
50
|
+
- ✅ `docs/QUICK_START_HISTORY.md` - 快速开始指南
|
|
51
|
+
- ✅ `docs/FILE_NAMING_IMPROVEMENT.md` - 文件命名改进文档
|
|
52
|
+
|
|
53
|
+
## 项目当前状态
|
|
54
|
+
|
|
55
|
+
### 文档结构
|
|
56
|
+
```
|
|
57
|
+
.
|
|
58
|
+
├── README.md # 主文档
|
|
59
|
+
├── CLAUDE.md # AI 助手指南
|
|
60
|
+
├── cloco.md # 行为指南
|
|
61
|
+
├── CTRL_C_EXPERIMENT.md # Ctrl+C 实验记录
|
|
62
|
+
├── winfix.md # Windows 修复说明
|
|
63
|
+
└── docs/
|
|
64
|
+
├── PROJECT_HISTORY_ISOLATION.md
|
|
65
|
+
├── QUICK_START_HISTORY.md
|
|
66
|
+
└── FILE_NAMING_IMPROVEMENT.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 源代码结构
|
|
70
|
+
```
|
|
71
|
+
src/
|
|
72
|
+
├── commands/ # CLI 命令
|
|
73
|
+
│ ├── batch.js
|
|
74
|
+
│ ├── chat.js
|
|
75
|
+
│ ├── config.js
|
|
76
|
+
│ ├── help.js
|
|
77
|
+
│ ├── history.js
|
|
78
|
+
│ ├── setup.js
|
|
79
|
+
│ ├── upgrade.js
|
|
80
|
+
│ └── workflow-tests.js
|
|
81
|
+
├── utils/ # 工具函数
|
|
82
|
+
├── closer-cli.jsx # 主 CLI(Ctrl+C 已修复)
|
|
83
|
+
├── batch-cli.js # 批处理模式
|
|
84
|
+
├── ai-client.js # AI 客户端
|
|
85
|
+
├── conversation.js # 对话管理
|
|
86
|
+
├── planner.js # 任务规划
|
|
87
|
+
├── tools.js # 工具执行
|
|
88
|
+
└── ... (其他核心模块)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 测试文件
|
|
92
|
+
```
|
|
93
|
+
test-ctrl-c.jsx # Ctrl+C 功能测试
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 核心改进
|
|
97
|
+
|
|
98
|
+
### Ctrl+C 双击退出功能 ✅
|
|
99
|
+
**问题**: 之前的实现尝试都失败了,会导致第一次 Ctrl+C 就退出
|
|
100
|
+
|
|
101
|
+
**正确方案** (test-ctrl-c.jsx):
|
|
102
|
+
1. 使用 `useInput` hook 的 `{ capture: true }` 选项
|
|
103
|
+
2. 在 `render()` 时设置 `exitOnCtrlC: false`
|
|
104
|
+
3. 不使用任何 SIGINT 处理器
|
|
105
|
+
4. 使用时间戳判断双击间隔(1.5秒)
|
|
106
|
+
|
|
107
|
+
**已应用**: `src/closer-cli.jsx` 已使用该方案
|
|
108
|
+
|
|
109
|
+
## 编译状态
|
|
110
|
+
✅ 所有代码编译通过 (`npm run check`)
|
|
111
|
+
|
|
112
|
+
## 项目健康度
|
|
113
|
+
- 📁 文档: 清理完成,结构清晰
|
|
114
|
+
- 🧪 测试: 保留核心测试文件
|
|
115
|
+
- 💻 代码: 编译通过,无遗留问题
|
|
116
|
+
- 🔧 配置: 完整且正确
|
|
117
|
+
|
|
118
|
+
## 后续建议
|
|
119
|
+
1. 保持文档简洁,避免重复
|
|
120
|
+
2. 新的实验和总结添加到 `CTRL_C_EXPERIMENT.md`
|
|
121
|
+
3. 定期清理临时文件和过时文档
|