@cannbot-ai/install-helper 0.0.2-beta.19 → 0.0.2-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -2
- package/dist/index.js +137 -19
- package/dist/index.js.map +1 -1
- package/dist/locales/en_US.json +6 -0
- package/dist/locales/zh_CN.json +6 -0
- package/dist/plugins.d/catlass-op-generator.yml +1 -1
- package/dist/plugins.d/model-infer-optimize.yml +1 -1
- package/dist/plugins.d/ops-code-reviewer.yml +1 -1
- package/dist/plugins.d/ops-direct-invoke-flash.yml +2 -2
- package/dist/plugins.d/ops-direct-invoke.yml +1 -1
- package/dist/plugins.d/ops-registry-invoke.yml +1 -1
- package/dist/plugins.d/pypto-op-orchestrator.yml +2 -2
- package/dist/plugins.d/tilelang-op-orchestrator.yml +2 -2
- package/dist/plugins.d/torch-compile.yml +1 -1
- package/dist/plugins.d/triton-op-generator.yml +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,6 +18,20 @@ npx @cannbot-ai/install-helper
|
|
|
18
18
|
|
|
19
19
|
交互式向导会自动检测已安装的 AI 编程工具(OpenCode / Claude Code / Trae / Cursor),通过箭头键选择场景即可完成安装。
|
|
20
20
|
|
|
21
|
+
## 一键安装所有 Skills
|
|
22
|
+
|
|
23
|
+
如果 opencode 等工具已安装,可直接一键安装全部 Skills(无需逐个点选):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 一键安装全部 Skills 到当前项目(跳过确认)
|
|
27
|
+
install-helper install --all --tool opencode --yes
|
|
28
|
+
|
|
29
|
+
# 一键安装全部 Skills 到全局
|
|
30
|
+
install-helper install --all --tool opencode --level global --yes
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> 交互式向导也支持「全选所有 Skills」和「全选当前类别」,详见下文。
|
|
34
|
+
|
|
21
35
|
## 主要特性
|
|
22
36
|
|
|
23
37
|
### 核心功能
|
|
@@ -42,6 +56,7 @@ npx @cannbot-ai/install-helper
|
|
|
42
56
|
| `install-helper list` | 列出可用场景及安装状态 |
|
|
43
57
|
| `install-helper install <name>` | 安装指定插件或 Skill(自动识别) |
|
|
44
58
|
| `install-helper install --list` | 按类别列出所有可用 Skills |
|
|
59
|
+
| `install-helper install --all --tool opencode --yes` | 一键安装全部 Skills |
|
|
45
60
|
| `install-helper update [plugin]` | 更新已安装的 Skills |
|
|
46
61
|
| `install-helper uninstall <plugin>` | 卸载指定场景 |
|
|
47
62
|
| `install-helper status` | 查看已安装插件详情 |
|
|
@@ -114,14 +129,19 @@ Skills 按 11 个大类组织:知识与参考、环境与工具、调试与诊
|
|
|
114
129
|
|
|
115
130
|
`install` 命令自动识别输入是插件还是 Skill,无需区分。
|
|
116
131
|
|
|
132
|
+
**交互式「全选」**:运行 `install-helper install`(不带参数)进入交互式选择时:
|
|
133
|
+
- 类别列表顶部有 **「全选所有 Skills」**,选中即一键安装全部 Skills。
|
|
134
|
+
- 进入某类别后,顶部有 **「全选当前类别」**,勾选后回车即选中该类别全部 Skills。
|
|
135
|
+
- 选完一个类别后会提示「继续选择其他类别 / 确认安装」,可跨类别累积选择后再统一安装。
|
|
136
|
+
|
|
117
137
|
**选项:**
|
|
118
138
|
|
|
119
139
|
| 选项 | 说明 |
|
|
120
140
|
|------|------|
|
|
121
141
|
| `--tool <tool>` | 指定 AI 工具(opencode, claude, trae, cursor, copilot) |
|
|
122
142
|
| `--level <level>` | 安装级别(project, global),默认 project |
|
|
123
|
-
| `--all` |
|
|
124
|
-
| `--yes` | 跳过所有确认提示 |
|
|
143
|
+
| `--all` `-a` | 安装全部 Skills(一键安装) |
|
|
144
|
+
| `--yes` `-y` | 跳过所有确认提示 |
|
|
125
145
|
|
|
126
146
|
**已装检测**:如果插件已安装,会提示是否覆盖安装。使用 `--yes` 可跳过提示直接覆盖。
|
|
127
147
|
|
package/dist/index.js
CHANGED
|
@@ -48,7 +48,6 @@ function loadPluginsFromYaml() {
|
|
|
48
48
|
}
|
|
49
49
|
} catch {
|
|
50
50
|
}
|
|
51
|
-
plugins.sort((a, b) => a.displayName < b.displayName ? -1 : a.displayName > b.displayName ? 1 : 0);
|
|
52
51
|
return plugins;
|
|
53
52
|
}
|
|
54
53
|
var PLUGIN_REGISTRY = loadPluginsFromYaml();
|
|
@@ -1906,22 +1905,34 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
1906
1905
|
}
|
|
1907
1906
|
return results;
|
|
1908
1907
|
}
|
|
1908
|
+
var SELECT_ALL = "__select_all__";
|
|
1909
|
+
var SELECT_ALL_CATEGORY = "__select_all_category__";
|
|
1910
|
+
var CONTINUE_SELECT = "__continue_select__";
|
|
1909
1911
|
async function interactiveSkillSelect(tool, level) {
|
|
1910
1912
|
const BACK3 = "__back__";
|
|
1911
1913
|
const CANCEL3 = "__cancel__";
|
|
1912
1914
|
const categories = getAllCategories();
|
|
1915
|
+
const allSkillIds = getAllSkills().map((s) => s.id);
|
|
1916
|
+
let accumulated = [];
|
|
1913
1917
|
let step = 0;
|
|
1914
1918
|
let selectedCategoryId = "";
|
|
1915
1919
|
while (true) {
|
|
1916
1920
|
switch (step) {
|
|
1917
1921
|
case 0: {
|
|
1918
|
-
|
|
1922
|
+
const titleSuffix = accumulated.length > 0 ? `${t("wizard_step_3_skill_title")}\uFF08${t("skill_count_format").replace("{count}", String(accumulated.length))}\uFF09` : t("wizard_step_3_skill_title");
|
|
1923
|
+
printBoxTitle(titleSuffix);
|
|
1919
1924
|
const categoryChoices = [
|
|
1925
|
+
{
|
|
1926
|
+
name: `>> ${t("skill_select_all").replace("{count}", String(allSkillIds.length))}`,
|
|
1927
|
+
value: SELECT_ALL
|
|
1928
|
+
},
|
|
1929
|
+
new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1920
1930
|
...categories.map((cat) => ({
|
|
1921
1931
|
name: `> ${cat.name} (${cat.skills.length} skills)`,
|
|
1922
1932
|
value: cat.id
|
|
1923
1933
|
})),
|
|
1924
1934
|
new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1935
|
+
...accumulated.length > 0 ? [{ name: `>> ${t("skill_confirm_install_count").replace("{count}", String(accumulated.length))}`, value: "install" }] : [],
|
|
1925
1936
|
{ name: "<- " + t("wizard_back"), value: BACK3 },
|
|
1926
1937
|
{ name: "x " + t("wizard_cancel"), value: CANCEL3 }
|
|
1927
1938
|
];
|
|
@@ -1935,6 +1946,12 @@ async function interactiveSkillSelect(tool, level) {
|
|
|
1935
1946
|
});
|
|
1936
1947
|
if (selectedCategoryId === BACK3) return "back";
|
|
1937
1948
|
if (selectedCategoryId === CANCEL3) return "cancel";
|
|
1949
|
+
if (selectedCategoryId === SELECT_ALL) {
|
|
1950
|
+
return allSkillIds;
|
|
1951
|
+
}
|
|
1952
|
+
if (selectedCategoryId === "install") {
|
|
1953
|
+
return accumulated;
|
|
1954
|
+
}
|
|
1938
1955
|
step = 1;
|
|
1939
1956
|
break;
|
|
1940
1957
|
}
|
|
@@ -1945,15 +1962,26 @@ async function interactiveSkillSelect(tool, level) {
|
|
|
1945
1962
|
const installPath = level === "project" ? process.cwd() : getConfigRoot(tool, level);
|
|
1946
1963
|
const installedSkills = getInstalledSkills(tool, level, installPath);
|
|
1947
1964
|
const installedSet = new Set(installedSkills);
|
|
1948
|
-
const
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
name:
|
|
1953
|
-
value:
|
|
1954
|
-
checked:
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1965
|
+
const categorySkillIds = new Set(category.skills.map((s) => s.id));
|
|
1966
|
+
const accumulatedInCategory = new Set(accumulated.filter((id) => categorySkillIds.has(id)));
|
|
1967
|
+
const skillChoices = [
|
|
1968
|
+
{
|
|
1969
|
+
name: `>> ${t("skill_select_all_category")}`,
|
|
1970
|
+
value: SELECT_ALL_CATEGORY,
|
|
1971
|
+
checked: accumulatedInCategory.size === category.skills.length
|
|
1972
|
+
},
|
|
1973
|
+
new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1974
|
+
...category.skills.map((skill) => {
|
|
1975
|
+
const isInstalled = installedSet.has(skill.id);
|
|
1976
|
+
const isAccumulated = accumulatedInCategory.has(skill.id);
|
|
1977
|
+
const suffix = isInstalled ? ` [${t("skill_already_installed")}]` : isAccumulated ? " [+]" : "";
|
|
1978
|
+
return {
|
|
1979
|
+
name: `${skill.id}${suffix} \u2014 ${skill.description}`,
|
|
1980
|
+
value: skill.id,
|
|
1981
|
+
checked: isAccumulated
|
|
1982
|
+
};
|
|
1983
|
+
})
|
|
1984
|
+
];
|
|
1957
1985
|
showOperationHints(true);
|
|
1958
1986
|
const selectedSkills = await checkbox2({
|
|
1959
1987
|
message: t("skill_select_items"),
|
|
@@ -1963,11 +1991,21 @@ async function interactiveSkillSelect(tool, level) {
|
|
|
1963
1991
|
theme: checkboxTheme,
|
|
1964
1992
|
pageSize: 15
|
|
1965
1993
|
});
|
|
1966
|
-
|
|
1994
|
+
let skillIds;
|
|
1995
|
+
if (selectedSkills.includes(SELECT_ALL_CATEGORY)) {
|
|
1996
|
+
skillIds = category.skills.map((s) => s.id);
|
|
1997
|
+
} else {
|
|
1998
|
+
skillIds = selectedSkills.filter((id) => id !== SELECT_ALL_CATEGORY);
|
|
1999
|
+
}
|
|
1967
2000
|
if (skillIds.length === 0) {
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2001
|
+
accumulated = accumulated.filter((id) => !categorySkillIds.has(id));
|
|
2002
|
+
const action2 = await select3({
|
|
2003
|
+
message: accumulated.length > 0 ? t("skill_continue_or_install").replace("{count}", String(accumulated.length)) : t("wizard_no_selection"),
|
|
2004
|
+
choices: accumulated.length > 0 ? [
|
|
2005
|
+
{ name: ">> " + t("skill_confirm_install_count").replace("{count}", String(accumulated.length)), value: "install" },
|
|
2006
|
+
{ name: "<- " + t("wizard_back_to_reselect"), value: "back" },
|
|
2007
|
+
{ name: "x " + t("wizard_cancel"), value: "cancel" }
|
|
2008
|
+
] : [
|
|
1971
2009
|
new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1972
2010
|
{ name: "<- " + t("wizard_back_to_reselect"), value: "back" },
|
|
1973
2011
|
{ name: "x " + t("wizard_cancel"), value: "cancel" }
|
|
@@ -1975,13 +2013,38 @@ async function interactiveSkillSelect(tool, level) {
|
|
|
1975
2013
|
loop: false,
|
|
1976
2014
|
theme: selectTheme
|
|
1977
2015
|
});
|
|
1978
|
-
if (
|
|
2016
|
+
if (action2 === "install") return accumulated;
|
|
2017
|
+
if (action2 === "back") {
|
|
1979
2018
|
step = 0;
|
|
1980
2019
|
break;
|
|
1981
2020
|
}
|
|
1982
2021
|
return "cancel";
|
|
1983
2022
|
}
|
|
1984
|
-
|
|
2023
|
+
accumulated = accumulated.filter((id) => !categorySkillIds.has(id));
|
|
2024
|
+
for (const id of skillIds) {
|
|
2025
|
+
if (!accumulated.includes(id)) {
|
|
2026
|
+
accumulated.push(id);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
const action = await select3({
|
|
2030
|
+
message: t("skill_continue_or_install").replace("{count}", String(accumulated.length)),
|
|
2031
|
+
choices: [
|
|
2032
|
+
{ name: ">> " + t("skill_confirm_install_count").replace("{count}", String(accumulated.length)), value: "install" },
|
|
2033
|
+
{ name: "> " + t("skill_continue_select"), value: CONTINUE_SELECT },
|
|
2034
|
+
new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
2035
|
+
{ name: "x " + t("wizard_cancel"), value: "cancel" }
|
|
2036
|
+
],
|
|
2037
|
+
loop: false,
|
|
2038
|
+
theme: selectTheme
|
|
2039
|
+
});
|
|
2040
|
+
if (action === "install") {
|
|
2041
|
+
return accumulated;
|
|
2042
|
+
}
|
|
2043
|
+
if (action === CONTINUE_SELECT) {
|
|
2044
|
+
step = 0;
|
|
2045
|
+
break;
|
|
2046
|
+
}
|
|
2047
|
+
return "cancel";
|
|
1985
2048
|
}
|
|
1986
2049
|
}
|
|
1987
2050
|
}
|
|
@@ -2536,6 +2599,61 @@ async function installCommand(names, options) {
|
|
|
2536
2599
|
listAllSkills();
|
|
2537
2600
|
return;
|
|
2538
2601
|
}
|
|
2602
|
+
if (options.all) {
|
|
2603
|
+
const scanSpinner2 = createSpinner(t("loading_skills_list"));
|
|
2604
|
+
scanSpinner2.start();
|
|
2605
|
+
try {
|
|
2606
|
+
const scanRepoManager = createRepositoryManager();
|
|
2607
|
+
await scanRepoManager.ensureRepoAndScan();
|
|
2608
|
+
scanSpinner2.succeed(t("loading_skills_list_complete"));
|
|
2609
|
+
} catch {
|
|
2610
|
+
scanSpinner2.warn(t("loading_skills_list_failed"));
|
|
2611
|
+
}
|
|
2612
|
+
const allSkills = getAllSkills();
|
|
2613
|
+
const skillIds = allSkills.map((s) => s.id);
|
|
2614
|
+
if (skillIds.length === 0) {
|
|
2615
|
+
logger.error(t("install_no_skill_selected"));
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
let tool2;
|
|
2619
|
+
if (options.tool) {
|
|
2620
|
+
tool2 = validateTool(options.tool);
|
|
2621
|
+
} else {
|
|
2622
|
+
const detected = await selectToolWithDetection();
|
|
2623
|
+
if (detected === "back" || detected === "cancel") return;
|
|
2624
|
+
tool2 = detected;
|
|
2625
|
+
}
|
|
2626
|
+
const level2 = options.level ? validateLevel(options.level) : "project";
|
|
2627
|
+
const repoManager = createRepositoryManager();
|
|
2628
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2629
|
+
spinner.start();
|
|
2630
|
+
const repoPath = await repoManager.ensureRepo();
|
|
2631
|
+
spinner.succeed(t("loading_plugin_data_complete"));
|
|
2632
|
+
logger.info(`${t("skill_all_install_progress").replace("{count}", chalk9.bold(String(skillIds.length)))}`);
|
|
2633
|
+
const results = await installSkills(skillIds, tool2, level2, repoPath);
|
|
2634
|
+
let successCount = 0;
|
|
2635
|
+
let failCount = 0;
|
|
2636
|
+
const total = results.length;
|
|
2637
|
+
for (let i = 0; i < results.length; i++) {
|
|
2638
|
+
const result = results[i];
|
|
2639
|
+
const progress = `[${i + 1}/${total}]`;
|
|
2640
|
+
if (result.success) {
|
|
2641
|
+
logger.success(`${progress} ${result.skillId}`);
|
|
2642
|
+
successCount++;
|
|
2643
|
+
} else {
|
|
2644
|
+
logger.error(`${progress} ${result.skillId}: ${result.error}`);
|
|
2645
|
+
failCount++;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
const configRoot = getConfigRoot(tool2, level2);
|
|
2649
|
+
logger.blank();
|
|
2650
|
+
logger.success(`${t("skill_install_done")}: ${chalk9.green(t("result_success_format").replace("{count}", String(successCount)))}, ${failCount > 0 ? chalk9.red(t("result_failed_format").replace("{count}", String(failCount))) : chalk9.dim(t("result_failed_format").replace("{count}", String(failCount)))}`);
|
|
2651
|
+
logger.blank();
|
|
2652
|
+
logger.info(`${t("install_to")}: ${chalk9.cyan(configRoot + "/skills/")}`);
|
|
2653
|
+
logger.info(`${t("start_to_use").replace("{tool}", chalk9.green(tool2))}`);
|
|
2654
|
+
logger.blank();
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2539
2657
|
if (names.length === 0) {
|
|
2540
2658
|
const scanSpinner2 = createSpinner(t("loading_skills_list"));
|
|
2541
2659
|
scanSpinner2.start();
|
|
@@ -3040,7 +3158,7 @@ function createCLI() {
|
|
|
3040
3158
|
setLanguage(config.language);
|
|
3041
3159
|
}
|
|
3042
3160
|
const program2 = new Command();
|
|
3043
|
-
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.
|
|
3161
|
+
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.20");
|
|
3044
3162
|
program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
|
|
3045
3163
|
await initCommand();
|
|
3046
3164
|
});
|
|
@@ -3053,7 +3171,7 @@ function createCLI() {
|
|
|
3053
3171
|
program2.command("status").description("Show installed plugins").action(async () => {
|
|
3054
3172
|
await statusCommand();
|
|
3055
3173
|
});
|
|
3056
|
-
program2.command("install [names...]").description("Install plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("--list", "List all available skills by category").action(async (names, options) => {
|
|
3174
|
+
program2.command("install [names...]").description("Install plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot)").option("-l, --level <level>", "Install level (project, global)", "project").option("-y, --yes", "Skip confirmation prompts").option("-a, --all", "Install ALL available skills").option("--list", "List all available skills by category").action(async (names, options) => {
|
|
3057
3175
|
await installCommand(names, options);
|
|
3058
3176
|
});
|
|
3059
3177
|
program2.command("uninstall <names...>").description("Uninstall plugins or skills (auto-detects type)").option("-t, --tool <tool>", "AI tool (opencode, claude, trae, cursor, copilot)").option("-l, --level <level>", "Install level (project, global)", "project").action(async (names, options) => {
|