@yivan-lab/pretty-please 1.0.0 → 1.1.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.
Files changed (64) hide show
  1. package/README.md +98 -27
  2. package/bin/pls.tsx +135 -24
  3. package/dist/bin/pls.d.ts +1 -1
  4. package/dist/bin/pls.js +117 -24
  5. package/dist/package.json +80 -0
  6. package/dist/src/ai.d.ts +1 -41
  7. package/dist/src/ai.js +9 -190
  8. package/dist/src/builtin-detector.d.ts +14 -8
  9. package/dist/src/builtin-detector.js +36 -16
  10. package/dist/src/chat-history.d.ts +16 -11
  11. package/dist/src/chat-history.js +26 -4
  12. package/dist/src/components/Chat.js +3 -3
  13. package/dist/src/components/CommandBox.js +1 -16
  14. package/dist/src/components/ConfirmationPrompt.d.ts +2 -1
  15. package/dist/src/components/ConfirmationPrompt.js +7 -3
  16. package/dist/src/components/MultiStepCommandGenerator.d.ts +2 -0
  17. package/dist/src/components/MultiStepCommandGenerator.js +110 -7
  18. package/dist/src/config.d.ts +27 -8
  19. package/dist/src/config.js +92 -33
  20. package/dist/src/history.d.ts +19 -5
  21. package/dist/src/history.js +26 -11
  22. package/dist/src/mastra-agent.d.ts +0 -1
  23. package/dist/src/mastra-agent.js +3 -4
  24. package/dist/src/mastra-chat.d.ts +28 -0
  25. package/dist/src/mastra-chat.js +93 -0
  26. package/dist/src/multi-step.d.ts +2 -2
  27. package/dist/src/multi-step.js +2 -2
  28. package/dist/src/prompts.d.ts +11 -0
  29. package/dist/src/prompts.js +140 -0
  30. package/dist/src/shell-hook.d.ts +35 -13
  31. package/dist/src/shell-hook.js +82 -7
  32. package/dist/src/sysinfo.d.ts +9 -5
  33. package/dist/src/sysinfo.js +2 -2
  34. package/dist/src/utils/console.d.ts +11 -11
  35. package/dist/src/utils/console.js +4 -6
  36. package/package.json +8 -6
  37. package/src/builtin-detector.ts +126 -0
  38. package/src/chat-history.ts +130 -0
  39. package/src/components/Chat.tsx +4 -4
  40. package/src/components/CommandBox.tsx +1 -16
  41. package/src/components/ConfirmationPrompt.tsx +9 -2
  42. package/src/components/MultiStepCommandGenerator.tsx +144 -7
  43. package/src/config.ts +309 -0
  44. package/src/history.ts +160 -0
  45. package/src/mastra-agent.ts +3 -4
  46. package/src/mastra-chat.ts +124 -0
  47. package/src/multi-step.ts +2 -2
  48. package/src/prompts.ts +154 -0
  49. package/src/shell-hook.ts +502 -0
  50. package/src/{sysinfo.js → sysinfo.ts} +28 -16
  51. package/src/utils/{console.js → console.ts} +16 -18
  52. package/bin/pls.js +0 -681
  53. package/src/ai.js +0 -324
  54. package/src/builtin-detector.js +0 -98
  55. package/src/chat-history.js +0 -94
  56. package/src/components/ChatStatus.tsx +0 -53
  57. package/src/components/CommandGenerator.tsx +0 -184
  58. package/src/components/ConfigDisplay.tsx +0 -64
  59. package/src/components/ConfigWizard.tsx +0 -101
  60. package/src/components/HistoryDisplay.tsx +0 -69
  61. package/src/components/HookManager.tsx +0 -150
  62. package/src/config.js +0 -221
  63. package/src/history.js +0 -131
  64. package/src/shell-hook.js +0 -393
package/README.md CHANGED
@@ -9,8 +9,9 @@
9
9
  - 🤖 **自然语言转命令** - 用人话说你想干什么,AI 自动生成命令
