@yivan-lab/pretty-please 1.3.1 → 1.5.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 (94) hide show
  1. package/README.md +250 -620
  2. package/bin/pls.tsx +178 -40
  3. package/dist/bin/pls.js +149 -27
  4. package/dist/package.json +10 -2
  5. package/dist/src/__integration__/command-generation.test.d.ts +5 -0
  6. package/dist/src/__integration__/command-generation.test.js +508 -0
  7. package/dist/src/__integration__/error-recovery.test.d.ts +5 -0
  8. package/dist/src/__integration__/error-recovery.test.js +511 -0
  9. package/dist/src/__integration__/shell-hook-workflow.test.d.ts +5 -0
  10. package/dist/src/__integration__/shell-hook-workflow.test.js +375 -0
  11. package/dist/src/__tests__/alias.test.d.ts +5 -0
  12. package/dist/src/__tests__/alias.test.js +421 -0
  13. package/dist/src/__tests__/chat-history.test.d.ts +5 -0
  14. package/dist/src/__tests__/chat-history.test.js +372 -0
  15. package/dist/src/__tests__/config.test.d.ts +5 -0
  16. package/dist/src/__tests__/config.test.js +822 -0
  17. package/dist/src/__tests__/history.test.d.ts +5 -0
  18. package/dist/src/__tests__/history.test.js +439 -0
  19. package/dist/src/__tests__/remote-history.test.d.ts +5 -0
  20. package/dist/src/__tests__/remote-history.test.js +641 -0
  21. package/dist/src/__tests__/remote.test.d.ts +5 -0
  22. package/dist/src/__tests__/remote.test.js +689 -0
  23. package/dist/src/__tests__/shell-hook-install.test.d.ts +5 -0
  24. package/dist/src/__tests__/shell-hook-install.test.js +413 -0
  25. package/dist/src/__tests__/shell-hook-remote.test.d.ts +5 -0
  26. package/dist/src/__tests__/shell-hook-remote.test.js +507 -0
  27. package/dist/src/__tests__/shell-hook.test.d.ts +5 -0
  28. package/dist/src/__tests__/shell-hook.test.js +440 -0
  29. package/dist/src/__tests__/sysinfo.test.d.ts +5 -0
  30. package/dist/src/__tests__/sysinfo.test.js +572 -0
  31. package/dist/src/__tests__/system-history.test.d.ts +5 -0
  32. package/dist/src/__tests__/system-history.test.js +457 -0
  33. package/dist/src/components/Chat.js +9 -28
  34. package/dist/src/config.d.ts +2 -0
  35. package/dist/src/config.js +30 -2
  36. package/dist/src/mastra-chat.js +10 -6
  37. package/dist/src/multi-step.js +10 -8
  38. package/dist/src/project-context.d.ts +22 -0
  39. package/dist/src/project-context.js +168 -0
  40. package/dist/src/prompts.d.ts +4 -4
  41. package/dist/src/prompts.js +23 -6
  42. package/dist/src/shell-hook.d.ts +32 -0
  43. package/dist/src/shell-hook.js +226 -33
  44. package/dist/src/sysinfo.d.ts +38 -9
  45. package/dist/src/sysinfo.js +245 -21
  46. package/dist/src/system-history.d.ts +18 -0
  47. package/dist/src/system-history.js +151 -0
  48. package/dist/src/ui/__tests__/theme.test.d.ts +5 -0
  49. package/dist/src/ui/__tests__/theme.test.js +688 -0
  50. package/dist/src/upgrade.js +3 -0
  51. package/dist/src/user-preferences.d.ts +44 -0
  52. package/dist/src/user-preferences.js +147 -0
  53. package/dist/src/utils/__tests__/platform-capabilities.test.d.ts +5 -0
  54. package/dist/src/utils/__tests__/platform-capabilities.test.js +214 -0
  55. package/dist/src/utils/__tests__/platform-exec.test.d.ts +5 -0
  56. package/dist/src/utils/__tests__/platform-exec.test.js +212 -0
  57. package/dist/src/utils/__tests__/platform-shell.test.d.ts +5 -0
  58. package/dist/src/utils/__tests__/platform-shell.test.js +300 -0
  59. package/dist/src/utils/__tests__/platform.test.d.ts +5 -0
  60. package/dist/src/utils/__tests__/platform.test.js +137 -0
  61. package/dist/src/utils/platform.d.ts +88 -0
  62. package/dist/src/utils/platform.js +331 -0
  63. package/package.json +10 -2
  64. package/src/__integration__/command-generation.test.ts +602 -0
  65. package/src/__integration__/error-recovery.test.ts +620 -0
  66. package/src/__integration__/shell-hook-workflow.test.ts +457 -0
  67. package/src/__tests__/alias.test.ts +545 -0
  68. package/src/__tests__/chat-history.test.ts +462 -0
  69. package/src/__tests__/config.test.ts +1043 -0
  70. package/src/__tests__/history.test.ts +538 -0
  71. package/src/__tests__/remote-history.test.ts +791 -0
  72. package/src/__tests__/remote.test.ts +866 -0
  73. package/src/__tests__/shell-hook-install.test.ts +510 -0
  74. package/src/__tests__/shell-hook-remote.test.ts +679 -0
  75. package/src/__tests__/shell-hook.test.ts +564 -0
  76. package/src/__tests__/sysinfo.test.ts +718 -0
  77. package/src/__tests__/system-history.test.ts +608 -0
  78. package/src/components/Chat.tsx +10 -37
  79. package/src/config.ts +29 -2
  80. package/src/mastra-chat.ts +12 -5
  81. package/src/multi-step.ts +11 -5
  82. package/src/project-context.ts +191 -0
  83. package/src/prompts.ts +26 -5
  84. package/src/shell-hook.ts +254 -32
  85. package/src/sysinfo.ts +326 -25
  86. package/src/system-history.ts +170 -0
  87. package/src/ui/__tests__/theme.test.ts +869 -0
  88. package/src/upgrade.ts +5 -0
  89. package/src/user-preferences.ts +178 -0
  90. package/src/utils/__tests__/platform-capabilities.test.ts +265 -0
  91. package/src/utils/__tests__/platform-exec.test.ts +278 -0
  92. package/src/utils/__tests__/platform-shell.test.ts +353 -0
  93. package/src/utils/__tests__/platform.test.ts +170 -0
  94. package/src/utils/platform.ts +431 -0
@@ -1,10 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import { createShellAgent } from './mastra-agent.js';
3
3
  import { SHELL_COMMAND_SYSTEM_PROMPT, buildUserContextPrompt } from './prompts.js';
4
- import { formatSystemInfo } from './sysinfo.js';
4
+ import { formatSystemInfo, getSystemInfo } from './sysinfo.js';
5
5
  import { formatHistoryForAI } from './history.js';
6
- import { formatShellHistoryForAI, getShellHistory } from './shell-hook.js';
7
- import { getConfig } from './config.js';
8
6
  import { formatRemoteHistoryForAI, formatRemoteShellHistoryForAI } from './remote-history.js';
9
7
  import { formatRemoteSysInfoForAI } from './remote.js';
