@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.
- package/README.md +98 -27
- package/bin/pls.tsx +135 -24
- package/dist/bin/pls.d.ts +1 -1
- package/dist/bin/pls.js +117 -24
- package/dist/package.json +80 -0
- package/dist/src/ai.d.ts +1 -41
- package/dist/src/ai.js +9 -190
- package/dist/src/builtin-detector.d.ts +14 -8
- package/dist/src/builtin-detector.js +36 -16
- package/dist/src/chat-history.d.ts +16 -11
- package/dist/src/chat-history.js +26 -4
- package/dist/src/components/Chat.js +3 -3
- package/dist/src/components/CommandBox.js +1 -16
- package/dist/src/components/ConfirmationPrompt.d.ts +2 -1
- package/dist/src/components/ConfirmationPrompt.js +7 -3
- package/dist/src/components/MultiStepCommandGenerator.d.ts +2 -0
- package/dist/src/components/MultiStepCommandGenerator.js +110 -7
- package/dist/src/config.d.ts +27 -8
- package/dist/src/config.js +92 -33
- package/dist/src/history.d.ts +19 -5
- package/dist/src/history.js +26 -11
- package/dist/src/mastra-agent.d.ts +0 -1
- package/dist/src/mastra-agent.js +3 -4
- package/dist/src/mastra-chat.d.ts +28 -0
- package/dist/src/mastra-chat.js +93 -0
- package/dist/src/multi-step.d.ts +2 -2
- package/dist/src/multi-step.js +2 -2
- package/dist/src/prompts.d.ts +11 -0
- package/dist/src/prompts.js +140 -0
- package/dist/src/shell-hook.d.ts +35 -13
- package/dist/src/shell-hook.js +82 -7
- package/dist/src/sysinfo.d.ts +9 -5
- package/dist/src/sysinfo.js +2 -2
- package/dist/src/utils/console.d.ts +11 -11
- package/dist/src/utils/console.js +4 -6
- package/package.json +8 -6
- package/src/builtin-detector.ts +126 -0
- package/src/chat-history.ts +130 -0
- package/src/components/Chat.tsx +4 -4
- package/src/components/CommandBox.tsx +1 -16
- package/src/components/ConfirmationPrompt.tsx +9 -2
- package/src/components/MultiStepCommandGenerator.tsx +144 -7
- package/src/config.ts +309 -0
- package/src/history.ts +160 -0
- package/src/mastra-agent.ts +3 -4
- package/src/mastra-chat.ts +124 -0
- package/src/multi-step.ts +2 -2
- package/src/prompts.ts +154 -0
- package/src/shell-hook.ts +502 -0
- package/src/{sysinfo.js → sysinfo.ts} +28 -16
- package/src/utils/{console.js → console.ts} +16 -18
- package/bin/pls.js +0 -681
- package/src/ai.js +0 -324
- package/src/builtin-detector.js +0 -98
- package/src/chat-history.js +0 -94
- package/src/components/ChatStatus.tsx +0 -53
- package/src/components/CommandGenerator.tsx +0 -184
- package/src/components/ConfigDisplay.tsx +0 -64
- package/src/components/ConfigWizard.tsx +0 -101
- package/src/components/HistoryDisplay.tsx +0 -69
- package/src/components/HookManager.tsx +0 -150
- package/src/config.js +0 -221
- package/src/history.js +0 -131
- 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
|
-
|
|
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
|
|
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
|
-
│ ├──
|
|
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.
|
|
310
|
-
│ ├── history.
|
|
311
|
-
│ ├── chat-history.
|
|
312
|
-
│ ├── shell-hook.
|
|
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.
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
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(
|
|
98
|
-
console.log(` ${chalk.hex('#00D9FF')('apiKey')}:
|
|
99
|
-
console.log(` ${chalk.hex('#00D9FF')('baseUrl')}:
|
|
100
|
-
console.log(` ${chalk.hex('#00D9FF')('provider')}:
|
|
101
|
-
console.log(` ${chalk.hex('#00D9FF')('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(
|
|
108
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
586
|
+
// 执行失败,标记状态
|
|
494
587
|
console2.error(
|
|
495
588
|
`步骤 ${currentStepNumber} 执行失败,退出码: ${exitCode} ${console2.formatDuration(execDuration)}`
|
|
496
589
|
)
|
|
497
590
|
console.log('')
|
|
498
591
|
console2.warning('正在请 AI 分析错误并调整策略...')
|
|
499
|
-
|
|
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
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
2
|
export {};
|