10
10
  - 🔄 **多步骤命令** - AI 自动规划多个步骤,后续命令依赖前面的执行结果
11
11
  - 🛡️ **智能错误恢复** - 命令失败时 AI 自动分析并调整策略
12
+ - ✏️ **命令编辑** - 执行前可编辑 AI 生成的命令,支持 manual/auto 两种模式
12
13
  - 💬 **AI 对话模式** - 随时问 AI 命令怎么用
13
- - 📜 **历史记录** - 保存执行过的命令,方便复用
14
+ - 📜 **三种历史记录** - 命令历史、对话历史、Shell 历史统一管理
14
15
  - 🎨 **精美界面** - 基于 React + Ink 的终端 UI,Markdown 渲染
15
16
  - 🔧 **多 Provider 支持** - 支持 OpenAI、DeepSeek、Anthropic 等多种 AI
16
17
 
@@ -29,13 +30,7 @@ pnpm add -g @yivan-lab/pretty-please
29
30
  yarn global add @yivan-lab/pretty-please
30
31
  ```
31
32
 
32
- 安装后,确保全局安装了 `tsx`:
33
-
34
- ```bash
35
- npm install -g tsx
36
- # 或
37
- pnpm add -g tsx
38
- ```
33
+ 安装完成后,你可以在任何目录使用 `pls` 或 `please` 命令了!
39
34
 
40
35
  ### 方式二:从源码安装
41
36
 
@@ -47,11 +42,11 @@ cd pretty-please
47
42
  # 安装依赖
48
43
  pnpm install
49
44
 
45
+ # 构建
46
+ pnpm build
47
+
50
48
  # 全局链接
51
49
  pnpm link --global
52
-
53
- # 确保全局安装了 tsx
54
- pnpm add -g tsx
55
50
  ```
56
51
 
57
52
  安装完成后,你可以在任何目录使用 `pls` 或 `please` 命令了!
@@ -159,6 +154,37 @@ pls 将 test.zip 移动到 a、b、c 三个文件夹
159
154
 
160
155
  AI 不会因为一次失败就放弃,而是理解错误原因并找到解决方案。
161
156
 
157
+ ### 命令编辑
158
+
159
+ AI 生成的命令可能不完全符合你的需求,你可以在执行前编辑它:
160
+
161
+ **manual 模式(默认)**:
162
+
163
+ ```
164
+ ┌─ 生成命令 ───────┐
165
+ │ ls -la │
166
+ └──────────────────┘
167
+
168
+ 执行? [回车执行 / E 编辑 / Esc 取消]
169
+
170
+ # 按 E 进入编辑
171
+ ┌─ 生成命令 ───────┐
172
+ │ ls -la │ ← AI 建议
173
+ └──────────────────┘
174
+ > ls -l█ ← 可编辑
175
+
176
+ [回车执行 / Esc 返回]
177
+ ```
178
+
179
+ **auto 模式**:自动进入编辑,直接修改后执行
180
+
181
+ ```bash
182
+ # 切换到 auto 模式
183
+ pls config set editMode auto
184
+ ```
185
+
186
+ 编辑后的命令会被记录到历史中,并标注修改前后的对比。
187
+
162
188
  ### 对话模式:命令讲解和问答
163
189
 
164
190
  想了解某个命令怎么用?用 `pls chat` 开启对话模式:
@@ -191,16 +217,25 @@ pls chat clear
191
217
  ### 查看历史记录
192
218
 
193
219
  ```bash
194
- # 查看所有执行过的命令
220
+ # 查看命令历史
195
221
  pls history
196
222
 
197
- # 清空历史记录
198
- pls history clear
223
+ # 查看对话历史
224
+ pls history chat
225
+
226
+ # 查看 Shell 历史(需要启用 Shell Hook)
227
+ pls history shell
228
+
229
+ # 清空各种历史
230
+ pls history clear # 清空命令历史
231
+ pls history chat clear # 清空对话历史
232
+ pls history shell clear # 清空 Shell 历史
199
233
  ```