10
8
  /**
@@ -46,14 +44,18 @@ export async function generateMultiStepCommand(userPrompt, previousSteps = [], o
46
44
  }
47
45
  else {
48
46
  // 本地执行:格式化本地系统信息和历史
49
- sysinfoStr = formatSystemInfo();
50
- const config = getConfig();
47
+ sysinfoStr = formatSystemInfo(await getSystemInfo());
51
48
  const plsHistory = formatHistoryForAI();
52
- const shellHistory = formatShellHistoryForAI();
53
- historyStr = (config.shellHook && getShellHistory().length > 0) ? shellHistory : plsHistory;
49
+ // 使用统一的历史获取接口(自动降级到系统历史)
50
+ const { formatShellHistoryForAIWithFallback } = await import('./shell-hook.js');
51
+ const shellHistory = formatShellHistoryForAIWithFallback();
52
+ historyStr = shellHistory || plsHistory; // 优先使用 shell 历史,降级到 pls 历史
54
53
  }
54
+ // 获取用户偏好
55
+ const { formatUserPreferences } = await import('./user-preferences.js');
56
+ const userPreferencesStr = formatUserPreferences();
55
57
  // 构建包含所有动态数据的 User Prompt(XML 格式)
56
- const userContextPrompt = buildUserContextPrompt(userPrompt, sysinfoStr, historyStr, previousSteps);
58
+ const userContextPrompt = buildUserContextPrompt(userPrompt, sysinfoStr, historyStr, userPreferencesStr, previousSteps);
57
59
  // 只发送一条 User Message
58
60
  const messages = [userContextPrompt];
59
61
  // 调用 Mastra Agent 生成结构化输出
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 项目上下文信息
3
+ */
4
+ export interface ProjectContext {
5
+ types: string[];
6
+ packageManager?: string;
7
+ git?: {
8
+ branch: string;
9
+ status: 'clean' | 'dirty' | 'unknown';
10
+ };
11
+ scripts?: string[];
12
+ }
13
+ /**
14
+ * 检测项目上下文(优化版:< 30ms)
15
+ * 若未识别到任何特征,返回 null
16
+ */
17
+ export declare function detectProjectContext(cwd: string): Promise<ProjectContext | null>;
18
+ /**
19
+ * 格式化项目上下文为字符串(供 AI 使用)
20
+ * 格式:当前项目: nodejs+docker+git | pnpm | Git分支: main (有改动) | 脚本: dev, build, test
21
+ */
22
+ export declare function formatProjectContext(project: ProjectContext): string;
@@ -0,0 +1,168 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { detect as detectPM } from 'detect-package-manager';
4
+ import { execSync } from 'child_process';
5
+ /**
6
+ * 检测项目上下文(优化版:< 30ms)
7
+ * 若未识别到任何特征,返回 null
8
+ */
9
+ export async function detectProjectContext(cwd) {
10
+ const types = [];
11
+ let packageManager;
12
+ let git;
13
+ let scripts;
14
+ try {
15
+ // 1. 快速读取目录文件列表(同步,< 5ms)
16
+ const files = fs.readdirSync(cwd);
17
+ // 2. 检测项目类型(纯文件检查,< 10ms)
18
+ if (files.includes('package.json')) {
19
+ types.push('nodejs');
20
+ // 检测 Node.js 包管理器
21
+ try {
22
+ packageManager = await detectPM({ cwd });
23
+ }
24
+ catch {
25
+ // 降级:根据 lock 文件推断
26
+ if (files.includes('pnpm-lock.yaml'))
27
+ packageManager = 'pnpm';
28
+ else if (files.includes('yarn.lock'))
29
+ packageManager = 'yarn';
30
+ else if (files.includes('bun.lockb'))
31
+ packageManager = 'bun';
32
+ else
33
+ packageManager = 'npm';
34
+ }
35
+ // 读取 package.json scripts(最多 5 个)
36
+ try {
37
+ const pkg = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf-8'));
38
+ if (pkg.scripts) {
39
+ scripts = Object.keys(pkg.scripts).slice(0, 5);
40
+ }
41
+ }
42
+ catch {
43
+ // 忽略读取错误
44
+ }
45
+ }
46
+ // Python
47
+ if (files.some(f => ['pyproject.toml', 'requirements.txt', 'Pipfile', 'uv.lock', 'poetry.lock'].includes(f))) {
48
+ types.push('python');
49
+ if (files.includes('uv.lock'))
50
+ packageManager = 'uv';
51
+ else if (files.includes('poetry.lock'))
52
+ packageManager = 'poetry';
53
+ else if (files.includes('Pipfile'))
54
+ packageManager = 'pipenv';
55
+ else
56
+ packageManager = 'pip';
57
+ }
58
+ // Rust
59
+ if (files.includes('Cargo.toml')) {
60
+ types.push('rust');
61
+ packageManager = 'cargo';
62
+ }
63
+ // Go
64
+ if (files.includes('go.mod')) {
65
+ types.push('go');
66
+ }
67
+ // Docker
68
+ if (files.some(f => f.includes('docker') || f === 'Dockerfile' || f === 'compose.yaml')) {
69
+ types.push('docker');
70
+ }
71
+ // Makefile
72
+ if (files.includes('Makefile')) {
73
+ types.push('make');
74
+ }
75
+ // 3. Git 检测优化(< 20ms)
76
+ if (files.includes('.git') || fs.existsSync(path.join(cwd, '.git'))) {
77
+ types.push('git');
78
+ try {
79
+ // 读取 .git/HEAD 文件获取分支(最快,< 5ms)
80
+ const headFile = fs.readFileSync(path.join(cwd, '.git/HEAD'), 'utf-8');
81
+ const refMatch = headFile.match(/ref: refs\/heads\/(.+)/);
82
+ if (refMatch) {
83
+ // 正常分支
84
+ git = {
85
+ branch: refMatch[1].trim(),
86
+ status: quickGitStatus(cwd),
87
+ };
88
+ }
89
+ else {
90
+ // detached HEAD 状态(直接 commit hash)
91
+ const shortHash = headFile.trim().substring(0, 7);
92
+ git = {
93
+ branch: `HEAD (${shortHash})`,
94
+ status: quickGitStatus(cwd),
95
+ };
96
+ }
97
+ }
98
+ catch {
99
+ // Git 检测失败,只标记类型,不提供详细信息
100
+ }
101
+ }
102
+ }
103
+ catch (error) {
104
+ // 检测失败,返回空上下文
105
+ }
106
+ const hasContext = types.length > 0 ||
107
+ !!packageManager ||
108
+ !!git ||
109
+ (scripts && scripts.length > 0);
110
+ if (!hasContext) {
111
+ return null;
112
+ }
113
+ return { types, packageManager, git, scripts };
114
+ }
115
+ /**
116
+ * Git status 快速检测(带超时)
117
+ */
118
+ function quickGitStatus(cwd) {
119
+ try {
120
+ // 使用 git status --porcelain,带超时保护
121
+ const result = execSync('git status --porcelain', {
122
+ cwd,
123
+ stdio: 'pipe',
124
+ timeout: 100, // 100ms 超时
125
+ encoding: 'utf-8',
126
+ });
127
+ return result.trim() === '' ? 'clean' : 'dirty';
128
+ }
129
+ catch {
130
+ // 超时或失败,返回 unknown
131
+ return 'unknown';
132
+ }
133
+ }
134
+ /**
135
+ * 格式化项目上下文为字符串(供 AI 使用)
136
+ * 格式:当前项目: nodejs+docker+git | pnpm | Git分支: main (有改动) | 脚本: dev, build, test
137
+ */
138
+ export function formatProjectContext(project) {
139
+ if (project.types.length === 0) {
140
+ return '';
141
+ }
142
+ const parts = [];
143
+ // 项目类型
144
+ parts.push(`当前项目: ${project.types.join('+')}`);
145
+ // 包管理器
146
+ if (project.packageManager) {
147
+ parts.push(` | ${project.packageManager}`);
148
+ }
149
+ // Git 信息
150
+ if (project.git) {
151
+ let statusDesc = '';
152
+ if (project.git.status === 'clean') {
153
+ statusDesc = '干净';
154
+ }
155
+ else if (project.git.status === 'dirty') {
156
+ statusDesc = '有改动';
157
+ }
158
+ else {
159
+ statusDesc = '未知';
160
+ }
161
+ parts.push(` | Git分支: ${project.git.branch} (${statusDesc})`);
162
+ }
163
+ // 可用脚本
164
+ if (project.scripts && project.scripts.length > 0) {
165
+ parts.push(` | 脚本: ${project.scripts.join(', ')}`);
166
+ }
167
+ return parts.join('');
168
+ }
@@ -8,14 +8,14 @@
8
8
  * 包含所有核心规则、输出格式定义、判断标准、错误处理策略和示例
9
9
  * 不包含任何动态数据(系统信息、历史记录等)
10
10
  */
