@cannbot-ai/install-helper 0.0.2-beta.40 → 0.0.2-beta.41
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/dist/index.js +636 -109
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { select, checkbox, Separator } from "@inquirer/prompts";
|
|
|
12
12
|
import chalk3 from "chalk";
|
|
13
13
|
|
|
14
14
|
// src/core/registry.ts
|
|
15
|
-
import { readdirSync, readFileSync as readFileSync2, existsSync } from "fs";
|
|
15
|
+
import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
16
16
|
import { join as join2, dirname as dirname2 } from "path";
|
|
17
17
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18
18
|
import { parse as parseYaml } from "yaml";
|
|
@@ -22,25 +22,401 @@ import chalk2 from "chalk";
|
|
|
22
22
|
import ora from "ora";
|
|
23
23
|
|
|
24
24
|
// src/utils/i18n.ts
|
|
25
|
-
import { readFileSync } from "fs";
|
|
25
|
+
import { readFileSync, existsSync } from "fs";
|
|
26
26
|
import { join, dirname } from "path";
|
|
27
27
|
import { fileURLToPath } from "url";
|
|
28
|
+
|
|
29
|
+
// src/locales/zh_CN.json
|
|
30
|
+
var zh_CN_default = {
|
|
31
|
+
wizard_title: "CANNBot Install Helper",
|
|
32
|
+
wizard_detect: "\u6B63\u5728\u68C0\u6D4B\u5DF2\u5B89\u88C5\u7684 AI \u7F16\u7A0B\u5DE5\u5177...",
|
|
33
|
+
wizard_select_tool: "\u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177",
|
|
34
|
+
wizard_select_level: "\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E",
|
|
35
|
+
wizard_select_plugins: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6",
|
|
36
|
+
wizard_confirm: "\u786E\u8BA4\u5B89\u88C5",
|
|
37
|
+
wizard_detected_tool: "\u68C0\u6D4B\u5230",
|
|
38
|
+
wizard_confirm_tool: "\u4F7F\u7528",
|
|
39
|
+
wizard_last_used: "\u4E0A\u6B21\u4F7F\u7528",
|
|
40
|
+
wizard_already_installed: "\u5DF2\u5B89\u88C5",
|
|
41
|
+
install_repo_ready: "\u4ED3\u5E93\u5C31\u7EEA",
|
|
42
|
+
install_progress: "\u6B63\u5728\u5B89\u88C5",
|
|
43
|
+
install_done: "\u5B89\u88C5\u5B8C\u6210",
|
|
44
|
+
install_success: "\u6210\u529F",
|
|
45
|
+
install_already_installed: "\u5DF2\u5B89\u88C5",
|
|
46
|
+
install_reinstall_confirm: "\u662F\u5426\u91CD\u65B0\u5B89\u88C5\uFF08\u8986\u76D6\uFF09",
|
|
47
|
+
install_skip: "\u8DF3\u8FC7",
|
|
48
|
+
install_enhanced_next_steps: "\u4E0B\u4E00\u6B65",
|
|
49
|
+
install_enhanced_launch: "\u542F\u52A8",
|
|
50
|
+
install_enhanced_try: "\u8BD5\u8BD5",
|
|
51
|
+
install_enhanced_more: "\u66F4\u591A",
|
|
52
|
+
install_enhanced_check: "\u68C0\u67E5",
|
|
53
|
+
install_enhanced_docs: "\u6587\u6863",
|
|
54
|
+
update_updating: "\u6B63\u5728\u66F4\u65B0",
|
|
55
|
+
update_done: "\u66F4\u65B0\u5B8C\u6210",
|
|
56
|
+
update_no_plugins: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
|
|
57
|
+
doctor_title: "CANNBot Doctor",
|
|
58
|
+
doctor_tools: "AI \u5DE5\u5177",
|
|
59
|
+
doctor_plugins: "\u5DF2\u5B89\u88C5\u63D2\u4EF6",
|
|
60
|
+
doctor_links: "\u94FE\u63A5\u5B8C\u6574\u6027",
|
|
61
|
+
doctor_config: "\u914D\u7F6E\u6587\u4EF6",
|
|
62
|
+
doctor_result: "\u7ED3\u679C",
|
|
63
|
+
doctor_fix_cleaning: "\u6E05\u7406\u5931\u6548\u94FE\u63A5",
|
|
64
|
+
doctor_fix_rebuilding: "\u91CD\u5EFA\u76EE\u5F55",
|
|
65
|
+
info_description: "\u63CF\u8FF0",
|
|
66
|
+
info_skills: "Skills",
|
|
67
|
+
info_agents: "Agents",
|
|
68
|
+
info_status: "\u72B6\u6001",
|
|
69
|
+
info_quickstart: "\u5FEB\u901F\u5F00\u59CB",
|
|
70
|
+
info_not_found: "\u672A\u627E\u5230\u63D2\u4EF6",
|
|
71
|
+
lang_title: "\u8BED\u8A00\u8BBE\u7F6E",
|
|
72
|
+
lang_current: "\u5F53\u524D\u8BED\u8A00",
|
|
73
|
+
lang_set: "\u8BED\u8A00\u5DF2\u8BBE\u7F6E\u4E3A",
|
|
74
|
+
lang_invalid: "\u65E0\u6548\u7684\u8BED\u8A00\uFF0C\u652F\u6301: zh_CN, en_US",
|
|
75
|
+
list_title: "\u53EF\u7528\u573A\u666F",
|
|
76
|
+
list_id: "\u5E8F\u53F7",
|
|
77
|
+
list_name: "\u573A\u666F\u540D",
|
|
78
|
+
list_status: "\u72B6\u6001",
|
|
79
|
+
list_description: "\u63CF\u8FF0",
|
|
80
|
+
status_installed: "\u5DF2\u88C5",
|
|
81
|
+
status_not_installed: "\u672A\u88C5",
|
|
82
|
+
error_tool_not_found: "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 AI \u7F16\u7A0B\u5DE5\u5177",
|
|
83
|
+
error_plugin_not_found: "\u672A\u627E\u5230\u63D2\u4EF6",
|
|
84
|
+
error_invalid_tool: "\u6682\u4E0D\u652F\u6301\u7684 AI \u5DE5\u5177: {tool}\n\u652F\u6301\u7684\u5DE5\u5177: {tools}",
|
|
85
|
+
error_invalid_level: "\u6682\u4E0D\u652F\u6301\u7684\u5B89\u88C5\u7EA7\u522B: {level}\n\u652F\u6301\u7684\u7EA7\u522B: {levels}",
|
|
86
|
+
error_skill_not_found: "\u672A\u5728\u6CE8\u518C\u8868\u4E2D\u627E\u5230 Skill",
|
|
87
|
+
error_source_not_found: "\u672A\u627E\u5230\u6E90\u6587\u4EF6: {path}",
|
|
88
|
+
error_script_not_found: "\u672A\u627E\u5230\u5B89\u88C5\u811A\u672C: {path}",
|
|
89
|
+
error_unknown: "\u672A\u77E5\u9519\u8BEF",
|
|
90
|
+
error_not_installed: "\u672A\u5B89\u88C5",
|
|
91
|
+
error_symlink_windows: "\u521B\u5EFA\u7B26\u53F7\u94FE\u63A5\u5931\u8D25\uFF0C\u8BF7\u4EE5\u7BA1\u7406\u5458\u8EAB\u4EFD\u8FD0\u884C\u6216\u5F00\u542F Windows \u5F00\u53D1\u8005\u6A21\u5F0F",
|
|
92
|
+
quick_start: "\u542F\u52A8\u547D\u4EE4",
|
|
93
|
+
quick_start_hint: "\u8BD5\u8BD5\u8F93\u5165: \u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50",
|
|
94
|
+
skill_select_category: "\u9009\u62E9 Skill \u7C7B\u522B",
|
|
95
|
+
skill_select_items: "\u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills",
|
|
96
|
+
skill_already_installed: "\u5DF2\u5B89\u88C5",
|
|
97
|
+
skill_select_all: "\u5168\u9009\u6240\u6709 Skills\uFF08\u5171 {count} \u4E2A\uFF09",
|
|
98
|
+
skill_select_all_category: "\u5168\u9009\u5F53\u524D\u7C7B\u522B",
|
|
99
|
+
skill_continue_or_install: "\u5DF2\u9009 {count} \u4E2A Skills\uFF0C\u8BF7\u9009\u62E9\u64CD\u4F5C",
|
|
100
|
+
skill_continue_select: "\u7EE7\u7EED\u9009\u62E9\u5176\u4ED6\u7C7B\u522B",
|
|
101
|
+
skill_confirm_install_count: "\u786E\u8BA4\u5B89\u88C5\uFF08\u5DF2\u9009 {count} \u4E2A Skills\uFF09",
|
|
102
|
+
skill_all_install_progress: "\u6B63\u5728\u5B89\u88C5\u5168\u90E8 {count} \u4E2A Skills...",
|
|
103
|
+
skill_install_progress: "\u6B63\u5728\u5B89\u88C5",
|
|
104
|
+
skill_install_done: "Skill \u5B89\u88C5\u5B8C\u6210",
|
|
105
|
+
skill_uninstall_done: "Skill \u5378\u8F7D\u5B8C\u6210",
|
|
106
|
+
skill_list_title: "\u53EF\u7528 Skills",
|
|
107
|
+
wizard_select_mode: "\u9009\u62E9\u5B89\u88C5\u7C7B\u578B",
|
|
108
|
+
wizard_mode_plugin: "\u5B89\u88C5 Plugin",
|
|
109
|
+
wizard_mode_plugin_desc: "\u5B8C\u6574\u5F00\u53D1\u5DE5\u4F5C\u6D41\uFF08Skills + Agents + \u914D\u7F6E\u6587\u4EF6\uFF09",
|
|
110
|
+
wizard_mode_skill: "\u5B89\u88C5 Skill",
|
|
111
|
+
wizard_mode_skill_desc: "\u4EC5\u5B89\u88C5\u9886\u57DF\u77E5\u8BC6\u6280\u80FD\uFF0C\u8BA9 AI \u638C\u63E1\u7279\u5B9A\u80FD\u529B",
|
|
112
|
+
wizard_back: "\u8FD4\u56DE",
|
|
113
|
+
wizard_cancel: "\u9000\u51FA",
|
|
114
|
+
wizard_no_selection: "\u672A\u9009\u62E9\u4EFB\u4F55\u9879\uFF0C\u8BF7\u9009\u62E9\u64CD\u4F5C",
|
|
115
|
+
wizard_back_to_reselect: "\u8FD4\u56DE",
|
|
116
|
+
status_title: "\u5DF2\u5B89\u88C5\u63D2\u4EF6",
|
|
117
|
+
status_none: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
|
|
118
|
+
status_hint: "\u8FD0\u884C install-helper init \u5F00\u59CB\u5B89\u88C5",
|
|
119
|
+
status_install_time: "\u5B89\u88C5\u65F6\u95F4",
|
|
120
|
+
install_installed_to: "\u5B89\u88C5\u5230",
|
|
121
|
+
install_skills_count: "Skills",
|
|
122
|
+
install_agents_count: "Agents",
|
|
123
|
+
lang_supported: "\u652F\u6301\u7684\u8BED\u8A00: zh_CN, en_US",
|
|
124
|
+
lang_usage: "\u7528\u6CD5: install-helper lang set <language>",
|
|
125
|
+
lang_specify: "\u8BF7\u6307\u5B9A\u8BED\u8A00: install-helper lang set zh_CN",
|
|
126
|
+
lang_unknown_action: "\u672A\u77E5\u64CD\u4F5C",
|
|
127
|
+
lang_supported_actions: "\u652F\u6301\u7684\u64CD\u4F5C: show, set",
|
|
128
|
+
info_aliases: "\u522B\u540D",
|
|
129
|
+
uninstall_not_found: "\u672A\u627E\u5230",
|
|
130
|
+
uninstall_no_record: "\u672A\u627E\u5230\u5B89\u88C5\u8BB0\u5F55\uFF0C\u53EF\u80FD\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
|
|
131
|
+
uninstall_no_record_hint: "\u5982\u9700\u5F3A\u5236\u6E05\u7406\uFF0C\u8BF7\u624B\u52A8\u5220\u9664 .opencode/ \u6216 .claude/ \u76EE\u5F55\u4E2D\u7684\u76F8\u5173\u6587\u4EF6",
|
|
132
|
+
uninstall_in_progress: "\u6B63\u5728\u5378\u8F7D",
|
|
133
|
+
uninstall_removed: "\u5DF2\u5378\u8F7D",
|
|
134
|
+
uninstall_summary_format: "{name}\uFF08\u79FB\u9664 {files} \u4E2A\u6587\u4EF6\uFF0C{dirs} \u4E2A\u76EE\u5F55\uFF09",
|
|
135
|
+
uninstall_files_gone: "\u7684\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728\uFF0C\u5DF2\u6E05\u7406\u5B89\u88C5\u8BB0\u5F55",
|
|
136
|
+
uninstall_skills_in_progress: "\u6B63\u5728\u5378\u8F7D",
|
|
137
|
+
init_pkg_dir_warn: "\u5F53\u524D\u76EE\u5F55\u770B\u8D77\u6765\u662F install-helper \u5305\u76EE\u5F55",
|
|
138
|
+
init_pkg_dir_hint: "\u8BF7\u5728\u4F60\u7684\u9879\u76EE\u76EE\u5F55\u4E2D\u8FD0\u884C\u6B64\u547D\u4EE4\uFF0C\u800C\u4E0D\u662F\u5728 install-helper \u5B89\u88C5\u76EE\u5F55\u4E2D",
|
|
139
|
+
init_pkg_dir_example: "\u793A\u4F8B\uFF1Acd ~/my-project && install-helper",
|
|
140
|
+
init_cancelled: "\u5DF2\u53D6\u6D88\u5B89\u88C5",
|
|
141
|
+
backup_detected: "\u68C0\u6D4B\u5230\u5F53\u524D\u76EE\u5F55\u5DF2\u5B89\u88C5\u63D2\u4EF6",
|
|
142
|
+
backup_current: "\u5F53\u524D\u5B89\u88C5",
|
|
143
|
+
backup_installing: "\u5373\u5C06\u5B89\u88C5",
|
|
144
|
+
backup_overwrite_warning: "\u7EE7\u7EED\u5B89\u88C5\u5C06\u8986\u76D6\u73B0\u6709\u7684 AGENTS.md \u914D\u7F6E\u6587\u4EF6\u3002",
|
|
145
|
+
backup_auto_create: "\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u521B\u5EFA\u5907\u4EFD\uFF0C\u4EE5\u4FBF\u540E\u7EED\u6062\u590D\u3002",
|
|
146
|
+
backup_overwrite: "\u8986\u76D6\u5B89\u88C5\uFF08\u81EA\u52A8\u5907\u4EFD\uFF09",
|
|
147
|
+
backup_cancel: "\u53D6\u6D88\u5B89\u88C5",
|
|
148
|
+
backup_restore_prompt: "\u68C0\u6D4B\u5230\u5907\u4EFD\u914D\u7F6E\uFF0C\u662F\u5426\u6062\u590D\uFF1F",
|
|
149
|
+
backup_restore: "\u6062\u590D",
|
|
150
|
+
backup_only_uninstall: "\u4EC5\u5378\u8F7D\uFF08\u4E0D\u6062\u590D\uFF09",
|
|
151
|
+
backup_select_action: "\u8BF7\u9009\u62E9\u64CD\u4F5C",
|
|
152
|
+
backup_restore_success: "\u5DF2\u6062\u590D\u914D\u7F6E",
|
|
153
|
+
backup_created: "\u5DF2\u521B\u5EFA\u5907\u4EFD",
|
|
154
|
+
backup_failed: "\u5907\u4EFD\u521B\u5EFA\u5931\u8D25\uFF0C\u5B89\u88C5\u5DF2\u4E2D\u6B62\u4EE5\u4FDD\u62A4\u73B0\u6709\u914D\u7F6E",
|
|
155
|
+
loading_skills_list: "\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...",
|
|
156
|
+
loading_skills_list_complete: "Skills \u5217\u8868\u52A0\u8F7D\u5B8C\u6210",
|
|
157
|
+
loading_plugin_data: "\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u6570\u636E...",
|
|
158
|
+
loading_plugin_data_complete: "\u63D2\u4EF6\u6570\u636E\u52A0\u8F7D\u5B8C\u6210",
|
|
159
|
+
loading_skills_list_failed: "Skills \u5217\u8868\u52A0\u8F7D\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u6570\u636E",
|
|
160
|
+
repo_pull_failed: "\u65E0\u6CD5\u62C9\u53D6\u6700\u65B0\u5185\u5BB9\uFF0C\u4F7F\u7528\u7F13\u5B58\u6570\u636E",
|
|
161
|
+
config_corrupted: "\u914D\u7F6E\u6587\u4EF6\u5DF2\u635F\u574F\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E",
|
|
162
|
+
record_corrupted: "\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F\uFF1A{file}",
|
|
163
|
+
skill_record_corrupted: "Skill \u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
|
|
164
|
+
plugin_yaml_error: "\u63D2\u4EF6\u914D\u7F6E\u89E3\u6790\u5931\u8D25\uFF1A{file}",
|
|
165
|
+
record_write_failed: "\u5B89\u88C5\u8BB0\u5F55\u5199\u5165\u5931\u8D25\uFF0C\u5378\u8F7D\u65F6\u53EF\u80FD\u65E0\u6CD5\u81EA\u52A8\u6E05\u7406",
|
|
166
|
+
install_no_skill_selected: "\u672A\u9009\u62E9\u4EFB\u4F55 Skill",
|
|
167
|
+
install_to: "\u5B89\u88C5\u5230",
|
|
168
|
+
start_to_use: "\u542F\u52A8 {tool} \u5373\u53EF\u4F7F\u7528",
|
|
169
|
+
wizard_step_1_title: "[1/4] \u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177",
|
|
170
|
+
wizard_step_2_title: "[2/4] \u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E",
|
|
171
|
+
wizard_step_3_title: "[3/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6",
|
|
172
|
+
wizard_step_4_title: "[4/4] \u786E\u8BA4\u5B89\u88C5",
|
|
173
|
+
wizard_step_3_skill_title: "[3/4] \u9009\u62E9 Skill \u7C7B\u522B",
|
|
174
|
+
wizard_step_4_skill_title: "[4/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills \u2014 {category}",
|
|
175
|
+
install_level_project: "\u5B89\u88C5\u5230\u5F53\u524D\u76EE\u5F55\uFF08\u63A8\u8350\uFF0C\u4EC5\u5F53\u524D\u9879\u76EE\u53EF\u7528\uFF09",
|
|
176
|
+
install_level_global: "\u5B89\u88C5\u5230\u5168\u5C40\uFF08\u6240\u6709\u9879\u76EE\u5171\u4EAB\uFF09",
|
|
177
|
+
wizard_select_mode_title: "\u9009\u62E9\u5B89\u88C5\u7C7B\u578B",
|
|
178
|
+
skill_count_format: "{count} \u4E2A Skills",
|
|
179
|
+
result_success_format: "{count} \u6210\u529F",
|
|
180
|
+
result_failed_format: "{count} \u5931\u8D25",
|
|
181
|
+
uninstall_remove_label: "\u79FB\u9664",
|
|
182
|
+
uninstall_remove_file_format: "\u79FB\u9664 {count} \u4E2A\u6587\u4EF6",
|
|
183
|
+
uninstall_remove_dir_format: "{count} \u4E2A\u76EE\u5F55",
|
|
184
|
+
uninstall_clean_empty_dir: "\u6E05\u7406\u7A7A\u76EE\u5F55",
|
|
185
|
+
uninstall_skill_not_installed: "\u672A\u5B89\u88C5",
|
|
186
|
+
available_plugins: "\u53EF\u7528\u63D2\u4EF6",
|
|
187
|
+
available_skills: "\u53EF\u7528 Skills",
|
|
188
|
+
skill_total_count: "\u5171 {count} \u4E2A Skills",
|
|
189
|
+
wizard_confirm_install_format: "\u5373\u5C06\u5B89\u88C5 {count} \u4E2A\u63D2\u4EF6\u5230 {tool}\uFF08{level} \u7EA7\u522B\uFF09\uFF1A",
|
|
190
|
+
wizard_install_path: "\u5B89\u88C5\u8DEF\u5F84",
|
|
191
|
+
update_install_hint: "\u4F7F\u7528 {cmd} \u5B89\u88C5\u63D2\u4EF6",
|
|
192
|
+
hint_select_move: "\u79FB\u52A8",
|
|
193
|
+
hint_select_space: "\u7A7A\u683C",
|
|
194
|
+
hint_select_check: "\u52FE\u9009",
|
|
195
|
+
hint_select_confirm: "\u786E\u8BA4",
|
|
196
|
+
hint_checkbox_suffix: "\u4E0D\u9009\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE",
|
|
197
|
+
doctor_not_installed: "\u672A\u5B89\u88C5",
|
|
198
|
+
doctor_links_valid: "{count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548",
|
|
199
|
+
doctor_broken_links: "{count} \u4E2A\u5931\u6548\u94FE\u63A5",
|
|
200
|
+
doctor_fixed: "\u5DF2\u6E05\u7406 {count} \u4E2A\u5931\u6548\u94FE\u63A5",
|
|
201
|
+
doctor_not_exist: "\u4E0D\u5B58\u5728",
|
|
202
|
+
doctor_created: "\u5DF2\u521B\u5EFA {path}",
|
|
203
|
+
doctor_config_exists: "\u5B58\u5728",
|
|
204
|
+
doctor_config_not_exist: "\u4E0D\u5B58\u5728",
|
|
205
|
+
doctor_result_with_fix: "{warnings} \u4E2A\u8B66\u544A, {fixes} \u9879\u5DF2\u4FEE\u590D",
|
|
206
|
+
doctor_result_without_fix: "{warnings} \u4E2A\u8B66\u544A",
|
|
207
|
+
count_suffix: "\u4E2A",
|
|
208
|
+
try_prompt: "\u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50"
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// src/locales/en_US.json
|
|
212
|
+
var en_US_default = {
|
|
213
|
+
wizard_title: "CANNBot Install Helper",
|
|
214
|
+
wizard_detect: "Detecting installed AI coding tools...",
|
|
215
|
+
wizard_select_tool: "Select AI coding tool",
|
|
216
|
+
wizard_select_level: "Select install level",
|
|
217
|
+
wizard_select_plugins: "Select scenarios to install",
|
|
218
|
+
wizard_confirm: "Confirm installation",
|
|
219
|
+
wizard_detected_tool: "Detected",
|
|
220
|
+
wizard_confirm_tool: "Confirm using",
|
|
221
|
+
wizard_last_used: "last used",
|
|
222
|
+
wizard_already_installed: "installed",
|
|
223
|
+
install_repo_ready: "Repository ready",
|
|
224
|
+
install_progress: "Installing",
|
|
225
|
+
install_done: "Installation complete",
|
|
226
|
+
install_success: "success",
|
|
227
|
+
install_already_installed: "already installed",
|
|
228
|
+
install_reinstall_confirm: "Reinstall (overwrite)",
|
|
229
|
+
install_skip: "skipped",
|
|
230
|
+
install_enhanced_next_steps: "Next steps",
|
|
231
|
+
install_enhanced_launch: "Launch",
|
|
232
|
+
install_enhanced_try: "Try",
|
|
233
|
+
install_enhanced_more: "More",
|
|
234
|
+
install_enhanced_check: "Check",
|
|
235
|
+
install_enhanced_docs: "Docs",
|
|
236
|
+
update_updating: "Updating",
|
|
237
|
+
update_done: "Update complete",
|
|
238
|
+
update_no_plugins: "No installed plugins",
|
|
239
|
+
doctor_title: "CANNBot Doctor",
|
|
240
|
+
doctor_tools: "AI Tools",
|
|
241
|
+
doctor_plugins: "Installed Plugins",
|
|
242
|
+
doctor_links: "Link Integrity",
|
|
243
|
+
doctor_config: "Configuration",
|
|
244
|
+
doctor_result: "Result",
|
|
245
|
+
doctor_fix_cleaning: "Cleaning broken links",
|
|
246
|
+
doctor_fix_rebuilding: "Rebuilding directories",
|
|
247
|
+
info_description: "Description",
|
|
248
|
+
info_skills: "Skills",
|
|
249
|
+
info_agents: "Agents",
|
|
250
|
+
info_status: "Status",
|
|
251
|
+
info_quickstart: "Quick Start",
|
|
252
|
+
info_not_found: "Plugin not found",
|
|
253
|
+
lang_title: "Language Settings",
|
|
254
|
+
lang_current: "Current language",
|
|
255
|
+
lang_set: "Language set to",
|
|
256
|
+
lang_invalid: "Invalid language, supported: zh_CN, en_US",
|
|
257
|
+
list_title: "Available Scenarios",
|
|
258
|
+
list_id: "#",
|
|
259
|
+
list_name: "Name",
|
|
260
|
+
list_status: "Status",
|
|
261
|
+
list_description: "Description",
|
|
262
|
+
status_installed: "installed",
|
|
263
|
+
status_not_installed: "not installed",
|
|
264
|
+
error_tool_not_found: "No AI coding tool detected",
|
|
265
|
+
error_plugin_not_found: "Plugin not found",
|
|
266
|
+
error_invalid_tool: "Unsupported AI tool: {tool}\nSupported tools: {tools}",
|
|
267
|
+
error_invalid_level: "Unsupported install level: {level}\nSupported levels: {levels}",
|
|
268
|
+
error_skill_not_found: "Skill not found in registry",
|
|
269
|
+
error_source_not_found: "Source not found: {path}",
|
|
270
|
+
error_script_not_found: "Script not found: {path}",
|
|
271
|
+
error_unknown: "Unknown error",
|
|
272
|
+
error_not_installed: "Not installed",
|
|
273
|
+
error_symlink_windows: "Failed to create symlink, please run as administrator or enable Windows Developer Mode",
|
|
274
|
+
quick_start: "Launch command",
|
|
275
|
+
quick_start_hint: "Try: help me develop an Abs operator",
|
|
276
|
+
skill_select_category: "Select Skill category",
|
|
277
|
+
skill_select_items: "Select Skills to install (space to toggle, enter to confirm)",
|
|
278
|
+
skill_already_installed: "installed",
|
|
279
|
+
skill_select_all: "Select ALL Skills ({count} total)",
|
|
280
|
+
skill_select_all_category: "Select all in this category",
|
|
281
|
+
skill_continue_or_install: "{count} Skills selected, choose an action",
|
|
282
|
+
skill_continue_select: "Continue selecting from other categories",
|
|
283
|
+
skill_confirm_install_count: "Install now ({count} Skills selected)",
|
|
284
|
+
skill_all_install_progress: "Installing all {count} Skills...",
|
|
285
|
+
skill_install_progress: "Installing",
|
|
286
|
+
skill_install_done: "Skill installation complete",
|
|
287
|
+
skill_uninstall_done: "Skill uninstallation complete",
|
|
288
|
+
skill_list_title: "Available Skills",
|
|
289
|
+
wizard_select_mode: "Select installation mode",
|
|
290
|
+
wizard_mode_plugin: "Install Plugin",
|
|
291
|
+
wizard_mode_plugin_desc: "Full development workflow (Skills + Agents + config)",
|
|
292
|
+
wizard_mode_skill: "Install Skill",
|
|
293
|
+
wizard_mode_skill_desc: "Domain knowledge only, give AI specific capabilities",
|
|
294
|
+
wizard_back: "Go back",
|
|
295
|
+
wizard_cancel: "Cancel installation",
|
|
296
|
+
wizard_no_selection: "No items selected, please choose an action",
|
|
297
|
+
wizard_back_to_reselect: "Go back",
|
|
298
|
+
status_title: "Installed Plugins",
|
|
299
|
+
status_none: "No installed plugins",
|
|
300
|
+
status_hint: "Run install-helper init to start",
|
|
301
|
+
status_install_time: "Installed at",
|
|
302
|
+
install_installed_to: "Installed to",
|
|
303
|
+
install_skills_count: "Skills",
|
|
304
|
+
install_agents_count: "Agents",
|
|
305
|
+
lang_supported: "Supported languages: zh_CN, en_US",
|
|
306
|
+
lang_usage: "Usage: install-helper lang set <language>",
|
|
307
|
+
lang_specify: "Please specify language: install-helper lang set zh_CN",
|
|
308
|
+
lang_unknown_action: "Unknown action",
|
|
309
|
+
lang_supported_actions: "Supported actions: show, set",
|
|
310
|
+
info_aliases: "Aliases",
|
|
311
|
+
uninstall_not_found: "Not found",
|
|
312
|
+
uninstall_no_record: "No install record found, may not be installed or record is corrupted",
|
|
313
|
+
uninstall_no_record_hint: "For manual cleanup, delete related files in .opencode/ or .claude/ directory",
|
|
314
|
+
uninstall_in_progress: "Uninstalling",
|
|
315
|
+
uninstall_removed: "Uninstalled",
|
|
316
|
+
uninstall_summary_format: "{name} (removed {files} files, {dirs} directories)",
|
|
317
|
+
uninstall_files_gone: " files no longer exist, install record cleaned",
|
|
318
|
+
uninstall_skills_in_progress: "Uninstalling",
|
|
319
|
+
init_pkg_dir_warn: "Current directory appears to be the install-helper package directory",
|
|
320
|
+
init_pkg_dir_hint: "Please run this command in your project directory, not in the install-helper package directory",
|
|
321
|
+
init_pkg_dir_example: "Example: cd ~/my-project && install-helper",
|
|
322
|
+
init_cancelled: "Installation cancelled",
|
|
323
|
+
backup_detected: "Plugin already installed in current directory",
|
|
324
|
+
backup_current: "Currently installed",
|
|
325
|
+
backup_installing: "About to install",
|
|
326
|
+
backup_overwrite_warning: "Continuing will overwrite existing AGENTS.md configuration.",
|
|
327
|
+
backup_auto_create: "System will automatically create backup for future restoration.",
|
|
328
|
+
backup_overwrite: "Overwrite (auto backup)",
|
|
329
|
+
backup_cancel: "Cancel installation",
|
|
330
|
+
backup_restore_prompt: "Backup configuration detected, restore?",
|
|
331
|
+
backup_restore: "Restore",
|
|
332
|
+
backup_only_uninstall: "Uninstall only (no restore)",
|
|
333
|
+
backup_select_action: "Please select an action",
|
|
334
|
+
backup_restore_success: "Configuration restored",
|
|
335
|
+
backup_created: "Backup created",
|
|
336
|
+
backup_failed: "Backup creation failed, installation aborted to protect existing config",
|
|
337
|
+
loading_skills_list: "Loading Skills list...",
|
|
338
|
+
loading_skills_list_complete: "Skills list loaded",
|
|
339
|
+
loading_plugin_data: "Loading plugin data...",
|
|
340
|
+
loading_plugin_data_complete: "Plugin data loaded",
|
|
341
|
+
loading_skills_list_failed: "Failed to load Skills list, using built-in data",
|
|
342
|
+
repo_pull_failed: "Failed to pull latest updates, using cached data",
|
|
343
|
+
config_corrupted: "Config file corrupted, using defaults",
|
|
344
|
+
record_corrupted: "Install record corrupted: {file}",
|
|
345
|
+
skill_record_corrupted: "Skill install record corrupted",
|
|
346
|
+
plugin_yaml_error: "Plugin config parse error: {file}",
|
|
347
|
+
record_write_failed: "Install record write failed, uninstall may not work properly",
|
|
348
|
+
install_no_skill_selected: "No Skill selected",
|
|
349
|
+
install_to: "Install to",
|
|
350
|
+
start_to_use: "Start {tool} to use",
|
|
351
|
+
wizard_step_1_title: "[1/4] Select AI coding tool",
|
|
352
|
+
wizard_step_2_title: "[2/4] Select installation location",
|
|
353
|
+
wizard_step_3_title: "[3/4] Select plugins to install",
|
|
354
|
+
wizard_step_4_title: "[4/4] Confirm installation",
|
|
355
|
+
wizard_step_3_skill_title: "[3/4] Select Skill category",
|
|
356
|
+
wizard_step_4_skill_title: "[4/4] Select Skills to install \u2014 {category}",
|
|
357
|
+
install_level_project: "Install to current directory (recommended, current project only)",
|
|
358
|
+
install_level_global: "Install globally (all projects)",
|
|
359
|
+
wizard_select_mode_title: "Select installation type",
|
|
360
|
+
skill_count_format: "{count} Skills",
|
|
361
|
+
result_success_format: "{count} succeeded",
|
|
362
|
+
result_failed_format: "{count} failed",
|
|
363
|
+
uninstall_remove_label: "Removed",
|
|
364
|
+
uninstall_remove_file_format: "Removed {count} files",
|
|
365
|
+
uninstall_remove_dir_format: "{count} directories",
|
|
366
|
+
uninstall_clean_empty_dir: "Cleaned empty directory",
|
|
367
|
+
uninstall_skill_not_installed: "Not installed",
|
|
368
|
+
available_plugins: "Available plugins",
|
|
369
|
+
available_skills: "Available Skills",
|
|
370
|
+
skill_total_count: "Total {count} Skills",
|
|
371
|
+
wizard_confirm_install_format: "About to install {count} plugins to {tool} ({level} level):",
|
|
372
|
+
wizard_install_path: "Install path",
|
|
373
|
+
update_install_hint: "Use {cmd} to install plugins",
|
|
374
|
+
hint_select_move: "Navigate",
|
|
375
|
+
hint_select_space: "Space",
|
|
376
|
+
hint_select_check: "Toggle",
|
|
377
|
+
hint_select_confirm: "Confirm",
|
|
378
|
+
hint_checkbox_suffix: "Press enter without selection to go back",
|
|
379
|
+
doctor_not_installed: "Not installed",
|
|
380
|
+
doctor_links_valid: "{count} symlinks all valid",
|
|
381
|
+
doctor_broken_links: "{count} broken links",
|
|
382
|
+
doctor_fixed: "Cleaned {count} broken links",
|
|
383
|
+
doctor_not_exist: "Does not exist",
|
|
384
|
+
doctor_created: "Created {path}",
|
|
385
|
+
doctor_config_exists: "Exists",
|
|
386
|
+
doctor_config_not_exist: "Does not exist",
|
|
387
|
+
doctor_result_with_fix: "{warnings} warnings, {fixes} fixed",
|
|
388
|
+
doctor_result_without_fix: "{warnings} warnings",
|
|
389
|
+
count_suffix: "",
|
|
390
|
+
try_prompt: "help me develop an Abs operator"
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/utils/i18n.ts
|
|
28
394
|
var __filename = fileURLToPath(import.meta.url);
|
|
29
395
|
var __dirname = dirname(__filename);
|
|
396
|
+
var EMBEDDED_LOCALES = {
|
|
397
|
+
zh_CN: zh_CN_default,
|
|
398
|
+
en_US: en_US_default
|
|
399
|
+
};
|
|
30
400
|
function loadLocale(locale) {
|
|
401
|
+
const embedded = EMBEDDED_LOCALES[locale];
|
|
402
|
+
if (embedded) return embedded;
|
|
31
403
|
const localePath = join(__dirname, "locales", `${locale}.json`);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
404
|
+
if (existsSync(localePath)) {
|
|
405
|
+
try {
|
|
406
|
+
const content = readFileSync(localePath, "utf-8");
|
|
407
|
+
return JSON.parse(content);
|
|
408
|
+
} catch {
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const fallbackPath = join(__dirname, "locales", "zh_CN.json");
|
|
412
|
+
if (existsSync(fallbackPath)) {
|
|
37
413
|
try {
|
|
38
414
|
const content = readFileSync(fallbackPath, "utf-8");
|
|
39
415
|
return JSON.parse(content);
|
|
40
416
|
} catch {
|
|
41
|
-
return {};
|
|
42
417
|
}
|
|
43
418
|
}
|
|
419
|
+
return EMBEDDED_LOCALES.zh_CN || {};
|
|
44
420
|
}
|
|
45
421
|
var currentLang = "zh_CN";
|
|
46
422
|
var messages = loadLocale("zh_CN");
|
|
@@ -192,6 +568,143 @@ function isDirectory(path) {
|
|
|
192
568
|
}
|
|
193
569
|
}
|
|
194
570
|
|
|
571
|
+
// src/embedded-plugins.json
|
|
572
|
+
var embedded_plugins_default = [
|
|
573
|
+
{
|
|
574
|
+
id: "ops-direct-invoke",
|
|
575
|
+
dir: "plugins-official/ops-direct-invoke",
|
|
576
|
+
displayName: "AscendC Kernel \u76F4\u8C03",
|
|
577
|
+
script: "init.sh",
|
|
578
|
+
aliases: [
|
|
579
|
+
"ops-direct",
|
|
580
|
+
"ascendc-direct",
|
|
581
|
+
"direct",
|
|
582
|
+
"kernel"
|
|
583
|
+
],
|
|
584
|
+
skills: 16,
|
|
585
|
+
agents: 3,
|
|
586
|
+
description: "Ascend C \u76F4\u8C03\u5168\u6D41\u7A0B\uFF1A\u73AF\u5883\u2192\u8BBE\u8BA1\u2192\u5F00\u53D1\u2192\u5BA1\u67E5\u2192\u6027\u80FD\u9A8C\u6536"
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
id: "ops-direct-invoke-flash",
|
|
590
|
+
dir: "plugins-official/ops-direct-invoke-flash",
|
|
591
|
+
displayName: "AscendC Kernel \u76F4\u8C03\uFF08\u5FEB\u901F\u7248\uFF09",
|
|
592
|
+
script: "init.sh",
|
|
593
|
+
aliases: [
|
|
594
|
+
"flash",
|
|
595
|
+
"kernel-flash"
|
|
596
|
+
],
|
|
597
|
+
skills: 1,
|
|
598
|
+
agents: 1,
|
|
599
|
+
description: "\u4ECE\u6570\u5B66\u516C\u5F0F\u6216\u4EE3\u7801\u7247\u6BB5\u5FEB\u901F\u6784\u5EFA\u5E76\u9A8C\u8BC1 Ascend NPU \u6838\u51FD\u6570"
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
id: "ops-registry-invoke",
|
|
603
|
+
dir: "plugins-official/ops-registry-invoke",
|
|
604
|
+
displayName: "AscendC \u7B97\u5B50\u6CE8\u518C\u8C03\u7528",
|
|
605
|
+
script: "init.sh",
|
|
606
|
+
aliases: [
|
|
607
|
+
"ops-registry",
|
|
608
|
+
"ascendc-registry",
|
|
609
|
+
"registry"
|
|
610
|
+
],
|
|
611
|
+
skills: 12,
|
|
612
|
+
agents: 4,
|
|
613
|
+
description: "\u751F\u4EA7\u7EA7 ACLNN \u6CE8\u518C\u7B97\u5B50\u5168\u6D41\u7A0B\uFF1A\u4EE3\u7801\u2192UT/ST\u2192\u4E0A\u5E93"
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
id: "catlass-op-generator",
|
|
617
|
+
dir: "plugins-official/catlass-op-generator",
|
|
618
|
+
displayName: "Catlass \u7B97\u5B50\u76F4\u8C03",
|
|
619
|
+
script: "init.sh",
|
|
620
|
+
aliases: [
|
|
621
|
+
"catlass"
|
|
622
|
+
],
|
|
623
|
+
skills: 10,
|
|
624
|
+
agents: 3,
|
|
625
|
+
description: "Catlass \u6A21\u677F\u62FC\u88C5 GEMM/Matmul/Epilogue \u7B97\u5B50\u5F00\u53D1"
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
id: "model-infer-optimize",
|
|
629
|
+
dir: "plugins-official/model-infer-optimize",
|
|
630
|
+
displayName: "NPU \u63A8\u7406\u4F18\u5316",
|
|
631
|
+
script: "init.sh",
|
|
632
|
+
aliases: [
|
|
633
|
+
"model-infer",
|
|
634
|
+
"infer",
|
|
635
|
+
"inference"
|
|
636
|
+
],
|
|
637
|
+
skills: 11,
|
|
638
|
+
agents: 3,
|
|
639
|
+
description: "NPU \u6A21\u578B\u63A8\u7406\u7AEF\u5230\u7AEF\u4F18\u5316\uFF08\u5E76\u884C/KVCache/\u878D\u5408/\u91CF\u5316/\u56FE\u6A21\u5F0F/\u591A\u6D41/SuperKernel\uFF09"
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
id: "pypto-op-orchestrator",
|
|
643
|
+
dir: "plugins-official/pypto-op-orchestrator",
|
|
644
|
+
displayName: "PyPTO \u7B97\u5B50\u5F00\u53D1",
|
|
645
|
+
script: "init.sh",
|
|
646
|
+
aliases: [
|
|
647
|
+
"pypto",
|
|
648
|
+
"pytorch"
|
|
649
|
+
],
|
|
650
|
+
skills: 8,
|
|
651
|
+
agents: 3,
|
|
652
|
+
description: "PyPTO Python API \u7B97\u5B50\u5168\u6D41\u7A0B\u5F00\u53D1\uFF0C\u8986\u76D6\u9700\u6C42\u7406\u89E3\u3001API \u63A2\u7D22\u3001\u5B9E\u73B0\u4E0E\u8C03\u4F18"
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
id: "tilelang-op-orchestrator",
|
|
656
|
+
dir: "plugins-official/tilelang-op-orchestrator",
|
|
657
|
+
displayName: "TileLang \u7B97\u5B50\u5F00\u53D1",
|
|
658
|
+
script: "init.sh",
|
|
659
|
+
aliases: [
|
|
660
|
+
"tilelang"
|
|
661
|
+
],
|
|
662
|
+
skills: 9,
|
|
663
|
+
agents: 3,
|
|
664
|
+
description: "TileLang Python DSL + @tilelang.jit \u7B97\u5B50\u5F00\u53D1\uFF08\u652F\u6301 Developer/Expert \u53CC\u6A21\u5F0F\uFF09"
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
id: "triton-op-generator",
|
|
668
|
+
dir: "plugins-official/triton-op-generator",
|
|
669
|
+
displayName: "Triton \u7B97\u5B50\u5F00\u53D1",
|
|
670
|
+
script: "init.sh",
|
|
671
|
+
aliases: [
|
|
672
|
+
"triton"
|
|
673
|
+
],
|
|
674
|
+
skills: 6,
|
|
675
|
+
agents: 1,
|
|
676
|
+
description: "Triton-Ascend \u7B97\u5B50 6 \u9636\u6BB5\u81EA\u52A8\u751F\u6210\u4E0E\u4F18\u5316\uFF08\u63CF\u8FF0\u2192\u4EE3\u7801\u2192\u9A8C\u8BC1\u2192\u4F18\u5316\uFF09"
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
id: "torch-compile",
|
|
680
|
+
dir: "plugins-official/torch-compile",
|
|
681
|
+
displayName: "torch.compile \u56FE\u6A21\u5F0F",
|
|
682
|
+
script: "init.sh",
|
|
683
|
+
aliases: [
|
|
684
|
+
"torch",
|
|
685
|
+
"compile",
|
|
686
|
+
"graph"
|
|
687
|
+
],
|
|
688
|
+
skills: 6,
|
|
689
|
+
agents: 1,
|
|
690
|
+
description: "NPU \u56FE\u6A21\u5F0F npugraph_ex \u914D\u7F6E\u3001\u811A\u672C\u8FC1\u79FB\u3001\u7F16\u8BD1\u8BCA\u65AD\u4E0E\u81EA\u5B9A\u4E49\u7B97\u5B50\u5165\u56FE"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
id: "ops-code-reviewer",
|
|
694
|
+
dir: "plugins-official/ops-code-reviewer",
|
|
695
|
+
displayName: "\u4EE3\u7801\u68C0\u89C6",
|
|
696
|
+
script: "init.sh",
|
|
697
|
+
aliases: [
|
|
698
|
+
"code-review",
|
|
699
|
+
"reviewer",
|
|
700
|
+
"review"
|
|
701
|
+
],
|
|
702
|
+
skills: 5,
|
|
703
|
+
agents: 1,
|
|
704
|
+
description: "Ascend C \u7B97\u5B50\u4EE3\u7801 4 \u9636\u6BB5\u5168\u91CF\u68C0\u89C6\uFF08\u4E3B Agent \u7F16\u6392 + \u5B50 Agent \u5E76\u884C\u68C0\u89C6\uFF09"
|
|
705
|
+
}
|
|
706
|
+
];
|
|
707
|
+
|
|
195
708
|
// src/core/registry.ts
|
|
196
709
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
197
710
|
var __dirname2 = dirname2(__filename2);
|
|
@@ -202,7 +715,7 @@ function findPluginsDir() {
|
|
|
202
715
|
join2(__dirname2, "..", "..", "plugins.d")
|
|
203
716
|
];
|
|
204
717
|
for (const dir of candidates) {
|
|
205
|
-
if (
|
|
718
|
+
if (existsSync2(dir)) return dir;
|
|
206
719
|
}
|
|
207
720
|
return candidates[0];
|
|
208
721
|
}
|
|
@@ -237,6 +750,9 @@ function loadPluginsFromYaml() {
|
|
|
237
750
|
}
|
|
238
751
|
} catch {
|
|
239
752
|
}
|
|
753
|
+
if (plugins.length === 0) {
|
|
754
|
+
return [...embedded_plugins_default];
|
|
755
|
+
}
|
|
240
756
|
plugins.sort(
|
|
241
757
|
(a, b) => a.displayName < b.displayName ? -1 : a.displayName > b.displayName ? 1 : 0
|
|
242
758
|
);
|
|
@@ -245,12 +761,12 @@ function loadPluginsFromYaml() {
|
|
|
245
761
|
var PLUGIN_REGISTRY = loadPluginsFromYaml();
|
|
246
762
|
var PLUGIN_DIRS = ["plugins-official", "plugins-community"];
|
|
247
763
|
function mergeDynamicPlugins(repoPath) {
|
|
248
|
-
if (!
|
|
764
|
+
if (!existsSync2(repoPath)) return;
|
|
249
765
|
const existingIds = new Set(PLUGIN_REGISTRY.map((p) => p.id));
|
|
250
766
|
const dynamic = [];
|
|
251
767
|
for (const pluginDir of PLUGIN_DIRS) {
|
|
252
768
|
const parent = join2(repoPath, pluginDir);
|
|
253
|
-
if (!
|
|
769
|
+
if (!existsSync2(parent)) continue;
|
|
254
770
|
let entries = [];
|
|
255
771
|
try {
|
|
256
772
|
entries = readdirSync(parent);
|
|
@@ -262,7 +778,7 @@ function mergeDynamicPlugins(repoPath) {
|
|
|
262
778
|
if (!isDirectory(pluginPath)) continue;
|
|
263
779
|
if (entry === "install-helper") continue;
|
|
264
780
|
const initSh = join2(pluginPath, "init.sh");
|
|
265
|
-
if (!
|
|
781
|
+
if (!existsSync2(initSh)) continue;
|
|
266
782
|
const pluginId = entry;
|
|
267
783
|
if (existingIds.has(pluginId)) continue;
|
|
268
784
|
dynamic.push({
|
|
@@ -307,14 +823,14 @@ function getPluginById(id) {
|
|
|
307
823
|
|
|
308
824
|
// src/core/detector.ts
|
|
309
825
|
import { execa } from "execa";
|
|
310
|
-
import { existsSync as
|
|
826
|
+
import { existsSync as existsSync4 } from "fs";
|
|
311
827
|
import { homedir as homedir2 } from "os";
|
|
312
828
|
import { join as join4 } from "path";
|
|
313
829
|
|
|
314
830
|
// src/utils/paths.ts
|
|
315
831
|
import { homedir } from "os";
|
|
316
832
|
import { join as join3 } from "path";
|
|
317
|
-
import { existsSync as
|
|
833
|
+
import { existsSync as existsSync3 } from "fs";
|
|
318
834
|
var VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
319
835
|
var VALID_LEVELS = ["project", "global"];
|
|
320
836
|
function validateTool(tool) {
|
|
@@ -335,9 +851,9 @@ function validateLevel(level) {
|
|
|
335
851
|
}
|
|
336
852
|
function detectTraeVariant() {
|
|
337
853
|
const home = homedir();
|
|
338
|
-
if (
|
|
339
|
-
if (
|
|
340
|
-
if (
|
|
854
|
+
if (existsSync3(join3(home, ".trae-cn"))) return "ide";
|
|
855
|
+
if (existsSync3(join3(home, ".marscode"))) return "plugin";
|
|
856
|
+
if (existsSync3(join3(home, ".traecli"))) return "cli";
|
|
341
857
|
return "unknown";
|
|
342
858
|
}
|
|
343
859
|
function getConfigRoot(tool, level, base) {
|
|
@@ -454,11 +970,11 @@ async function detectTrae() {
|
|
|
454
970
|
const home = homedir2();
|
|
455
971
|
const variant = detectTraeVariant();
|
|
456
972
|
let path;
|
|
457
|
-
if (variant === "ide" &&
|
|
973
|
+
if (variant === "ide" && existsSync4(join4(home, ".trae-cn"))) {
|
|
458
974
|
path = join4(home, ".trae-cn");
|
|
459
|
-
} else if (variant === "plugin" &&
|
|
975
|
+
} else if (variant === "plugin" && existsSync4(join4(home, ".marscode"))) {
|
|
460
976
|
path = join4(home, ".marscode");
|
|
461
|
-
} else if (variant === "cli" &&
|
|
977
|
+
} else if (variant === "cli" && existsSync4(join4(home, ".traecli"))) {
|
|
462
978
|
path = join4(home, ".traecli");
|
|
463
979
|
} else if (variant === "unknown") {
|
|
464
980
|
const cmdPath = await getCommandPath("trae");
|
|
@@ -475,7 +991,7 @@ async function detectCursor() {
|
|
|
475
991
|
}
|
|
476
992
|
if (process.platform === "darwin") {
|
|
477
993
|
const appPath = "/Applications/Cursor.app";
|
|
478
|
-
if (
|
|
994
|
+
if (existsSync4(appPath)) {
|
|
479
995
|
return { name: "cursor", path: appPath };
|
|
480
996
|
}
|
|
481
997
|
}
|
|
@@ -523,11 +1039,11 @@ function getAllTools() {
|
|
|
523
1039
|
}
|
|
524
1040
|
|
|
525
1041
|
// src/core/manifest.ts
|
|
526
|
-
import { existsSync as
|
|
1042
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
527
1043
|
import { join as join5 } from "path";
|
|
528
1044
|
function readManifest(configRoot) {
|
|
529
1045
|
const manifestPath = getManifestPath(configRoot);
|
|
530
|
-
if (
|
|
1046
|
+
if (existsSync5(manifestPath)) {
|
|
531
1047
|
try {
|
|
532
1048
|
const content = readFileSync3(manifestPath, "utf-8");
|
|
533
1049
|
return JSON.parse(content);
|
|
@@ -540,7 +1056,7 @@ function readAllManifests(configRoot) {
|
|
|
540
1056
|
const manifests = [];
|
|
541
1057
|
const plugins = getAllPlugins();
|
|
542
1058
|
const standardPath = getManifestPath(configRoot);
|
|
543
|
-
if (
|
|
1059
|
+
if (existsSync5(standardPath)) {
|
|
544
1060
|
try {
|
|
545
1061
|
const content = readFileSync3(standardPath, "utf-8");
|
|
546
1062
|
manifests.push(JSON.parse(content));
|
|
@@ -549,7 +1065,7 @@ function readAllManifests(configRoot) {
|
|
|
549
1065
|
}
|
|
550
1066
|
for (const plugin of plugins) {
|
|
551
1067
|
const pluginManifestPath = join5(configRoot, `${plugin.id}-manifest.json`);
|
|
552
|
-
if (
|
|
1068
|
+
if (existsSync5(pluginManifestPath)) {
|
|
553
1069
|
try {
|
|
554
1070
|
const content = readFileSync3(pluginManifestPath, "utf-8");
|
|
555
1071
|
manifests.push(JSON.parse(content));
|
|
@@ -599,14 +1115,14 @@ function verifyPluginFilesExist(configRoot, manifest, tool, level) {
|
|
|
599
1115
|
if (manifest.installed_skills && manifest.installed_skills.length > 0) {
|
|
600
1116
|
const hasAnySkill = manifest.installed_skills.some((skillId) => {
|
|
601
1117
|
const skillPath = join5(skillsDir, skillId);
|
|
602
|
-
return
|
|
1118
|
+
return existsSync5(skillPath);
|
|
603
1119
|
});
|
|
604
1120
|
if (!hasAnySkill) return false;
|
|
605
1121
|
}
|
|
606
1122
|
if (manifest.installed_agents && manifest.installed_agents.length > 0) {
|
|
607
1123
|
const hasAnyAgent = manifest.installed_agents.some((agentId) => {
|
|
608
1124
|
const agentPath = join5(agentsDir, agentId);
|
|
609
|
-
return
|
|
1125
|
+
return existsSync5(agentPath);
|
|
610
1126
|
});
|
|
611
1127
|
if (!hasAnyAgent) return false;
|
|
612
1128
|
}
|
|
@@ -616,26 +1132,26 @@ function verifyPluginFilesExist(configRoot, manifest, tool, level) {
|
|
|
616
1132
|
} else {
|
|
617
1133
|
agentsMdPath = join5(configRoot, "AGENTS.md");
|
|
618
1134
|
}
|
|
619
|
-
if (!
|
|
1135
|
+
if (!existsSync5(agentsMdPath)) return false;
|
|
620
1136
|
return true;
|
|
621
1137
|
}
|
|
622
1138
|
|
|
623
1139
|
// src/utils/config.ts
|
|
624
|
-
import { existsSync as
|
|
1140
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync4 } from "fs";
|
|
625
1141
|
import { join as join6 } from "path";
|
|
626
1142
|
import { parse, stringify } from "yaml";
|
|
627
1143
|
|
|
628
1144
|
// src/utils/fs.ts
|
|
629
|
-
import { writeFileSync, renameSync, existsSync as
|
|
1145
|
+
import { writeFileSync, renameSync, existsSync as existsSync6, unlinkSync } from "fs";
|
|
630
1146
|
import { dirname as dirname3 } from "path";
|
|
631
1147
|
function atomicWriteFileSync(filePath, data, encoding = "utf-8") {
|
|
632
1148
|
const dir = dirname3(filePath);
|
|
633
|
-
if (!
|
|
1149
|
+
if (!existsSync6(dir)) {
|
|
634
1150
|
throw new Error(`Directory does not exist: ${dir}`);
|
|
635
1151
|
}
|
|
636
1152
|
const tmpPath = `${filePath}.tmp`;
|
|
637
1153
|
writeFileSync(tmpPath, data, encoding);
|
|
638
|
-
if (
|
|
1154
|
+
if (existsSync6(filePath)) {
|
|
639
1155
|
try {
|
|
640
1156
|
unlinkSync(filePath);
|
|
641
1157
|
} catch {
|
|
@@ -653,7 +1169,7 @@ function getConfigPath() {
|
|
|
653
1169
|
}
|
|
654
1170
|
function readConfig() {
|
|
655
1171
|
const configPath = getConfigPath();
|
|
656
|
-
if (!
|
|
1172
|
+
if (!existsSync7(configPath)) {
|
|
657
1173
|
return {
|
|
658
1174
|
language: "zh_CN",
|
|
659
1175
|
installedPlugins: []
|
|
@@ -679,7 +1195,7 @@ function readConfig() {
|
|
|
679
1195
|
}
|
|
680
1196
|
function writeConfig(config) {
|
|
681
1197
|
const configDir = getConfigDir();
|
|
682
|
-
if (!
|
|
1198
|
+
if (!existsSync7(configDir)) {
|
|
683
1199
|
mkdirSync(configDir, { recursive: true });
|
|
684
1200
|
}
|
|
685
1201
|
const configPath = getConfigPath();
|
|
@@ -957,14 +1473,14 @@ async function stepConfirm(tool, level, plugins) {
|
|
|
957
1473
|
}
|
|
958
1474
|
|
|
959
1475
|
// src/core/repository.ts
|
|
960
|
-
import { existsSync as
|
|
1476
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
|
|
961
1477
|
import { join as join8, dirname as dirname5 } from "path";
|
|
962
1478
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
963
1479
|
import { execa as execa2 } from "execa";
|
|
964
1480
|
import { parse as parseYaml3 } from "yaml";
|
|
965
1481
|
|
|
966
1482
|
// src/core/scanner.ts
|
|
967
|
-
import { existsSync as
|
|
1483
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
968
1484
|
import { join as join7, dirname as dirname4 } from "path";
|
|
969
1485
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
970
1486
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -1016,26 +1532,26 @@ function scanSkills(repoPath) {
|
|
|
1016
1532
|
const seen = /* @__PURE__ */ new Set();
|
|
1017
1533
|
for (const dir of SKILL_SCAN_DIRS) {
|
|
1018
1534
|
const fullPath = join7(repoPath, dir);
|
|
1019
|
-
if (!
|
|
1535
|
+
if (!existsSync8(fullPath)) continue;
|
|
1020
1536
|
scanDirectory(fullPath, repoPath, dir, skills, seen);
|
|
1021
1537
|
}
|
|
1022
1538
|
for (const pluginDir of PLUGIN_SCAN_DIRS) {
|
|
1023
1539
|
const pluginParent = join7(repoPath, pluginDir);
|
|
1024
|
-
if (!
|
|
1540
|
+
if (!existsSync8(pluginParent)) continue;
|
|
1025
1541
|
for (const plugin of safeReaddir(pluginParent)) {
|
|
1026
1542
|
const pluginPath = join7(pluginParent, plugin);
|
|
1027
1543
|
if (!isDirectory(pluginPath)) continue;
|
|
1028
1544
|
const skillsDir = join7(pluginPath, "skills");
|
|
1029
|
-
if (
|
|
1545
|
+
if (existsSync8(skillsDir)) {
|
|
1030
1546
|
scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
|
|
1031
1547
|
}
|
|
1032
1548
|
const skillDir = join7(pluginPath, "skill");
|
|
1033
|
-
if (
|
|
1549
|
+
if (existsSync8(skillDir)) {
|
|
1034
1550
|
scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
|
|
1035
1551
|
}
|
|
1036
1552
|
const rootSkillMd = join7(pluginPath, "SKILL.md");
|
|
1037
1553
|
const initSh = join7(pluginPath, "init.sh");
|
|
1038
|
-
if (
|
|
1554
|
+
if (existsSync8(rootSkillMd) && !existsSync8(initSh)) {
|
|
1039
1555
|
const frontmatter = parseFrontmatter(rootSkillMd);
|
|
1040
1556
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
1041
1557
|
seen.add(frontmatter.name);
|
|
@@ -1084,15 +1600,15 @@ function parseFrontmatter(filePath) {
|
|
|
1084
1600
|
function getCurrentCommit(repoPath) {
|
|
1085
1601
|
try {
|
|
1086
1602
|
const headFile = join7(repoPath, ".git", "HEAD");
|
|
1087
|
-
if (!
|
|
1603
|
+
if (!existsSync8(headFile)) return "unknown";
|
|
1088
1604
|
const headContent = readFileSync5(headFile, "utf-8").trim();
|
|
1089
1605
|
if (headContent.startsWith("ref: ")) {
|
|
1090
1606
|
const refPath = join7(repoPath, ".git", headContent.slice(5));
|
|
1091
|
-
if (
|
|
1607
|
+
if (existsSync8(refPath)) {
|
|
1092
1608
|
return readFileSync5(refPath, "utf-8").trim();
|
|
1093
1609
|
}
|
|
1094
1610
|
const packedRefsPath = join7(repoPath, ".git", "packed-refs");
|
|
1095
|
-
if (
|
|
1611
|
+
if (existsSync8(packedRefsPath)) {
|
|
1096
1612
|
const packedRefs = readFileSync5(packedRefsPath, "utf-8");
|
|
1097
1613
|
const refName = headContent.slice(5);
|
|
1098
1614
|
const lines = packedRefs.split("\n");
|
|
@@ -1111,7 +1627,7 @@ function getCurrentCommit(repoPath) {
|
|
|
1111
1627
|
function readScanCache() {
|
|
1112
1628
|
try {
|
|
1113
1629
|
const cachePath = getCachePath();
|
|
1114
|
-
if (!
|
|
1630
|
+
if (!existsSync8(cachePath)) return null;
|
|
1115
1631
|
const content = readFileSync5(cachePath, "utf-8");
|
|
1116
1632
|
const cache = JSON.parse(content);
|
|
1117
1633
|
if (!cache.skills || !cache.timestamp) return null;
|
|
@@ -1126,7 +1642,7 @@ function writeScanCache(cache) {
|
|
|
1126
1642
|
try {
|
|
1127
1643
|
const cachePath = getCachePath();
|
|
1128
1644
|
const cacheDir = dirname4(cachePath);
|
|
1129
|
-
if (!
|
|
1645
|
+
if (!existsSync8(cacheDir)) {
|
|
1130
1646
|
mkdirSync2(cacheDir, { recursive: true });
|
|
1131
1647
|
}
|
|
1132
1648
|
atomicWriteFileSync(cachePath, JSON.stringify(cache, null, 2));
|
|
@@ -1142,7 +1658,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
|
1142
1658
|
if (EXCLUDE_DIRS.has(entry)) continue;
|
|
1143
1659
|
if (!isDirectory(fullPath)) continue;
|
|
1144
1660
|
const skillMd = join7(fullPath, "SKILL.md");
|
|
1145
|
-
if (
|
|
1661
|
+
if (existsSync8(skillMd)) {
|
|
1146
1662
|
const frontmatter = parseFrontmatter(skillMd);
|
|
1147
1663
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
1148
1664
|
seen.add(frontmatter.name);
|
|
@@ -1479,18 +1995,18 @@ var RepositoryManager = class {
|
|
|
1479
1995
|
return this.repoPath;
|
|
1480
1996
|
}
|
|
1481
1997
|
isValidRepo(path) {
|
|
1482
|
-
if (!
|
|
1998
|
+
if (!existsSync9(path)) return false;
|
|
1483
1999
|
const gitDir = join8(path, ".git");
|
|
1484
2000
|
const pluginsDir = join8(path, "plugins-official");
|
|
1485
|
-
return
|
|
2001
|
+
return existsSync9(gitDir) && existsSync9(pluginsDir);
|
|
1486
2002
|
}
|
|
1487
2003
|
async cloneRepo() {
|
|
1488
2004
|
const configDir = getCannbotConfigDir();
|
|
1489
|
-
if (!
|
|
2005
|
+
if (!existsSync9(configDir)) {
|
|
1490
2006
|
mkdirSync3(configDir, { recursive: true });
|
|
1491
2007
|
}
|
|
1492
2008
|
const targetPath = getCannbotRepoPath();
|
|
1493
|
-
if (
|
|
2009
|
+
if (existsSync9(targetPath)) {
|
|
1494
2010
|
if (this.isValidRepo(targetPath)) {
|
|
1495
2011
|
this.repoPath = targetPath;
|
|
1496
2012
|
return targetPath;
|
|
@@ -1516,12 +2032,12 @@ function createRepositoryManager(customPath) {
|
|
|
1516
2032
|
}
|
|
1517
2033
|
|
|
1518
2034
|
// src/core/installer.ts
|
|
1519
|
-
import { existsSync as
|
|
2035
|
+
import { existsSync as existsSync13 } from "fs";
|
|
1520
2036
|
import { join as join12 } from "path";
|
|
1521
2037
|
import { execa as execa4 } from "execa";
|
|
1522
2038
|
|
|
1523
2039
|
// src/core/record.ts
|
|
1524
|
-
import { existsSync as
|
|
2040
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
1525
2041
|
import { join as join9 } from "path";
|
|
1526
2042
|
function getInstallsDir() {
|
|
1527
2043
|
return join9(getCannbotConfigDir(), "installs");
|
|
@@ -1531,7 +2047,7 @@ function getRecordPath(pluginId) {
|
|
|
1531
2047
|
}
|
|
1532
2048
|
function readRecord(pluginId) {
|
|
1533
2049
|
const recordPath = getRecordPath(pluginId);
|
|
1534
|
-
if (!
|
|
2050
|
+
if (!existsSync10(recordPath)) {
|
|
1535
2051
|
return null;
|
|
1536
2052
|
}
|
|
1537
2053
|
try {
|
|
@@ -1544,7 +2060,7 @@ function readRecord(pluginId) {
|
|
|
1544
2060
|
}
|
|
1545
2061
|
function writeRecord(record) {
|
|
1546
2062
|
const installsDir = getInstallsDir();
|
|
1547
|
-
if (!
|
|
2063
|
+
if (!existsSync10(installsDir)) {
|
|
1548
2064
|
mkdirSync4(installsDir, { recursive: true });
|
|
1549
2065
|
}
|
|
1550
2066
|
const recordPath = getRecordPath(record.pluginId);
|
|
@@ -1552,7 +2068,7 @@ function writeRecord(record) {
|
|
|
1552
2068
|
}
|
|
1553
2069
|
function deleteRecord(pluginId) {
|
|
1554
2070
|
const recordPath = getRecordPath(pluginId);
|
|
1555
|
-
if (
|
|
2071
|
+
if (existsSync10(recordPath)) {
|
|
1556
2072
|
unlinkSync2(recordPath);
|
|
1557
2073
|
}
|
|
1558
2074
|
}
|
|
@@ -1561,24 +2077,24 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1561
2077
|
const directories = [];
|
|
1562
2078
|
if (manifest) {
|
|
1563
2079
|
const skillsDir = join9(configRoot, "skills");
|
|
1564
|
-
if (
|
|
2080
|
+
if (existsSync10(skillsDir)) {
|
|
1565
2081
|
directories.push(skillsDir);
|
|
1566
2082
|
for (const skillName of manifest.installed_skills || []) {
|
|
1567
2083
|
const skillPath = join9(skillsDir, skillName);
|
|
1568
|
-
if (
|
|
2084
|
+
if (existsSync10(skillPath) || isSymlink(skillPath)) {
|
|
1569
2085
|
files.push(skillPath);
|
|
1570
2086
|
}
|
|
1571
2087
|
}
|
|
1572
2088
|
}
|
|
1573
2089
|
const agentsDir = join9(configRoot, "agents");
|
|
1574
|
-
if (
|
|
2090
|
+
if (existsSync10(agentsDir)) {
|
|
1575
2091
|
directories.push(agentsDir);
|
|
1576
2092
|
for (const agentName of manifest.installed_agents || []) {
|
|
1577
2093
|
const agentPath = join9(agentsDir, agentName);
|
|
1578
2094
|
const agentPathMd = join9(agentsDir, agentName + ".md");
|
|
1579
|
-
if (
|
|
2095
|
+
if (existsSync10(agentPath) || isSymlink(agentPath)) {
|
|
1580
2096
|
files.push(agentPath);
|
|
1581
|
-
} else if (
|
|
2097
|
+
} else if (existsSync10(agentPathMd) || isSymlink(agentPathMd)) {
|
|
1582
2098
|
files.push(agentPathMd);
|
|
1583
2099
|
}
|
|
1584
2100
|
}
|
|
@@ -1589,16 +2105,16 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1589
2105
|
files.push(workflowsLink);
|
|
1590
2106
|
}
|
|
1591
2107
|
const manifestPath = join9(configRoot, "cannbot-manifest.json");
|
|
1592
|
-
if (
|
|
2108
|
+
if (existsSync10(manifestPath)) {
|
|
1593
2109
|
files.push(manifestPath);
|
|
1594
2110
|
}
|
|
1595
2111
|
const pluginManifestPath = join9(configRoot, `${pluginId}-manifest.json`);
|
|
1596
|
-
if (
|
|
2112
|
+
if (existsSync10(pluginManifestPath)) {
|
|
1597
2113
|
files.push(pluginManifestPath);
|
|
1598
2114
|
}
|
|
1599
2115
|
const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
1600
2116
|
const configFilePath = level === "project" ? join9(installPath, configFileName) : join9(configRoot, configFileName);
|
|
1601
|
-
if (
|
|
2117
|
+
if (existsSync10(configFilePath)) {
|
|
1602
2118
|
files.push(configFilePath);
|
|
1603
2119
|
}
|
|
1604
2120
|
const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
|
|
@@ -1629,7 +2145,7 @@ function getSkillRecordPath() {
|
|
|
1629
2145
|
}
|
|
1630
2146
|
function readSkillRecord() {
|
|
1631
2147
|
const recordPath = getSkillRecordPath();
|
|
1632
|
-
if (!
|
|
2148
|
+
if (!existsSync10(recordPath)) {
|
|
1633
2149
|
return {};
|
|
1634
2150
|
}
|
|
1635
2151
|
try {
|
|
@@ -1642,7 +2158,7 @@ function readSkillRecord() {
|
|
|
1642
2158
|
}
|
|
1643
2159
|
function writeSkillRecord(record) {
|
|
1644
2160
|
const installsDir = getInstallsDir();
|
|
1645
|
-
if (!
|
|
2161
|
+
if (!existsSync10(installsDir)) {
|
|
1646
2162
|
mkdirSync4(installsDir, { recursive: true });
|
|
1647
2163
|
}
|
|
1648
2164
|
const recordPath = getSkillRecordPath();
|
|
@@ -1687,12 +2203,12 @@ function getInstalledSkills(tool, level, installPath) {
|
|
|
1687
2203
|
const skillsDir = join9(configRoot, "skills");
|
|
1688
2204
|
return recordedSkills.filter((skillId) => {
|
|
1689
2205
|
const skillPath = join9(skillsDir, skillId);
|
|
1690
|
-
return
|
|
2206
|
+
return existsSync10(skillPath) || isSymlink(skillPath);
|
|
1691
2207
|
});
|
|
1692
2208
|
}
|
|
1693
2209
|
|
|
1694
2210
|
// src/core/backup.ts
|
|
1695
|
-
import { existsSync as
|
|
2211
|
+
import { existsSync as existsSync11, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
1696
2212
|
import { join as join10 } from "path";
|
|
1697
2213
|
function detectCurrentPlugin(configRoot, tool) {
|
|
1698
2214
|
const manifest = readManifest(configRoot);
|
|
@@ -1706,7 +2222,7 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1706
2222
|
}
|
|
1707
2223
|
}
|
|
1708
2224
|
const agentsFile = join10(configRoot, getAgentsFileName(tool));
|
|
1709
|
-
if (!
|
|
2225
|
+
if (!existsSync11(agentsFile)) {
|
|
1710
2226
|
return null;
|
|
1711
2227
|
}
|
|
1712
2228
|
const allRecords = readAllRecords();
|
|
@@ -1725,7 +2241,7 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1725
2241
|
}
|
|
1726
2242
|
function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
1727
2243
|
const agentsFile = join10(configRoot, getAgentsFileName(tool));
|
|
1728
|
-
if (!
|
|
2244
|
+
if (!existsSync11(agentsFile)) {
|
|
1729
2245
|
return null;
|
|
1730
2246
|
}
|
|
1731
2247
|
const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
|
|
@@ -1744,7 +2260,7 @@ function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
|
1744
2260
|
}
|
|
1745
2261
|
}
|
|
1746
2262
|
function findBackups(configRoot) {
|
|
1747
|
-
if (!
|
|
2263
|
+
if (!existsSync11(configRoot)) {
|
|
1748
2264
|
return [];
|
|
1749
2265
|
}
|
|
1750
2266
|
const files = readdirSync3(configRoot);
|
|
@@ -1782,7 +2298,7 @@ function restoreBackup(backupPath, configRoot, tool) {
|
|
|
1782
2298
|
}
|
|
1783
2299
|
function deleteBackup(backupPath) {
|
|
1784
2300
|
try {
|
|
1785
|
-
if (
|
|
2301
|
+
if (existsSync11(backupPath)) {
|
|
1786
2302
|
unlinkSync3(backupPath);
|
|
1787
2303
|
return true;
|
|
1788
2304
|
}
|
|
@@ -1851,12 +2367,12 @@ async function showRestorePrompt(backups) {
|
|
|
1851
2367
|
}
|
|
1852
2368
|
|
|
1853
2369
|
// src/core/plugin-installer.ts
|
|
1854
|
-
import { existsSync as
|
|
2370
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, realpathSync, copyFileSync as copyFileSync2, cpSync, writeFileSync as writeFileSync3, readFileSync as readFileSync8 } from "fs";
|
|
1855
2371
|
import { join as join11 } from "path";
|
|
1856
2372
|
import { execa as execa3 } from "execa";
|
|
1857
2373
|
function readPluginManifest(pluginDir) {
|
|
1858
2374
|
const manifestPath = join11(pluginDir, "plugin-manifest.json");
|
|
1859
|
-
if (!
|
|
2375
|
+
if (!existsSync12(manifestPath)) return null;
|
|
1860
2376
|
try {
|
|
1861
2377
|
const content = JSON.parse(readFileSync8(manifestPath, "utf-8"));
|
|
1862
2378
|
if (!content || !content.id) return null;
|
|
@@ -1868,7 +2384,7 @@ function readPluginManifest(pluginDir) {
|
|
|
1868
2384
|
function installLink(source, target) {
|
|
1869
2385
|
try {
|
|
1870
2386
|
const resolved = realpathSync(source);
|
|
1871
|
-
if (
|
|
2387
|
+
if (existsSync12(target) || isSymlink(target)) {
|
|
1872
2388
|
unlinkSync4(target);
|
|
1873
2389
|
}
|
|
1874
2390
|
try {
|
|
@@ -1887,7 +2403,7 @@ function installLink(source, target) {
|
|
|
1887
2403
|
}
|
|
1888
2404
|
function installConfigFile(pluginDir, configFile, tool, level, configRoot, installPath) {
|
|
1889
2405
|
const sourcePath = join11(pluginDir, configFile);
|
|
1890
|
-
if (!
|
|
2406
|
+
if (!existsSync12(sourcePath)) return;
|
|
1891
2407
|
const agentsFileName = getAgentsFileName(tool);
|
|
1892
2408
|
const isProjectLevel = level === "project";
|
|
1893
2409
|
let primaryTarget;
|
|
@@ -1896,7 +2412,7 @@ function installConfigFile(pluginDir, configFile, tool, level, configRoot, insta
|
|
|
1896
2412
|
} else {
|
|
1897
2413
|
primaryTarget = join11(configRoot, agentsFileName);
|
|
1898
2414
|
}
|
|
1899
|
-
if (
|
|
2415
|
+
if (existsSync12(primaryTarget) || isSymlink(primaryTarget)) {
|
|
1900
2416
|
unlinkSync4(primaryTarget);
|
|
1901
2417
|
}
|
|
1902
2418
|
try {
|
|
@@ -1910,7 +2426,7 @@ function installConfigFile(pluginDir, configFile, tool, level, configRoot, insta
|
|
|
1910
2426
|
}
|
|
1911
2427
|
if (isProjectLevel && primaryTarget !== join11(configRoot, agentsFileName)) {
|
|
1912
2428
|
const configRootTarget = join11(configRoot, agentsFileName);
|
|
1913
|
-
if (
|
|
2429
|
+
if (existsSync12(configRootTarget) || isSymlink(configRootTarget)) {
|
|
1914
2430
|
unlinkSync4(configRootTarget);
|
|
1915
2431
|
}
|
|
1916
2432
|
try {
|
|
@@ -1926,7 +2442,7 @@ async function installExternalRepos(repos, repoPath) {
|
|
|
1926
2442
|
if (!repos || repos.length === 0) return;
|
|
1927
2443
|
for (const repo of repos) {
|
|
1928
2444
|
const targetDir = join11(repoPath, repo.dir);
|
|
1929
|
-
if (
|
|
2445
|
+
if (existsSync12(targetDir)) {
|
|
1930
2446
|
logger.info(` ${repo.dir} already exists, skipping clone`);
|
|
1931
2447
|
continue;
|
|
1932
2448
|
}
|
|
@@ -1973,7 +2489,7 @@ async function installViaManifest(manifest, pluginDir, repoPath, tool, level, in
|
|
|
1973
2489
|
const installedAgents = [];
|
|
1974
2490
|
for (const source of manifest.skills) {
|
|
1975
2491
|
const sourceDir = join11(repoPath, source.dir);
|
|
1976
|
-
if (!
|
|
2492
|
+
if (!existsSync12(sourceDir)) {
|
|
1977
2493
|
logger.warn(` Skill source not found: ${source.dir}`);
|
|
1978
2494
|
continue;
|
|
1979
2495
|
}
|
|
@@ -1981,7 +2497,7 @@ async function installViaManifest(manifest, pluginDir, repoPath, tool, level, in
|
|
|
1981
2497
|
const skillName = typeof skillEntry === "string" ? skillEntry : skillEntry.name;
|
|
1982
2498
|
const skillAlias = typeof skillEntry === "string" ? skillName : skillEntry.as || skillName;
|
|
1983
2499
|
const skillPath = join11(sourceDir, skillName);
|
|
1984
|
-
if (!
|
|
2500
|
+
if (!existsSync12(skillPath)) {
|
|
1985
2501
|
logger.warn(` Skill not found: ${skillName} in ${source.dir}`);
|
|
1986
2502
|
continue;
|
|
1987
2503
|
}
|
|
@@ -1997,7 +2513,7 @@ async function installViaManifest(manifest, pluginDir, repoPath, tool, level, in
|
|
|
1997
2513
|
for (const agentName of manifest.agents) {
|
|
1998
2514
|
const agentFile = agentName.endsWith(".md") ? agentName : `${agentName}.md`;
|
|
1999
2515
|
const agentPath = join11(pluginDir, "agents", agentFile);
|
|
2000
|
-
if (!
|
|
2516
|
+
if (!existsSync12(agentPath)) {
|
|
2001
2517
|
logger.warn(` Agent not found: ${agentFile}`);
|
|
2002
2518
|
continue;
|
|
2003
2519
|
}
|
|
@@ -2056,7 +2572,7 @@ async function installPlugin(opts) {
|
|
|
2056
2572
|
const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
|
|
2057
2573
|
const agentsFile = join12(configRoot, getAgentsFileName(opts.tool));
|
|
2058
2574
|
let backupInfo = null;
|
|
2059
|
-
if (
|
|
2575
|
+
if (existsSync13(agentsFile)) {
|
|
2060
2576
|
const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
|
|
2061
2577
|
if (currentPlugin && currentPlugin.pluginId !== opts.pluginId) {
|
|
2062
2578
|
let choice = "overwrite";
|
|
@@ -2150,7 +2666,7 @@ async function installPlugin(opts) {
|
|
|
2150
2666
|
}
|
|
2151
2667
|
}
|
|
2152
2668
|
const scriptPath = join12(pluginDir, plugin.script);
|
|
2153
|
-
if (!
|
|
2669
|
+
if (!existsSync13(scriptPath)) {
|
|
2154
2670
|
return {
|
|
2155
2671
|
success: false,
|
|
2156
2672
|
pluginId: opts.pluginId,
|
|
@@ -2227,7 +2743,7 @@ async function installPlugin(opts) {
|
|
|
2227
2743
|
}
|
|
2228
2744
|
|
|
2229
2745
|
// src/core/skill-installer.ts
|
|
2230
|
-
import { existsSync as
|
|
2746
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, symlinkSync as symlinkSync2, unlinkSync as unlinkSync5, readdirSync as readdirSync4, rmdirSync, realpathSync as realpathSync2 } from "fs";
|
|
2231
2747
|
import { join as join13, dirname as dirname7 } from "path";
|
|
2232
2748
|
import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
|
|
2233
2749
|
import chalk5 from "chalk";
|
|
@@ -2236,7 +2752,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
2236
2752
|
const configRoot = getConfigRoot(tool, level);
|
|
2237
2753
|
const skillsDir = join13(configRoot, "skills");
|
|
2238
2754
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
2239
|
-
if (!
|
|
2755
|
+
if (!existsSync14(skillsDir)) {
|
|
2240
2756
|
mkdirSync6(skillsDir, { recursive: true });
|
|
2241
2757
|
}
|
|
2242
2758
|
const results = [];
|
|
@@ -2249,13 +2765,13 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
2249
2765
|
}
|
|
2250
2766
|
const sourcePath = resolveSkillSourcePath(skill, repoPath);
|
|
2251
2767
|
const targetPath = join13(skillsDir, skillId);
|
|
2252
|
-
if (!
|
|
2768
|
+
if (!existsSync14(sourcePath)) {
|
|
2253
2769
|
results.push({ skillId, success: false, error: t("error_source_not_found").replace("{path}", sourcePath) });
|
|
2254
2770
|
continue;
|
|
2255
2771
|
}
|
|
2256
2772
|
try {
|
|
2257
2773
|
const resolvedSource = realpathSync2(sourcePath);
|
|
2258
|
-
if (
|
|
2774
|
+
if (existsSync14(targetPath) || isSymlink(targetPath)) {
|
|
2259
2775
|
unlinkSync5(targetPath);
|
|
2260
2776
|
}
|
|
2261
2777
|
symlinkSync2(resolvedSource, targetPath);
|
|
@@ -2283,7 +2799,7 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2283
2799
|
for (const skillId of skillIds) {
|
|
2284
2800
|
const targetPath = join13(skillsDir, skillId);
|
|
2285
2801
|
try {
|
|
2286
|
-
if (
|
|
2802
|
+
if (existsSync14(targetPath) || isSymlink(targetPath)) {
|
|
2287
2803
|
unlinkSync5(targetPath);
|
|
2288
2804
|
results.push({ skillId, success: true });
|
|
2289
2805
|
removedIds.push(skillId);
|
|
@@ -2299,7 +2815,7 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2299
2815
|
if (removedIds.length > 0) {
|
|
2300
2816
|
removeSkillsFromRecord(removedIds, tool, level, installPath);
|
|
2301
2817
|
}
|
|
2302
|
-
if (
|
|
2818
|
+
if (existsSync14(skillsDir)) {
|
|
2303
2819
|
try {
|
|
2304
2820
|
const entries = readdirSync4(skillsDir);
|
|
2305
2821
|
if (entries.length === 0) {
|
|
@@ -2483,7 +2999,7 @@ function listAllSkills() {
|
|
|
2483
2999
|
function resolveSkillSourcePath(skill, repoPath) {
|
|
2484
3000
|
if (skill.filePath) {
|
|
2485
3001
|
const absPath = skill.filePath.startsWith("/") ? skill.filePath : join13(repoPath, skill.filePath);
|
|
2486
|
-
if (
|
|
3002
|
+
if (existsSync14(absPath)) {
|
|
2487
3003
|
return dirname7(absPath);
|
|
2488
3004
|
}
|
|
2489
3005
|
}
|
|
@@ -2579,11 +3095,11 @@ function printEnhancedSummary(results, tool, configRoot) {
|
|
|
2579
3095
|
}
|
|
2580
3096
|
|
|
2581
3097
|
// src/commands/init.ts
|
|
2582
|
-
import { existsSync as
|
|
3098
|
+
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
2583
3099
|
import { join as join14 } from "path";
|
|
2584
3100
|
async function initCommand() {
|
|
2585
3101
|
const cwd = process.cwd();
|
|
2586
|
-
if (
|
|
3102
|
+
if (existsSync15(join14(cwd, "package.json")) && (() => {
|
|
2587
3103
|
try {
|
|
2588
3104
|
const pkg = JSON.parse(readFileSync9(join14(cwd, "package.json"), "utf-8"));
|
|
2589
3105
|
return pkg.name === "@cannbot-ai/install-helper";
|
|
@@ -2810,7 +3326,7 @@ async function listCommand() {
|
|
|
2810
3326
|
|
|
2811
3327
|
// src/commands/doctor.ts
|
|
2812
3328
|
import chalk8 from "chalk";
|
|
2813
|
-
import { existsSync as
|
|
3329
|
+
import { existsSync as existsSync16, readdirSync as readdirSync5, lstatSync as lstatSync2, unlinkSync as unlinkSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
2814
3330
|
import { join as join15 } from "path";
|
|
2815
3331
|
async function doctorCommand(options = {}) {
|
|
2816
3332
|
console.log();
|
|
@@ -2853,7 +3369,7 @@ async function doctorCommand(options = {}) {
|
|
|
2853
3369
|
const configRoot = getConfigRoot(primaryTool, "project");
|
|
2854
3370
|
const skillsDir = getSkillsDir(configRoot);
|
|
2855
3371
|
const agentsDir = getAgentsDir(configRoot);
|
|
2856
|
-
if (
|
|
3372
|
+
if (existsSync16(skillsDir)) {
|
|
2857
3373
|
const brokenLinks = checkBrokenLinks(skillsDir);
|
|
2858
3374
|
if (brokenLinks === 0) {
|
|
2859
3375
|
const count = readdirSync5(skillsDir).length;
|
|
@@ -2875,7 +3391,7 @@ async function doctorCommand(options = {}) {
|
|
|
2875
3391
|
console.log(chalk8.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: ${t("doctor_created").replace("{path}", skillsDir)}`);
|
|
2876
3392
|
}
|
|
2877
3393
|
}
|
|
2878
|
-
if (
|
|
3394
|
+
if (existsSync16(agentsDir)) {
|
|
2879
3395
|
const brokenLinks = checkBrokenLinks(agentsDir);
|
|
2880
3396
|
if (brokenLinks === 0) {
|
|
2881
3397
|
const count = readdirSync5(agentsDir).length;
|
|
@@ -2901,7 +3417,7 @@ async function doctorCommand(options = {}) {
|
|
|
2901
3417
|
console.log(chalk8.bold(` ${t("doctor_config")}`));
|
|
2902
3418
|
const configFile = getConfigFileName(primaryTool);
|
|
2903
3419
|
const configPath = join15(process.cwd(), configFile);
|
|
2904
|
-
if (
|
|
3420
|
+
if (existsSync16(configPath)) {
|
|
2905
3421
|
console.log(chalk8.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
|
|
2906
3422
|
} else {
|
|
2907
3423
|
console.log(chalk8.dim(" \u2014") + ` ${configFile} ${t("doctor_config_not_exist")}`);
|
|
@@ -2928,7 +3444,7 @@ function checkBrokenLinks(dir) {
|
|
|
2928
3444
|
try {
|
|
2929
3445
|
const stats = lstatSync2(fullPath);
|
|
2930
3446
|
if (stats.isSymbolicLink()) {
|
|
2931
|
-
if (!
|
|
3447
|
+
if (!existsSync16(fullPath)) {
|
|
2932
3448
|
broken++;
|
|
2933
3449
|
}
|
|
2934
3450
|
}
|
|
@@ -2949,7 +3465,7 @@ function fixBrokenLinks(dir) {
|
|
|
2949
3465
|
try {
|
|
2950
3466
|
const stats = lstatSync2(fullPath);
|
|
2951
3467
|
if (stats.isSymbolicLink()) {
|
|
2952
|
-
if (!
|
|
3468
|
+
if (!existsSync16(fullPath)) {
|
|
2953
3469
|
unlinkSync6(fullPath);
|
|
2954
3470
|
fixed++;
|
|
2955
3471
|
}
|
|
@@ -3295,7 +3811,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
|
|
|
3295
3811
|
}
|
|
3296
3812
|
|
|
3297
3813
|
// src/commands/uninstall.ts
|
|
3298
|
-
import { existsSync as
|
|
3814
|
+
import { existsSync as existsSync17, unlinkSync as unlinkSync7, rmdirSync as rmdirSync2, readdirSync as readdirSync6 } from "fs";
|
|
3299
3815
|
import { resolve, basename as basename2 } from "path";
|
|
3300
3816
|
import chalk11 from "chalk";
|
|
3301
3817
|
async function uninstallCommand(names, options) {
|
|
@@ -3337,7 +3853,7 @@ async function uninstallCommand(names, options) {
|
|
|
3337
3853
|
for (const filePath of record.files) {
|
|
3338
3854
|
if (!isSafePath(filePath)) continue;
|
|
3339
3855
|
try {
|
|
3340
|
-
if (
|
|
3856
|
+
if (existsSync17(filePath) || isSymlink(filePath)) {
|
|
3341
3857
|
unlinkSync7(filePath);
|
|
3342
3858
|
const name = basename2(filePath);
|
|
3343
3859
|
logger.step(` ${t("uninstall_remove_label")}: ${name}`);
|
|
@@ -3352,7 +3868,7 @@ async function uninstallCommand(names, options) {
|
|
|
3352
3868
|
if (resolve(dirPath) === resolve(configRoot)) {
|
|
3353
3869
|
continue;
|
|
3354
3870
|
}
|
|
3355
|
-
if (
|
|
3871
|
+
if (existsSync17(dirPath)) {
|
|
3356
3872
|
const entries = readdirSync6(dirPath);
|
|
3357
3873
|
if (entries.length === 0) {
|
|
3358
3874
|
rmdirSync2(dirPath);
|
|
@@ -3491,7 +4007,7 @@ async function updateCommand(pluginNames, options) {
|
|
|
3491
4007
|
|
|
3492
4008
|
// src/commands/info.ts
|
|
3493
4009
|
import chalk13 from "chalk";
|
|
3494
|
-
import { existsSync as
|
|
4010
|
+
import { existsSync as existsSync18, readdirSync as readdirSync7 } from "fs";
|
|
3495
4011
|
import { join as join16 } from "path";
|
|
3496
4012
|
async function infoCommand(pluginName) {
|
|
3497
4013
|
const plugin = findPlugin(pluginName);
|
|
@@ -3518,11 +4034,11 @@ async function infoCommand(pluginName) {
|
|
|
3518
4034
|
const repoManager = createRepositoryManager();
|
|
3519
4035
|
const repoPath = await repoManager.ensureRepo();
|
|
3520
4036
|
const quickstartPath = join16(repoPath, plugin.dir, "quickstart.md");
|
|
3521
|
-
if (
|
|
4037
|
+
if (existsSync18(quickstartPath)) {
|
|
3522
4038
|
console.log(` ${chalk13.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
|
|
3523
4039
|
}
|
|
3524
4040
|
const agentsDir = join16(repoPath, plugin.dir, "agents");
|
|
3525
|
-
if (
|
|
4041
|
+
if (existsSync18(agentsDir)) {
|
|
3526
4042
|
const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
|
|
3527
4043
|
if (agentFiles.length > 0) {
|
|
3528
4044
|
console.log();
|
|
@@ -3574,16 +4090,27 @@ async function langCommand(action, value) {
|
|
|
3574
4090
|
}
|
|
3575
4091
|
|
|
3576
4092
|
// src/cli.ts
|
|
3577
|
-
import { readFileSync as readFileSync10 } from "fs";
|
|
4093
|
+
import { readFileSync as readFileSync10, existsSync as existsSync19 } from "fs";
|
|
3578
4094
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
3579
4095
|
import { dirname as dirname8, join as join17 } from "path";
|
|
3580
4096
|
function readVersion() {
|
|
3581
4097
|
try {
|
|
3582
4098
|
const __filename5 = fileURLToPath5(import.meta.url);
|
|
3583
4099
|
const __dirname5 = dirname8(__filename5);
|
|
3584
|
-
const
|
|
3585
|
-
|
|
3586
|
-
|
|
4100
|
+
const candidates = [
|
|
4101
|
+
join17(__dirname5, "..", "package.json"),
|
|
4102
|
+
join17(__dirname5, "package.json"),
|
|
4103
|
+
join17(process.cwd(), "package.json")
|
|
4104
|
+
];
|
|
4105
|
+
for (const pkgPath of candidates) {
|
|
4106
|
+
if (existsSync19(pkgPath)) {
|
|
4107
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
4108
|
+
if (pkg.name === "@cannbot-ai/install-helper" && pkg.version) {
|
|
4109
|
+
return pkg.version;
|
|
4110
|
+
}
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
return "0.0.0";
|
|
3587
4114
|
} catch {
|
|
3588
4115
|
return "0.0.0";
|
|
3589
4116
|
}
|