200
234
 
201
235
  历史记录包含:
202
236
  - 你的原始需求(自然语言)
203
237
  - AI 生成的命令
238
+ - 用户修改后的命令(如有修改)
204
239
  - 执行状态(成功/失败/退出码)
205
240
  - 执行时间
206
241
 
@@ -222,7 +257,10 @@ pls config set <key> <value> # 设置单个配置项
222
257
  | `provider` | AI Provider | `openai` |
223
258
  | `model` | 模型名称 | `gpt-4-turbo` |
224
259
  | `shellHook` | 启用终端历史记录 | `false` |
260
+ | `editMode` | 命令编辑模式(manual/auto) | `manual` |
225
261
  | `chatHistoryLimit` | 对话历史保留轮数 | `10` |
262
+ | `commandHistoryLimit` | 命令历史保留条数 | `10` |
263
+ | `shellHistoryLimit` | Shell 历史保留条数 | `15` |
226
264
 
227
265
  ### 支持的 Provider
228
266
 
@@ -272,8 +310,12 @@ pls config list
272
310
  pls config set <key> <value>
273
311
 
274
312
  # 历史
275
- pls history
276
- pls history clear
313
+ pls history # 命令历史
314
+ pls history clear # 清空命令历史
315
+ pls history chat # 对话历史
316
+ pls history chat clear # 清空对话历史
317
+ pls history shell # Shell 历史
318
+ pls history shell clear # 清空 Shell 历史
277
319
 
278
320
  # 对话
279
321
  pls chat <问题>
@@ -292,7 +334,7 @@ pls hook status
292
334
 
293
335
  - **React 19 + Ink 6** - 终端 UI 组件化框架
294
336
  - **Mastra 0.24** - AI Agent 框架,支持 Structured Output
295
- - **TypeScript 5.9** - 类型安全
337
+ - **TypeScript 5.9** - 100% TypeScript,完整类型安全
296
338
  - **Zod 3.25** - Schema 验证
297
339
  - **Commander 14** - CLI 参数解析
298
340
 
@@ -303,31 +345,56 @@ pretty-please/
303
345
  ├── bin/
304
346
  │ └── pls.tsx # 主入口
305
347
  ├── src/
306
- │ ├── ai.js # OpenAI 客户端 + 提示词
307
- │ ├── mastra-agent.ts # Mastra Agent 配置
348
+ │ ├── prompts.ts # 统一 AI 提示词管理
349
+ │ ├── mastra-agent.ts # Mastra Agent(命令生成)
350
+ │ ├── mastra-chat.ts # Mastra Chat Agent(对话模式)
308
351
  │ ├── multi-step.ts # 多步骤命令核心
309
- │ ├── config.js # 配置管理
310
- │ ├── history.js # 命令历史
311
- │ ├── chat-history.js # 对话历史
312
- │ ├── shell-hook.js # Shell 集成
352
+ │ ├── config.ts # 配置管理
353
+ │ ├── history.ts # 命令历史
354
+ │ ├── chat-history.ts # 对话历史
355
+ │ ├── shell-hook.ts # Shell 集成
356
+ │ ├── builtin-detector.ts # Shell builtin 检测
357
+ │ ├── sysinfo.ts # 系统信息采集
313
358
  │ ├── components/ # React Ink 组件
314
359
  │ │ ├── MultiStepCommandGenerator.tsx
315
360
  │ │ ├── Chat.tsx
316
361
  │ │ ├── MarkdownDisplay.tsx
317
362
  │ │ └── ...
318
363
  │ └── utils/
319
- │ └── console.js # 原生输出工具
364
+ │ └── console.ts # 原生输出工具
320
365
  ├── package.json
321
366
  └── tsconfig.json
