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,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Thinking 功能演示脚本
|
|
4
|
+
*
|
|
5
|
+
* 这个脚本演示了如何使用 AI 的 thinking 功能
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
const DEMO_SCENARIOS = [
|
|
12
|
+
{
|
|
13
|
+
name: '简单查询',
|
|
14
|
+
description: '演示基本的 thinking 过程',
|
|
15
|
+
input: '列出当前目录的文件\n',
|
|
16
|
+
duration: 5000
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: '复杂任务',
|
|
20
|
+
description: '演示多步骤思考过程',
|
|
21
|
+
input: '请分析一下 src/ 目录下的所有 JavaScript 文件,总结它们的功能\n',
|
|
22
|
+
duration: 15000
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: '问题解决',
|
|
26
|
+
description: '演示问题分析和解决过程',
|
|
27
|
+
input: '帮我检查一下 package.json 中的依赖是否有安全漏洞\n',
|
|
28
|
+
duration: 10000
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// 颜色输出
|
|
33
|
+
const colors = {
|
|
34
|
+
reset: '\x1b[0m',
|
|
35
|
+
green: '\x1b[32m',
|
|
36
|
+
cyan: '\x1b[36m',
|
|
37
|
+
yellow: '\x1b[33m',
|
|
38
|
+
blue: '\x1b[34m'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function log(message, color = 'reset') {
|
|
42
|
+
const colorCode = colors[color] || colors.reset;
|
|
43
|
+
console.log(`${colorCode}${message}${colors.reset}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function runDemo() {
|
|
47
|
+
log('='.repeat(70), 'blue');
|
|
48
|
+
log('AI Thinking 功能演示', 'blue');
|
|
49
|
+
log('='.repeat(70), 'blue');
|
|
50
|
+
|
|
51
|
+
log('\n这个演示将展示 AI 的思考过程。', 'cyan');
|
|
52
|
+
log('请注意观察 "AI Thinking Process" 区域的内容。', 'cyan');
|
|
53
|
+
log('\n按 Enter 键开始演示...', 'yellow');
|
|
54
|
+
|
|
55
|
+
// 等待用户输入
|
|
56
|
+
await new Promise(resolve => {
|
|
57
|
+
process.stdin.once('data', resolve);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
for (const scenario of DEMO_SCENARIOS) {
|
|
61
|
+
log('\n' + '='.repeat(70), 'blue');
|
|
62
|
+
log(`场景: ${scenario.name}`, 'blue');
|
|
63
|
+
log(`描述: ${scenario.description}`, 'cyan');
|
|
64
|
+
log('='.repeat(70), 'blue');
|
|
65
|
+
|
|
66
|
+
log('\n启动 Closer Code...', 'yellow');
|
|
67
|
+
|
|
68
|
+
// 启动 CLI
|
|
69
|
+
const cli = spawn('node', ['dist/closer-cli.js'], {
|
|
70
|
+
cwd: process.cwd(),
|
|
71
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
72
|
+
env: {
|
|
73
|
+
...process.env,
|
|
74
|
+
CLOSER_AUTO_PLAN: 'false',
|
|
75
|
+
CLOSER_AUTO_EXECUTE: 'false'
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// 等待一段时间后发送输入
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
81
|
+
|
|
82
|
+
log(`\n发送输入: ${scenario.input.trim()}`, 'cyan');
|
|
83
|
+
cli.stdin.write(scenario.input);
|
|
84
|
+
|
|
85
|
+
// 等待场景完成
|
|
86
|
+
await new Promise(resolve => setTimeout(resolve, scenario.duration));
|
|
87
|
+
|
|
88
|
+
// 终止进程
|
|
89
|
+
cli.kill('SIGTERM');
|
|
90
|
+
|
|
91
|
+
log(`\n场景 "${scenario.name}" 完成`, 'green');
|
|
92
|
+
|
|
93
|
+
// 等待一段时间再进行下一个场景
|
|
94
|
+
if (scenario !== DEMO_SCENARIOS[DEMO_SCENARIOS.length - 1]) {
|
|
95
|
+
log('\n按 Enter 键继续下一个场景...', 'yellow');
|
|
96
|
+
await new Promise(resolve => {
|
|
97
|
+
process.stdin.once('data', resolve);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
log('\n' + '='.repeat(70), 'blue');
|
|
103
|
+
log('演示完成!', 'green');
|
|
104
|
+
log('='.repeat(70), 'blue');
|
|
105
|
+
log('\n你应该已经看到 AI 的思考过程在 "AI Thinking Process" 区域显示。', 'cyan');
|
|
106
|
+
log('这个功能可以帮助你了解 AI 如何分析和解决问题。', 'cyan');
|
|
107
|
+
log('\n更多信息请查看: docs/THINKING_FEATURE.md', 'yellow');
|
|
108
|
+
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 处理错误
|
|
113
|
+
process.on('uncaughtException', (error) => {
|
|
114
|
+
log(`\n错误: ${error.message}`, 'red');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
process.on('SIGINT', () => {
|
|
119
|
+
log('\n\n演示已中断', 'yellow');
|
|
120
|
+
process.exit(0);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 运行演示
|
|
124
|
+
runDemo();
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# UI 优化和 AI Thinking 功能 - 最终验证报告
|
|
2
|
+
|
|
3
|
+
## 执行时间
|
|
4
|
+
2025-01-18
|
|
5
|
+
|
|
6
|
+
## 任务概述
|
|
7
|
+
|
|
8
|
+
### 任务 1: UI 优化
|
|
9
|
+
**目标**: 解决 Conversation 和 Tool Execution 区域内容过长导致 UI 撑大的问题
|
|
10
|
+
|
|
11
|
+
### 任务 2: AI Thinking 显示
|
|
12
|
+
**目标**: 添加 AI 模型思考过程的可视化显示
|
|
13
|
+
|
|
14
|
+
## 实施情况
|
|
15
|
+
|
|
16
|
+
### ✅ 任务 1: UI 优化
|
|
17
|
+
|
|
18
|
+
#### 问题分析
|
|
19
|
+
- Conversation 区域随着消息增加会变得很长
|
|
20
|
+
- Tool Execution 区域随着工具调用增加会撑大 UI
|
|
21
|
+
- Task Progress 区域被遮挡,不可见
|
|
22
|
+
|
|
23
|
+
#### 解决方案
|
|
24
|
+
1. **Conversation 区域**
|
|
25
|
+
- ✅ 限制显示最后 15 条消息
|
|
26
|
+
- ✅ 支持滚动查看历史消息
|
|
27
|
+
- ✅ 添加滚动提示
|
|
28
|
+
- ✅ 实现键盘控制(PageUp/PageDown, Alt+↑/↓)
|
|
29
|
+
|
|
30
|
+
2. **Tool Execution 区域**
|
|
31
|
+
- ✅ 限制显示最后 5 条工具执行记录
|
|
32
|
+
- ✅ 每条记录限制输入/输出为 100 字符
|
|
33
|
+
- ✅ 超出部分用 `...` 表示
|
|
34
|
+
|
|
35
|
+
3. **其他区域**
|
|
36
|
+
- ✅ Latest Logs: 显示最后 15 行
|
|
37
|
+
- ✅ AI Thinking: 显示最后 10 条
|
|
38
|
+
|
|
39
|
+
#### 验证测试
|
|
40
|
+
```bash
|
|
41
|
+
$ node test/ui-verification-test.js
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**测试结果**:
|
|
45
|
+
- 总测试数: 5
|
|
46
|
+
- 通过: 5
|
|
47
|
+
- 失败: 0
|
|
48
|
+
- **成功率: 100%** ✅
|
|
49
|
+
|
|
50
|
+
**详细结果**:
|
|
51
|
+
- ✅ Conversation 滚动限制: 应该限制 Conversation 显示的消息数量
|
|
52
|
+
- ✅ Tool Execution 数量限制: 应该限制 Tool Execution 显示的数量
|
|
53
|
+
- ✅ Thinking 区域: 应该有 AI Thinking Process 区域
|
|
54
|
+
- ✅ Thinking 状态处理: 应该处理 thinking 事件
|
|
55
|
+
- ✅ Thinking API 配置: 应该启用 thinking API
|
|
56
|
+
|
|
57
|
+
### ✅ 任务 2: AI Thinking 显示
|
|
58
|
+
|
|
59
|
+
#### 实现内容
|
|
60
|
+
1. **API 集成**
|
|
61
|
+
- ✅ 在 AI 请求中启用 thinking 功能
|
|
62
|
+
- ✅ 配置 budget_tokens 为 1600
|
|
63
|
+
- ✅ 支持流式响应中的 thinking 事件
|
|
64
|
+
|
|
65
|
+
2. **UI 显示**
|
|
66
|
+
- ✅ 添加专门的 "AI Thinking Process" 区域
|
|
67
|
+
- ✅ 实时更新 thinking 内容
|
|
68
|
+
- ✅ 限制显示最后 10 条记录
|
|
69
|
+
- ✅ 每条记录带有时间戳
|
|
70
|
+
|
|
71
|
+
3. **事件处理**
|
|
72
|
+
- ✅ 监听 thinking 事件
|
|
73
|
+
- ✅ 更新 UI 状态
|
|
74
|
+
- ✅ 区分 thinking 和其他进度事件
|
|
75
|
+
|
|
76
|
+
#### 验证测试
|
|
77
|
+
```bash
|
|
78
|
+
$ node test/verify-thinking.js
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**测试结果**:
|
|
82
|
+
- 总测试数: 15
|
|
83
|
+
- 通过: 15
|
|
84
|
+
- 失败: 0
|
|
85
|
+
- **成功率: 100%** ✅
|
|
86
|
+
|
|
87
|
+
**详细结果**:
|
|
88
|
+
|
|
89
|
+
**源代码验证**:
|
|
90
|
+
- ✅ ai-client.js - chat 方法中的 thinking 配置
|
|
91
|
+
- ✅ ai-client.js - chatStream 方法中的 thinking 配置
|
|
92
|
+
- ✅ conversation.js - thinking 事件处理
|
|
93
|
+
- ✅ conversation.js - thinking delta 检查
|
|
94
|
+
- ✅ closer-cli.jsx - thinking 进度处理
|
|
95
|
+
- ✅ closer-cli.jsx - thinking 状态更新
|
|
96
|
+
- ✅ closer-cli.jsx - thinking UI 区域
|
|
97
|
+
|
|
98
|
+
**编译代码验证**:
|
|
99
|
+
- ✅ 包含关键字 "thinking"
|
|
100
|
+
- ✅ 包含关键字 "AI Thinking Process"
|
|
101
|
+
- ✅ 包含关键字 "budget_tokens"
|
|
102
|
+
- ✅ 包含关键字 "enabled"
|
|
103
|
+
|
|
104
|
+
**文档验证**:
|
|
105
|
+
- ✅ THINKING_FEATURE.md - 概述部分
|
|
106
|
+
- ✅ THINKING_FEATURE.md - 使用场景
|
|
107
|
+
- ✅ THINKING_FEATURE.md - 技术细节
|
|
108
|
+
- ✅ THINKING_FEATURE.md - 示例
|
|
109
|
+
|
|
110
|
+
## 技术实现
|
|
111
|
+
|
|
112
|
+
### 修改的文件
|
|
113
|
+
|
|
114
|
+
1. **src/ai-client.js**
|
|
115
|
+
- 添加 thinking 配置到 chat() 方法
|
|
116
|
+
- 添加 thinking 配置到 chatStream() 方法
|
|
117
|
+
|
|
118
|
+
2. **src/conversation.js**
|
|
119
|
+
- 添加 thinking 事件处理
|
|
120
|
+
- 检查 thinking delta
|
|
121
|
+
- 触发 onProgress 回调
|
|
122
|
+
|
|
123
|
+
3. **src/closer-cli.jsx**
|
|
124
|
+
- 添加 thinking 进度处理
|
|
125
|
+
- 更新 thinking 状态
|
|
126
|
+
- 显示 thinking UI 区域
|
|
127
|
+
- 优化各个区域的内容长度限制
|
|
128
|
+
|
|
129
|
+
### 新增的文件
|
|
130
|
+
|
|
131
|
+
1. **test/ui-verification-test.js** - UI 优化验证测试
|
|
132
|
+
2. **test/verify-thinking.js** - Thinking 功能验证测试
|
|
133
|
+
3. **test/demo-thinking.js** - Thinking 功能演示脚本
|
|
134
|
+
4. **docs/THINKING_FEATURE.md** - Thinking 功能完整文档
|
|
135
|
+
|
|
136
|
+
## UI 布局优化
|
|
137
|
+
|
|
138
|
+
### 优化前
|
|
139
|
+
```
|
|
140
|
+
┌─────────────────────────────────────────┐
|
|
141
|
+
│ Conversation (很长,可能超过一屏幕) │
|
|
142
|
+
│ │
|
|
143
|
+
│ ... 很多消息 ... │
|
|
144
|
+
│ │
|
|
145
|
+
├─────────────────────────────────────────┤
|
|
146
|
+
│ Tool Execution (很长,撑大 UI) │
|
|
147
|
+
│ │
|
|
148
|
+
│ ... 很多工具调用 ... │
|
|
149
|
+
│ │
|
|
150
|
+
├─────────────────────────────────────────┤
|
|
151
|
+
│ Task Progress (被遮挡,看不见) ❌ │
|
|
152
|
+
└─────────────────────────────────────────┘
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 优化后
|
|
156
|
+
```
|
|
157
|
+
┌─────────────────────────────────────────┐
|
|
158
|
+
│ 顶部状态栏 │
|
|
159
|
+
├─────────────────────────────────────────┤
|
|
160
|
+
│ 📋 Latest Logs (17.5%) │
|
|
161
|
+
│ - 显示最后 15 行 ✅ │
|
|
162
|
+
├─────────────────────────────────────────┤
|
|
163
|
+
│ 🧠 AI Thinking Process (17.5%) ✅ │
|
|
164
|
+
│ - 显示最后 10 条 thinking │
|
|
165
|
+
├─────────────────────────────┬───────────┤
|
|
166
|
+
│ 💬 Conversation (50%) │ 📋 Task │
|
|
167
|
+
│ - 显示最后 15 条消息 ✅ │ Progress │
|
|
168
|
+
│ - 支持滚动 ✅ │ (25%) ✅ │
|
|
169
|
+
├─────────────────────────────┼───────────┤
|
|
170
|
+
│ 🔧 Tool Execution │ │
|
|
171
|
+
│ - 显示最后 5 条 ✅ │ │
|
|
172
|
+
│ - 每条最多 100 字符 ✅ │ │
|
|
173
|
+
└─────────────────────────────┴───────────┘
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Git 提交记录
|
|
177
|
+
|
|
178
|
+
### Commit 1: a49e870
|
|
179
|
+
```
|
|
180
|
+
feat: UI优化 - 添加AI思考过程显示和内容长度限制
|
|
181
|
+
|
|
182
|
+
主要改进:
|
|
183
|
+
1. 添加AI思考过程(thinking)显示功能
|
|
184
|
+
- 在AI请求中启用thinking API
|
|
185
|
+
- 添加专门的Thinking区域显示AI思考内容
|
|
186
|
+
- 实时更新thinking状态
|
|
187
|
+
- 限制显示最后10条thinking记录
|
|
188
|
+
|
|
189
|
+
2. 优化UI布局,防止内容过长撑大界面
|
|
190
|
+
- Conversation区域:限制显示最后15条消息,支持滚动
|
|
191
|
+
- Tool Execution区域:限制显示最后5条,每条最多100字符
|
|
192
|
+
- Latest Logs区域:限制显示最后15行
|
|
193
|
+
- AI Thinking区域:限制显示最后10条
|
|
194
|
+
|
|
195
|
+
3. 添加自动化验证测试
|
|
196
|
+
- 创建UI验证测试脚本
|
|
197
|
+
- 验证所有UI元素是否正确实现
|
|
198
|
+
- 测试通过率100%
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Commit 2: 05e5dd7
|
|
202
|
+
```
|
|
203
|
+
feat: 添加AI思考过程功能的文档和验证测试
|
|
204
|
+
|
|
205
|
+
主要改进:
|
|
206
|
+
1. 添加完整的 Thinking 功能文档
|
|
207
|
+
- 功能概述和使用场景
|
|
208
|
+
- 技术实现细节
|
|
209
|
+
- 配置选项说明
|
|
210
|
+
- 使用示例
|
|
211
|
+
|
|
212
|
+
2. 添加 Thinking 功能演示脚本
|
|
213
|
+
- 交互式演示场景
|
|
214
|
+
- 展示不同复杂度的任务
|
|
215
|
+
- 帮助用户理解 thinking 过程
|
|
216
|
+
|
|
217
|
+
3. 添加 Thinking 功能验证测试
|
|
218
|
+
- 验证源代码实现
|
|
219
|
+
- 验证编译后的代码
|
|
220
|
+
- 验证文档完整性
|
|
221
|
+
- 测试通过率 100%
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 用户体验改进
|
|
225
|
+
|
|
226
|
+
### 之前的问题
|
|
227
|
+
- ❌ Conversation 区域过长,看不到 Task Progress
|
|
228
|
+
- ❌ Tool Execution 区域撑大整个 UI
|
|
229
|
+
- ❌ 无法看到 AI 的思考过程
|
|
230
|
+
- ❌ 不了解 AI 为什么做出某些决策
|
|
231
|
+
|
|
232
|
+
### 之后的改进
|
|
233
|
+
- ✅ 所有区域都有合理的高度限制
|
|
234
|
+
- ✅ Task Progress 始终可见
|
|
235
|
+
- ✅ 可以实时看到 AI 的思考过程
|
|
236
|
+
- ✅ 更好地理解 AI 的工作方式
|
|
237
|
+
- ✅ 支持滚动查看历史内容
|
|
238
|
+
|
|
239
|
+
## 功能演示
|
|
240
|
+
|
|
241
|
+
### 如何查看 AI Thinking 过程
|
|
242
|
+
|
|
243
|
+
1. 启动 Closer Code:
|
|
244
|
+
```bash
|
|
245
|
+
npm start
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
2. 发送一个复杂任务:
|
|
249
|
+
```
|
|
250
|
+
请分析一下这个项目的架构
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
3. 观察 "AI Thinking Process" 区域:
|
|
254
|
+
```
|
|
255
|
+
🧠 AI Thinking Process
|
|
256
|
+
──────────────────────
|
|
257
|
+
🤔 [14:30:45] 分析用户请求...
|
|
258
|
+
🤔 [14:30:46] 考虑使用工具...
|
|
259
|
+
⚡ [14:30:47] 调用工具: readFile
|
|
260
|
+
📊 [14:30:48] 工具执行结果: ✓ 成功
|
|
261
|
+
✍️ [14:30:49] 生成响应中...
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 如何使用滚动功能
|
|
265
|
+
|
|
266
|
+
- **PageUp/PageDown**: 快速滚动
|
|
267
|
+
- **Alt+↑/↓**: 精确滚动(当输入框有内容时)
|
|
268
|
+
- **↑/↓**: 滚动(当输入框为空时)
|
|
269
|
+
|
|
270
|
+
## 总结
|
|
271
|
+
|
|
272
|
+
### 完成情况
|
|
273
|
+
- ✅ **任务 1**: UI 优化 - 100% 完成
|
|
274
|
+
- ✅ **任务 2**: AI Thinking 显示 - 100% 完成
|
|
275
|
+
|
|
276
|
+
### 测试验证
|
|
277
|
+
- ✅ UI 验证测试 - 100% 通过
|
|
278
|
+
- ✅ Thinking 功能验证测试 - 100% 通过
|
|
279
|
+
|
|
280
|
+
### 文档和测试
|
|
281
|
+
- ✅ 完整的功能文档
|
|
282
|
+
- ✅ 自动化验证测试
|
|
283
|
+
- ✅ 交互式演示脚本
|
|
284
|
+
|
|
285
|
+
### Git 提交
|
|
286
|
+
- ✅ 2 个清晰的提交
|
|
287
|
+
- ✅ 详细的提交信息
|
|
288
|
+
- ✅ 所有改动已提交
|
|
289
|
+
|
|
290
|
+
## 结论
|
|
291
|
+
|
|
292
|
+
本次任务成功完成了所有目标:
|
|
293
|
+
|
|
294
|
+
1. **UI 优化**: 通过限制显示内容和添加滚动功能,解决了 UI 撑大的问题
|
|
295
|
+
2. **AI Thinking 显示**: 成功集成并显示 AI 的思考过程
|
|
296
|
+
|
|
297
|
+
所有改进都已经:
|
|
298
|
+
- ✅ 实现并测试通过
|
|
299
|
+
- ✅ 提交到 Git
|
|
300
|
+
- ✅ 编写了完整的文档
|
|
301
|
+
- ✅ 创建了验证测试
|
|
302
|
+
|
|
303
|
+
用户现在可以享受更好的 UI 体验,并实时查看 AI 的思考过程!🎉
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 研究 thinking 内容的实际长度和结构
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
7
|
+
import { loadConfig } from '../src/config.js';
|
|
8
|
+
|
|
9
|
+
async function testThinkingContent() {
|
|
10
|
+
console.log('='.repeat(70));
|
|
11
|
+
console.log('研究 Thinking 内容的实际结构');
|
|
12
|
+
console.log('='.repeat(70));
|
|
13
|
+
|
|
14
|
+
const config = await loadConfig();
|
|
15
|
+
const apiKey = config.api?.anthropicApiKey;
|
|
16
|
+
|
|
17
|
+
if (!apiKey) {
|
|
18
|
+
console.error('❌ 未找到 API Key');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const client = new Anthropic({ apiKey });
|
|
23
|
+
|
|
24
|
+
// 测试不同复杂度的任务和不同的 budget_tokens
|
|
25
|
+
const testCases = [
|
|
26
|
+
{
|
|
27
|
+
name: '简单问题(budget: 1600)',
|
|
28
|
+
budget: 1600,
|
|
29
|
+
message: '2 + 2 = ?'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: '中等问题(budget: 1600)',
|
|
33
|
+
budget: 1600,
|
|
34
|
+
message: '解释一下什么是递归,并给出一个例子'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: '复杂问题(budget: 1600)',
|
|
38
|
+
budget: 1600,
|
|
39
|
+
message: '分析一下快速排序算法的时间复杂度,包括最好、最坏和平均情况'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: '复杂问题(budget: 20000)',
|
|
43
|
+
budget: 20000,
|
|
44
|
+
message: '分析一下快速排序算法的时间复杂度,包括最好、最坏和平均情况,并解释为什么在实际应用中它通常比其他O(n log n)算法更快'
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
for (const testCase of testCases) {
|
|
49
|
+
console.log(`\n${'='.repeat(70)}`);
|
|
50
|
+
console.log(`测试: ${testCase.name}`);
|
|
51
|
+
console.log(`问题: ${testCase.message}`);
|
|
52
|
+
console.log(`${'='.repeat(70)}`);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const stream = client.messages.stream({
|
|
56
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
57
|
+
max_tokens: 1000,
|
|
58
|
+
messages: [{ role: 'user', content: testCase.message }],
|
|
59
|
+
thinking: {
|
|
60
|
+
type: 'enabled',
|
|
61
|
+
budget_tokens: testCase.budget
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
let thinkingContent = '';
|
|
66
|
+
let thinkingLength = 0;
|
|
67
|
+
let textContent = '';
|
|
68
|
+
let signature = '';
|
|
69
|
+
|
|
70
|
+
stream.on('thinking', (thinkingDelta, thinkingSnapshot) => {
|
|
71
|
+
// thinkingDelta: 增量
|
|
72
|
+
// thinkingSnapshot: 完整快照
|
|
73
|
+
thinkingContent = thinkingSnapshot;
|
|
74
|
+
thinkingLength = thinkingSnapshot.length;
|
|
75
|
+
|
|
76
|
+
process.stdout.write('\r🤔 Thinking 长度: ' + thinkingLength);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
stream.on('text', (textDelta) => {
|
|
80
|
+
textContent += textDelta;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
stream.on('signature', (sig) => {
|
|
84
|
+
signature = sig;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const finalMessage = await stream.finalMessage();
|
|
88
|
+
|
|
89
|
+
console.log('\n\n📊 结果统计:');
|
|
90
|
+
console.log(` Budget Tokens: ${testCase.budget}`);
|
|
91
|
+
console.log(` Thinking 长度: ${thinkingLength} 字符`);
|
|
92
|
+
console.log(` Thinking Token数 (估算): ~${Math.ceil(thinkingLength / 4)}`);
|
|
93
|
+
console.log(` 文本长度: ${textContent.length} 字符`);
|
|
94
|
+
console.log(` 有签名: ${signature ? '是' : '否'}`);
|
|
95
|
+
|
|
96
|
+
// 显示thinking内容的前500字符
|
|
97
|
+
console.log('\n📝 Thinking 内容预览 (前500字符):');
|
|
98
|
+
console.log('─'.repeat(70));
|
|
99
|
+
console.log(thinkingContent.substring(0, 500));
|
|
100
|
+
if (thinkingContent.length > 500) {
|
|
101
|
+
console.log('...\n(内容被截断)');
|
|
102
|
+
}
|
|
103
|
+
console.log('─'.repeat(70));
|
|
104
|
+
|
|
105
|
+
// 显示完整thinking内容的统计
|
|
106
|
+
const lines = thinkingContent.split('\n');
|
|
107
|
+
console.log(`\n📈 Thinking 内容分析:`);
|
|
108
|
+
console.log(` 总行数: ${lines.length}`);
|
|
109
|
+
console.log(` 平均行长度: ${Math.ceil(thinkingLength / lines.length)} 字符`);
|
|
110
|
+
|
|
111
|
+
// 分析thinking内容的结构
|
|
112
|
+
const hasNumbering = /^\d+\./.test(thinkingContent);
|
|
113
|
+
const hasBullets = /^[-*]/.test(thinkingContent);
|
|
114
|
+
const hasHeaders = /^#+\s/.test(thinkingContent);
|
|
115
|
+
|
|
116
|
+
console.log(` 包含编号列表: ${hasNumbering ? '是' : '否'}`);
|
|
117
|
+
console.log(` 包含项目符号: ${hasBullets ? '是' : '否'}`);
|
|
118
|
+
console.log(` 包含标题: ${hasHeaders ? '是' : '否'}`);
|
|
119
|
+
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.error(`\n❌ 错误: ${error.message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log('\n' + '='.repeat(70));
|
|
126
|
+
console.log('研究完成');
|
|
127
|
+
console.log('='.repeat(70));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
testThinkingContent().catch(console.error);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 单元测试:验证 writeFile 错误处理和 AI 自我修复能力
|
|
4
|
+
*
|
|
5
|
+
* 测试场景:
|
|
6
|
+
* 1. 尝试写入不存在的目录 → 应该返回 ENOENT 错误
|
|
7
|
+
* 2. 错误响应包含修复建议
|
|
8
|
+
* 3. 创建目录后重试 → 应该成功
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import fs from 'fs/promises';
|
|
14
|
+
import { setToolExecutorContext, writeFileTool } from '../src/tools.js';
|
|
15
|
+
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
18
|
+
|
|
19
|
+
async function testErrorHandlingAndRetry() {
|
|
20
|
+
console.log('🧪 单元测试:writeFile 错误处理和自我修复\n');
|
|
21
|
+
console.log('═'.repeat(60));
|
|
22
|
+
|
|
23
|
+
// 创建临时测试目录
|
|
24
|
+
const testDir = path.join(__dirname, 'temp-error-test');
|
|
25
|
+
await fs.mkdir(testDir, { recursive: true });
|
|
26
|
+
console.log(`✅ 测试目录: ${testDir}\n`);
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
// 初始化工具上下文
|
|
30
|
+
setToolExecutorContext({
|
|
31
|
+
behavior: { workingDir: testDir },
|
|
32
|
+
tools: { enabled: ['writeFile', 'bash'] }
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// 测试1:尝试写入不存在的目录(应该失败并返回详细错误)
|
|
36
|
+
console.log('测试1: 尝试写入不存在的目录');
|
|
37
|
+
console.log('文件路径: chapters/chapter-01.txt\n');
|
|
38
|
+
|
|
39
|
+
const result1 = await writeFileTool.run({
|
|
40
|
+
filePath: 'chapters/chapter-01.txt',
|
|
41
|
+
content: '# 第一章\n\n这是第一章的内容。'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const parsed1 = JSON.parse(result1);
|
|
45
|
+
console.log('工具响应:');
|
|
46
|
+
console.log(JSON.stringify(parsed1, null, 2));
|
|
47
|
+
console.log();
|
|
48
|
+
|
|
49
|
+
if (!parsed1.success && parsed1.error === 'ENOENT') {
|
|
50
|
+
console.log('✅ 正确返回 ENOENT 错误');
|
|
51
|
+
console.log(`✅ 包含修复建议: ${parsed1.suggestion ? 'Yes' : 'No'}`);
|
|
52
|
+
console.log(`✅ 包含提示信息: ${parsed1.hint ? 'Yes' : 'No'}`);
|
|
53
|
+
} else {
|
|
54
|
+
console.log('❌ 错误:应该返回 ENOENT 错误');
|
|
55
|
+
}
|
|
56
|
+
console.log();
|
|
57
|
+
|
|
58
|
+
// 测试2:创建目录(模拟 AI 的自我修复)
|
|
59
|
+
console.log('测试2: 创建目录(模拟 AI 自我修复)');
|
|
60
|
+
console.log('命令: mkdir -p chapters\n');
|
|
61
|
+
|
|
62
|
+
const { executeBashCommand } = await import('../src/bash-runner.js');
|
|
63
|
+
const mkdirResult = await executeBashCommand('mkdir -p chapters', {
|
|
64
|
+
cwd: testDir
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (mkdirResult.success) {
|
|
68
|
+
console.log('✅ 目录创建成功');
|
|
69
|
+
} else {
|
|
70
|
+
console.log('❌ 目录创建失败:', mkdirResult.stderr);
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
73
|
+
|
|
74
|
+
// 测试3:重试写入文件(应该成功)
|
|
75
|
+
console.log('测试3: 重试写入文件');
|
|
76
|
+
console.log('文件路径: chapters/chapter-01.txt\n');
|
|
77
|
+
|
|
78
|
+
const result3 = await writeFileTool.run({
|
|
79
|
+
filePath: 'chapters/chapter-01.txt',
|
|
80
|
+
content: '# 第一章\n\n这是第一章的内容。'
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const parsed3 = JSON.parse(result3);
|
|
84
|
+
console.log('工具响应:');
|
|
85
|
+
console.log(JSON.stringify(parsed3, null, 2));
|
|
86
|
+
console.log();
|
|
87
|
+
|
|
88
|
+
if (parsed3.success) {
|
|
89
|
+
console.log('✅ 重试成功!');
|
|
90
|
+
console.log(`✅ 文件路径: ${parsed3.path}`);
|
|
91
|
+
console.log(`✅ 文件大小: ${parsed3.size} bytes`);
|
|
92
|
+
} else {
|
|
93
|
+
console.log('❌ 重试失败');
|
|
94
|
+
}
|
|
95
|
+
console.log();
|
|
96
|
+
|
|
97
|
+
// 验证文件内容
|
|
98
|
+
console.log('═'.repeat(60));
|
|
99
|
+
console.log('\n🔍 验证文件内容:\n');
|
|
100
|
+
|
|
101
|
+
const filePath = path.join(testDir, 'chapters/chapter-01.txt');
|
|
102
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
103
|
+
console.log(content);
|
|
104
|
+
console.log('\n' + '═'.repeat(60));
|
|
105
|
+
console.log('\n✅ 所有测试通过!\n');
|
|
106
|
+
console.log('📊 测试总结:');
|
|
107
|
+
console.log(' ✅ writeFile 正确返回 ENOENT 错误');
|
|
108
|
+
console.log(' ✅ 错误响应包含详细的修复建议');
|
|
109
|
+
console.log(' ✅ AI 可以根据错误信息进行自我修复');
|
|
110
|
+
console.log(' ✅ 修复后重试操作成功\n');
|
|
111
|
+
|
|
112
|
+
// 清理
|
|
113
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
114
|
+
console.log('🧹 清理完成\n');
|
|
115
|
+
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('\n❌ 测试失败:', error.message);
|
|
118
|
+
console.error(error.stack);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 运行测试
|
|
123
|
+
testErrorHandlingAndRetry().catch(console.error);
|