skillhelper 0.4.2

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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/bin/lib/atomic-write.mjs +72 -0
  4. package/bin/lib/paths.mjs +65 -0
  5. package/bin/lib/port.mjs +23 -0
  6. package/bin/skillhelper.mjs +720 -0
  7. package/build/build-site.mjs +35 -0
  8. package/build/build-web.mjs +29 -0
  9. package/build/pack-smoke.mjs +195 -0
  10. package/build/prepare-publish.mjs +3 -0
  11. package/build/verify.mjs +157 -0
  12. package/config/sources.example.yaml +126 -0
  13. package/docs/Frontend-Spec.md +1207 -0
  14. package/docs/scan_skills_rules.md +432 -0
  15. package/package.json +95 -0
  16. package/packages/scanner/package.json +15 -0
  17. package/packages/scanner/src/adapters/claude-agents.mjs +134 -0
  18. package/packages/scanner/src/adapters/claude-plugin.mjs +260 -0
  19. package/packages/scanner/src/adapters/codex-plugin.mjs +330 -0
  20. package/packages/scanner/src/adapters/directory-skill.mjs +239 -0
  21. package/packages/scanner/src/adapters/file-docs.mjs +158 -0
  22. package/packages/scanner/src/adapters/hermes-plugin.mjs +149 -0
  23. package/packages/scanner/src/adapters/markdown-skill.mjs +229 -0
  24. package/packages/scanner/src/adapters/mcp-config.mjs +190 -0
  25. package/packages/scanner/src/adapters/scan-tier.mjs +99 -0
  26. package/packages/scanner/src/adapters/skill-adapter.mjs +345 -0
  27. package/packages/scanner/src/adapters/tier1-editor-skills.mjs +278 -0
  28. package/packages/scanner/src/adapters/tier2-user-skills.mjs +218 -0
  29. package/packages/scanner/src/adapters/tier3-other-skills.mjs +225 -0
  30. package/packages/scanner/src/config/editor-tiers.mjs +191 -0
  31. package/packages/scanner/src/core/atomic-write.mjs +11 -0
  32. package/packages/scanner/src/core/descriptor.mjs +143 -0
  33. package/packages/scanner/src/core/path-hash.mjs +89 -0
  34. package/packages/scanner/src/core/registry.mjs +128 -0
  35. package/packages/scanner/src/hash/path-hash.mjs +8 -0
  36. package/packages/scanner/src/icon/brand-map.mjs +268 -0
  37. package/packages/scanner/src/icon/icon-extractor.mjs +466 -0
  38. package/packages/scanner/src/index.mjs +450 -0
  39. package/packages/scanner/src/types.d.ts +144 -0
  40. package/packages/scanner/src/utils.mjs +194 -0
  41. package/packages/server/package.json +15 -0
  42. package/packages/server/src/index.mjs +1071 -0
  43. package/packages/server/src/labels.mjs +64 -0
  44. package/packages/server/src/langdetect.mjs +34 -0
  45. package/packages/server/src/llm-client.mjs +42 -0
  46. package/packages/server/src/translate-cache.mjs +132 -0
  47. package/packages/server/src/translator.mjs +53 -0
  48. package/packages/web/README.md +36 -0
  49. package/packages/web/dist/assets/index-CGt04vt0.js +304 -0
  50. package/packages/web/dist/assets/index-CLSDoa3H.css +1 -0
  51. package/packages/web/dist/brand-icon.png +0 -0
  52. package/packages/web/dist/brand-logo.png +0 -0
  53. package/packages/web/dist/favicon-16x16.png +0 -0
  54. package/packages/web/dist/favicon-192x192.png +0 -0
  55. package/packages/web/dist/favicon-32x32.png +0 -0
  56. package/packages/web/dist/favicon-512x512.png +0 -0
  57. package/packages/web/dist/favicon-source.svg +5 -0
  58. package/packages/web/dist/favicon.ico +0 -0
  59. package/packages/web/dist/favicon.svg +5 -0
  60. package/packages/web/dist/icons/hermes-128.png +0 -0
  61. package/packages/web/dist/icons/hermes-192.png +0 -0
  62. package/packages/web/dist/icons/hermes-256.png +0 -0
  63. package/packages/web/dist/icons/hermes-32.png +0 -0
  64. package/packages/web/dist/icons/hermes-512.png +0 -0
  65. package/packages/web/dist/icons/hermes-64.png +0 -0
  66. package/packages/web/dist/icons/hermes.png +0 -0
  67. package/packages/web/dist/index.html +37 -0
  68. package/packages/web/dist/robots.txt +3 -0
  69. package/packages/web/dist/site.webmanifest +24 -0
  70. package/packages/web/public/brand-icon.png +0 -0
  71. package/packages/web/public/brand-logo.png +0 -0
  72. package/packages/web/public/favicon-16x16.png +0 -0
  73. package/packages/web/public/favicon-192x192.png +0 -0
  74. package/packages/web/public/favicon-32x32.png +0 -0
  75. package/packages/web/public/favicon-512x512.png +0 -0
  76. package/packages/web/public/favicon-source.svg +5 -0
  77. package/packages/web/public/favicon.ico +0 -0
  78. package/packages/web/public/favicon.svg +5 -0
  79. package/packages/web/public/icons/hermes-128.png +0 -0
  80. package/packages/web/public/icons/hermes-192.png +0 -0
  81. package/packages/web/public/icons/hermes-256.png +0 -0
  82. package/packages/web/public/icons/hermes-32.png +0 -0
  83. package/packages/web/public/icons/hermes-512.png +0 -0
  84. package/packages/web/public/icons/hermes-64.png +0 -0
  85. package/packages/web/public/icons/hermes.png +0 -0
  86. package/packages/web/public/robots.txt +3 -0
  87. package/packages/web/public/site.webmanifest +24 -0
  88. package/scripts/install-and-sync.sh +209 -0
  89. package/scripts/sync-skills.sh +605 -0