11
- export declare const SHELL_COMMAND_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 shell \u811A\u672C\u751F\u6210\u5668\u3002\n\u4F60\u5C06\u63A5\u6536\u5230\u5305\u542B XML \u6807\u7B7E\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF0C\u7136\u540E\u6839\u636E\u7528\u6237\u9700\u6C42\u751F\u6210\u53EF\u6267\u884C\u7684 shell \u547D\u4EE4\u3002\n\n### \uD83D\uDCCB \u8F93\u5165\u6570\u636E\u683C\u5F0F\u8BF4\u660E\n\u4F60\u4F1A\u6536\u5230\u4EE5\u4E0B XML \u6807\u7B7E\u5305\u88F9\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF1A\n- <system_info>\uFF1A\u7528\u6237\u7684\u64CD\u4F5C\u7CFB\u7EDF\u3001Shell \u7C7B\u578B\u3001\u5F53\u524D\u76EE\u5F55\u3001\u5305\u7BA1\u7406\u5668\u7B49\u73AF\u5883\u4FE1\u606F\n- <command_history>\uFF1A\u7528\u6237\u6700\u8FD1\u6267\u884C\u7684\u547D\u4EE4\u5386\u53F2\uFF08\u7528\u4E8E\u7406\u89E3\u4E0A\u4E0B\u6587\u5F15\u7528\uFF0C\u5982\"\u521A\u624D\u7684\u6587\u4EF6\"\u3001\"\u4E0A\u4E00\u4E2A\u547D\u4EE4\"\uFF09\n- <execution_log>\uFF1A**\u591A\u6B65\u9AA4\u4EFB\u52A1\u7684\u5173\u952E\u4FE1\u606F**\uFF0C\u8BB0\u5F55\u4E86\u4E4B\u524D\u6B65\u9AA4\u7684\u547D\u4EE4\u3001\u9000\u51FA\u7801\u548C\u8F93\u51FA\u7ED3\u679C\n - \u5982\u679C\u5B58\u5728\u6B64\u6807\u7B7E\uFF0C\u8BF4\u660E\u8FD9\u662F\u4E00\u4E2A\u591A\u6B65\u9AA4\u4EFB\u52A1\n - \u5FC5\u987B\u68C0\u67E5\u6BCF\u4E2A <step> \u4E2D\u7684 <exit_code>\uFF0C0=\u6210\u529F\uFF0C\u975E0=\u5931\u8D25\n - \u6839\u636E <output> \u7684\u5185\u5BB9\u51B3\u5B9A\u4E0B\u4E00\u6B65\u64CD\u4F5C\n- <user_request>\uFF1A\u7528\u6237\u7684\u539F\u59CB\u81EA\u7136\u8BED\u8A00\u9700\u6C42\n\n### \u26A0\uFE0F \u91CD\u8981\u89C4\u5219\n1. \u8FD4\u56DE JSON \u683C\u5F0F\uFF0Ccommand \u5B57\u6BB5\u5FC5\u987B\u662F\u53EF\u76F4\u63A5\u6267\u884C\u7684\u547D\u4EE4\uFF08\u65E0\u89E3\u91CA\u3001\u65E0\u6CE8\u91CA\u3001\u65E0 markdown\uFF09\n2. \u4E0D\u8981\u6DFB\u52A0 shebang\uFF08\u5982 #!/bin/bash\uFF09\n3. command \u53EF\u4EE5\u5305\u542B\u591A\u6761\u547D\u4EE4\uFF08\u7528 && \u8FDE\u63A5\uFF09\uFF0C\u4F46\u6574\u4F53\u7B97\u4E00\u4E2A\u547D\u4EE4\n4. \u6839\u636E <system_info> \u4E2D\u7684\u4FE1\u606F\u9009\u62E9\u5408\u9002\u7684\u547D\u4EE4\uFF08\u5982\u5305\u7BA1\u7406\u5668\uFF09\n5. \u5982\u679C\u7528\u6237\u5F15\u7528\u4E86\u4E4B\u524D\u7684\u64CD\u4F5C\uFF08\u5982\"\u521A\u624D\u7684\"\u3001\"\u4E0A\u4E00\u4E2A\"\uFF09\uFF0C\u8BF7\u53C2\u8003 <command_history>\n6. \u7EDD\u5BF9\u4E0D\u8981\u8F93\u51FA pls \u6216 please \u547D\u4EE4\uFF01\n\n### \uD83D\uDCE4 \u8F93\u51FA\u683C\u5F0F - \u975E\u5E38\u91CD\u8981\n\n**\u5355\u6B65\u6A21\u5F0F\uFF08\u4E00\u4E2A\u547D\u4EE4\u5B8C\u6210\uFF09\uFF1A**\n\u5982\u679C\u4EFB\u52A1\u53EA\u9700\u8981\u4E00\u4E2A\u547D\u4EE4\u5C31\u80FD\u5B8C\u6210\uFF0C\u53EA\u8FD4\u56DE\uFF1A\n{\n \"command\": \"ls -la\"\n}\n\n**\u591A\u6B65\u6A21\u5F0F\uFF08\u9700\u8981\u591A\u4E2A\u547D\u4EE4\uFF0C\u540E\u7EED\u4F9D\u8D56\u524D\u9762\u7684\u7ED3\u679C\uFF09\uFF1A**\n\u5982\u679C\u4EFB\u52A1\u9700\u8981\u591A\u4E2A\u547D\u4EE4\uFF0C\u4E14\u540E\u7EED\u547D\u4EE4\u5FC5\u987B\u6839\u636E\u524D\u9762\u7684\u6267\u884C\u7ED3\u679C\u6765\u51B3\u5B9A\uFF0C\u5219\u8FD4\u56DE\uFF1A\n\n\u3010\u591A\u6B65\u9AA4\u5B8C\u6574\u793A\u4F8B\u3011\n\u7528\u6237\uFF1A\"\u67E5\u627E\u5927\u4E8E100MB\u7684\u65E5\u5FD7\u6587\u4EF6\u5E76\u538B\u7F29\"\n\n\u7B2C\u4E00\u6B65\u4F60\u8FD4\u56DE\uFF1A\n{\n \"command\": \"find . -name '*.log' -size +100M\",\n \"continue\": true,\n \"reasoning\": \"\u5148\u67E5\u627E\u7B26\u5408\u6761\u4EF6\u7684\u65E5\u5FD7\u6587\u4EF6\",\n \"nextStepHint\": \"\u6839\u636E\u67E5\u627E\u7ED3\u679C\u538B\u7F29\u6587\u4EF6\"\n}\n\n\u6267\u884C\u540E\u4F60\u4F1A\u6536\u5230\uFF08\u5728 <execution_log> \u4E2D\uFF09\uFF1A\n<execution_log>\n<step index=\"1\">\n<command>find . -name '*.log' -size +100M</command>\n<exit_code>0</exit_code>\n<output>\n./app.log\n./system.log\n</output>\n</step>\n</execution_log>\n\n\u7136\u540E\u4F60\u8FD4\u56DE\u7B2C\u4E8C\u6B65\uFF1A\n{\n \"command\": \"tar -czf logs.tar.gz ./app.log ./system.log\",\n \"continue\": false,\n \"reasoning\": \"\u538B\u7F29\u627E\u5230\u7684\u65E5\u5FD7\u6587\u4EF6\"\n}\n\n### \uD83C\uDFAF \u5173\u952E\u5224\u65AD\u6807\u51C6\n- **\u591A\u6B65** = \u540E\u7EED\u547D\u4EE4\u4F9D\u8D56\u524D\u9762\u7684\u8F93\u51FA\uFF08\u5982\u5148 find \u770B\u6709\u54EA\u4E9B\uFF0C\u518D\u6839\u636E\u7ED3\u679C\u64CD\u4F5C\u5177\u4F53\u6587\u4EF6\uFF09\n- **\u5355\u6B65** = \u4E00\u4E2A\u547D\u4EE4\u5C31\u80FD\u5B8C\u6210\uFF08\u5373\u4F7F\u547D\u4EE4\u91CC\u6709 && \u8FDE\u63A5\u591A\u6761\uFF0C\u4E5F\u7B97\u4E00\u4E2A\u547D\u4EE4\uFF09\n\n### \uD83D\uDCDA \u5E38\u89C1\u573A\u666F\u4E3E\u4F8B\n- \"\u5220\u9664\u7A7A\u6587\u4EF6\u5939\" \u2192 \u5355\u6B65\uFF1A`find . -empty -delete` \uFF08\u4E00\u4E2A\u547D\u4EE4\u5B8C\u6210\uFF09\n- \"\u67E5\u627E\u5927\u6587\u4EF6\u5E76\u538B\u7F29\" \u2192 \u591A\u6B65\uFF1A\u5148 find \u770B\u6709\u54EA\u4E9B\uFF0C\u518D tar \u538B\u7F29\u5177\u4F53\u6587\u4EF6\n- \"\u5B89\u88C5 git\" \u2192 \u5355\u6B65\uFF1A`brew install git` \u6216 `apt-get install git`\n- \"\u5907\u4EFD\u5E76\u5220\u9664\u65E7\u65E5\u5FD7\" \u2192 \u591A\u6B65\uFF1A\u5148 `mkdir backup`\uFF0C\u518D `mv` \u6587\u4EF6\u5230 backup\n- \"\u67E5\u770B\u76EE\u5F55\" \u2192 \u5355\u6B65\uFF1A`ls -la`\n- \"\u67E5\u770B\u78C1\u76D8\u4F7F\u7528\u60C5\u51B5\u5E76\u6392\u5E8F\" \u2192 \u5355\u6B65\uFF1A`df -h | sort -k5 -rh` \uFF08\u4E00\u4E2A\u7BA1\u9053\u547D\u4EE4\uFF09\n- \"\u67E5\u770B\u8FDB\u7A0B\u5E76\u6740\u6B7B\u67D0\u4E2A\u8FDB\u7A0B\" \u2192 \u591A\u6B65\uFF1A\u5148 `ps aux | grep xxx` \u770B PID\uFF0C\u518D `kill` \u5177\u4F53 PID\n\n**\u4E25\u683C\u8981\u6C42**\uFF1A\u5355\u6B65\u6A21\u5F0F\u53EA\u8FD4\u56DE {\"command\": \"xxx\"}\uFF0C\u7EDD\u5BF9\u4E0D\u8981\u8F93\u51FA continue/reasoning/nextStepHint\uFF01\n\n### \uD83D\uDD27 \u9519\u8BEF\u5904\u7406\u7B56\u7565\n\n**\u5F53 <execution_log> \u4E2D\u6700\u540E\u4E00\u6B65\u7684 <exit_code> \u4E0D\u4E3A 0 \u65F6\uFF1A**\n\n1. **\u5206\u6790\u9519\u8BEF\u539F\u56E0**\uFF1A\u4ED4\u7EC6\u9605\u8BFB <output> \u4E2D\u7684\u9519\u8BEF\u4FE1\u606F\n2. **\u8C03\u6574\u547D\u4EE4\u7B56\u7565**\uFF1A\u751F\u6210\u4FEE\u6B63\u540E\u7684\u547D\u4EE4\n3. **\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED**\uFF1A\n - \u8BBE\u7F6E `continue: true` \u91CD\u8BD5\u4FEE\u6B63\u540E\u7684\u547D\u4EE4\n - \u8BBE\u7F6E `continue: false` \u653E\u5F03\u4EFB\u52A1\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 1\uFF1A\u6743\u9650\u9519\u8BEF**\n<execution_log>\n<step index=\"1\">\n<command>mkdir /var/log/myapp</command>\n<exit_code>1</exit_code>\n<output>mkdir: cannot create directory '/var/log/myapp': Permission denied</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u8FD4\u56DE\u4FEE\u6B63\uFF1A\n{\n \"command\": \"sudo mkdir /var/log/myapp\",\n \"continue\": true,\n \"reasoning\": \"\u6743\u9650\u4E0D\u8DB3\uFF0C\u4F7F\u7528 sudo \u91CD\u8BD5\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 2\uFF1A\u6587\u4EF6\u4E0D\u5B58\u5728**\n<execution_log>\n<step index=\"1\">\n<command>mv test.zip backup/</command>\n<exit_code>1</exit_code>\n<output>mv: cannot stat 'test.zip': No such file or directory</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u51B3\u5B9A\u653E\u5F03\uFF1A\n{\n \"command\": \"\",\n \"continue\": false,\n \"reasoning\": \"\u6E90\u6587\u4EF6 test.zip \u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u79FB\u52A8\uFF0C\u4EFB\u52A1\u65E0\u6CD5\u7EE7\u7EED\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 3\uFF1A\u547D\u4EE4\u4E0D\u5B58\u5728\uFF0C\u5C1D\u8BD5\u5B89\u88C5**\n<execution_log>\n<step index=\"1\">\n<command>docker ps</command>\n<exit_code>127</exit_code>\n<output>bash: docker: command not found</output>\n</step>\n</execution_log>\n\n\u4F60\u6839\u636E <system_info> \u4E2D\u7684\u5305\u7BA1\u7406\u5668\u8FD4\u56DE\uFF1A\n{\n \"command\": \"brew install docker\",\n \"continue\": true,\n \"reasoning\": \"docker \u672A\u5B89\u88C5\uFF0C\u6839\u636E\u7CFB\u7EDF\u5305\u7BA1\u7406\u5668\u5B89\u88C5\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 4\uFF1A\u7F51\u7EDC\u9519\u8BEF**\n<execution_log>\n<step index=\"1\">\n<command>ping -c 3 example.com</command>\n<exit_code>2</exit_code>\n<output>ping: example.com: Name or service not known</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u8FD4\u56DE\uFF1A\n{\n \"command\": \"\",\n \"continue\": false,\n \"reasoning\": \"\u7F51\u7EDC\u4E0D\u53EF\u8FBE\u6216 DNS \u89E3\u6790\u5931\u8D25\uFF0C\u65E0\u6CD5\u7EE7\u7EED\"\n}\n\n### \uD83D\uDED1 \u4F55\u65F6\u5E94\u8BE5\u653E\u5F03\uFF08continue: false\uFF09\n- \u7528\u6237\u8F93\u5165\u7684\u8DEF\u5F84\u4E0D\u5B58\u5728\u4E14\u65E0\u6CD5\u63A8\u6D4B\n- \u9700\u8981\u7684\u5DE5\u5177\u672A\u5B89\u88C5\u4E14\u65E0\u6CD5\u81EA\u52A8\u5B89\u88C5\uFF08\u5982\u975E root \u7528\u6237\u65E0\u6CD5 apt install\uFF09\n- \u6743\u9650\u95EE\u9898\u4E14\u65E0\u6CD5\u7528 sudo \u89E3\u51B3\uFF08\u5982 SELinux \u9650\u5236\uFF09\n- \u7F51\u7EDC\u4E0D\u53EF\u8FBE\u6216 DNS \u89E3\u6790\u5931\u8D25\n- \u91CD\u8BD5 2 \u6B21\u540E\u4ECD\u7136\u5931\u8D25\n- \u4EFB\u52A1\u672C\u8EAB\u4E0D\u5408\u7406\uFF08\u5982\"\u5220\u9664\u6839\u76EE\u5F55\"\uFF09\n\n**\u653E\u5F03\u65F6\u7684\u8981\u6C42**\uFF1A\n- `command` \u5B57\u6BB5\u53EF\u4EE5\u7559\u7A7A\uFF08\"\"\uFF09\n- `continue` \u5FC5\u987B\u4E3A false\n- `reasoning` \u5FC5\u987B\u8BE6\u7EC6\u8BF4\u660E\u4E3A\u4EC0\u4E48\u653E\u5F03\uFF0C\u4EE5\u53CA\u5C1D\u8BD5\u4E86\u4EC0\u4E48\n\n### \uD83D\uDCCC \u5173\u4E8E pls/please \u5DE5\u5177\n\u7528\u6237\u6B63\u5728\u4F7F\u7528 pls\uFF08pretty-please\uFF09\u5DE5\u5177\uFF0C\u8FD9\u662F\u4E00\u4E2A\u5C06\u81EA\u7136\u8BED\u8A00\u8F6C\u6362\u4E3A shell \u547D\u4EE4\u7684 AI \u52A9\u624B\u3002\n\u5F53\u7528\u6237\u8F93\u5165 \"pls <\u63CF\u8FF0>\" \u65F6\uFF0CAI\uFF08\u4E5F\u5C31\u662F\u4F60\uFF09\u4F1A\u751F\u6210\u5BF9\u5E94\u7684 shell \u547D\u4EE4\u4F9B\u7528\u6237\u786E\u8BA4\u6267\u884C\u3002\n<command_history> \u4E2D\u6807\u8BB0\u4E3A [pls] \u7684\u6761\u76EE\u8868\u793A\u7528\u6237\u901A\u8FC7 pls \u5DE5\u5177\u6267\u884C\u7684\u547D\u4EE4\u3002\n";
11
+ export declare const SHELL_COMMAND_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684 shell \u811A\u672C\u751F\u6210\u5668\u3002\n\u4F60\u5C06\u63A5\u6536\u5230\u5305\u542B XML \u6807\u7B7E\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF0C\u7136\u540E\u6839\u636E\u7528\u6237\u9700\u6C42\u751F\u6210\u53EF\u6267\u884C\u7684 shell \u547D\u4EE4\u3002\n\n### \uD83D\uDCCB \u8F93\u5165\u6570\u636E\u683C\u5F0F\u8BF4\u660E\n\u4F60\u4F1A\u6536\u5230\u4EE5\u4E0B XML \u6807\u7B7E\u5305\u88F9\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF1A\n- <system_info>\uFF1A\u7528\u6237\u7684\u64CD\u4F5C\u7CFB\u7EDF\u3001Shell \u7C7B\u578B\u3001\u5F53\u524D\u76EE\u5F55\u3001\u5305\u7BA1\u7406\u5668\u3001\u53EF\u7528\u5DE5\u5177\u7B49\u73AF\u5883\u4FE1\u606F\n- <command_history>\uFF1A\u7528\u6237\u6700\u8FD1\u6267\u884C\u7684\u547D\u4EE4\u5386\u53F2\uFF08\u7528\u4E8E\u7406\u89E3\u4E0A\u4E0B\u6587\u5F15\u7528\uFF0C\u5982\"\u521A\u624D\u7684\u6587\u4EF6\"\u3001\"\u4E0A\u4E00\u4E2A\u547D\u4EE4\"\uFF09\n- <user_preferences>\uFF1A**\u7528\u6237\u7684\u547D\u4EE4\u4F7F\u7528\u504F\u597D**\uFF08\u683C\u5F0F\uFF1A\u547D\u4EE4\u540D(\u4F7F\u7528\u6B21\u6570)\uFF09\uFF0C\u5E2E\u52A9\u4F60\u4E86\u89E3\u7528\u6237\u4E60\u60EF\n - \u4F8B\u5982\uFF1Agit(234), eza(156) \u8868\u793A\u7528\u6237\u7ECF\u5E38\u4F7F\u7528 git \u548C eza \u547D\u4EE4\n - \u751F\u6210\u547D\u4EE4\u65F6\u53EF\u53C2\u8003\u504F\u597D\uFF0C\u4F46\u6700\u7EC8\u5E94\u7ED3\u5408\u4EFB\u52A1\u9700\u6C42\u548C <system_info> \u7EFC\u5408\u5224\u65AD\n- <execution_log>\uFF1A**\u591A\u6B65\u9AA4\u4EFB\u52A1\u7684\u5173\u952E\u4FE1\u606F**\uFF0C\u8BB0\u5F55\u4E86\u4E4B\u524D\u6B65\u9AA4\u7684\u547D\u4EE4\u3001\u9000\u51FA\u7801\u548C\u8F93\u51FA\u7ED3\u679C\n - \u5982\u679C\u5B58\u5728\u6B64\u6807\u7B7E\uFF0C\u8BF4\u660E\u8FD9\u662F\u4E00\u4E2A\u591A\u6B65\u9AA4\u4EFB\u52A1\n - \u5FC5\u987B\u68C0\u67E5\u6BCF\u4E2A <step> \u4E2D\u7684 <exit_code>\uFF0C0=\u6210\u529F\uFF0C\u975E0=\u5931\u8D25\n - \u6839\u636E <output> \u7684\u5185\u5BB9\u51B3\u5B9A\u4E0B\u4E00\u6B65\u64CD\u4F5C\n- <user_request>\uFF1A\u7528\u6237\u7684\u539F\u59CB\u81EA\u7136\u8BED\u8A00\u9700\u6C42\n\n### \u26A0\uFE0F \u91CD\u8981\u89C4\u5219\n1. \u8FD4\u56DE JSON \u683C\u5F0F\uFF0Ccommand \u5B57\u6BB5\u5FC5\u987B\u662F\u53EF\u76F4\u63A5\u6267\u884C\u7684\u547D\u4EE4\uFF08\u65E0\u89E3\u91CA\u3001\u65E0\u6CE8\u91CA\u3001\u65E0 markdown\uFF09\n2. \u4E0D\u8981\u6DFB\u52A0 shebang\uFF08\u5982 #!/bin/bash\uFF09\n3. command \u53EF\u4EE5\u5305\u542B\u591A\u6761\u547D\u4EE4\uFF08\u7528 && \u8FDE\u63A5\uFF09\uFF0C\u4F46\u6574\u4F53\u7B97\u4E00\u4E2A\u547D\u4EE4\n4. \u6839\u636E <system_info> \u4E2D\u7684\u4FE1\u606F\u9009\u62E9\u5408\u9002\u7684\u547D\u4EE4\uFF08\u5982\u5305\u7BA1\u7406\u5668\uFF09\n5. \u5982\u679C\u7528\u6237\u5F15\u7528\u4E86\u4E4B\u524D\u7684\u64CD\u4F5C\uFF08\u5982\"\u521A\u624D\u7684\"\u3001\"\u4E0A\u4E00\u4E2A\"\uFF09\uFF0C\u8BF7\u53C2\u8003 <command_history>\n6. \u7EDD\u5BF9\u4E0D\u8981\u8F93\u51FA pls \u6216 please \u547D\u4EE4\uFF01\n7. **\u5EFA\u8BAE\u4F18\u5148\u4F7F\u7528\u6807\u51C6\u547D\u4EE4**\uFF08ls/find/grep/cat/ps\uFF09\u4EE5\u786E\u4FDD\u517C\u5BB9\u6027\u548C\u8F93\u51FA\u6355\u83B7\uFF0C\u800C\u4E0D\u662F\u4F7F\u7528 eza/bat/delta \u7B49\u73B0\u4EE3\u5DE5\u5177\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F7F\u7528\u76F8\u5173\u5DE5\u5177\uFF0C\u6216\u8005\u7528\u6237\u7279\u522B\u504F\u597D\u4F7F\u7528\u76F8\u5173\u5DE5\u5177\u3002\n\n### \uD83D\uDCE4 \u8F93\u51FA\u683C\u5F0F - \u975E\u5E38\u91CD\u8981\n\n**\u5355\u6B65\u6A21\u5F0F\uFF08\u4E00\u4E2A\u547D\u4EE4\u5B8C\u6210\uFF09\uFF1A**\n\u5982\u679C\u4EFB\u52A1\u53EA\u9700\u8981\u4E00\u4E2A\u547D\u4EE4\u5C31\u80FD\u5B8C\u6210\uFF0C\u53EA\u8FD4\u56DE\uFF1A\n{\n \"command\": \"ls -la\"\n}\n\n**\u591A\u6B65\u6A21\u5F0F\uFF08\u9700\u8981\u591A\u4E2A\u547D\u4EE4\uFF0C\u540E\u7EED\u4F9D\u8D56\u524D\u9762\u7684\u7ED3\u679C\uFF09\uFF1A**\n\u5982\u679C\u4EFB\u52A1\u9700\u8981\u591A\u4E2A\u547D\u4EE4\uFF0C\u4E14\u540E\u7EED\u547D\u4EE4\u5FC5\u987B\u6839\u636E\u524D\u9762\u7684\u6267\u884C\u7ED3\u679C\u6765\u51B3\u5B9A\uFF0C\u5219\u8FD4\u56DE\uFF1A\n\n\u3010\u591A\u6B65\u9AA4\u5B8C\u6574\u793A\u4F8B\u3011\n\u7528\u6237\uFF1A\"\u67E5\u627E\u5927\u4E8E100MB\u7684\u65E5\u5FD7\u6587\u4EF6\u5E76\u538B\u7F29\"\n\n\u7B2C\u4E00\u6B65\u4F60\u8FD4\u56DE\uFF1A\n{\n \"command\": \"find . -name '*.log' -size +100M\",\n \"continue\": true,\n \"reasoning\": \"\u5148\u67E5\u627E\u7B26\u5408\u6761\u4EF6\u7684\u65E5\u5FD7\u6587\u4EF6\",\n \"nextStepHint\": \"\u6839\u636E\u67E5\u627E\u7ED3\u679C\u538B\u7F29\u6587\u4EF6\"\n}\n\n\u6267\u884C\u540E\u4F60\u4F1A\u6536\u5230\uFF08\u5728 <execution_log> \u4E2D\uFF09\uFF1A\n<execution_log>\n<step index=\"1\">\n<command>find . -name '*.log' -size +100M</command>\n<exit_code>0</exit_code>\n<output>\n./app.log\n./system.log\n</output>\n</step>\n</execution_log>\n\n\u7136\u540E\u4F60\u8FD4\u56DE\u7B2C\u4E8C\u6B65\uFF1A\n{\n \"command\": \"tar -czf logs.tar.gz ./app.log ./system.log\",\n \"continue\": false,\n \"reasoning\": \"\u538B\u7F29\u627E\u5230\u7684\u65E5\u5FD7\u6587\u4EF6\"\n}\n\n### \uD83C\uDFAF \u5173\u952E\u5224\u65AD\u6807\u51C6\n- **\u591A\u6B65** = \u540E\u7EED\u547D\u4EE4\u4F9D\u8D56\u524D\u9762\u7684\u8F93\u51FA\uFF08\u5982\u5148 find \u770B\u6709\u54EA\u4E9B\uFF0C\u518D\u6839\u636E\u7ED3\u679C\u64CD\u4F5C\u5177\u4F53\u6587\u4EF6\uFF09\n- **\u5355\u6B65** = \u4E00\u4E2A\u547D\u4EE4\u5C31\u80FD\u5B8C\u6210\uFF08\u5373\u4F7F\u547D\u4EE4\u91CC\u6709 && \u8FDE\u63A5\u591A\u6761\uFF0C\u4E5F\u7B97\u4E00\u4E2A\u547D\u4EE4\uFF09\n\n### \uD83D\uDCDA \u5E38\u89C1\u573A\u666F\u4E3E\u4F8B\n- \"\u5220\u9664\u7A7A\u6587\u4EF6\u5939\" \u2192 \u5355\u6B65\uFF1A`find . -empty -delete` \uFF08\u4E00\u4E2A\u547D\u4EE4\u5B8C\u6210\uFF09\n- \"\u67E5\u627E\u5927\u6587\u4EF6\u5E76\u538B\u7F29\" \u2192 \u591A\u6B65\uFF1A\u5148 find \u770B\u6709\u54EA\u4E9B\uFF0C\u518D tar \u538B\u7F29\u5177\u4F53\u6587\u4EF6\n- \"\u5B89\u88C5 git\" \u2192 \u5355\u6B65\uFF1A`brew install git` \u6216 `apt-get install git`\n- \"\u5907\u4EFD\u5E76\u5220\u9664\u65E7\u65E5\u5FD7\" \u2192 \u591A\u6B65\uFF1A\u5148 `mkdir backup`\uFF0C\u518D `mv` \u6587\u4EF6\u5230 backup\n- \"\u67E5\u770B\u76EE\u5F55\" \u2192 \u5355\u6B65\uFF1A`ls -la`\n- \"\u67E5\u770B\u78C1\u76D8\u4F7F\u7528\u60C5\u51B5\u5E76\u6392\u5E8F\" \u2192 \u5355\u6B65\uFF1A`df -h | sort -k5 -rh` \uFF08\u4E00\u4E2A\u7BA1\u9053\u547D\u4EE4\uFF09\n- \"\u67E5\u770B\u8FDB\u7A0B\u5E76\u6740\u6B7B\u67D0\u4E2A\u8FDB\u7A0B\" \u2192 \u591A\u6B65\uFF1A\u5148 `ps aux | grep xxx` \u770B PID\uFF0C\u518D `kill` \u5177\u4F53 PID\n\n**\u4E25\u683C\u8981\u6C42**\uFF1A\u5355\u6B65\u6A21\u5F0F\u53EA\u8FD4\u56DE {\"command\": \"xxx\"}\uFF0C\u7EDD\u5BF9\u4E0D\u8981\u8F93\u51FA continue/reasoning/nextStepHint\uFF01\n\n### \uD83D\uDD27 \u9519\u8BEF\u5904\u7406\u7B56\u7565\n\n**\u5F53 <execution_log> \u4E2D\u6700\u540E\u4E00\u6B65\u7684 <exit_code> \u4E0D\u4E3A 0 \u65F6\uFF1A**\n\n1. **\u5206\u6790\u9519\u8BEF\u539F\u56E0**\uFF1A\u4ED4\u7EC6\u9605\u8BFB <output> \u4E2D\u7684\u9519\u8BEF\u4FE1\u606F\n2. **\u8C03\u6574\u547D\u4EE4\u7B56\u7565**\uFF1A\u751F\u6210\u4FEE\u6B63\u540E\u7684\u547D\u4EE4\n3. **\u51B3\u5B9A\u662F\u5426\u7EE7\u7EED**\uFF1A\n - \u8BBE\u7F6E `continue: true` \u91CD\u8BD5\u4FEE\u6B63\u540E\u7684\u547D\u4EE4\n - \u8BBE\u7F6E `continue: false` \u653E\u5F03\u4EFB\u52A1\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 1\uFF1A\u6743\u9650\u9519\u8BEF**\n<execution_log>\n<step index=\"1\">\n<command>mkdir /var/log/myapp</command>\n<exit_code>1</exit_code>\n<output>mkdir: cannot create directory '/var/log/myapp': Permission denied</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u8FD4\u56DE\u4FEE\u6B63\uFF1A\n{\n \"command\": \"sudo mkdir /var/log/myapp\",\n \"continue\": true,\n \"reasoning\": \"\u6743\u9650\u4E0D\u8DB3\uFF0C\u4F7F\u7528 sudo \u91CD\u8BD5\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 2\uFF1A\u6587\u4EF6\u4E0D\u5B58\u5728**\n<execution_log>\n<step index=\"1\">\n<command>mv test.zip backup/</command>\n<exit_code>1</exit_code>\n<output>mv: cannot stat 'test.zip': No such file or directory</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u51B3\u5B9A\u653E\u5F03\uFF1A\n{\n \"command\": \"\",\n \"continue\": false,\n \"reasoning\": \"\u6E90\u6587\u4EF6 test.zip \u4E0D\u5B58\u5728\uFF0C\u65E0\u6CD5\u79FB\u52A8\uFF0C\u4EFB\u52A1\u65E0\u6CD5\u7EE7\u7EED\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 3\uFF1A\u547D\u4EE4\u4E0D\u5B58\u5728\uFF0C\u5C1D\u8BD5\u5B89\u88C5**\n<execution_log>\n<step index=\"1\">\n<command>docker ps</command>\n<exit_code>127</exit_code>\n<output>bash: docker: command not found</output>\n</step>\n</execution_log>\n\n\u4F60\u6839\u636E <system_info> \u4E2D\u7684\u5305\u7BA1\u7406\u5668\u8FD4\u56DE\uFF1A\n{\n \"command\": \"brew install docker\",\n \"continue\": true,\n \"reasoning\": \"docker \u672A\u5B89\u88C5\uFF0C\u6839\u636E\u7CFB\u7EDF\u5305\u7BA1\u7406\u5668\u5B89\u88C5\"\n}\n\n**\u9519\u8BEF\u5904\u7406\u793A\u4F8B 4\uFF1A\u7F51\u7EDC\u9519\u8BEF**\n<execution_log>\n<step index=\"1\">\n<command>ping -c 3 example.com</command>\n<exit_code>2</exit_code>\n<output>ping: example.com: Name or service not known</output>\n</step>\n</execution_log>\n\n\u4F60\u5206\u6790\u540E\u8FD4\u56DE\uFF1A\n{\n \"command\": \"\",\n \"continue\": false,\n \"reasoning\": \"\u7F51\u7EDC\u4E0D\u53EF\u8FBE\u6216 DNS \u89E3\u6790\u5931\u8D25\uFF0C\u65E0\u6CD5\u7EE7\u7EED\"\n}\n\n### \uD83D\uDED1 \u4F55\u65F6\u5E94\u8BE5\u653E\u5F03\uFF08continue: false\uFF09\n- \u7528\u6237\u8F93\u5165\u7684\u8DEF\u5F84\u4E0D\u5B58\u5728\u4E14\u65E0\u6CD5\u63A8\u6D4B\n- \u9700\u8981\u7684\u5DE5\u5177\u672A\u5B89\u88C5\u4E14\u65E0\u6CD5\u81EA\u52A8\u5B89\u88C5\uFF08\u5982\u975E root \u7528\u6237\u65E0\u6CD5 apt install\uFF09\n- \u6743\u9650\u95EE\u9898\u4E14\u65E0\u6CD5\u7528 sudo \u89E3\u51B3\uFF08\u5982 SELinux \u9650\u5236\uFF09\n- \u7F51\u7EDC\u4E0D\u53EF\u8FBE\u6216 DNS \u89E3\u6790\u5931\u8D25\n- \u91CD\u8BD5 2 \u6B21\u540E\u4ECD\u7136\u5931\u8D25\n- \u4EFB\u52A1\u672C\u8EAB\u4E0D\u5408\u7406\uFF08\u5982\"\u5220\u9664\u6839\u76EE\u5F55\"\uFF09\n\n**\u653E\u5F03\u65F6\u7684\u8981\u6C42**\uFF1A\n- `command` \u5B57\u6BB5\u53EF\u4EE5\u7559\u7A7A\uFF08\"\"\uFF09\n- `continue` \u5FC5\u987B\u4E3A false\n- `reasoning` \u5FC5\u987B\u8BE6\u7EC6\u8BF4\u660E\u4E3A\u4EC0\u4E48\u653E\u5F03\uFF0C\u4EE5\u53CA\u5C1D\u8BD5\u4E86\u4EC0\u4E48\n\n### \uD83D\uDCCC \u5173\u4E8E pls/please \u5DE5\u5177\n\u7528\u6237\u6B63\u5728\u4F7F\u7528 pls\uFF08pretty-please\uFF09\u5DE5\u5177\uFF0C\u8FD9\u662F\u4E00\u4E2A\u5C06\u81EA\u7136\u8BED\u8A00\u8F6C\u6362\u4E3A shell \u547D\u4EE4\u7684 AI \u52A9\u624B\u3002\n\u5F53\u7528\u6237\u8F93\u5165 \"pls <\u63CF\u8FF0>\" \u65F6\uFF0CAI\uFF08\u4E5F\u5C31\u662F\u4F60\uFF09\u4F1A\u751F\u6210\u5BF9\u5E94\u7684 shell \u547D\u4EE4\u4F9B\u7528\u6237\u786E\u8BA4\u6267\u884C\u3002\n<command_history> \u4E2D\u6807\u8BB0\u4E3A [pls] \u7684\u6761\u76EE\u8868\u793A\u7528\u6237\u901A\u8FC7 pls \u5DE5\u5177\u6267\u884C\u7684\u547D\u4EE4\u3002\n";
12
12
  /**
13
13
  * ============================================================
14
14
  * 构建动态 User Prompt(XML 格式)
15
15
  * ============================================================
16
16
  * 将系统信息、历史记录、执行日志等动态数据组装成 XML 结构
17
17
  */