322
367
  ```
323
368
 
324
369
  ## 🔨 开发指南
325
370
 
371
+ ### 命令版本
372
+
373
+ | 命令 | 类型 | 说明 |
374
+ |------|------|------|
375
+ | `pls` / `please` | 生产版本 | 编译后的 JS |
376
+ | `pls-dev` | 开发版本 | 热重载,代码修改立即生效 |
377
+
378
+ ### 首次设置
379
+
380
+ ```bash
381
+ # 1. 安装依赖
382
+ pnpm install
383
+
384
+ # 2. 构建并链接生产版本
385
+ pnpm build
386
+ pnpm link --global
387
+
388
+ # 3. 创建开发版本链接(需要全局安装 tsx)
389
+ pnpm add -g tsx
390
+ pnpm link:dev
391
+ ```
392
+
326
393
  ### 开发模式
327
394
 
328
395
  ```bash
329
- # 直接运行(热重载)
330
- pls <命令>
396
+ # 使用开发命令(推荐,热重载)
397
+ pls-dev <命令>
331
398
 
332
399
  # 或使用 dev 脚本
333
400
  pnpm dev <参数>
@@ -335,10 +402,14 @@ pnpm dev <参数>
335
402
 
336
403
  代码修改会立即生效,无需重新编译。
337
404
 
338
- ### 编译
405
+ ### 构建和发布
339
406
 
340
407
  ```bash
408
+ # 构建
341
409
  pnpm build
410
+
411
+ # 发布到 npm(会自动先执行 build)
412
+ npm publish
342
413
  ```
343
414
 
344
415
  ### 目录说明
package/bin/pls.tsx CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env tsx
2
2
  import React from 'react'
3
3
  import { render } from 'ink'
4
4
  import { Command } from 'commander'
@@ -8,12 +8,11 @@ import { exec } from 'child_process'
8
8
  import fs from 'fs'
9
9
  import os from 'os'
10
10
  import chalk from 'chalk'
11
- import { CommandGenerator } from '../src/components/CommandGenerator.js'
12
11
  import { MultiStepCommandGenerator } from '../src/components/MultiStepCommandGenerator.js'
13
12
  import { Chat } from '../src/components/Chat.js'
14
13
  import { isConfigValid, setConfigValue, getConfig, maskApiKey } from '../src/config.js'
15
14
  import { clearHistory, addHistory, getHistory, getHistoryFilePath } from '../src/history.js'
16
- import { clearChatHistory, getChatRoundCount, getChatHistoryFilePath } from '../src/chat-history.js'
15
+ import { clearChatHistory, getChatRoundCount, getChatHistoryFilePath, displayChatHistory } from '../src/chat-history.js'
17
16
  import { type ExecutedStep } from '../src/multi-step.js'