@@ -0,0 +1,605 @@
1
+ #!/bin/bash
2
+ # SkillHelper 编辑器技能同步脚本 v0.1.5
3
+
4
+ RED='\033[0;31m'
5
+ GREEN='\033[0;32m'
6
+ YELLOW='\033[1;33m'
7
+ BLUE='\033[0;34m'
8
+ CYAN='\033[0;36m'
9
+ NC='\033[0m'
10
+
11
+ log_info() { echo -e "${BLUE}ℹ${NC} $*"; }
12
+ log_success() { echo -e "${GREEN}✓${NC} $*"; }
13
+ log_warn() { echo -e "${YELLOW}⚠${NC} $*"; }
14
+ log_error() { echo -e "${RED}✗${NC} $*" >&2; }
15
+
16
+ get_os() {
17
+ [[ "$OSTYPE" == "darwin"* ]] && echo "macos" || echo "linux"
18
+ }
19
+
20
+ detect_editors() {
21
+ local i=0
22
+ local os=$(get_os)
23
+
24
+ # Cursor
25
+ case "$os" in
26
+ macos) [[ -d "$HOME/Library/Application Support/Cursor" ]] && echo "$i|cursor|$HOME/Library/Application Support/Cursor" && i=$((i+1)) ;;
27
+ linux) [[ -d "$HOME/.config/Cursor" ]] && echo "$i|cursor|$HOME/.config/Cursor" && i=$((i+1)) ;;
28
+ esac
29
+
30
+ # VS Code
31
+ case "$os" in
32
+ macos) [[ -d "$HOME/Library/Application Support/Code" ]] && echo "$i|vscode|$HOME/Library/Application Support/Code" && i=$((i+1)) ;;
33
+ linux) [[ -d "$HOME/.config/Code" ]] && echo "$i|vscode|$HOME/.config/Code" && i=$((i+1)) ;;
34
+ esac
35
+
36
+ # VS Code Insiders
37
+ case "$os" in
38
+ macos) [[ -d "$HOME/Library/Application Support/Code - Insiders" ]] && echo "$i|vscode-insiders|$HOME/Library/Application Support/Code - Insiders" && i=$((i+1)) ;;
39
+ linux) [[ -d "$HOME/.config/Code - Insiders" ]] && echo "$i|vscode-insiders|$HOME/.config/Code - Insiders" && i=$((i+1)) ;;
40
+ esac
41
+
42
+ # Windsurf
43
+ case "$os" in
44
+ macos) [[ -d "$HOME/Library/Application Support/Windsurf" ]] && echo "$i|windsurf|$HOME/Library/Application Support/Windsurf" && i=$((i+1)) ;;
45
+ linux) [[ -d "$HOME/.config/windsurf" ]] && echo "$i|windsurf|$HOME/.config/windsurf" && i=$((i+1)) ;;
46
+ esac
47
+
48
+ # Zed
49
+ case "$os" in
50
+ macos) [[ -d "$HOME/Library/Application Support/Zed" ]] && echo "$i|zed|$HOME/Library/Application Support/Zed" && i=$((i+1)) ;;
51
+ linux) [[ -d "$HOME/.config/zed" ]] && echo "$i|zed|$HOME/.config/zed" && i=$((i+1)) ;;
52
+ esac
53
+
54
+ # Helix
55
+ case "$os" in
56
+ macos) [[ -d "$HOME/Library/Application Support/Helix" ]] && echo "$i|helix|$HOME/Library/Application Support/Helix" && i=$((i+1)) ;;
57
+ linux) [[ -d "$HOME/.config/helix" ]] && echo "$i|helix|$HOME/.config/helix" && i=$((i+1)) ;;
58
+ esac
59
+
60
+ # Neovim
61
+ [[ -d "$HOME/.config/nvim" ]] && echo "$i|neovim|$HOME/.config/nvim" && i=$((i+1))
62
+
63
+ # Vim
64
+ [[ -d "$HOME/.vim" ]] && echo "$i|vim|$HOME/.vim" && i=$((i+1))
65
+
66
+ # Emacs
67
+ [[ -d "$HOME/.emacs.d" ]] && echo "$i|emacs|$HOME/.emacs.d" && i=$((i+1))
68
+
69
+ # Sublime Text
70
+ case "$os" in
71
+ macos) [[ -d "$HOME/Library/Application Support/Sublime Text" ]] && echo "$i|sublime|$HOME/Library/Application Support/Sublime Text" && i=$((i+1)) ;;
72
+ linux) [[ -d "$HOME/.config/sublime-text-3" ]] && echo "$i|sublime|$HOME/.config/sublime-text-3" && i=$((i+1)) ;;
73
+ esac
74
+
75
+ # Sublime Text 4
76
+ case "$os" in
77
+ macos) [[ -d "$HOME/Library/Application Support/Sublime Text 4" ]] && echo "$i|sublime4|$HOME/Library/Application Support/Sublime Text 4" && i=$((i+1)) ;;
78
+ esac
79
+
80
+ # TextMate
81
+ case "$os" in
82
+ macos) [[ -d "$HOME/Library/Application Support/TextMate" ]] && echo "$i|textmate|$HOME/Library/Application Support/TextMate" && i=$((i+1)) ;;
83
+ esac
84
+
85
+ # BBEdit
86
+ case "$os" in
87
+ macos) [[ -d "$HOME/Library/Application Support/BBEdit" ]] && echo "$i|bbedit|$HOME/Library/Application Support/BBEdit" && i=$((i+1)) ;;
88
+ esac
89
+
90
+ # Atom
91
+ case "$os" in
92
+ macos) [[ -d "$HOME/.atom" ]] && echo "$i|atom|$HOME/.atom" && i=$((i+1)) ;;
93
+ linux) [[ -d "$HOME/.atom" ]] && echo "$i|atom|$HOME/.atom" && i=$((i+1)) ;;
94
+ esac
95
+
96
+ # Kate
97
+ case "$os" in
98
+ linux) [[ -d "$HOME/.config/kate" ]] && echo "$i|kate|$HOME/.config/kate" && i=$((i+1)) ;;
99
+ esac
100
+
101
+ # Gedit
102
+ case "$os" in
103
+ linux) [[ -d "$HOME/.config/gedit" ]] && echo "$i|gedit|$HOME/.config/gedit" && i=$((i+1)) ;;
104
+ esac
105
+
106
+ # JetBrains IDEs (IntelliJ IDEA, PyCharm, WebStorm, etc.)
107
+ case "$os" in
108
+ macos)
109
+ [[ -d "$HOME/Library/Application Support/JetBrains" ]] && echo "$i|jetbrains|$HOME/Library/Application Support/JetBrains" && i=$((i+1))
110
+ ;;
111
+ linux)
112
+ [[ -d "$HOME/.config/jetbrains" ]] && echo "$i|jetbrains|$HOME/.config/jetbrains" && i=$((i+1))
113
+ ;;
114
+ esac
115
+
116
+ # Openclaw
117
+ case "$os" in
118
+ macos) [[ -d "$HOME/Library/Application Support/Openclaw" ]] && echo "$i|openclaw|$HOME/Library/Application Support/Openclaw" && i=$((i+1)) ;;
119
+ linux) [[ -d "$HOME/.config/openclaw" ]] && echo "$i|openclaw|$HOME/.config/openclaw" && i=$((i+1)) ;;
120
+ esac
121
+
122
+ # Herems
123
+ case "$os" in
124
+ macos) [[ -d "$HOME/Library/Application Support/Herems" ]] && echo "$i|herems|$HOME/Library/Application Support/Herems" && i=$((i+1)) ;;
125
+ linux) [[ -d "$HOME/.config/herems" ]] && echo "$i|herems|$HOME/.config/herems" && i=$((i+1)) ;;
126
+ esac
127
+
128
+ # Trae
129
+ case "$os" in
130
+ macos) [[ -d "$HOME/Library/Application Support/Trae" ]] && echo "$i|trae|$HOME/Library/Application Support/Trae" && i=$((i+1)) ;;
131
+ linux) [[ -d "$HOME/.config/trae" ]] && echo "$i|trae|$HOME/.config/trae" && i=$((i+1)) ;;
132
+ esac
133
+
134
+ # Trae CN (中文版本,目录名为 "Trae CN" 带空格)
135
+ case "$os" in
136
+ macos) [[ -d "$HOME/Library/Application Support/Trae CN" ]] && echo "$i|trae-cn|$HOME/Library/Application Support/Trae CN" && i=$((i+1)) ;;
137
+ linux) [[ -d "$HOME/.config/trae-cn" ]] && echo "$i|trae-cn|$HOME/.config/trae-cn" && i=$((i+1)) ;;
138
+ esac
139
+
140
+ # Codex (AI 编程助手)
141
+ case "$os" in
142
+ macos) [[ -d "$HOME/Library/Application Support/Codex" ]] && echo "$i|codex|$HOME/Library/Application Support/Codex" && i=$((i+1)) ;;
143
+ linux) [[ -d "$HOME/.config/codex" ]] && echo "$i|codex|$HOME/.config/codex" && i=$((i+1)) ;;
144
+ esac
145
+
146
+ # Claude (Anthropic AI 助手)
147
+ case "$os" in
148
+ macos) [[ -d "$HOME/Library/Application Support/Claude" ]] && echo "$i|claude|$HOME/Library/Application Support/Claude" && i=$((i+1)) ;;
149
+ linux) [[ -d "$HOME/.config/claude" ]] && echo "$i|claude|$HOME/.config/claude" && i=$((i+1)) ;;
150
+ esac
151
+ }
152
+
153
+ show_editors() {
154
+ local editors="$1"
155
+ echo -e "\n${CYAN}╔════════════════════════════════════════════════════════╗${NC}"
156
+ echo -e "${CYAN}║ 请选择要同步技能的编辑器(多选,用逗号分隔) ║${NC}"
157
+ echo -e "${CYAN}╚════════════════════════════════════════════════════════╝${NC}\n"
158
+
159
+ local count=1
160
+ echo "$editors" | while IFS='|' read -r idx name path; do
161
+ printf " ${BLUE}[%-2d]${NC} %-20s %s\n" "$count" "$name" "$path"
162
+ count=$((count+1))
163
+ done
164
+
165
+ echo
166
+ echo -e " ${YELLOW}0${NC} - 全选 ${YELLOW}q${NC} - 退出"
167
+ echo
168
+ }
169
+
170
+ find_skillhelper_root() {
171
+ if [[ -n "${SKILLHELPER_LOCAL_PATH:-}" ]]; then
172
+ echo "$SKILLHELPER_LOCAL_PATH"
173
+ return 0
174
+ fi
175
+
176
+ local script_dir
177
+ script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
178
+
179
+ if [[ -f "$script_dir/package.json" ]]; then
180
+ echo "$script_dir"
181
+ return 0
182
+ fi
183
+
184
+ log_error "未找到 SkillHelper 项目"
185
+ return 1
186
+ }
187
+
188
+ sync_to_cursor() {
189
+ local editor_path="$1" root="$2"
190
+ [[ -f "$root/.cursorrules" ]] && cp "$root/.cursorrules" "$editor_path/.cursorrules" && log_success "Cursor: 已同步" || log_warn "Cursor: 跳过"
191
+ }
192
+
193
+ sync_to_vscode() {
194
+ local editor_path="$1" root="$2"
195
+ mkdir -p "$editor_path/User/snippets"
196
+
197
+ # 尝试同步 .cursorrules 作为注释文件用于参考
198
+ if [[ -f "$root/.cursorrules" ]]; then
199
+ cp "$root/.cursorrules" "$editor_path/User/.cursorrules.txt" 2>/dev/null || true
200
+ fi
201
+
202
+ log_success "VS Code: 已同步"
203
+ }
204
+
205
+ sync_to_vscode_insiders() {
206
+ local editor_path="$1" root="$2"
207
+ mkdir -p "$editor_path/User/snippets"
208
+
209
+ # 尝试同步 .cursorrules 作为注释文件用于参考
210
+ if [[ -f "$root/.cursorrules" ]]; then
211
+ cp "$root/.cursorrules" "$editor_path/User/.cursorrules.txt" 2>/dev/null || true
212
+ fi
213
+
214
+ log_success "VS Code Insiders: 已同步"
215
+ }
216
+
217
+ sync_to_windsurf() {
218
+ local editor_path="$1" root="$2"
219
+ mkdir -p "$editor_path"
220
+
221
+ # 同步 .cursorrules 如果存在
222
+ if [[ -f "$root/.cursorrules" ]]; then
223
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Windsurf: .cursorrules 复制失败"
224
+ fi
225
+
226
+ log_success "Windsurf: 已同步"
227
+ }
228
+
229
+ sync_to_zed() {
230
+ local editor_path="$1" root="$2"
231
+ mkdir -p "$editor_path"
232
+
233
+ # Zed 支持 .cursorrules
234
+ if [[ -f "$root/.cursorrules" ]]; then
235
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Zed: .cursorrules 复制失败"
236
+ fi
237
+
238
+ log_success "Zed: 已同步"
239
+ }
240
+
241
+ sync_to_helix() {
242
+ local editor_path="$1" root="$2"
243
+ mkdir -p "$editor_path"
244
+
245
+ # 尝试同步技能相关的配置
246
+ if [[ -f "$root/.cursorrules" ]]; then
247
+ cp "$root/.cursorrules" "$editor_path/rules.md" 2>/dev/null || log_warn "Helix: rules 复制失败"
248
+ fi
249
+
250
+ log_success "Helix: 已同步"
251
+ }
252
+
253
+ sync_to_neovim() {
254
+ local editor_path="$1" root="$2"
255
+ mkdir -p "$editor_path/plugin"
256
+
257
+ # 创建基础配置加载文件
258
+ if [[ -f "$root/.cursorrules" ]]; then
259
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "Neovim: rules 复制失败"
260
+ fi
261
+
262
+ log_success "Neovim: 已同步"
263
+ }
264
+
265
+ sync_to_vim() {
266
+ local editor_path="$1" root="$2"
267
+ mkdir -p "$editor_path/plugin"
268
+
269
+ # 创建基础配置加载文件
270
+ if [[ -f "$root/.cursorrules" ]]; then
271
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "Vim: rules 复制失败"
272
+ fi
273
+
274
+ log_success "Vim: 已同步"
275
+ }
276
+
277
+ sync_to_emacs() {
278
+ local editor_path="$1" root="$2"
279
+ mkdir -p "$editor_path"
280
+
281
+ # Emacs 用户可以加载规则文件
282
+ if [[ -f "$root/.cursorrules" ]]; then
283
+ cp "$root/.cursorrules" "$editor_path/skillhelper-rules.md" 2>/dev/null || log_warn "Emacs: rules 复制失败"
284
+ fi
285
+
286
+ log_success "Emacs: 已同步"
287
+ }
288
+
289
+ sync_to_sublime() {
290
+ local editor_path="$1" root="$2"
291
+ mkdir -p "$editor_path/Packages/User"
292
+
293
+ # 同步规则到 Sublime 用户目录
294
+ if [[ -f "$root/.cursorrules" ]]; then
295
+ cp "$root/.cursorrules" "$editor_path/Packages/User/skillhelper_rules.md" 2>/dev/null || log_warn "Sublime Text: rules 复制失败"
296
+ fi
297
+
298
+ log_success "Sublime Text: 已同步"
299
+ }
300
+
301
+ sync_to_sublime4() {
302
+ local editor_path="$1" root="$2"
303
+ mkdir -p "$editor_path/Packages/User"
304
+
305
+ # 同步规则到 Sublime 用户目录
306
+ if [[ -f "$root/.cursorrules" ]]; then
307
+ cp "$root/.cursorrules" "$editor_path/Packages/User/skillhelper_rules.md" 2>/dev/null || log_warn "Sublime Text 4: rules 复制失败"
308
+ fi
309
+
310
+ log_success "Sublime Text 4: 已同步"
311
+ }
312
+
313
+ sync_to_textmate() {
314
+ local editor_path="$1" root="$2"
315
+ mkdir -p "$editor_path"
316
+
317
+ if [[ -f "$root/.cursorrules" ]]; then
318
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "TextMate: rules 复制失败"
319
+ fi
320
+
321
+ log_success "TextMate: 已同步"
322
+ }
323
+
324
+ sync_to_bbedit() {
325
+ local editor_path="$1" root="$2"
326
+ mkdir -p "$editor_path"
327
+
328
+ if [[ -f "$root/.cursorrules" ]]; then
329
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "BBEdit: rules 复制失败"
330
+ fi
331
+
332
+ log_success "BBEdit: 已同步"
333
+ }
334
+
335
+ sync_to_atom() {
336
+ local editor_path="$1" root="$2"
337
+ mkdir -p "$editor_path/packages"
338
+
339
+ if [[ -f "$root/.cursorrules" ]]; then
340
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "Atom: rules 复制失败"
341
+ fi
342
+
343
+ log_success "Atom: 已同步"
344
+ }
345
+
346
+ sync_to_kate() {
347
+ local editor_path="$1" root="$2"
348
+ mkdir -p "$editor_path"
349
+
350
+ if [[ -f "$root/.cursorrules" ]]; then
351
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "Kate: rules 复制失败"
352
+ fi
353
+
354
+ log_success "Kate: 已同步"
355
+ }
356
+
357
+ sync_to_gedit() {
358
+ local editor_path="$1" root="$2"
359
+ mkdir -p "$editor_path"
360
+
361
+ if [[ -f "$root/.cursorrules" ]]; then
362
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "Gedit: rules 复制失败"
363
+ fi
364
+
365
+ log_success "Gedit: 已同步"
366
+ }
367
+
368
+ sync_to_jetbrains() {
369
+ local editor_path="$1" root="$2"
370
+ mkdir -p "$editor_path"
371
+
372
+ if [[ -f "$root/.cursorrules" ]]; then
373
+ cp "$root/.cursorrules" "$editor_path/skillhelper_rules.md" 2>/dev/null || log_warn "JetBrains IDEs: rules 复制失败"
374
+ fi
375
+
376
+ log_success "JetBrains IDEs: 已同步"
377
+ }
378
+
379
+ sync_to_openclaw() {
380
+ local editor_path="$1" root="$2"
381
+ mkdir -p "$editor_path"
382
+
383
+ if [[ -f "$root/.cursorrules" ]]; then
384
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Openclaw: .cursorrules 复制失败"
385
+ fi
386
+
387
+ log_success "Openclaw: 已同步"
388
+ }
389
+
390
+ sync_to_herems() {
391
+ local editor_path="$1" root="$2"
392
+ mkdir -p "$editor_path"
393
+
394
+ if [[ -f "$root/.cursorrules" ]]; then
395
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Herems: .cursorrules 复制失败"
396
+ fi
397
+
398
+ log_success "Herems: 已同步"
399
+ }
400
+
401
+ sync_to_trae() {
402
+ local editor_path="$1" root="$2"
403
+ mkdir -p "$editor_path"
404
+
405
+ if [[ -f "$root/.cursorrules" ]]; then
406
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Trae: .cursorrules 复制失败"
407
+ fi
408
+
409
+ log_success "Trae: 已同步"
410
+ }
411
+
412
+ sync_to_trae_cn() {
413
+ local editor_path="$1" root="$2"
414
+ mkdir -p "$editor_path"
415
+
416
+ if [[ -f "$root/.cursorrules" ]]; then
417
+ cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null || log_warn "Trae CN: .cursorrules 复制失败"
418
+ fi
419
+
420
+ log_success "Trae CN: 已同步"
421
+ }
422
+
423
+ sync_to_codex() {
424
+ local editor_path="$1" root="$2"
425
+ [[ -f "$root/.cursorrules" ]] && cp "$root/.cursorrules" "$editor_path/.cursorrules" 2>/dev/null && log_success "Codex: 已同步" || log_warn "Codex: 跳过"
426
+ }
427
+
428
+ sync_to_claude() {
429
+ local editor_path="$1" root="$2"
430
+ [[ -f "$root/.cursorrules" ]] && cp "$root/.cursorrules" "$editor_path/.cursorrules" && log_success "Claude: 已同步" || log_warn "Claude: 跳过"
431
+ }
432
+
433
+ main() {
434
+ local selection="$1"
435
+ local editor_name="$2"
436
+ local is_auto_mode=false
437
+
438
+ # 如果通过 --editor 参数指定编辑器名称
439
+ if [[ "$selection" == "--editor" && -n "$editor_name" ]]; then
440
+ selection="$editor_name"
441
+ is_auto_mode=true
442
+ # 如果通过环境变量指定编辑器
443
+ elif [[ -n "${SKILLHELPER_EDITOR:-}" ]]; then
444
+ selection="$SKILLHELPER_EDITOR"
445
+ is_auto_mode=true
446
+ # 如果通过参数指定了选择,进入自动模式
447
+ elif [[ -n "$selection" && "$selection" != "" && "$selection" != "0" ]]; then
448
+ is_auto_mode=true
449
+ fi
450
+
451
+ if [[ "$is_auto_mode" == false ]]; then
452
+ echo -e "\n${CYAN}╔════════════════════════════════════════════════════════╗${NC}"
453
+ echo -e "${CYAN}║ SkillHelper 编辑器技能同步 v0.1.5 ║${NC}"
454
+ echo -e "${CYAN}╚════════════════════════════════════════════════════════╝${NC}\n"
455
+
456
+ log_info "扫描已安装的编辑器...\n"
457
+
458
+ editors=$(detect_editors)
459
+
460
+ if [[ -z "$editors" ]]; then
461
+ log_error "未发现支持的编辑器"
462
+ exit 1
463
+ fi
464
+
465
+ count=$(echo "$editors" | wc -l)
466
+ log_success "发现 $count 个编辑器"
467
+
468
+ show_editors "$editors"
469
+ read -p "请输入选择 (0/1,2,...或q): " selection
470
+
471
+ [[ "$selection" == "q" ]] && exit 0
472
+ fi
473
+
474
+ skillhelper_root=$(find_skillhelper_root) || exit 1
475
+
476
+ if [[ "$is_auto_mode" == false ]]; then
477
+ log_info "同步根目录: $skillhelper_root\n"
478
+
479
+ echo -e "${CYAN}╔════════════════════════════════════════════════════════╗${NC}"
480
+ echo -e "${CYAN}║ 开始同步编辑器技能 ║${NC}"
481
+ echo -e "${CYAN}╚════════════════════════════════════════════════════════╝${NC}\n"
482
+ fi
483
+
484
+ editors=$(detect_editors)
485
+
486
+ # 处理编辑器名称(如 cursor, vscode 等)
487
+ if [[ "$is_auto_mode" == true && "$selection" != "0" ]]; then
488
+ # 将编辑器名称转换为可处理的格式
489
+ local editor_name="$selection"
490
+ local editor_path=""
491
+
492
+ # 从 editors 列表中找到对应的路径
493
+ editor_path=$(echo "$editors" | grep "|$editor_name|" | cut -d'|' -f3)
494
+
495
+ if [[ -n "$editor_path" ]]; then
496
+ case "$editor_name" in
497
+ cursor) sync_to_cursor "$editor_path" "$skillhelper_root" ;;
498
+ vscode) sync_to_vscode "$editor_path" "$skillhelper_root" ;;
499
+ vscode-insiders) sync_to_vscode_insiders "$editor_path" "$skillhelper_root" ;;
500
+ windsurf) sync_to_windsurf "$editor_path" "$skillhelper_root" ;;
501
+ zed) sync_to_zed "$editor_path" "$skillhelper_root" ;;
502
+ helix) sync_to_helix "$editor_path" "$skillhelper_root" ;;
503
+ neovim) sync_to_neovim "$editor_path" "$skillhelper_root" ;;
504
+ vim) sync_to_vim "$editor_path" "$skillhelper_root" ;;
505
+ emacs) sync_to_emacs "$editor_path" "$skillhelper_root" ;;
506
+ sublime) sync_to_sublime "$editor_path" "$skillhelper_root" ;;
507
+ sublime4) sync_to_sublime4 "$editor_path" "$skillhelper_root" ;;
508
+ textmate) sync_to_textmate "$editor_path" "$skillhelper_root" ;;
509
+ bbedit) sync_to_bbedit "$editor_path" "$skillhelper_root" ;;
510
+ atom) sync_to_atom "$editor_path" "$skillhelper_root" ;;
511
+ kate) sync_to_kate "$editor_path" "$skillhelper_root" ;;
512
+ gedit) sync_to_gedit "$editor_path" "$skillhelper_root" ;;
513
+ jetbrains) sync_to_jetbrains "$editor_path" "$skillhelper_root" ;;
514
+ openclaw) sync_to_openclaw "$editor_path" "$skillhelper_root" ;;
515
+ herems) sync_to_herems "$editor_path" "$skillhelper_root" ;;
516
+ trae) sync_to_trae "$editor_path" "$skillhelper_root" ;;
517
+ trae-cn) sync_to_trae_cn "$editor_path" "$skillhelper_root" ;;
518
+ codex) sync_to_codex "$editor_path" "$skillhelper_root" ;;
519
+ claude) sync_to_claude "$editor_path" "$skillhelper_root" ;;
520
+ esac
521
+ echo
522
+ echo -e "${GREEN}✨ 技能同步完成!${NC}\n"
523
+ return 0
524
+ else
525
+ log_error "未找到编辑器: $editor_name"
526
+ exit 1
527
+ fi
528
+ fi
529
+
530
+ if [[ "$selection" == "0" ]]; then
531
+ echo "$editors" | while IFS='|' read -r idx name path; do
532
+ case "$name" in
533
+ cursor) sync_to_cursor "$path" "$skillhelper_root" ;;
534
+ vscode) sync_to_vscode "$path" "$skillhelper_root" ;;
535
+ vscode-insiders) sync_to_vscode_insiders "$path" "$skillhelper_root" ;;
536
+ windsurf) sync_to_windsurf "$path" "$skillhelper_root" ;;
537
+ zed) sync_to_zed "$path" "$skillhelper_root" ;;
538
+ helix) sync_to_helix "$path" "$skillhelper_root" ;;
539
+ neovim) sync_to_neovim "$path" "$skillhelper_root" ;;
540
+ vim) sync_to_vim "$path" "$skillhelper_root" ;;
541
+ emacs) sync_to_emacs "$path" "$skillhelper_root" ;;
542
+ sublime) sync_to_sublime "$path" "$skillhelper_root" ;;
543
+ sublime4) sync_to_sublime4 "$path" "$skillhelper_root" ;;
544
+ textmate) sync_to_textmate "$path" "$skillhelper_root" ;;
545
+ bbedit) sync_to_bbedit "$path" "$skillhelper_root" ;;
546
+ atom) sync_to_atom "$path" "$skillhelper_root" ;;
547
+ kate) sync_to_kate "$path" "$skillhelper_root" ;;
548
+ gedit) sync_to_gedit "$path" "$skillhelper_root" ;;
549
+ jetbrains) sync_to_jetbrains "$path" "$skillhelper_root" ;;
550
+ openclaw) sync_to_openclaw "$path" "$skillhelper_root" ;;
551
+ herems) sync_to_herems "$path" "$skillhelper_root" ;;
552
+ trae) sync_to_trae "$path" "$skillhelper_root" ;;
553
+ trae-cn) sync_to_trae_cn "$path" "$skillhelper_root" ;;
554
+ codex) sync_to_codex "$path" "$skillhelper_root" ;;
555
+ claude) sync_to_claude "$path" "$skillhelper_root" ;;
556
+ esac
557
+ done
558
+ else
559
+ # Parse selection: handle both comma and space separated numbers
560
+ # Convert to 0-based indexing
561
+ for sel in $(echo "$selection" | tr ',' ' '); do
562
+ # Convert from 1-based to 0-based
563
+ line_num=$((sel))
564
+ editor=$(echo "$editors" | sed -n "$line_num"p)
565
+ [[ -z "$editor" ]] && continue
566
+
567
+ idx=$(echo "$editor" | cut -d'|' -f1)
568
+ name=$(echo "$editor" | cut -d'|' -f2)
569
+ path=$(echo "$editor" | cut -d'|' -f3)
570
+
571
+ case "$name" in
572
+ cursor) sync_to_cursor "$path" "$skillhelper_root" ;;
573
+ vscode) sync_to_vscode "$path" "$skillhelper_root" ;;
574
+ vscode-insiders) sync_to_vscode_insiders "$path" "$skillhelper_root" ;;
575
+ windsurf) sync_to_windsurf "$path" "$skillhelper_root" ;;
576
+ zed) sync_to_zed "$path" "$skillhelper_root" ;;
577
+ helix) sync_to_helix "$path" "$skillhelper_root" ;;
578
+ neovim) sync_to_neovim "$path" "$skillhelper_root" ;;
579
+ vim) sync_to_vim "$path" "$skillhelper_root" ;;
580
+ emacs) sync_to_emacs "$path" "$skillhelper_root" ;;
581
+ sublime) sync_to_sublime "$path" "$skillhelper_root" ;;
582
+ sublime4) sync_to_sublime4 "$path" "$skillhelper_root" ;;
583
+ textmate) sync_to_textmate "$path" "$skillhelper_root" ;;
584
+ bbedit) sync_to_bbedit "$path" "$skillhelper_root" ;;
585
+ atom) sync_to_atom "$path" "$skillhelper_root" ;;
586
+ kate) sync_to_kate "$path" "$skillhelper_root" ;;
587
+ gedit) sync_to_gedit "$path" "$skillhelper_root" ;;
588
+ jetbrains) sync_to_jetbrains "$path" "$skillhelper_root" ;;
589
+ openclaw) sync_to_openclaw "$path" "$skillhelper_root" ;;
590
+ herems) sync_to_herems "$path" "$skillhelper_root" ;;
591
+ trae) sync_to_trae "$path" "$skillhelper_root" ;;
592
+ trae-cn) sync_to_trae_cn "$path" "$skillhelper_root" ;;
593
+ codex) sync_to_codex "$path" "$skillhelper_root" ;;
594
+ claude) sync_to_claude "$path" "$skillhelper_root" ;;
595
+ esac
596
+ done
597
+ fi
598
+
599
+ echo
600
+ echo -e "${CYAN}╔════════════════════════════════════════════════════════╗${NC}"
601
+ echo -e "${GREEN}✨ 技能同步完成!${NC}"
602
+ echo -e "${CYAN}╚════════════════════════════════════════════════════════╝${NC}\n"
603
+ }
604
+
605
+ main "$@"