18
- export declare function buildUserContextPrompt(userRequest: string, sysInfoStr: string, historyStr: string, executedSteps: Array<{
18
+ export declare function buildUserContextPrompt(userRequest: string, sysInfoStr: string, historyStr: string, userPreferencesStr: string, executedSteps: Array<{
19
19
  command: string;
20
20
  exitCode: number;
21
21
  output: string;
@@ -26,7 +26,7 @@ export declare function buildUserContextPrompt(userRequest: string, sysInfoStr:
26
26
  * ============================================================
27
27
  * 包含所有核心规则和能力描述,不包含动态数据
28
28
  */
29
- export declare const CHAT_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4E2A\u547D\u4EE4\u884C\u4E13\u5BB6\u52A9\u624B\uFF0C\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u548C\u4F7F\u7528\u547D\u4EE4\u884C\u5DE5\u5177\u3002\n\n### \uD83D\uDCCB \u8F93\u5165\u6570\u636E\u683C\u5F0F\u8BF4\u660E\n\u4F60\u4F1A\u6536\u5230\u4EE5\u4E0B XML \u6807\u7B7E\u5305\u88F9\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF1A\n- <system_info>\uFF1A\u7528\u6237\u7684\u64CD\u4F5C\u7CFB\u7EDF\u3001Shell \u7C7B\u578B\u3001\u5F53\u524D\u76EE\u5F55\u7B49\u73AF\u5883\u4FE1\u606F\n- <command_history>\uFF1A\u7528\u6237\u6700\u8FD1\u901A\u8FC7 pls \u6267\u884C\u7684\u547D\u4EE4\uFF08\u7528\u4E8E\u7406\u89E3\u4E0A\u4E0B\u6587\u5F15\u7528\uFF09\n- <shell_history>\uFF1A\u7528\u6237\u6700\u8FD1\u5728\u7EC8\u7AEF\u6267\u884C\u7684\u6240\u6709\u547D\u4EE4\uFF08\u5982\u679C\u542F\u7528\u4E86 Shell Hook\uFF09\n- <user_question>\uFF1A\u7528\u6237\u7684\u5177\u4F53\u95EE\u9898\n\n### \uD83C\uDFAF \u4F60\u7684\u80FD\u529B\n- \u89E3\u91CA\u547D\u4EE4\u7684\u542B\u4E49\u3001\u53C2\u6570\u3001\u7528\u6CD5\n- \u5206\u6790\u547D\u4EE4\u7684\u6267\u884C\u6548\u679C\u548C\u6F5C\u5728\u98CE\u9669\n- \u56DE\u7B54\u547D\u4EE4\u884C\u3001Shell\u3001\u7CFB\u7EDF\u7BA1\u7406\u76F8\u5173\u95EE\u9898\n- \u6839\u636E\u7528\u6237\u9700\u6C42\u63A8\u8350\u5408\u9002\u7684\u547D\u4EE4\u5E76\u89E3\u91CA\n\n### \uD83D\uDCDD \u56DE\u7B54\u8981\u6C42\n- \u7B80\u6D01\u6E05\u6670\uFF0C\u907F\u514D\u5197\u4F59\u89E3\u91CA\n- \u5371\u9669\u64CD\u4F5C\u8981\u660E\u786E\u8B66\u544A\uFF08\u5982 rm -rf\u3001chmod 777 \u7B49\uFF09\n- \u9002\u5F53\u7ED9\u51FA\u793A\u4F8B\u547D\u4EE4\uFF08\u4F7F\u7528\u4EE3\u7801\u5757\u683C\u5F0F\uFF09\n- \u7ED3\u5408 <system_info> \u4E2D\u7684\u7CFB\u7EDF\u73AF\u5883\u7ED9\u51FA\u9488\u5BF9\u6027\u5EFA\u8BAE\n- \u5982\u679C\u7528\u6237\u5F15\u7528\u4E86\"\u521A\u624D\u7684\u547D\u4EE4\"\u3001\"\u4E0A\u4E00\u4E2A\u64CD\u4F5C\"\uFF0C\u8BF7\u53C2\u8003\u5386\u53F2\u8BB0\u5F55\n\n### \uD83D\uDCCC \u5173\u4E8E pls/please \u5DE5\u5177\n\u7528\u6237\u6B63\u5728\u4F7F\u7528 pls\uFF08pretty-please\uFF09\u5DE5\u5177\uFF0C\u8FD9\u662F\u4E00\u4E2A\u5C06\u81EA\u7136\u8BED\u8A00\u8F6C\u6362\u4E3A shell \u547D\u4EE4\u7684 AI \u52A9\u624B\u3002\n<command_history> \u4E2D\u6807\u8BB0\u4E3A [pls] \u7684\u6761\u76EE\u8868\u793A\u7528\u6237\u901A\u8FC7 pls \u5DE5\u5177\u6267\u884C\u7684\u547D\u4EE4\u3002\n\u4F60\u53EF\u4EE5\u89E3\u91CA\u8FD9\u4E9B\u547D\u4EE4\uFF0C\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u5B83\u4EEC\u7684\u4F5C\u7528\u3002";
29
+ export declare const CHAT_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4E2A\u547D\u4EE4\u884C\u4E13\u5BB6\u52A9\u624B\uFF0C\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u548C\u4F7F\u7528\u547D\u4EE4\u884C\u5DE5\u5177\u3002\n\n### \uD83D\uDCCB \u8F93\u5165\u6570\u636E\u683C\u5F0F\u8BF4\u660E\n\u4F60\u4F1A\u6536\u5230\u4EE5\u4E0B XML \u6807\u7B7E\u5305\u88F9\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\uFF1A\n- <system_info>\uFF1A\u7528\u6237\u7684\u64CD\u4F5C\u7CFB\u7EDF\u3001Shell \u7C7B\u578B\u3001\u5F53\u524D\u76EE\u5F55\u7B49\u73AF\u5883\u4FE1\u606F\n- <command_history>\uFF1A\u7528\u6237\u6700\u8FD1\u901A\u8FC7 pls \u6267\u884C\u7684\u547D\u4EE4\uFF08\u7528\u4E8E\u7406\u89E3\u4E0A\u4E0B\u6587\u5F15\u7528\uFF09\n- <shell_history>\uFF1A\u7528\u6237\u6700\u8FD1\u5728\u7EC8\u7AEF\u6267\u884C\u7684\u6240\u6709\u547D\u4EE4\uFF08\u5982\u679C\u542F\u7528\u4E86 Shell Hook\uFF09\n- <user_preferences>\uFF1A\u7528\u6237\u7684\u547D\u4EE4\u4F7F\u7528\u504F\u597D\uFF08\u547D\u4EE4\u540D(\u4F7F\u7528\u6B21\u6570)\uFF09\uFF0C\u5E2E\u52A9\u4F60\u4E86\u89E3\u7528\u6237\u4E60\u60EF\n- <user_question>\uFF1A\u7528\u6237\u7684\u5177\u4F53\u95EE\u9898\n\n### \uD83C\uDFAF \u4F60\u7684\u80FD\u529B\n- \u89E3\u91CA\u547D\u4EE4\u7684\u542B\u4E49\u3001\u53C2\u6570\u3001\u7528\u6CD5\n- \u5206\u6790\u547D\u4EE4\u7684\u6267\u884C\u6548\u679C\u548C\u6F5C\u5728\u98CE\u9669\n- \u56DE\u7B54\u547D\u4EE4\u884C\u3001Shell\u3001\u7CFB\u7EDF\u7BA1\u7406\u76F8\u5173\u95EE\u9898\n- \u6839\u636E\u7528\u6237\u9700\u6C42\u63A8\u8350\u5408\u9002\u7684\u547D\u4EE4\u5E76\u89E3\u91CA\n\n### \uD83D\uDCDD \u56DE\u7B54\u8981\u6C42\n- \u7B80\u6D01\u6E05\u6670\uFF0C\u907F\u514D\u5197\u4F59\u89E3\u91CA\n- \u5371\u9669\u64CD\u4F5C\u8981\u660E\u786E\u8B66\u544A\uFF08\u5982 rm -rf\u3001chmod 777 \u7B49\uFF09\n- \u9002\u5F53\u7ED9\u51FA\u793A\u4F8B\u547D\u4EE4\uFF08\u4F7F\u7528\u4EE3\u7801\u5757\u683C\u5F0F\uFF09\n- \u7ED3\u5408 <system_info> \u4E2D\u7684\u7CFB\u7EDF\u73AF\u5883\u7ED9\u51FA\u9488\u5BF9\u6027\u5EFA\u8BAE\n- \u5982\u679C\u7528\u6237\u5F15\u7528\u4E86\"\u521A\u624D\u7684\u547D\u4EE4\"\u3001\"\u4E0A\u4E00\u4E2A\u64CD\u4F5C\"\uFF0C\u8BF7\u53C2\u8003\u5386\u53F2\u8BB0\u5F55\n\n### \uD83D\uDCCC \u5173\u4E8E pls/please \u5DE5\u5177\n\u7528\u6237\u6B63\u5728\u4F7F\u7528 pls\uFF08pretty-please\uFF09\u5DE5\u5177\uFF0C\u8FD9\u662F\u4E00\u4E2A\u5C06\u81EA\u7136\u8BED\u8A00\u8F6C\u6362\u4E3A shell \u547D\u4EE4\u7684 AI \u52A9\u624B\u3002\n<command_history> \u4E2D\u6807\u8BB0\u4E3A [pls] \u7684\u6761\u76EE\u8868\u793A\u7528\u6237\u901A\u8FC7 pls \u5DE5\u5177\u6267\u884C\u7684\u547D\u4EE4\u3002\n\u4F60\u53EF\u4EE5\u89E3\u91CA\u8FD9\u4E9B\u547D\u4EE4\uFF0C\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u5B83\u4EEC\u7684\u4F5C\u7528\u3002";
30
30
  /**
31
31
  * ============================================================
32
32
  * 构建 Chat 动态 User Context(XML 格式)
@@ -34,4 +34,4 @@ export declare const CHAT_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4E2A\u547D\u4EE4\
34
34
  * 将系统信息、历史记录等动态数据组装成 XML 结构
35
35
  * 这个上下文会作为最新一条 user 消息发送给 AI
36
36
  */
37
- export declare function buildChatUserContext(userQuestion: string, sysInfoStr: string, plsHistory: string, shellHistory: string, shellHookEnabled: boolean): string;
37
+ export declare function buildChatUserContext(userQuestion: string, sysInfoStr: string, plsHistory: string, shellHistory: string, shellHookEnabled: boolean, userPreferencesStr?: string): string;
@@ -13,8 +13,11 @@ export const SHELL_COMMAND_SYSTEM_PROMPT = `你是一个专业的 shell 脚本
13
13
 
14
14
  ### 📋 输入数据格式说明
15
15
  你会收到以下 XML 标签包裹的上下文信息:
16
- - <system_info>:用户的操作系统、Shell 类型、当前目录、包管理器等环境信息
16
+ - <system_info>:用户的操作系统、Shell 类型、当前目录、包管理器、可用工具等环境信息
17
17
  - <command_history>:用户最近执行的命令历史(用于理解上下文引用,如"刚才的文件"、"上一个命令")
18
+ - <user_preferences>:**用户的命令使用偏好**(格式:命令名(使用次数)),帮助你了解用户习惯
19
+ - 例如:git(234), eza(156) 表示用户经常使用 git 和 eza 命令
20
+ - 生成命令时可参考偏好,但最终应结合任务需求和 <system_info> 综合判断
18
21
  - <execution_log>:**多步骤任务的关键信息**,记录了之前步骤的命令、退出码和输出结果
19
22
  - 如果存在此标签,说明这是一个多步骤任务
20
23
  - 必须检查每个 <step> 中的 <exit_code>,0=成功,非0=失败
@@ -28,6 +31,7 @@ export const SHELL_COMMAND_SYSTEM_PROMPT = `你是一个专业的 shell 脚本
28
31
  4. 根据 <system_info> 中的信息选择合适的命令(如包管理器)
29
32
  5. 如果用户引用了之前的操作(如"刚才的"、"上一个"),请参考 <command_history>
30
33
  6. 绝对不要输出 pls 或 please 命令!
34
+ 7. **建议优先使用标准命令**(ls/find/grep/cat/ps)以确保兼容性和输出捕获,而不是使用 eza/bat/delta 等现代工具,除非用户明确要求使用相关工具,或者用户特别偏好使用相关工具。
31
35
 
32
36
  ### 📤 输出格式 - 非常重要
33
37
 
@@ -183,7 +187,7 @@ export const SHELL_COMMAND_SYSTEM_PROMPT = `你是一个专业的 shell 脚本
183
187
  * ============================================================
184
188
  * 将系统信息、历史记录、执行日志等动态数据组装成 XML 结构
185
189
  */
186
- export function buildUserContextPrompt(userRequest, sysInfoStr, historyStr, executedSteps) {
190
+ export function buildUserContextPrompt(userRequest, sysInfoStr, historyStr, userPreferencesStr, executedSteps) {
187
191
  const parts = [];
188
192
  // 1. 系统信息
189
193
  parts.push(`<system_info>`);
@@ -195,7 +199,13 @@ export function buildUserContextPrompt(userRequest, sysInfoStr, historyStr, exec
195
199
  parts.push(historyStr);
196
200
  parts.push(`</command_history>`);
197
201
  }
198
- // 3. 执行日志(多步骤的核心,紧凑 XML 结构)
202
+ // 3. 用户偏好(如果有)
203
+ if (userPreferencesStr && userPreferencesStr.trim()) {
204
+ parts.push(`<user_preferences>`);
205
+ parts.push(userPreferencesStr);
206
+ parts.push(`</user_preferences>`);
207
+ }
208
+ // 4. 执行日志(多步骤的核心,紧凑 XML 结构)
199
209
  if (executedSteps && executedSteps.length > 0) {
200
210
  parts.push(`<execution_log>`);
201
211
  executedSteps.forEach((step, i) => {
@@ -218,7 +228,7 @@ export function buildUserContextPrompt(userRequest, sysInfoStr, historyStr, exec
218
228
  parts.push(``);
219
229
  parts.push(`⚠️ 注意:请检查 <execution_log> 中最后一步的 <exit_code>。如果非 0,请分析 <output> 并修复命令。`);
220
230
  }
221
- // 4. 用户需求
231
+ // 5. 用户需求
222
232
  parts.push(`<user_request>`);
223
233
  parts.push(userRequest);
224
234
  parts.push(`</user_request>`);
@@ -237,6 +247,7 @@ export const CHAT_SYSTEM_PROMPT = `你是一个命令行专家助手,帮助用
237
247
  - <system_info>:用户的操作系统、Shell 类型、当前目录等环境信息
238
248
  - <command_history>:用户最近通过 pls 执行的命令(用于理解上下文引用)
239
249
  - <shell_history>:用户最近在终端执行的所有命令(如果启用了 Shell Hook)
250
+ - <user_preferences>:用户的命令使用偏好(命令名(使用次数)),帮助你了解用户习惯
240
251
  - <user_question>:用户的具体问题
241
252
 
242
253
  ### 🎯 你的能力
@@ -263,7 +274,7 @@ export const CHAT_SYSTEM_PROMPT = `你是一个命令行专家助手,帮助用
263
274
  * 将系统信息、历史记录等动态数据组装成 XML 结构
264
275
  * 这个上下文会作为最新一条 user 消息发送给 AI
265
276
  */
266
- export function buildChatUserContext(userQuestion, sysInfoStr, plsHistory, shellHistory, shellHookEnabled) {
277
+ export function buildChatUserContext(userQuestion, sysInfoStr, plsHistory, shellHistory, shellHookEnabled, userPreferencesStr) {
267
278
  const parts = [];
268
279
  // 1. 系统信息
269
280
  parts.push('<system_info>');
@@ -280,7 +291,13 @@ export function buildChatUserContext(userQuestion, sysInfoStr, plsHistory, shell
280
291
  parts.push(plsHistory);
281
292
  parts.push('</command_history>');
282
293
  }
283
- // 3. 用户问题
294
+ // 3. 用户偏好(如果有)
295
+ if (userPreferencesStr && userPreferencesStr.trim()) {
296
+ parts.push('<user_preferences>');
297
+ parts.push(userPreferencesStr);
298
+ parts.push('</user_preferences>');
299
+ }
300
+ // 4. 用户问题
284
301
  parts.push('<user_question>');
285
302
  parts.push(userQuestion);
286
303
  parts.push('</user_question>');
@@ -19,6 +19,7 @@ export interface HookStatus {
19
19
  }
20
20
  /**
21
21
  * 检测当前 shell 类型
22
+ * 使用 platform 模块进行跨平台检测
22
23
  */
23
24
  export declare function detectShell(): ShellType;
24
25
  /**
@@ -50,6 +51,18 @@ export declare function getHookStatus(): HookStatus;
50
51
  * 显示 shell 历史
51
52
  */
52
53
  export declare function displayShellHistory(): void;
54
+ /**
55
+ * 重新安装 Shell Hook(通用函数)
56
+ * 用于版本升级、配置变更等场景
57
+ *
58
+ * @param options.silent 是否静默模式(不输出日志)
59
+ * @param options.reason 重装原因(用于日志显示)
60
+ * @returns 是否成功重装
61
+ */
62
+ export declare function reinstallShellHook(options?: {
63
+ silent?: boolean;
64
+ reason?: string;
65
+ }): Promise<boolean>;
53
66
  /**
54
67
  * 当 shellHistoryLimit 变化时,自动重装 Hook
55
68
  * 返回是否成功重装
@@ -59,6 +72,25 @@ export declare function reinstallHookForLimitChange(oldLimit: number, newLimit:
59
72
  * 清空 shell 历史
60
73
  */
61
74
  export declare function clearShellHistory(): void;
75
+ /**
76
+ * 获取 shell 历史(统一接口)
77
+ * 优先使用 shell hook,降级到系统历史文件
78
+ *
79
+ * 这是推荐的历史获取方式,会自动选择最佳来源:
80
+ * 1. 优先:shell hook(有退出码,最准确)
81
+ * 2. 降级:系统历史文件(无退出码,兼容未安装 hook 的情况)
82
+ */
83
+ export declare function getShellHistoryWithFallback(): ShellHistoryItem[];
84
+ /**
85
+ * 获取最近一条非 pls 的命令(统一接口)
86
+ * 自动选择最佳历史来源
87
+ */
88
+ export declare function getLastNonPlsCommand(): ShellHistoryItem | null;
89
+ /**
90
+ * 格式化 shell 历史供 AI 使用(统一接口)
91
+ * 自动选择最佳历史来源
92
+ */
93
+ export declare function formatShellHistoryForAIWithFallback(): string;
62
94
  /**
63
95
  * 检测远程服务器的 shell 类型
64
96
  */