jinzd-ai-cli 0.1.9 → 0.1.11
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/CLAUDE.md +400 -285
- package/README.md +155 -155
- package/dist/index.js +388 -203
- package/package.json +88 -88
package/CLAUDE.md
CHANGED
|
@@ -1,285 +1,400 @@
|
|
|
1
|
-
# ai-cli 项目说明
|
|
2
|
-
|
|
3
|
-
## 项目简介
|
|
4
|
-
|
|
5
|
-
一个跨平台的 REPL 风格 AI 对话工具,支持多个主流 AI 提供商(Claude、Gemini、DeepSeek、智谱清言、Kimi),
|
|
6
|
-
带有 **AI 工具调用(Agentic)** 能力,支持执行 bash 命令、读写文件、运行交互式程序、流式生成大文档。
|
|
7
|
-
代理支持(`proxy` 配置字段 + 环境变量),Gemini 完整支持(2.5 Pro/Flash,array items schema 修复)。
|
|
8
|
-
设计上可扩展至 Electron/Tauri 桌面 GUI。
|
|
9
|
-
|
|
10
|
-
## 技术栈
|
|
11
|
-
|
|
12
|
-
- **语言**: TypeScript (ESM,`"type": "module"`,导入须用 `.js` 扩展名)
|
|
13
|
-
- **运行时**: Node.js >= 20
|
|
14
|
-
- **构建工具**: tsup → `dist/index.js`
|
|
15
|
-
- **包管理**: npm
|
|
16
|
-
|
|
17
|
-
## 项目结构
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
src/
|
|
21
|
-
├── index.ts # CLI 入口点 (Commander bin 脚本)
|
|
22
|
-
├── core/
|
|
23
|
-
│ ├── types.ts # 所有共享 TypeScript 接口(ChatRequest 含 timeout/_extraMessages)
|
|
24
|
-
│ ├── constants.ts # VERSION 等常量
|
|
25
|
-
│ ├── errors.ts # AiCliError → ProviderError / AuthError / RateLimitError 等
|
|
26
|
-
│ └── event-bus.ts # 类型安全的 EventEmitter(session.start/end, message.before/after)
|
|
27
|
-
├── providers/
|
|
28
|
-
│ ├── base.ts # 抽象 BaseProvider(chat/chatStream/validateApiKey/listModels/initialize)
|
|
29
|
-
│ ├── registry.ts # ProviderRegistry(initialize 时注入 apiKey + baseUrl + timeout)
|
|
30
|
-
│ ├── openai-compatible.ts # DeepSeek/Zhipu/Kimi 共用基类;实现 chatWithTools + buildToolResultMessages
|
|
31
|
-
│ ├── claude.ts # Anthropic SDK provider
|
|
32
|
-
│ ├── gemini.ts # Google Generative AI provider(role: assistant → model)
|
|
33
|
-
│ ├── deepseek.ts / zhipu.ts / kimi.ts # 继承 OpenAICompatibleProvider,只声明 defaultBaseUrl 和 info
|
|
34
|
-
├── config/
|
|
35
|
-
│ ├── schema.ts # Zod schema(含 timeouts / customBaseUrls / defaultModels)
|
|
36
|
-
│ ├── config-manager.ts # 读写 ~/.aicli/config.json,三层优先级:env > file > default
|
|
37
|
-
│ └── env-loader.ts # AICLI_API_KEY_* 等环境变量映射
|
|
38
|
-
├── session/
|
|
39
|
-
│ ├── session.ts # Session(addMessage / clear / toJSON / fromJSON)
|
|
40
|
-
│ └── session-manager.ts # CRUD for ~/.aicli/history/*.json
|
|
41
|
-
├── repl/
|
|
42
|
-
│ ├── repl.ts # 主 REPL 循环(MAX_TOOL_ROUNDS=20,handleChatWithTools agentic loop)
|
|
43
|
-
│ ├── renderer.ts # 终端输出(renderStream / renderResponse 均不加前置 \n)
|
|
44
|
-
│ ├── setup-wizard.ts # @inquirer/prompts 首次运行交互式设置
|
|
45
|
-
│ └── commands/
|
|
46
|
-
│ └── index.ts # CommandRegistry + 15个命令(/help /about /provider /model /clear /session /system /context /status /search /undo /export /tools /config /exit)
|
|
47
|
-
└── tools/
|
|
48
|
-
├── types.ts # ToolDefinition / ToolCall / ToolResult / DangerLevel / getDangerLevel
|
|
49
|
-
├── registry.ts # ToolRegistry(注册全部内置工具,共11个)
|
|
50
|
-
├── executor.ts # ToolExecutor(确认逻辑 + printToolCall/printToolResult)
|
|
51
|
-
└── builtin/
|
|
52
|
-
├── bash.ts # bash 工具(Windows: PowerShell + Buffer→UTF-8;Unix: $SHELL)
|
|
53
|
-
├── read-file.ts # read_file 工具
|
|
54
|
-
├── write-file.ts # write_file 工具
|
|
55
|
-
├── list-dir.ts # list_dir 工具
|
|
56
|
-
└── run-interactive.ts # run_interactive 工具(spawn 直连可执行文件,stdin_lines 依次输入)
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## 常用命令
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
npm run dev # 开发模式(tsx 热重载)
|
|
63
|
-
npm run build # 构建到 dist/index.js(ESM)和 dist-cjs/index.cjs(CJS)
|
|
64
|
-
node dist/index.js # 运行
|
|
65
|
-
|
|
66
|
-
# 子命令
|
|
67
|
-
node dist/index.js providers # 列出所有 provider 及配置状态
|
|
68
|
-
node dist/index.js sessions # 列出最近会话
|
|
69
|
-
node dist/index.js config # 运行配置向导
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## 打包为独立可执行文件
|
|
73
|
-
|
|
74
|
-
使用 `@yao-pkg/pkg` 将项目打包为无需 Node.js 环境即可运行的单文件可执行程序(约 56MB)。
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm run pack:win # Windows x64 → release/ai-cli-win.exe
|
|
78
|
-
npm run pack:mac # macOS arm64 → release/ai-cli-mac
|
|
79
|
-
npm run pack:mac-x64 # macOS x64 → release/ai-cli-mac-x64
|
|
80
|
-
npm run pack:linux # Linux x64 → release/ai-cli-linux
|
|
81
|
-
npm run pack:all # 同时打包所有平台
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 打包原理
|
|
85
|
-
|
|
86
|
-
- tsup 输出两套产物:
|
|
87
|
-
- `dist/index.js`(ESM,供 `node` 直接运行)
|
|
88
|
-
- `dist-cjs/index.cjs`(CJS + `noExternal: /.*/` 内联所有依赖,供 pkg 打包)
|
|
89
|
-
- pkg 使用 `--options no-deprecation` 内嵌到二进制,消除 punycode 弃用警告
|
|
90
|
-
- macOS/Linux 产物需在对应平台执行 `chmod +x` 后运行
|
|
91
|
-
|
|
92
|
-
### 关键兼容性问题(已解决)
|
|
93
|
-
|
|
94
|
-
**ora 在 pkg exe 中 Segfault**:`ora` spinner 在 `@yao-pkg/pkg` 打包的 Node 22 exe 里会触发段错误(exit code 139)。
|
|
95
|
-
**解决方案**:完全移除 `ora` 依赖,在 `src/repl/renderer.ts` 中用原生 `setInterval` + `process.stdout.write('\r\x1b[2K')` 实现轻量 spinner,非 TTY 环境自动降级为空操作。
|
|
96
|
-
|
|
97
|
-
## 配置存储
|
|
98
|
-
|
|
99
|
-
- **配置文件**: `~/.aicli/config.json`
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
|
134
|
-
|
|
135
|
-
|
|
|
136
|
-
| `
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
- `
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
##
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
-
|
|
241
|
-
-
|
|
242
|
-
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
-
|
|
263
|
-
-
|
|
264
|
-
-
|
|
265
|
-
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
###
|
|
270
|
-
-
|
|
271
|
-
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
1
|
+
# ai-cli 项目说明
|
|
2
|
+
|
|
3
|
+
## 项目简介
|
|
4
|
+
|
|
5
|
+
一个跨平台的 REPL 风格 AI 对话工具,支持多个主流 AI 提供商(Claude、Gemini、DeepSeek、智谱清言、Kimi),
|
|
6
|
+
带有 **AI 工具调用(Agentic)** 能力,支持执行 bash 命令、读写文件、运行交互式程序、流式生成大文档。
|
|
7
|
+
代理支持(`proxy` 配置字段 + 环境变量),Gemini 完整支持(2.5 Pro/Flash,array items schema 修复)。
|
|
8
|
+
设计上可扩展至 Electron/Tauri 桌面 GUI。
|
|
9
|
+
|
|
10
|
+
## 技术栈
|
|
11
|
+
|
|
12
|
+
- **语言**: TypeScript (ESM,`"type": "module"`,导入须用 `.js` 扩展名)
|
|
13
|
+
- **运行时**: Node.js >= 20
|
|
14
|
+
- **构建工具**: tsup → `dist/index.js`
|
|
15
|
+
- **包管理**: npm
|
|
16
|
+
|
|
17
|
+
## 项目结构
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
src/
|
|
21
|
+
├── index.ts # CLI 入口点 (Commander bin 脚本)
|
|
22
|
+
├── core/
|
|
23
|
+
│ ├── types.ts # 所有共享 TypeScript 接口(ChatRequest 含 timeout/_extraMessages)
|
|
24
|
+
│ ├── constants.ts # VERSION 等常量
|
|
25
|
+
│ ├── errors.ts # AiCliError → ProviderError / AuthError / RateLimitError 等
|
|
26
|
+
│ └── event-bus.ts # 类型安全的 EventEmitter(session.start/end, message.before/after)
|
|
27
|
+
├── providers/
|
|
28
|
+
│ ├── base.ts # 抽象 BaseProvider(chat/chatStream/validateApiKey/listModels/initialize)
|
|
29
|
+
│ ├── registry.ts # ProviderRegistry(initialize 时注入 apiKey + baseUrl + timeout)
|
|
30
|
+
│ ├── openai-compatible.ts # DeepSeek/Zhipu/Kimi 共用基类;实现 chatWithTools + buildToolResultMessages
|
|
31
|
+
│ ├── claude.ts # Anthropic SDK provider
|
|
32
|
+
│ ├── gemini.ts # Google Generative AI provider(role: assistant → model)
|
|
33
|
+
│ ├── deepseek.ts / zhipu.ts / kimi.ts # 继承 OpenAICompatibleProvider,只声明 defaultBaseUrl 和 info
|
|
34
|
+
├── config/
|
|
35
|
+
│ ├── schema.ts # Zod schema(含 timeouts / customBaseUrls / defaultModels)
|
|
36
|
+
│ ├── config-manager.ts # 读写 ~/.aicli/config.json,三层优先级:env > file > default
|
|
37
|
+
│ └── env-loader.ts # AICLI_API_KEY_* 等环境变量映射
|
|
38
|
+
├── session/
|
|
39
|
+
│ ├── session.ts # Session(addMessage / clear / toJSON / fromJSON)
|
|
40
|
+
│ └── session-manager.ts # CRUD for ~/.aicli/history/*.json
|
|
41
|
+
├── repl/
|
|
42
|
+
│ ├── repl.ts # 主 REPL 循环(MAX_TOOL_ROUNDS=20,handleChatWithTools agentic loop)
|
|
43
|
+
│ ├── renderer.ts # 终端输出(renderStream / renderResponse 均不加前置 \n)
|
|
44
|
+
│ ├── setup-wizard.ts # @inquirer/prompts 首次运行交互式设置
|
|
45
|
+
│ └── commands/
|
|
46
|
+
│ └── index.ts # CommandRegistry + 15个命令(/help /about /provider /model /clear /session /system /context /status /search /undo /export /tools /config /exit)
|
|
47
|
+
└── tools/
|
|
48
|
+
├── types.ts # ToolDefinition / ToolCall / ToolResult / DangerLevel / getDangerLevel
|
|
49
|
+
├── registry.ts # ToolRegistry(注册全部内置工具,共11个)
|
|
50
|
+
├── executor.ts # ToolExecutor(确认逻辑 + printToolCall/printToolResult)
|
|
51
|
+
└── builtin/
|
|
52
|
+
├── bash.ts # bash 工具(Windows: PowerShell + Buffer→UTF-8;Unix: $SHELL)
|
|
53
|
+
├── read-file.ts # read_file 工具
|
|
54
|
+
├── write-file.ts # write_file 工具
|
|
55
|
+
├── list-dir.ts # list_dir 工具
|
|
56
|
+
└── run-interactive.ts # run_interactive 工具(spawn 直连可执行文件,stdin_lines 依次输入)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 常用命令
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run dev # 开发模式(tsx 热重载)
|
|
63
|
+
npm run build # 构建到 dist/index.js(ESM)和 dist-cjs/index.cjs(CJS)
|
|
64
|
+
node dist/index.js # 运行
|
|
65
|
+
|
|
66
|
+
# 子命令
|
|
67
|
+
node dist/index.js providers # 列出所有 provider 及配置状态
|
|
68
|
+
node dist/index.js sessions # 列出最近会话
|
|
69
|
+
node dist/index.js config # 运行配置向导
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 打包为独立可执行文件
|
|
73
|
+
|
|
74
|
+
使用 `@yao-pkg/pkg` 将项目打包为无需 Node.js 环境即可运行的单文件可执行程序(约 56MB)。
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm run pack:win # Windows x64 → release/ai-cli-win.exe
|
|
78
|
+
npm run pack:mac # macOS arm64 → release/ai-cli-mac
|
|
79
|
+
npm run pack:mac-x64 # macOS x64 → release/ai-cli-mac-x64
|
|
80
|
+
npm run pack:linux # Linux x64 → release/ai-cli-linux
|
|
81
|
+
npm run pack:all # 同时打包所有平台
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 打包原理
|
|
85
|
+
|
|
86
|
+
- tsup 输出两套产物:
|
|
87
|
+
- `dist/index.js`(ESM,供 `node` 直接运行)
|
|
88
|
+
- `dist-cjs/index.cjs`(CJS + `noExternal: /.*/` 内联所有依赖,供 pkg 打包)
|
|
89
|
+
- pkg 使用 `--options no-deprecation` 内嵌到二进制,消除 punycode 弃用警告
|
|
90
|
+
- macOS/Linux 产物需在对应平台执行 `chmod +x` 后运行
|
|
91
|
+
|
|
92
|
+
### 关键兼容性问题(已解决)
|
|
93
|
+
|
|
94
|
+
**ora 在 pkg exe 中 Segfault**:`ora` spinner 在 `@yao-pkg/pkg` 打包的 Node 22 exe 里会触发段错误(exit code 139)。
|
|
95
|
+
**解决方案**:完全移除 `ora` 依赖,在 `src/repl/renderer.ts` 中用原生 `setInterval` + `process.stdout.write('\r\x1b[2K')` 实现轻量 spinner,非 TTY 环境自动降级为空操作。
|
|
96
|
+
|
|
97
|
+
## 配置存储
|
|
98
|
+
|
|
99
|
+
- **配置文件**: `~/.aicli/config.json`
|
|
100
|
+
- **全局上下文**: `~/.aicli/AICLI.md`(或 `CLAUDE.md`,全局层级上下文)
|
|
101
|
+
- **持久记忆**: `~/.aicli/memory.md`(AI 通过 `save_memory` 工具写入,跨会话自动加载)
|
|
102
|
+
- **对话历史**: `~/.aicli/history/*.json`
|
|
103
|
+
- **插件目录**: `~/.aicli/plugins/`(暂未实现)
|
|
104
|
+
|
|
105
|
+
当前已配置(用户机器):
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"defaultProvider": "deepseek",
|
|
109
|
+
"apiKeys": { "deepseek": "sk-d89cdb5490844071ad250996b04dc7b0" },
|
|
110
|
+
"customBaseUrls": { "deepseek": "https://api.deepseek.com" },
|
|
111
|
+
"timeouts": { "deepseek": 60000 }
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 环境变量(优先级高于配置文件)
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
AICLI_API_KEY_CLAUDE Claude API Key
|
|
119
|
+
AICLI_API_KEY_GEMINI Gemini API Key
|
|
120
|
+
AICLI_API_KEY_DEEPSEEK DeepSeek API Key
|
|
121
|
+
AICLI_API_KEY_ZHIPU 智谱 API Key
|
|
122
|
+
AICLI_API_KEY_KIMI Kimi API Key
|
|
123
|
+
AICLI_PROVIDER 默认 Provider ID
|
|
124
|
+
AICLI_NO_STREAM 设为 1 禁用流式输出
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 层级上下文文件系统
|
|
128
|
+
|
|
129
|
+
类似 Gemini CLI 的 `GEMINI.md` 层级机制,ai-cli 支持三层级上下文文件自动发现与拼接:
|
|
130
|
+
|
|
131
|
+
### 层级结构(按顺序拼接注入 system prompt)
|
|
132
|
+
|
|
133
|
+
| 层级 | 路径 | 用途 |
|
|
134
|
+
|------|------|------|
|
|
135
|
+
| 全局层 | `~/.aicli/AICLI.md` (或 `CLAUDE.md`) | 所有项目通用的个人偏好 |
|
|
136
|
+
| 项目层 | `<git-root>/AICLI.md` (或 `CLAUDE.md`) | 项目级规则(提交到 git 供团队共享) |
|
|
137
|
+
| 子目录层 | `<cwd>/AICLI.md` (或 `CLAUDE.md`) | 当前工作子目录的特定指令 |
|
|
138
|
+
|
|
139
|
+
### 规则
|
|
140
|
+
|
|
141
|
+
- 每层按候选文件名 `AICLI.md → CLAUDE.md` 优先级查找,找到第一个即停止
|
|
142
|
+
- 项目层通过 `git rev-parse --show-toplevel` 确定 git 仓库根目录;不在 git 仓库中时 projectRoot = cwd
|
|
143
|
+
- 子目录层仅当 cwd ≠ projectRoot 时才加载(避免重复)
|
|
144
|
+
- 所有层级内容用 `\n\n---\n\n` 分隔后注入 system prompt
|
|
145
|
+
- 配置 `contextFile: false` 可禁用所有层级;设为具体文件名可回退到单文件行为
|
|
146
|
+
|
|
147
|
+
### 相关命令
|
|
148
|
+
|
|
149
|
+
- `/context` — 查看当前加载的各层级详情
|
|
150
|
+
- `/context reload` — 重新加载上下文文件
|
|
151
|
+
|
|
152
|
+
## Tool Use(Agentic 工具调用)架构
|
|
153
|
+
|
|
154
|
+
### 工具一览
|
|
155
|
+
|
|
156
|
+
| 工具名 | 危险级别 | 说明 |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `bash` | write/safe/destructive(按命令判断) | PowerShell(Win) / $SHELL(Unix) 执行命令,Windows 强制 UTF-8 |
|
|
159
|
+
| `read_file` | safe | 读取文件内容 |
|
|
160
|
+
| `write_file` | write(需确认) | 写入文件 |
|
|
161
|
+
| `edit_file` | write(需确认) | 精确字符串替换编辑文件 |
|
|
162
|
+
| `list_dir` | safe | 列出目录内容 |
|
|
163
|
+
| `grep_files` | safe | 正则搜索文件内容 |
|
|
164
|
+
| `glob_files` | safe | 按 glob 模式匹配文件路径 |
|
|
165
|
+
| `run_interactive` | safe | spawn 直连可执行文件 + stdin_lines 依次输入,用于交互式程序(猜数游戏等) |
|
|
166
|
+
| `web_fetch` | safe | 抓取网页内容并转为 Markdown(含私有 IP 防 SSRF) |
|
|
167
|
+
| `save_last_response` | write(需确认) | 保存上一次 AI 回答到文件(tee 流式写盘) |
|
|
168
|
+
| `save_memory` | safe | 将重要信息追加到 `~/.aicli/memory.md`,跨会话持久化,启动时自动注入 system prompt |
|
|
169
|
+
|
|
170
|
+
### 危险级别与确认机制
|
|
171
|
+
|
|
172
|
+
`src/tools/types.ts` 的 `getDangerLevel()` 判断:
|
|
173
|
+
- `safe` → 自动执行,无需确认
|
|
174
|
+
- `write` → 显示 `✎ Write operation:` 并等待用户按 `y/N`
|
|
175
|
+
- `destructive` → 显示 `⚠ DESTRUCTIVE operation:` 并等待确认
|
|
176
|
+
|
|
177
|
+
### Agentic 循环(`repl.ts` → `handleChatWithTools`)
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
用户输入 → rl.pause() + rl.output=null(静默 readline)
|
|
181
|
+
→ chatWithTools(messages + toolDefs) → AI 返回 { toolCalls } 或 { content }
|
|
182
|
+
→ 若 toolCalls:executor.executeAll() → buildToolResultMessages() → 下一轮(最多 20 轮)
|
|
183
|
+
→ 若 content:renderResponse() → rl.output=savedOutput + rl.resume() + showPrompt()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### stdin/readline 关键设计(重要!勿破坏)
|
|
187
|
+
|
|
188
|
+
1. **`rl.output = null`**:在 `line` handler 开始时执行,处理完毕后恢复。
|
|
189
|
+
防止 readline 在 AI 处理期间因 spinner/输出 触发行缓冲区重绘,导致用户输入被重复打印。
|
|
190
|
+
|
|
191
|
+
2. **`confirm()` 读取单键**:使用 `process.stdin.setRawMode(true)` + `data` 事件读取单个字符。
|
|
192
|
+
**禁止**:调用 `rl.question()`(会 pause readline,REPL 随后失去响应);
|
|
193
|
+
**禁止**:额外调用 `stdin.resume()`(会产生残留字节 `yy`);
|
|
194
|
+
**禁止**:在 executor 内操控 `rl.output`(由 repl.ts 统一管理)。
|
|
195
|
+
|
|
196
|
+
3. **`rl.prompt()` 而非 `stdout.write`**:readline 内部追踪 prompt 列宽,backspace 不会吃掉 prompt。
|
|
197
|
+
|
|
198
|
+
4. **`renderer.ts` 中 `renderStream/renderResponse` 不加前置 `\n`**:
|
|
199
|
+
用户按回车后 readline 已换行,spinner stop 后也已换行,再加 `\n` 会触发 readline 重绘。
|
|
200
|
+
|
|
201
|
+
5. **`processing` 标志防止 `rl.on('close')` 误触发退出**:
|
|
202
|
+
`line` handler 是 async 的,readline 不等待它完成。若 AI 处理期间 stdin 意外关闭(如 spinner 操作),
|
|
203
|
+
`close` 事件会提前 resolve Promise 导致 REPL 退出。用 `processing` 布尔标志,在 `close` handler 中判断,
|
|
204
|
+
仅在非处理中时才 resolve。
|
|
205
|
+
|
|
206
|
+
6. **全局异常捕获**(`src/index.ts`):`uncaughtException` + `unhandledRejection` 均打印完整堆栈到 stderr,
|
|
207
|
+
防止未知错误导致静默崩溃。ESM 中这两个 handler 必须写在文件顶部(import 语句之前)才能在模块加载期生效。
|
|
208
|
+
|
|
209
|
+
### Windows 编码处理
|
|
210
|
+
|
|
211
|
+
- **bash 工具**:命令前注入 `[Console]::OutputEncoding = UTF8`;`execSync` 用 `encoding:'buffer'`,手动 `.toString('utf-8')` 解码。
|
|
212
|
+
- **run_interactive 工具**:直接 `spawn(pythonExe, args)`,不经过任何 shell;环境变量 `PYTHONUTF8=1` + `PYTHONIOENCODING=utf-8`,stdout 用 `setEncoding('utf-8')`。
|
|
213
|
+
- **关键**:不要用 `cmd /c` 或 `powershell -Command` 包装 spawn——这会截断 stdin 管道,交互式程序收不到输入。
|
|
214
|
+
|
|
215
|
+
### run_interactive 工具参数容错设计
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// args 可能是数组(正确)或字符串(AI 传参错误时降级兼容)
|
|
219
|
+
const cmdArgs = Array.isArray(rawArgs) ? rawArgs.map(String) : [rawArgs.trim()];
|
|
220
|
+
// stdin_lines 可能是数组或逗号分隔字符串
|
|
221
|
+
const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String)
|
|
222
|
+
: rawStdin.split(',').map(s => s.trim());
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 添加新 Provider
|
|
226
|
+
|
|
227
|
+
1. 在 `src/providers/` 创建新文件(如 `openrouter.ts`)
|
|
228
|
+
2. 继承 `OpenAICompatibleProvider`(OpenAI 兼容)或 `BaseProvider`
|
|
229
|
+
3. 实现 `info` 属性(id, displayName, defaultModel, models 数组)和 `defaultBaseUrl`
|
|
230
|
+
4. 在 `src/providers/registry.ts` 的 `BUILT_IN_PROVIDERS` 数组中添加该类
|
|
231
|
+
|
|
232
|
+
## 添加新 Tool
|
|
233
|
+
|
|
234
|
+
1. 在 `src/tools/builtin/` 创建新文件,实现 `Tool` 接口(`definition` + `execute(args)`)
|
|
235
|
+
2. 在 `src/tools/registry.ts` 的 `constructor` 中 `this.register(newTool)`
|
|
236
|
+
3. 在 `src/tools/types.ts` 的 `getDangerLevel()` 中为新工具设置危险级别
|
|
237
|
+
|
|
238
|
+
## GUI 扩展(Electron/Tauri)
|
|
239
|
+
|
|
240
|
+
- `src/core/`、`src/providers/`、`src/session/`、`src/config/`、`src/tools/` 无终端依赖,可直接被 Electron 主进程导入
|
|
241
|
+
- `src/repl/` 仅是 CLI 层,GUI 时完全替换此目录
|
|
242
|
+
- `EventBus` 作为 Electron IPC 桥接
|
|
243
|
+
- `package.json` 中的 `exports` 字段暴露核心 API 供第三方使用
|
|
244
|
+
|
|
245
|
+
## 代码风格
|
|
246
|
+
|
|
247
|
+
- TypeScript strict 模式
|
|
248
|
+
- 所有文件使用 `.js` 扩展名导入(ESM 要求)
|
|
249
|
+
- Provider 错误统一转换为 `ProviderError` 子类
|
|
250
|
+
- 不在核心层(`src/core/`)引入任何 CLI/终端相关依赖
|
|
251
|
+
|
|
252
|
+
## Gemini CLI 追赶路线(进行中)
|
|
253
|
+
|
|
254
|
+
对标 Gemini CLI 的功能差距,按优先级逐步实现:
|
|
255
|
+
|
|
256
|
+
### 已完成
|
|
257
|
+
- [x] **层级上下文文件系统**(2026-02-22):全局 `~/.aicli/AICLI.md` + 项目 `<git-root>/AICLI.md` + 子目录 `<cwd>/AICLI.md` 三层级自动发现、拼接注入 system prompt。`/context` 命令显示各层详情。
|
|
258
|
+
- [x] **持久记忆系统 `save_memory`**(2026-02-22):AI 可调用 `save_memory` 工具将重要信息追加到 `~/.aicli/memory.md`,跨会话自动加载注入 system prompt。支持时间戳、大小限制(10K 字符截取最新)。
|
|
259
|
+
|
|
260
|
+
### 下一步待实现
|
|
261
|
+
- [ ] **`ask_user` 工具**:AI 在执行过程中向用户请求澄清或确认,增强代理交互能力
|
|
262
|
+
- [ ] **`write_todos` 工具**:AI 自动拆解复杂任务为子任务列表,跟踪进度
|
|
263
|
+
- [ ] **Google 搜索集成**:AI 可主动搜索网页验证事实(需接入搜索 API)
|
|
264
|
+
- [ ] **MCP 协议支持**:Model Context Protocol 扩展生态,接入外部工具
|
|
265
|
+
- [ ] **Agent Skills 系统**:可复用的专业技能包(`.aicli/skills/`)
|
|
266
|
+
|
|
267
|
+
## 已知待改进项
|
|
268
|
+
|
|
269
|
+
### 低优先级
|
|
270
|
+
- [ ] **macOS/Linux 完整测试**:跨平台逻辑已处理(`$SHELL` fallback、UTF-8 env vars),但尚未在非 Windows 环境实际运行验证。
|
|
271
|
+
- [ ] **Token 用量显示**:`ui.showTokenCount` 配置字段已有,但终端展示逻辑未完整实现。
|
|
272
|
+
- [ ] **GitHub 仓库迁移**:当前在 gitee,npm 包受众需要 GitHub 托管。
|
|
273
|
+
- [ ] **web_fetch DNS 解析时 SSRF 防护**:当前只检查 URL hostname 字符串,若 hostname 是域名(非裸 IP)则未检查其解析后的 IP 是否为私有地址。需在发起请求后对实际连接 IP 做二次校验(复杂,低频风险)。
|
|
274
|
+
- [ ] **`persistentCwd` 全局状态**:bash 工具的当前工作目录是模块级全局变量,多 session 并发时可能串扰。现阶段单 session REPL 无影响,GUI 多会话扩展时需重构为 per-session 状态。
|
|
275
|
+
|
|
276
|
+
## 本轮开发完成记录(2026-02-22,安全加固版 0.1.10)
|
|
277
|
+
|
|
278
|
+
### 背景
|
|
279
|
+
对 ai-cli 全量代码进行安全审计,共发现并修复 **3 个高危、4 个中危、4 个低危**漏洞,版本从 0.1.9 升至 0.1.10 发布。
|
|
280
|
+
|
|
281
|
+
### 修复:高危(H)
|
|
282
|
+
|
|
283
|
+
**H1 — `executor.ts`:`write` 级别操作未触发用户确认**
|
|
284
|
+
- 根本原因:`execute()` 条件分支逻辑缺陷,`write` 级别跳过了 `confirm()` 调用
|
|
285
|
+
- 修复:重构三路分支;`write` → printToolCall + printDiffPreview + confirm;`destructive` → confirm + printToolCall;`safe` → printToolCall 后直接执行
|
|
286
|
+
|
|
287
|
+
**H2 — `types.ts`:`getDangerLevel()` bash 危险命令覆盖不完整**
|
|
288
|
+
- 漏洞:`rm -r`(不带 `-f`)、`rm file.txt`(无标志)、`--recursive`/`--force` 长标志均被识别为 `safe`;`del + mkdir` 组合绕过 destructive 判断;PowerShell 写操作(Set-Content、Out-File 等)未分类
|
|
289
|
+
- 修复:扩展正则覆盖上述所有情形;移除错误的 `del+mkdir` 豁免;新增 PowerShell 写操作 → `write`
|
|
290
|
+
|
|
291
|
+
**H3 — `registry.ts` / `schema.ts` / `repl.ts`:插件系统无权限门控,任意 JS 文件自动加载执行**
|
|
292
|
+
- 漏洞:`loadPlugins()` 对 `~/.aicli/plugins/` 下所有 `.js` 文件无条件加载,权限等同当前用户
|
|
293
|
+
- 修复:
|
|
294
|
+
- `schema.ts` 新增 `allowPlugins: z.boolean().default(false)`(默认关闭)
|
|
295
|
+
- `loadPlugins(pluginsDir, allowPlugins)` 新增 flag 参数;未启用时打印警告并返回,不加载任何插件
|
|
296
|
+
- 启用时在 stderr 打印完整插件路径作为安全日志
|
|
297
|
+
- `repl.ts` 传入 `this.config.get('allowPlugins')` 控制
|
|
298
|
+
|
|
299
|
+
### 修复:中危(M)
|
|
300
|
+
|
|
301
|
+
**M4 — `web-fetch.ts`:SSRF(服务端请求伪造)**
|
|
302
|
+
- 漏洞:AI 可指定任意 URL,攻击者可让工具访问内网服务(如 192.168.x.x、metadata API 等)
|
|
303
|
+
- 修复:新增 `isPrivateHost()` 函数,拦截 localhost / 0.0.0.0 / ::1 / fe80:: / 10.x / 127.x / 172.16-31.x / 192.168.x / 169.254.x;对初始 URL 和重定向后的最终 URL 均校验
|
|
304
|
+
|
|
305
|
+
**M5 — `types.ts`:PowerShell 写操作未分类为 `write`**(并入 H2 修复)
|
|
306
|
+
|
|
307
|
+
**M6 — `read-file.ts`:大文件读取触发 OOM**
|
|
308
|
+
- 漏洞:`readFileSync` 在 size 检查之前执行,超大文件直接撑爆堆内存
|
|
309
|
+
- 修复:用 `statSync` 在读取前获取文件大小,超过 10MB(`MAX_FILE_BYTES`)直接报错返回
|
|
310
|
+
|
|
311
|
+
**M8 — `read-file.ts`:读取敏感配置文件(API Key、SSH 私钥等)无警告**
|
|
312
|
+
- 修复:`getSensitiveWarning()` 检测以下路径:`~/.aicli/config.json`、`.env*`、`~/.ssh/id_*`、`~/.aws/credentials`;匹配时在文件内容前追加醒目警告(不阻断,保留调试能力)
|
|
313
|
+
|
|
314
|
+
### 修复:低危(L)
|
|
315
|
+
|
|
316
|
+
**L8 — `bash.ts`:`fixWindowsDeleteCommand` 路径注入**
|
|
317
|
+
- 漏洞:pathValue 直接插入 `cmd /c rmdir /s /q "..."` 字符串,含 `"` 的路径可逃逸引号
|
|
318
|
+
- 修复:`const safePath = pathValue.replace(/"/g, '\\"');`
|
|
319
|
+
|
|
320
|
+
**L9 — `bash.ts`:timeout 由 AI 任意控制,无上限**
|
|
321
|
+
- 修复:`Math.min(Math.max(Number(args['timeout'] ?? 30_000), 1000), 300_000)`,最小 1s,最大 300s
|
|
322
|
+
|
|
323
|
+
**L10 — `bash.ts`:`updateCwdFromCommand` 正则误匹配字符串内的 `cd`**
|
|
324
|
+
- 修复:更新正则为 `/(?:^|[;&|])\s*cd\s+(['"]?)([^\s;&|'"]+)\1/g`,捕获组 2 取路径(去除引号),仅匹配命令边界处的 `cd`
|
|
325
|
+
|
|
326
|
+
**L11 — `bash.ts`:`persistentCwd` 全局状态注释缺失**
|
|
327
|
+
- 修复:添加架构说明注释,提示 GUI 多 session 扩展时需重构为 per-session 状态
|
|
328
|
+
|
|
329
|
+
### 版本与发布
|
|
330
|
+
- `src/core/constants.ts`:VERSION `0.1.9` → `0.1.10`
|
|
331
|
+
- `package.json`:version `0.1.9` → `0.1.10`
|
|
332
|
+
- `npm publish` → `jinzd-ai-cli@0.1.10`(https://www.npmjs.com/package/jinzd-ai-cli)
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 本轮开发完成记录(2026-02-23)
|
|
337
|
+
|
|
338
|
+
### 新增功能
|
|
339
|
+
- **Gemini 完整支持**:`GeminiProvider` 接入代理(undici ProxyAgent)、baseUrl 透传、array 参数 `items` schema 修复(解决 400 Bad Request)、429/网络错误中文提示
|
|
340
|
+
- **代理配置**:`config.json` 新增 `proxy` 字段;`src/index.ts` 的 `setupProxy()` 读取配置+环境变量(优先级:env > config);设置向导新增 `Configure proxy` 入口(支持设置/修改/清除)
|
|
341
|
+
- **`stream_to_file` 工具上线**:注册到 `ToolRegistry`;`repl.ts` 在 `executeAll` 前注入 provider/model/messages/systemPrompt 上下文;`getDangerLevel` 添加 `write` 级别
|
|
342
|
+
- **`/config` REPL 命令**:REPL 内直接调用配置向导,无需退出;`repl.ts` 的 `runSetupWizard` 回调临时恢复 readline 状态供 inquirer 使用
|
|
343
|
+
- **README.md**:创建完整 npm 包文档(Provider 表、工具表、命令表、代理配置、项目上下文说明)
|
|
344
|
+
- **pkg 打包零警告**:`scripts/patch-sqlite.mjs` 在打包前替换 undici 内部 `require("sqlite")` 为 IIFE stub
|
|
345
|
+
- **版本升至 0.1.4**,发布至 npmjs
|
|
346
|
+
|
|
347
|
+
### 架构变更
|
|
348
|
+
- `src/config/schema.ts`:新增 `proxy?: string` 字段
|
|
349
|
+
- `src/repl/commands/index.ts`:`CommandContext` 新增 `runSetupWizard` 回调;新增 `/config` 命令;工具/命令计数更新(11工具、15命令)
|
|
350
|
+
- `src/repl/setup-wizard.ts`:`runFull()` 新增代理配置选项;`input` from `@inquirer/prompts` 用于代理 URL 输入
|
|
351
|
+
|
|
352
|
+
## 本轮开发完成记录(2026-02-22)
|
|
353
|
+
|
|
354
|
+
### 新增功能
|
|
355
|
+
- **全局超时统一为 300s**:`~/.aicli/config.json` 中 `timeouts.deepseek` 60000→300000、`timeouts.kimi` 600000→300000;`modelParams` 中所有模型的 `timeout` 统一为 300000(moonshot-v1-8k 新增 timeout 字段)
|
|
356
|
+
- **跨 session 历史搜索 `/search <keyword>`**:`SessionManager.searchMessages()` 遍历全部历史 JSON,不区分大小写全文匹配,每个 session 最多返回 3 条带上下文的匹配片段,全局最多 20 个 session;REPL 新增 `/search` 命令,结果按 updated 倒序展示,提示用 `/session load <id>` 加载
|
|
357
|
+
- **`run_interactive` 参数容错可观测化**:`args` 或 `stdin_lines` 传入错误类型(string 非 array)时,双路输出警告:① `process.stderr.write`(终端可见);② 工具返回值前缀追加警告文本(AI 可在工具结果中看到),便于持续观察 AI 实际调用行为
|
|
358
|
+
- **`/about` 命令升级**:新增工具列表(10个完整)、REPL 命令列表(14个)、主要特性区块;移除仓库地址(待迁移至 GitHub)
|
|
359
|
+
- **版本号升级至 0.1.2**,`constants.ts` 与 `package.json` 保持同步
|
|
360
|
+
- **发布至 npmjs**:`npm publish` → `jinzd-ai-cli@0.1.2`(https://www.npmjs.com/package/jinzd-ai-cli)
|
|
361
|
+
|
|
362
|
+
## 本轮开发完成记录(2026-02-22)
|
|
363
|
+
|
|
364
|
+
### 新增功能
|
|
365
|
+
- **层级上下文文件系统**:三层级(全局/项目/子目录)上下文自动发现与拼接,取代旧的单文件加载。新增 `getGitRoot()` 获取 git 仓库根目录,`findContextFile()` 按候选列表查找,`loadHierarchicalContext()` 三层加载。`ContextLayer` 接口导出供命令模块使用。`/context` 命令显示各层详情,`/status` 显示层级摘要。
|
|
366
|
+
- **持久记忆系统**:新增 `save_memory` 工具(`src/tools/builtin/save-memory.ts`),追加式写入 `~/.aicli/memory.md`,自动带时间戳。`repl.ts` 新增 `loadMemoryContent()` 方法,在 `buildCurrentSystemPrompt()` 中注入 `# Persistent Memory` 段落。启动时显示 `📝 Memory loaded: X entries (Y chars)`。超过 10,000 字符时截取末尾最新部分。
|
|
367
|
+
|
|
368
|
+
### 架构变更
|
|
369
|
+
- `constants.ts`:新增 `CONTEXT_FILE_CANDIDATES`、`MEMORY_FILE_NAME`、`MEMORY_MAX_CHARS` 常量
|
|
370
|
+
- `git-context.ts`:新增 `getGitRoot()` 导出函数
|
|
371
|
+
- `repl.ts`:`contextFilePath: string | null` → `contextLayers: ContextLayer[]`;`loadProjectContext()` → `loadHierarchicalContext()`;`buildCurrentSystemPrompt()` 重构为 parts 数组拼接模式(日期时间 → 记忆 → 上下文)
|
|
372
|
+
- `commands/index.ts`:`CommandContext.getContextFilePath()` → `getContextLayers()`;`/context` 和 `/status` 命令适配新数据结构
|
|
373
|
+
|
|
374
|
+
## 历史开发记录(2026-02-21)
|
|
375
|
+
|
|
376
|
+
### 新增功能
|
|
377
|
+
- **模型上下文长度展示**:`/model` 选择器 hint 显示 `ctx:128K`;`/status` 新增 `Ctx Win` 行;启动欢迎界面 Model 行显示 `(ctx: 128K)`
|
|
378
|
+
- **Claude/Gemini 工具调用(Agentic)**:`ClaudeProvider` 和 `GeminiProvider` 均实现 `chatWithTools` + `buildToolResultMessages`,现在三大 provider 系列均支持完整 agentic 工具调用能力
|
|
379
|
+
- **工具调用最终回答流式输出**:`handleChatWithTools` 最终 content 轮次改为 `chatStream` 真正流式,`streaming=true` 时打字机效果;`streaming=false` 时保持原有非流式路径
|
|
380
|
+
- **Ctrl+C 取消工具确认**:`confirm()` 等待期间按 Ctrl+C 视为"按 N 取消",不再异常退出 REPL;通过 `ToolExecutor.cancelConfirm()` + SIGINT handler 协作实现
|
|
381
|
+
- **System prompt 注入当前日期时间**:每次会话启动自动注入 `当前日期时间:2026年02月21日 星期六 08:30:00`,所有模型均可感知;使用手动数字拼接(不依赖 locale API,兼容 pkg 精简 ICU 环境)
|
|
382
|
+
- **Kimi 长文本模型超时配置**:`~/.aicli/config.json` 中 `kimi-k2-0711-preview`、`kimi-k2-turbo-preview`、`moonshot-v1-128k` 统一设置 300000ms(5分钟)超时,适合出题等长文本生成场景
|
|
383
|
+
|
|
384
|
+
### 架构变更
|
|
385
|
+
- `repl.ts`:引入 `ToolCapableProvider` 接口(duck typing),`handleChatWithTools` 不再依赖 `OpenAICompatibleProvider` 具体类,Claude/Gemini 自动识别并走 agentic 路径
|
|
386
|
+
- `executor.ts`:新增 `cancelConfirmFn` 私有回调 + `cancelConfirm()` 公开方法
|
|
387
|
+
|
|
388
|
+
## 已解决的重大问题记录
|
|
389
|
+
|
|
390
|
+
| 问题 | 根本原因 | 解决方案 |
|
|
391
|
+
|------|---------|---------|
|
|
392
|
+
| exe 启动后发消息立即崩溃(Segfault) | `ora` 在 `@yao-pkg/pkg` Node 22 exe 中调用底层 TTY 接口触发段错误 | 完全移除 `ora`,用原生 `setInterval + stdout.write` 实现 spinner |
|
|
393
|
+
| punycode 弃用警告 | Node 22 对 `punycode` 内置模块发出 DEP0040 警告 | pkg 打包时加 `--options no-deprecation` |
|
|
394
|
+
| `yy` 双字符回显 | `rl.question()` 内部 echo + 手动 echo 叠加 | 改用 `setRawMode(true)` + `data` 事件读单字符,彻底不用 `rl.question()` |
|
|
395
|
+
| REPL 一轮后退出 | `rl.question()` 内部调用 `rl.pause()`,readline 失去响应 | 移除 `rl.question()`,仅用 raw stdin |
|
|
396
|
+
| 用户输入重复出现 | readline `terminal:true` + spinner 输出触发行缓冲区重绘 | AI 处理期间设 `rlAny.output = null` 禁止 readline 输出 |
|
|
397
|
+
| Windows 中文乱码 | PowerShell 默认 GBK 编码 | bash 工具注入 `[Console]::OutputEncoding=UTF8` + `encoding:'buffer'` 手动解码 |
|
|
398
|
+
| run_interactive stdin 截断 | 通过 shell 包装 spawn 时 stdin pipe 被截断 | 直接 `spawn(pythonExe, args)` 不经过任何 shell |
|
|
399
|
+
| Ctrl+C 在工具确认时异常退出 | SIGINT handler 直接调用 `handleExit()`,未检查 `confirm()` 状态 | SIGINT handler 先检查 `confirming` 标志,是则 `cancelConfirm()` 取消而非退出 |
|
|
400
|
+
| 日期注入在 pkg exe 中显示错误 | `toLocaleDateString/toLocaleTimeString` 依赖完整 ICU,pkg 精简版不支持 | 改为手动数字拼接:`${year}年${month}月${day}日 ${weekday} ${HH}:${mm}:${ss}` |
|