18
17
  import {
19
18
  installShellHook,
@@ -21,26 +20,34 @@ import {
21
20
  getHookStatus,
22
21
  detectShell,
23
22
  getShellConfigPath,
23
+ displayShellHistory,
24
+ clearShellHistory,
24
25
  } from '../src/shell-hook.js'
25
26
  import * as console2 from '../src/utils/console.js'
27
+ // 导入 package.json(Bun 会自动打包进二进制)
28
+ import packageJson from '../package.json'
26
29
 
27
- // 获取 package.json 版本
30
+ // 保留这些用于其他可能的用途
28
31
  const __filename = fileURLToPath(import.meta.url)
29
32
  const __dirname = dirname(__filename)
30
- const packageJson = JSON.parse(fs.readFileSync(join(__dirname, '../package.json'), 'utf-8'))
31
33
 
32
34
  const program = new Command()
33
35
 
34
36
  /**
35
37
  * 执行命令(原生版本)
36
38
  */
37
- function executeCommand(command: string, prompt: string): Promise<{ exitCode: number; output: string }> {
39
+ function executeCommand(command: string): Promise<{ exitCode: number; output: string }> {
38
40
  return new Promise((resolve) => {
39
41
  let output = ''
40
42
  let hasOutput = false
41
43
 
42
44
  console.log('') // 空行
43
- console2.printSeparator('输出')
45
+
46
+ // 计算命令框宽度,让分隔线长度一致
47
+ const lines = command.split('\n')
48
+ const maxContentWidth = Math.max(...lines.map(l => console2.getDisplayWidth(l)))
49
+ const boxWidth = Math.max(maxContentWidth + 4, console2.getDisplayWidth('生成命令') + 6, 20)
50
+ console2.printSeparator('输出', boxWidth)
44
51
 
45
52
  const child = exec(command)
46
53
 
@@ -58,17 +65,17 @@ function executeCommand(command: string, prompt: string): Promise<{ exitCode: nu
58
65
 
59
66
  child.on('close', (code) => {
60
67
  if (hasOutput) {
61
- console2.printSeparator('')
68
+ console2.printSeparator('', boxWidth)
62
69
  }
63
70
  resolve({ exitCode: code || 0, output })
64
71
  })
65
72
 
66
73
  child.on('error', (err) => {
67
74
  if (!hasOutput) {
68
- console2.printSeparator('')
75
+ console2.printSeparator('', boxWidth)
69
76
  }
70
77
  console2.error(err.message)
71
- console2.printSeparator('')
78
+ console2.printSeparator('', boxWidth)
72
79
  resolve({ exitCode: 1, output: err.message })
73
80
  })
74
81
  })
@@ -94,18 +101,25 @@ configCmd
94
101
 
95
102
  console.log('')
96
103
  console2.title('当前配置:')
97
- console2.muted('━'.repeat(40))
98
- console.log(` ${chalk.hex('#00D9FF')('apiKey')}: ${maskApiKey(config.apiKey)}`)
99
- console.log(` ${chalk.hex('#00D9FF')('baseUrl')}: ${config.baseUrl}`)
100
- console.log(` ${chalk.hex('#00D9FF')('provider')}: ${config.provider}`)
101
- console.log(` ${chalk.hex('#00D9FF')('model')}: ${config.model}`)
104
+ console2.muted('━'.repeat(50))
105
+ console.log(` ${chalk.hex('#00D9FF')('apiKey')}: ${maskApiKey(config.apiKey)}`)
106
+ console.log(` ${chalk.hex('#00D9FF')('baseUrl')}: ${config.baseUrl}`)
107
+ console.log(` ${chalk.hex('#00D9FF')('provider')}: ${config.provider}`)
108
+ console.log(` ${chalk.hex('#00D9FF')('model')}: ${config.model}`)
102
109
  console.log(
103
- ` ${chalk.hex('#00D9FF')('shellHook')}: ${
110
+ ` ${chalk.hex('#00D9FF')('shellHook')}: ${
104
111
  config.shellHook ? chalk.hex('#10B981')('已启用') : chalk.gray('未启用')
105
112
  }`
106
113
  )
107
- console.log(` ${chalk.hex('#00D9FF')('chatHistoryLimit')}: ${config.chatHistoryLimit} 轮`)
108
- console2.muted(''.repeat(40))
114
+ console.log(
115
+ ` ${chalk.hex('#00D9FF')('editMode')}: ${
116
+ config.editMode === 'auto' ? chalk.hex('#00D9FF')('auto (自动编辑)') : chalk.gray('manual (按E编辑)')
117
+ }`
118
+ )
119
+ console.log(` ${chalk.hex('#00D9FF')('chatHistoryLimit')}: ${config.chatHistoryLimit} 轮`)
120
+ console.log(` ${chalk.hex('#00D9FF')('commandHistoryLimit')}: ${config.commandHistoryLimit} 条`)
121
+ console.log(` ${chalk.hex('#00D9FF')('shellHistoryLimit')}: ${config.shellHistoryLimit} 条`)
122
+ console2.muted('━'.repeat(50))
109
123
  console2.muted(`配置文件: ${CONFIG_FILE}`)
110
124
  console.log('')
111
125
  })
@@ -161,7 +175,15 @@ historyCmd
161
175
  : chalk.gray('(未执行)')
162
176
 
163
177
  console.log(`\n${chalk.gray(`${index + 1}.`)} ${chalk.hex('#00D9FF')(item.userPrompt)}`)
164
- console.log(` ${chalk.dim('→')} ${item.command} ${status}`)
178
+
179
+ // 显示用户修改信息
180
+ if (item.userModified && item.aiGeneratedCommand) {
181
+ console.log(` ${chalk.dim('AI 生成:')} ${chalk.gray(item.aiGeneratedCommand)}`)
182
+ console.log(` ${chalk.dim('用户修改为:')} ${item.command} ${status} ${chalk.yellow('(已修改)')}`)
183
+ } else {
184
+ console.log(` ${chalk.dim('→')} ${item.command} ${status}`)
185
+ }
186
+
165
187
  console.log(` ${chalk.gray(item.timestamp)}`)
166
188
  })
167
189
 
@@ -180,7 +202,38 @@ historyCmd
180
202
  console.log('')
181
203
  })
182
204
 
183
- // 默认 history 命令(显示历史)
205
+ // history chat 子命令
206
+ const historyChatCmd = historyCmd.command('chat').description('查看或管理对话历史')
207
+
208
+ historyChatCmd.action(() => {
209
+ displayChatHistory()
210
+ })
211
+
212
+ historyChatCmd
213
+ .command('clear')
214
+ .description('清空对话历史')
215
+ .action(() => {
216
+ clearChatHistory()
217
+ console.log('')
218
+ console2.success('对话历史已清空')
219
+ console.log('')
220
+ })
221
+
222
+ // history shell 子命令
223
+ const historyShellCmd = historyCmd.command('shell').description('查看或管理 Shell 历史')
224
+
225
+ historyShellCmd.action(() => {
226
+ displayShellHistory()
227
+ })
228
+
229
+ historyShellCmd
230
+ .command('clear')
231
+ .description('清空 Shell 历史')
232
+ .action(() => {
233
+ clearShellHistory()
234
+ })
235
+
236
+ // 默认 history 命令(显示命令历史)
184
237
  historyCmd.action(() => {
185
238
  const history = getHistory()
186
239
 
@@ -203,7 +256,15 @@ historyCmd.action(() => {
203
256
  : chalk.gray('(未执行)')
204
257
 
205
258
  console.log(`\n${chalk.gray(`${index + 1}.`)} ${chalk.hex('#00D9FF')(item.userPrompt)}`)
206
- console.log(` ${chalk.dim('→')} ${item.command} ${status}`)
259
+
260
+ // 显示用户修改信息
261
+ if (item.userModified && item.aiGeneratedCommand) {
262
+ console.log(` ${chalk.dim('AI 生成:')} ${chalk.gray(item.aiGeneratedCommand)}`)
263
+ console.log(` ${chalk.dim('用户修改为:')} ${item.command} ${status} ${chalk.yellow('(已修改)')}`)
264
+ } else {
265
+ console.log(` ${chalk.dim('→')} ${item.command} ${status}`)
266
+ }
267
+
207
268
  console.log(` ${chalk.gray(item.timestamp)}`)
208
269
  })
209
270
 
@@ -411,6 +472,7 @@ program
411
472
  ;(async () => {
412
473
  const executedSteps: ExecutedStep[] = []
413
474
  let currentStepNumber = 1
475
+ let lastStepFailed = false // 跟踪上一步是否失败
414
476
 
415
477
  while (true) {
416
478
  let stepResult: any = null
@@ -444,6 +506,8 @@ program
444
506
  addHistory({
445
507
  userPrompt: currentStepNumber === 1 ? prompt : `[步骤${currentStepNumber}] ${prompt}`,
446
508
  command: stepResult.command,
509
+ aiGeneratedCommand: stepResult.aiGeneratedCommand, // AI 原始命令
510
+ userModified: stepResult.userModified || false,
447
511
  executed: false,
448
512
  exitCode: null,
449
513
  output: '',
@@ -453,9 +517,35 @@ program
453
517
  }
454
518
 
455
519
  if (stepResult.confirmed) {
520
+ // 如果命令为空,说明 AI 决定放弃
521
+ if (!stepResult.command || stepResult.command.trim() === '') {
522
+ console.log('')
523
+ if (stepResult.reasoning) {
524
+ console2.info(`💡 AI 分析: ${stepResult.reasoning}`)
525
+ }
526
+ console2.muted('❌ AI 决定停止尝试,任务失败')
527
+ console.log('')
528
+ process.exit(1)
529
+ }
530
+
531
+ // 特殊处理:如果上一步失败,且 AI 决定放弃(continue: false),直接显示原因并退出
532
+ if (
533
+ lastStepFailed &&
534
+ stepResult.needsContinue === false &&
535
+ stepResult.command.startsWith('echo')
536
+ ) {
537
+ console.log('')
538
+ if (stepResult.reasoning) {
539
+ console2.info(`💡 AI 分析: ${stepResult.reasoning}`)
540
+ }
541
+ console2.muted('❌ AI 决定停止尝试,任务失败')
542
+ console.log('')
543
+ process.exit(1)
544
+ }
545
+
456
546
  // 执行命令
457
547
  const execStart = Date.now()
458
- const { exitCode, output } = await executeCommand(stepResult.command, prompt)
548
+ const { exitCode, output } = await executeCommand(stepResult.command)
459
549
  const execDuration = Date.now() - execStart
460
550
 
461
551
  // 保存到执行历史
@@ -474,6 +564,8 @@ program
474
564
  userPrompt:
475
565
  currentStepNumber === 1 ? prompt : `[步骤${currentStepNumber}] ${stepResult.reasoning || prompt}`,
476
566
  command: stepResult.command,
567
+ aiGeneratedCommand: stepResult.aiGeneratedCommand, // AI 原始命令
568
+ userModified: stepResult.userModified || false,
477
569
  executed: true,
478
570
  exitCode,
479
571
  output,
@@ -489,14 +581,19 @@ program
489
581
  // 多步命令
490
582
  console2.success(`步骤 ${currentStepNumber} 执行完成 ${console2.formatDuration(execDuration)}`)
491
583
  }
584
+ lastStepFailed = false
492
585
  } else {
493
- // 执行失败,但不立即退出,让 AI 分析错误并调整策略
586
+ // 执行失败,标记状态
494
587
  console2.error(
495
588
  `步骤 ${currentStepNumber} 执行失败,退出码: ${exitCode} ${console2.formatDuration(execDuration)}`
496
589
  )
497
590
  console.log('')
498
591
  console2.warning('正在请 AI 分析错误并调整策略...')
499
- // 不退出,继续循环,AI 会收到错误信息
592
+ lastStepFailed = true
593
+ // 继续循环,让 AI 分析错误
594
+ console.log('')
595
+ currentStepNumber++
596
+ continue
500
597
  }
501
598
 
502
599
  // 判断是否继续
@@ -511,6 +608,20 @@ program
511
608
 
512
609
  console.log('')
513
610
  currentStepNumber++
611
+ } else if (!stepResult.confirmed && !stepResult.cancelled) {
612
+ // AI 返回了结果但没有确认(空命令的情况)
613
+ if (lastStepFailed && stepResult.reasoning) {
614
+ console.log('')
615
+ console2.info(`💡 AI 分析: ${stepResult.reasoning}`)
616
+ console2.muted('❌ AI 决定停止尝试,任务失败')
617
+ console.log('')
618
+ process.exit(1)
619
+ }
620
+ // 其他情况也退出
621
+ console.log('')
622
+ console2.muted('任务结束')
623
+ console.log('')
624
+ process.exit(0)
514
625
  }
515
626
  }
516
627
  })()
package/dist/bin/pls.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env tsx
2
2
  export {};