polished-localization-for-claude-code 0.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/LICENSE +21 -0
- package/README.md +529 -0
- package/bin/install.js +813 -0
- package/bin/restore.js +39 -0
- package/localize/keyword.js +624 -0
- package/localize/localize.js +176 -0
- package/package.json +57 -0
- package/tool-tips-post.sh +382 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const MAGENTA = '\x1b[38;5;206m';
|
|
8
|
+
const GREEN = '\x1b[0;32m';
|
|
9
|
+
const YELLOW = '\x1b[0;33m';
|
|
10
|
+
const RED = '\x1b[0;31m';
|
|
11
|
+
const NC = '\x1b[0m';
|
|
12
|
+
|
|
13
|
+
function mustHaveCli() {
|
|
14
|
+
const pkgName = '@anthropic-ai/claude-code';
|
|
15
|
+
let npmRoot = '';
|
|
16
|
+
try {
|
|
17
|
+
const installed = execSync(`npm list -g ${pkgName} --depth=0`, { encoding: 'utf8' });
|
|
18
|
+
if (!installed.includes(pkgName)) {
|
|
19
|
+
throw new Error('not-installed');
|
|
20
|
+
}
|
|
21
|
+
npmRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(`${RED}请先安装 Claude Code: npm install -g ${pkgName}${NC}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const cliPath = path.join(npmRoot, pkgName, 'cli.js');
|
|
27
|
+
const backupPath = path.join(npmRoot, pkgName, 'cli.bak.js');
|
|
28
|
+
if (!fs.existsSync(cliPath)) {
|
|
29
|
+
console.log(`${RED}找不到 Claude Code CLI 文件${NC}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
if (!fs.existsSync(backupPath)) {
|
|
33
|
+
fs.copyFileSync(cliPath, backupPath);
|
|
34
|
+
console.log(`${GREEN}已创建备份: cli.bak.js${NC}`);
|
|
35
|
+
}
|
|
36
|
+
return { cliPath, backupPath };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function esc(str) {
|
|
40
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function normalizeKeyVariants(key) {
|
|
44
|
+
const variants = new Set([key]);
|
|
45
|
+
if (key.includes('...')) variants.add(key.replace(/\.\.\./g, '…'));
|
|
46
|
+
if (key.includes('…')) variants.add(key.replace(/…/g, '...'));
|
|
47
|
+
if (key.startsWith('Tip:')) {
|
|
48
|
+
variants.add(key.replace(/^Tip:\s*/, 'Tip:'));
|
|
49
|
+
variants.add(key.replace(/^Tip:\s*/, 'Tip: '));
|
|
50
|
+
variants.add(key.replace(/^Tip:/, 'Tips:'));
|
|
51
|
+
variants.add(key.replace(/^Tip:/, 'Tips: '));
|
|
52
|
+
}
|
|
53
|
+
if (key.startsWith('Tips:')) {
|
|
54
|
+
variants.add(key.replace(/^Tips:\s*/, 'Tips:'));
|
|
55
|
+
variants.add(key.replace(/^Tips:\s*/, 'Tips: '));
|
|
56
|
+
variants.add(key.replace(/^Tips:/, 'Tip:'));
|
|
57
|
+
variants.add(key.replace(/^Tips:/, 'Tip: '));
|
|
58
|
+
}
|
|
59
|
+
return Array.from(variants);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildEntries(keywordMap) {
|
|
63
|
+
const merged = new Map();
|
|
64
|
+
for (const [key, value] of Object.entries(keywordMap)) {
|
|
65
|
+
for (const variant of normalizeKeyVariants(key)) {
|
|
66
|
+
if (!merged.has(variant)) merged.set(variant, value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return Array.from(merged.entries()).sort((a, b) => b[0].length - a[0].length);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function replaceQuoted(content, key, value) {
|
|
73
|
+
const rawKey = esc(key).replace(/\\n/g, '\\\\n');
|
|
74
|
+
const escapedValue = value.replace(/\n/g, '\\n');
|
|
75
|
+
let count = 0;
|
|
76
|
+
const doubleRegex = new RegExp(`"${rawKey}"`, 'g');
|
|
77
|
+
const singleRegex = new RegExp(`'${rawKey}'`, 'g');
|
|
78
|
+
const dm = content.match(doubleRegex);
|
|
79
|
+
if (dm) {
|
|
80
|
+
content = content.replace(doubleRegex, `"${escapedValue}"`);
|
|
81
|
+
count += dm.length;
|
|
82
|
+
}
|
|
83
|
+
const sm = content.match(singleRegex);
|
|
84
|
+
if (sm) {
|
|
85
|
+
content = content.replace(singleRegex, `'${escapedValue}'`);
|
|
86
|
+
count += sm.length;
|
|
87
|
+
}
|
|
88
|
+
return { content, count };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function replaceLiteral(content, key, value) {
|
|
92
|
+
if (!content.includes(key)) return { content, count: 0 };
|
|
93
|
+
const parts = content.split(key);
|
|
94
|
+
return { content: parts.join(value), count: parts.length - 1 };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function applyLocalization(content, entries) {
|
|
98
|
+
let replacedKeyCount = 0;
|
|
99
|
+
let replacementCount = 0;
|
|
100
|
+
const missed = [];
|
|
101
|
+
for (const [key, value] of entries) {
|
|
102
|
+
let current = content;
|
|
103
|
+
let count = 0;
|
|
104
|
+
const quoted = replaceQuoted(current, key, value);
|
|
105
|
+
current = quoted.content;
|
|
106
|
+
count += quoted.count;
|
|
107
|
+
if (count === 0 && (key.startsWith('`') || key.startsWith('\\') || key.startsWith('function '))) {
|
|
108
|
+
const literal = replaceLiteral(current, key, value);
|
|
109
|
+
current = literal.content;
|
|
110
|
+
count += literal.count;
|
|
111
|
+
}
|
|
112
|
+
if (count > 0) {
|
|
113
|
+
content = current;
|
|
114
|
+
replacedKeyCount++;
|
|
115
|
+
replacementCount += count;
|
|
116
|
+
console.log(` ${GREEN}+${NC} ${key.slice(0, 54)}${key.length > 54 ? '...' : ''} ${YELLOW}->${NC} ${value.slice(0, 54)}${value.length > 54 ? '...' : ''}`);
|
|
117
|
+
} else {
|
|
118
|
+
missed.push(key);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { content, replacedKeyCount, replacementCount, missed };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function applyFixedPairs(content) {
|
|
125
|
+
const pairs = [
|
|
126
|
+
[
|
|
127
|
+
'name:"claude-api",description:"Build apps with the Claude API or Anthropic SDK.\\nTRIGGER when: code imports `anthropic`/`@anthropic-ai/sdk`/`claude_agent_sdk`, or user asks to use Claude API, Anthropic SDKs, or Agent SDK.\\nDO NOT TRIGGER when: code imports `openai`/other AI SDK, general programming, or ML/data-science tasks."',
|
|
128
|
+
'name:"claude-api",description:"使用 Claude API 或 Anthropic SDK 构建应用。\\n触发条件:代码导入 `anthropic`/`@anthropic-ai/sdk`/`claude_agent_sdk`,或用户要求使用 Claude API、Anthropic SDK 或 Agent SDK。\\n不触发条件:代码导入 `openai`/其他 AI SDK、通用编程或机器学习/数据科学任务。"'
|
|
129
|
+
]
|
|
130
|
+
];
|
|
131
|
+
let fixed = 0;
|
|
132
|
+
for (const [from, to] of pairs) {
|
|
133
|
+
if (content.includes(from)) {
|
|
134
|
+
content = content.split(from).join(to);
|
|
135
|
+
fixed++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { content, fixed };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function strWidth(str) {
|
|
142
|
+
let width = 0;
|
|
143
|
+
for (const char of str) {
|
|
144
|
+
width += (char.charCodeAt(0) > 255) ? 2 : 1;
|
|
145
|
+
}
|
|
146
|
+
return width;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function centerPad(str, width = 70) {
|
|
150
|
+
const diff = width - strWidth(str);
|
|
151
|
+
const pad = Math.max(0, Math.floor(diff / 2));
|
|
152
|
+
return ' '.repeat(pad) + str;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function run() {
|
|
156
|
+
const { cliPath, backupPath } = mustHaveCli();
|
|
157
|
+
fs.copyFileSync(backupPath, cliPath);
|
|
158
|
+
const keywordMap = require(path.join(__dirname, 'keyword.js'));
|
|
159
|
+
const entries = buildEntries(keywordMap);
|
|
160
|
+
let content = fs.readFileSync(cliPath, 'utf8');
|
|
161
|
+
const localized = applyLocalization(content, entries);
|
|
162
|
+
content = localized.content;
|
|
163
|
+
const fixed = applyFixedPairs(content);
|
|
164
|
+
content = fixed.content;
|
|
165
|
+
fs.writeFileSync(cliPath, content, 'utf8');
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log(`${MAGENTA}汉化完成!${NC}`);
|
|
168
|
+
console.log(`${GREEN}${localized.replacedKeyCount}/${entries.length} 条匹配, ${localized.replacementCount} 处替换${NC}`);
|
|
169
|
+
if (fixed.fixed > 0) {
|
|
170
|
+
console.log(`${GREEN}额外结构修正: ${fixed.fixed} 项${NC}`);
|
|
171
|
+
}
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(`${YELLOW}请重启 Claude Code 使汉化生效${NC}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
run();
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "polished-localization-for-claude-code",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Polished Localization for Claude Code 是一个面向 Claude Code 的高质量中文本地化与可用性增强工具包,不仅提供完整的界面翻译,还通过上下文感知的工具提示把每一步操作解释清楚,帮助用户快速理解 Claude 在做什么、为什么这么做。项目覆盖 Windows/macOS/Linux 跨平台安装与恢复流程,内置可维护的词条映射与替换机制,支持持续扩展和版本迭代,适合个人开发者、中文团队以及希望构建稳定中文开发体验的场景。",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"postinstall": "node -e \"console.log('\\n✨ 感谢安装 polished-localization-for-claude-code! ✨\\n\\n请运行以下命令完成安装:\\n\\n Windows: polished-localization-install\\n macOS/Linux: polished-localization-install\\n\\n')\"",
|
|
8
|
+
"uninstall": "node -e \"console.log('\\n✨ 卸载 polished-localization-for-claude-code... ✨\\n请手动删除 ~/.claude/hooks/tool-tips-post.sh 和 ~/.claude/localize/ 目录\\n')\""
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"polished-localization-install": "bin/install.js",
|
|
12
|
+
"polished-localization-restore": "bin/restore.js",
|
|
13
|
+
"cute-claude-hooks-install": "bin/install.js",
|
|
14
|
+
"cute-claude-hooks-restore": "bin/restore.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin/",
|
|
18
|
+
"localize/",
|
|
19
|
+
"tool-tips-post.sh",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"keywords": [
|
|
24
|
+
"claude",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"claude-hooks",
|
|
27
|
+
"chinese",
|
|
28
|
+
"localization",
|
|
29
|
+
"i18n",
|
|
30
|
+
"hooks",
|
|
31
|
+
"中文",
|
|
32
|
+
"汉化",
|
|
33
|
+
"中文提示",
|
|
34
|
+
"polished-localization"
|
|
35
|
+
],
|
|
36
|
+
"author": "ZHAIXX",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/Dublin1231/polished-localization-for-claude-code.git"
|
|
41
|
+
},
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/Dublin1231/polished-localization-for-claude-code/issues"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/Dublin1231/polished-localization-for-claude-code#readme",
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=14.0.0"
|
|
48
|
+
},
|
|
49
|
+
"os": [
|
|
50
|
+
"win32",
|
|
51
|
+
"darwin",
|
|
52
|
+
"linux"
|
|
53
|
+
],
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@anthropic-ai/sdk": "^0.82.0"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
input=$(cat)
|
|
2
|
+
|
|
3
|
+
# 提取 JSON 字段(处理转义引号 \")
|
|
4
|
+
extract_field() {
|
|
5
|
+
local key="$1"
|
|
6
|
+
# 将 \" 替换为占位符,避免 sed 的 [^"] 在引号处中断
|
|
7
|
+
local clean
|
|
8
|
+
clean=$(printf '%s' "$input" | sed 's/\\"/__DQ__/g')
|
|
9
|
+
local val
|
|
10
|
+
val=$(printf '%s' "$clean" | sed -n "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" | head -1)
|
|
11
|
+
# 恢复转义: __DQ__ → ", \n → 换行
|
|
12
|
+
val=$(printf '%s' "$val" | sed 's/__DQ__/"/g; s/\\n/\n/g')
|
|
13
|
+
printf '%s' "$val"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
tool_name=$(extract_field "tool_name")
|
|
17
|
+
file_path=$(extract_field "file_path")
|
|
18
|
+
pattern=$(extract_field "pattern")
|
|
19
|
+
bash_cmd=$(extract_field "command")
|
|
20
|
+
|
|
21
|
+
# 路径简化:只显示文件名
|
|
22
|
+
short_path() {
|
|
23
|
+
echo "$1" | sed 's/.*[\\/]//' | head -c 50
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# 翻译 Bash 命令为中文解释
|
|
27
|
+
explain_cmd() {
|
|
28
|
+
local cmd="$1"
|
|
29
|
+
# 取第一个关键词
|
|
30
|
+
local first=$(echo "$cmd" | awk '{print $1}')
|
|
31
|
+
local rest=$(echo "$cmd" | awk '{$1=""; print}' | sed 's/^ *//')
|
|
32
|
+
|
|
33
|
+
case "$first" in
|
|
34
|
+
# === Git 版本控制 ===
|
|
35
|
+
git)
|
|
36
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
37
|
+
case "$sub" in
|
|
38
|
+
status) echo "查看代码仓库状态(有哪些文件被修改了)" ;;
|
|
39
|
+
log) echo "查看代码提交历史记录" ;;
|
|
40
|
+
diff) echo "查看代码的具体修改内容" ;;
|
|
41
|
+
add) echo "把修改的文件加入待提交列表" ;;
|
|
42
|
+
commit) echo "保存提交代码变更(写一条提交说明)" ;;
|
|
43
|
+
push) echo "把本地代码上传到远程仓库" ;;
|
|
44
|
+
pull) echo "从远程仓库下载最新代码" ;;
|
|
45
|
+
fetch) echo "获取远程仓库的最新信息" ;;
|
|
46
|
+
checkout|switch) echo "切换到另一个代码分支" ;;
|
|
47
|
+
branch) echo "查看或管理代码分支" ;;
|
|
48
|
+
merge) echo "把不同分支的代码合并到一起" ;;
|
|
49
|
+
rebase) echo "整理提交历史(变基)" ;;
|
|
50
|
+
stash) echo "临时保存未提交的修改" ;;
|
|
51
|
+
clone) echo "从远程复制一份代码仓库" ;;
|
|
52
|
+
init) echo "初始化一个新的代码仓库" ;;
|
|
53
|
+
reset) echo "撤销提交或恢复文件" ;;
|
|
54
|
+
revert) echo "创建新提交来撤销之前的修改" ;;
|
|
55
|
+
cherry-pick) echo "把某个特定提交应用到当前分支" ;;
|
|
56
|
+
remote) echo "管理远程仓库地址" ;;
|
|
57
|
+
show) echo "查看提交的详细内容" ;;
|
|
58
|
+
tag) echo "管理代码版本标签" ;;
|
|
59
|
+
rm) echo "从仓库中删除文件" ;;
|
|
60
|
+
mv) echo "重命名仓库中的文件" ;;
|
|
61
|
+
*) echo "Git 版本控制操作" ;;
|
|
62
|
+
esac
|
|
63
|
+
;;
|
|
64
|
+
# === Node.js 包管理 ===
|
|
65
|
+
npm|npx)
|
|
66
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
67
|
+
case "$sub" in
|
|
68
|
+
install|i) echo "安装项目依赖包" ;;
|
|
69
|
+
run) echo "运行项目脚本命令" ;;
|
|
70
|
+
init) echo "初始化新项目" ;;
|
|
71
|
+
build) echo "构建/编译项目" ;;
|
|
72
|
+
test) echo "运行项目测试" ;;
|
|
73
|
+
start) echo "启动项目" ;;
|
|
74
|
+
*) echo "Node.js 包管理操作" ;;
|
|
75
|
+
esac
|
|
76
|
+
;;
|
|
77
|
+
yarn)
|
|
78
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
79
|
+
case "$sub" in
|
|
80
|
+
add) echo "添加依赖包" ;;
|
|
81
|
+
install) echo "安装项目依赖" ;;
|
|
82
|
+
run) echo "运行项目脚本" ;;
|
|
83
|
+
build) echo "构建项目" ;;
|
|
84
|
+
*) echo "Yarn 包管理操作" ;;
|
|
85
|
+
esac
|
|
86
|
+
;;
|
|
87
|
+
pnpm)
|
|
88
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
89
|
+
case "$sub" in
|
|
90
|
+
add) echo "添加依赖包" ;;
|
|
91
|
+
install) echo "安装项目依赖" ;;
|
|
92
|
+
run) echo "运行项目脚本" ;;
|
|
93
|
+
*) echo "pnpm 包管理操作" ;;
|
|
94
|
+
esac
|
|
95
|
+
;;
|
|
96
|
+
# === Python ===
|
|
97
|
+
pip|pip3)
|
|
98
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
99
|
+
case "$sub" in
|
|
100
|
+
install) echo "安装 Python 依赖包" ;;
|
|
101
|
+
uninstall) echo "卸载 Python 包" ;;
|
|
102
|
+
list) echo "列出已安装的 Python 包" ;;
|
|
103
|
+
show) echo "查看 Python 包的详细信息" ;;
|
|
104
|
+
freeze) echo "导出依赖包列表" ;;
|
|
105
|
+
*) echo "Python 包管理操作" ;;
|
|
106
|
+
esac
|
|
107
|
+
;;
|
|
108
|
+
python|python3)
|
|
109
|
+
echo "运行 Python 程序"
|
|
110
|
+
;;
|
|
111
|
+
pytest)
|
|
112
|
+
echo "运行 Python 单元测试"
|
|
113
|
+
;;
|
|
114
|
+
# === 文件操作 ===
|
|
115
|
+
ls|dir)
|
|
116
|
+
echo "查看目录中的文件列表" ;;
|
|
117
|
+
cat|bat)
|
|
118
|
+
echo "查看文件内容" ;;
|
|
119
|
+
head)
|
|
120
|
+
echo "查看文件开头几行" ;;
|
|
121
|
+
tail)
|
|
122
|
+
echo "查看文件末尾几行" ;;
|
|
123
|
+
less|more)
|
|
124
|
+
echo "分页查看文件内容" ;;
|
|
125
|
+
rm)
|
|
126
|
+
echo "删除文件或目录" ;;
|
|
127
|
+
mkdir)
|
|
128
|
+
echo "创建新文件夹" ;;
|
|
129
|
+
cp)
|
|
130
|
+
echo "复制文件" ;;
|
|
131
|
+
mv)
|
|
132
|
+
echo "移动或重命名文件" ;;
|
|
133
|
+
touch)
|
|
134
|
+
echo "创建空文件或更新时间戳" ;;
|
|
135
|
+
chmod)
|
|
136
|
+
echo "修改文件权限" ;;
|
|
137
|
+
chown)
|
|
138
|
+
echo "修改文件所有者" ;;
|
|
139
|
+
find)
|
|
140
|
+
echo "搜索文件或目录" ;;
|
|
141
|
+
wc)
|
|
142
|
+
echo "统计文件的行数/字数" ;;
|
|
143
|
+
sort)
|
|
144
|
+
echo "对文本内容排序" ;;
|
|
145
|
+
uniq)
|
|
146
|
+
echo "去除重复行" ;;
|
|
147
|
+
diff)
|
|
148
|
+
echo "比较两个文件的差异" ;;
|
|
149
|
+
# === 网络 ===
|
|
150
|
+
curl)
|
|
151
|
+
echo "请求网络资源" ;;
|
|
152
|
+
wget)
|
|
153
|
+
echo "从网络下载文件" ;;
|
|
154
|
+
ping)
|
|
155
|
+
echo "测试网络连通性" ;;
|
|
156
|
+
ssh)
|
|
157
|
+
echo "远程连接服务器" ;;
|
|
158
|
+
scp)
|
|
159
|
+
echo "远程复制文件" ;;
|
|
160
|
+
# === Docker ===
|
|
161
|
+
docker)
|
|
162
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
163
|
+
case "$sub" in
|
|
164
|
+
build) echo "构建 Docker 镜像" ;;
|
|
165
|
+
run) echo "运行 Docker 容器" ;;
|
|
166
|
+
ps) echo "查看运行中的容器" ;;
|
|
167
|
+
stop) echo "停止 Docker 容器" ;;
|
|
168
|
+
rm) echo "删除 Docker 容器" ;;
|
|
169
|
+
images) echo "查看 Docker 镜像列表" ;;
|
|
170
|
+
compose|up) echo "启动多容器应用" ;;
|
|
171
|
+
*) echo "Docker 容器操作" ;;
|
|
172
|
+
esac
|
|
173
|
+
;;
|
|
174
|
+
# === 系统 ===
|
|
175
|
+
echo)
|
|
176
|
+
echo "输出文本信息" ;;
|
|
177
|
+
which|where|command)
|
|
178
|
+
echo "查找命令的安装位置" ;;
|
|
179
|
+
env|printenv)
|
|
180
|
+
echo "查看环境变量" ;;
|
|
181
|
+
export)
|
|
182
|
+
echo "设置环境变量" ;;
|
|
183
|
+
source|\.)
|
|
184
|
+
echo "加载配置文件到当前环境" ;;
|
|
185
|
+
cd)
|
|
186
|
+
echo "切换工作目录" ;;
|
|
187
|
+
pwd)
|
|
188
|
+
echo "显示当前目录路径" ;;
|
|
189
|
+
whoami)
|
|
190
|
+
echo "查看当前用户名" ;;
|
|
191
|
+
date)
|
|
192
|
+
echo "显示当前日期时间" ;;
|
|
193
|
+
# === 编译/构建 ===
|
|
194
|
+
make)
|
|
195
|
+
echo "编译构建项目" ;;
|
|
196
|
+
gcc|g\+\+|cc)
|
|
197
|
+
echo "编译 C/C++ 程序" ;;
|
|
198
|
+
cargo)
|
|
199
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
200
|
+
case "$sub" in
|
|
201
|
+
build) echo "编译 Rust 项目" ;;
|
|
202
|
+
run) echo "运行 Rust 程序" ;;
|
|
203
|
+
test) echo "运行 Rust 测试" ;;
|
|
204
|
+
*) echo "Rust 构建操作" ;;
|
|
205
|
+
esac
|
|
206
|
+
;;
|
|
207
|
+
go)
|
|
208
|
+
local sub=$(echo "$rest" | awk '{print $1}')
|
|
209
|
+
case "$sub" in
|
|
210
|
+
build) echo "编译 Go 程序" ;;
|
|
211
|
+
run) echo "运行 Go 程序" ;;
|
|
212
|
+
test) echo "运行 Go 测试" ;;
|
|
213
|
+
mod) echo "管理 Go 模块" ;;
|
|
214
|
+
*) echo "Go 语言操作" ;;
|
|
215
|
+
esac
|
|
216
|
+
;;
|
|
217
|
+
# === 编辑器 ===
|
|
218
|
+
code)
|
|
219
|
+
echo "用 VS Code 打开文件" ;;
|
|
220
|
+
vim|vi|nano)
|
|
221
|
+
echo "用终端编辑器打开文件" ;;
|
|
222
|
+
# === 压缩 ===
|
|
223
|
+
tar)
|
|
224
|
+
echo "打包或解压文件" ;;
|
|
225
|
+
zip)
|
|
226
|
+
echo "压缩文件" ;;
|
|
227
|
+
unzip)
|
|
228
|
+
echo "解压 ZIP 文件" ;;
|
|
229
|
+
# === 进程 ===
|
|
230
|
+
ps)
|
|
231
|
+
echo "查看运行中的进程" ;;
|
|
232
|
+
kill)
|
|
233
|
+
echo "终止进程" ;;
|
|
234
|
+
top|htop)
|
|
235
|
+
echo "查看系统资源使用情况" ;;
|
|
236
|
+
# === 默认 ===
|
|
237
|
+
*)
|
|
238
|
+
# 如果命令较短直接显示
|
|
239
|
+
if [ ${#cmd} -le 20 ]; then
|
|
240
|
+
echo "执行系统命令: $cmd"
|
|
241
|
+
else
|
|
242
|
+
echo "执行系统命令"
|
|
243
|
+
fi
|
|
244
|
+
;;
|
|
245
|
+
esac
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# 生成提示 - 每条都带小白解释
|
|
249
|
+
get_tip() {
|
|
250
|
+
case "$1" in
|
|
251
|
+
"Read")
|
|
252
|
+
if [ -n "$file_path" ]; then
|
|
253
|
+
echo "📖 读取文件: $(short_path "$file_path") — 查看这个文件里写了什么"
|
|
254
|
+
else
|
|
255
|
+
echo "📖 读取完成 — 刚才查看了文件内容"
|
|
256
|
+
fi
|
|
257
|
+
;;
|
|
258
|
+
"Write")
|
|
259
|
+
if [ -n "$file_path" ]; then
|
|
260
|
+
echo "📝 写入文件: $(short_path "$file_path") — 创建或覆盖这个文件的全部内容"
|
|
261
|
+
else
|
|
262
|
+
echo "📝 写入完成 — 刚才创建/覆盖了文件"
|
|
263
|
+
fi
|
|
264
|
+
;;
|
|
265
|
+
"Edit"|"MultiEdit")
|
|
266
|
+
if [ -n "$file_path" ]; then
|
|
267
|
+
echo "✏️ 编辑文件: $(short_path "$file_path") — 修改这个文件的部分内容"
|
|
268
|
+
else
|
|
269
|
+
echo "✏️ 编辑完成 — 刚才修改了文件内容"
|
|
270
|
+
fi
|
|
271
|
+
;;
|
|
272
|
+
"Bash")
|
|
273
|
+
if [ -n "$bash_cmd" ]; then
|
|
274
|
+
# 跳过注释行和空行,取第一条真正的命令
|
|
275
|
+
real_cmd=$(echo "$bash_cmd" | grep -v '^[[:space:]]*#' | grep -v '^[[:space:]]*$' | head -1)
|
|
276
|
+
if [ -z "$real_cmd" ]; then
|
|
277
|
+
echo "🖥️ 命令执行完成"
|
|
278
|
+
else
|
|
279
|
+
# 按分隔符拆分多条命令(&&, ||, ;)
|
|
280
|
+
split_cmd=$(echo "$real_cmd" | sed 's/ && /\n/g; s/ || /\n/g; s/; /\n/g')
|
|
281
|
+
# 过滤空行
|
|
282
|
+
split_cmd=$(echo "$split_cmd" | grep -v '^[[:space:]]*$')
|
|
283
|
+
cmd_count=$(echo "$split_cmd" | grep -c .)
|
|
284
|
+
if [ "$cmd_count" -le 1 ]; then
|
|
285
|
+
explain=$(explain_cmd "$real_cmd")
|
|
286
|
+
echo "🖥️ 执行命令: $real_cmd — $explain"
|
|
287
|
+
else
|
|
288
|
+
echo "🖥️ 共${cmd_count}条命令:"
|
|
289
|
+
idx=1
|
|
290
|
+
while IFS= read -r line; do
|
|
291
|
+
[ -z "$line" ] && continue
|
|
292
|
+
[ "$idx" -gt 3 ] && break
|
|
293
|
+
explain=$(explain_cmd "$line")
|
|
294
|
+
echo " $idx. $line — $explain"
|
|
295
|
+
idx=$((idx+1))
|
|
296
|
+
done <<< "$split_cmd"
|
|
297
|
+
[ "$cmd_count" -gt 3 ] && echo " ...(还有$((cmd_count-3))条)"
|
|
298
|
+
fi
|
|
299
|
+
fi
|
|
300
|
+
else
|
|
301
|
+
echo "🖥️ 命令执行完成"
|
|
302
|
+
fi
|
|
303
|
+
;;
|
|
304
|
+
"Glob")
|
|
305
|
+
if [ -n "$pattern" ]; then
|
|
306
|
+
echo "🔍 搜索文件: \"$pattern\" — 按名称模式查找文件"
|
|
307
|
+
else
|
|
308
|
+
echo "🔍 文件搜索完成"
|
|
309
|
+
fi
|
|
310
|
+
;;
|
|
311
|
+
"Grep")
|
|
312
|
+
if [ -n "$pattern" ]; then
|
|
313
|
+
echo "🔎 搜索内容: \"$pattern\" — 在文件中搜索包含这段文字的地方"
|
|
314
|
+
else
|
|
315
|
+
echo "🔎 内容搜索完成"
|
|
316
|
+
fi
|
|
317
|
+
;;
|
|
318
|
+
"Agent")
|
|
319
|
+
echo "🤖 AI助手完成任务 — 派了一个AI小助手去独立处理任务"
|
|
320
|
+
;;
|
|
321
|
+
"Skill")
|
|
322
|
+
echo "⚡ 技能执行完成 — 使用了一个预设的专业技能"
|
|
323
|
+
;;
|
|
324
|
+
"Task"|"TaskCreate"|"TaskUpdate"|"TaskGet"|"TaskList")
|
|
325
|
+
echo "📋 任务管理 — 管理和跟踪工作进度"
|
|
326
|
+
;;
|
|
327
|
+
"TodoWrite")
|
|
328
|
+
echo "📋 待办更新 — 更新工作待办清单"
|
|
329
|
+
;;
|
|
330
|
+
"EnterPlanMode")
|
|
331
|
+
echo "🤔 进入规划模式 — AI正在仔细思考解决方案"
|
|
332
|
+
;;
|
|
333
|
+
"ExitPlanMode")
|
|
334
|
+
echo "✅ 规划完成 — AI想好了方案,准备开始执行"
|
|
335
|
+
;;
|
|
336
|
+
*)
|
|
337
|
+
if [[ "$1" == mcp__* ]]; then
|
|
338
|
+
srv=$(echo "$1" | sed -n 's/mcp__\([^_]*\)__.*/\1/p')
|
|
339
|
+
tool=$(echo "$1" | sed 's/mcp__[^_]*__//')
|
|
340
|
+
if [ -z "$srv" ]; then
|
|
341
|
+
echo "🔌 外部工具: $1 — 调用了第三方扩展功能"
|
|
342
|
+
else
|
|
343
|
+
case "$srv" in
|
|
344
|
+
"context7") echo "📚 查询文档: $tool — 从官方文档中查找最新资料" ;;
|
|
345
|
+
"exa") echo "🌐 网络搜索: $tool — 在互联网上搜索信息" ;;
|
|
346
|
+
"basic-memory") echo "🧠 记忆操作: $tool — 读写AI的长期记忆" ;;
|
|
347
|
+
"Playwright") echo "🎭 浏览器: $tool — 自动操控网页浏览器" ;;
|
|
348
|
+
"lark-mcp") echo "📱 飞书操作: $tool — 操作飞书办公软件" ;;
|
|
349
|
+
"web_reader") echo "📖 网页阅读: $tool — 读取网页内容" ;;
|
|
350
|
+
"4_5v-mcp") echo "🖼️ 图像处理: $tool — 分析或生成图片" ;;
|
|
351
|
+
"zai-mcp-server") echo "🤖 AI视觉: $tool — AI图像分析能力" ;;
|
|
352
|
+
*) echo "🔌 $srv: $tool — 调用了第三方工具服务" ;;
|
|
353
|
+
esac
|
|
354
|
+
fi
|
|
355
|
+
else
|
|
356
|
+
echo "✅ $1 — 操作完成"
|
|
357
|
+
fi
|
|
358
|
+
;;
|
|
359
|
+
esac
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
# JSON 转义
|
|
363
|
+
json_escape() {
|
|
364
|
+
local s="$1"
|
|
365
|
+
s="${s//\\/\\\\}"
|
|
366
|
+
s="${s//\"/\\\"}"
|
|
367
|
+
s="${s//$'\n'/\\n}"
|
|
368
|
+
s="${s//$'\t'/\\t}"
|
|
369
|
+
s="${s//$'\r'/\\r}"
|
|
370
|
+
echo "$s"
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
# 主逻辑
|
|
374
|
+
if [ -n "$tool_name" ]; then
|
|
375
|
+
tip=$(get_tip "$tool_name")
|
|
376
|
+
if [ -n "$tip" ]; then
|
|
377
|
+
escaped_tip=$(json_escape "✨ ${tip} ✨")
|
|
378
|
+
printf '{"systemMessage":"%s"}\n' "$escaped_tip"
|
|
379
|
+
fi
|
|
380
|
+
fi
|
|
381
|
+
|
|
382
|
+
exit 0
|