bfi-cli 0.1.4 → 0.1.7
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/cli.mjs +463 -462
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1199,12 +1199,12 @@ async function tryGhClone(repo, tempDir, ref) {
|
|
|
1199
1199
|
return true;
|
|
1200
1200
|
}
|
|
1201
1201
|
function buildGitHubAuthError(url, repo, message) {
|
|
1202
|
-
if (repo && isGitHubSsoAuthError(message)) return `GitHub
|
|
1203
|
-
if (repo) return
|
|
1204
|
-
return
|
|
1202
|
+
if (repo && isGitHubSsoAuthError(message)) return `GitHub 阻止了 ${url} 的 HTTPS 访问,因为组织强制使用 SAML SSO。\n skills 已尝试您现有的 git 凭据和可用回退方案,但均未成功。\n - 重新授权您的 GitHub 凭据/应用以符合该组织的 SSO 策略\n - 或使用 SSH 重新运行:npx skills add ${repo.sshUrl}\n - 验证访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1203
|
+
if (repo) return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - 使用 SSH 重试:npx skills add ${repo.sshUrl}\n - 检查访问权限:gh auth status -h github.com 或 ssh -T git@github.com`;
|
|
1204
|
+
return `身份验证失败:${url}。\n - 私有仓库请确保您有访问权限\n - SSH:使用 'ssh -T git@github.com' 检查您的密钥\n - HTTPS:运行 'gh auth login' 或配置 git 凭据`;
|
|
1205
1205
|
}
|
|
1206
1206
|
async function cloneRepo(url, ref) {
|
|
1207
|
-
if (/^ext::/i.test(url)) throw new GitCloneError("
|
|
1207
|
+
if (/^ext::/i.test(url)) throw new GitCloneError("不支持的 Git 传输协议:ext", url);
|
|
1208
1208
|
const tempDir = await mkdtemp(join(tmpdir(), "skills-"));
|
|
1209
1209
|
const cloneOptions = ref ? [
|
|
1210
1210
|
"--depth",
|
|
@@ -1225,7 +1225,7 @@ async function cloneRepo(url, ref) {
|
|
|
1225
1225
|
recursive: true,
|
|
1226
1226
|
force: true
|
|
1227
1227
|
}).catch(() => {});
|
|
1228
|
-
throw new GitCloneError(
|
|
1228
|
+
throw new GitCloneError(`克隆超时(${Math.round(CLONE_TIMEOUT_MS / 1e3)} 秒)。常见原因:\n - 仓库过大:使用 SKILLS_CLONE_TIMEOUT_MS=600000 (10 分钟) 提高超时时间\n - 网络较慢:重试,或手动克隆后将本地路径传给 'skills add'\n - 私有仓库未配置凭据:请确保身份验证已配置\n - SSH:ssh-add -l(检查已加载的密钥)\n - HTTPS:gh auth status(如果使用 GitHub CLI)`, url, true, false);
|
|
1229
1229
|
}
|
|
1230
1230
|
if (isAuthError && repo && isGitHubHttpsCloneUrl(url)) {
|
|
1231
1231
|
try {
|
|
@@ -1243,7 +1243,7 @@ async function cloneRepo(url, ref) {
|
|
|
1243
1243
|
force: true
|
|
1244
1244
|
}).catch(() => {});
|
|
1245
1245
|
if (isAuthError) throw new GitCloneError(buildGitHubAuthError(url, repo, errorMessage), url, false, true);
|
|
1246
|
-
throw new GitCloneError(
|
|
1246
|
+
throw new GitCloneError(`克隆失败 ${url}:${errorMessage}`, url, false, false);
|
|
1247
1247
|
}
|
|
1248
1248
|
}
|
|
1249
1249
|
async function cleanupTempDir(dir) {
|
|
@@ -2366,7 +2366,7 @@ const agents = {
|
|
|
2366
2366
|
},
|
|
2367
2367
|
universal: {
|
|
2368
2368
|
name: "universal",
|
|
2369
|
-
displayName: "
|
|
2369
|
+
displayName: "共享目录",
|
|
2370
2370
|
skillsDir: ".agents/skills",
|
|
2371
2371
|
globalSkillsDir: join(configHome, "agents/skills"),
|
|
2372
2372
|
showInUniversalList: false,
|
|
@@ -2502,7 +2502,7 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
2502
2502
|
success: false,
|
|
2503
2503
|
path: "",
|
|
2504
2504
|
mode: options.mode ?? "symlink",
|
|
2505
|
-
error: `${agent.displayName}
|
|
2505
|
+
error: `${agent.displayName} 不支持全局技能安装`
|
|
2506
2506
|
};
|
|
2507
2507
|
const skillName = sanitizeName(skill.name || basename(skill.path));
|
|
2508
2508
|
const installMode = options.mode ?? "symlink";
|
|
@@ -2514,13 +2514,13 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
2514
2514
|
success: false,
|
|
2515
2515
|
path: agentDir,
|
|
2516
2516
|
mode: installMode,
|
|
2517
|
-
error: "
|
|
2517
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2518
2518
|
};
|
|
2519
2519
|
if (!isPathSafe$1(agentBase, agentDir)) return {
|
|
2520
2520
|
success: false,
|
|
2521
2521
|
path: agentDir,
|
|
2522
2522
|
mode: installMode,
|
|
2523
|
-
error: "
|
|
2523
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2524
2524
|
};
|
|
2525
2525
|
try {
|
|
2526
2526
|
if (pathsOverlap(skill.path, agentDir)) return {
|
|
@@ -2584,7 +2584,7 @@ async function installSkillForAgent(skill, agentType, options = {}) {
|
|
|
2584
2584
|
success: false,
|
|
2585
2585
|
path: agentDir,
|
|
2586
2586
|
mode: installMode,
|
|
2587
|
-
error: error instanceof Error ? error.message : "
|
|
2587
|
+
error: error instanceof Error ? error.message : "未知错误"
|
|
2588
2588
|
};
|
|
2589
2589
|
}
|
|
2590
2590
|
}
|
|
@@ -2687,7 +2687,7 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
2687
2687
|
success: false,
|
|
2688
2688
|
path: "",
|
|
2689
2689
|
mode: installMode,
|
|
2690
|
-
error: `${agent.displayName}
|
|
2690
|
+
error: `${agent.displayName} 不支持全局技能安装`
|
|
2691
2691
|
};
|
|
2692
2692
|
const skillName = sanitizeName(skill.installName);
|
|
2693
2693
|
const canonicalBase = agentType === "eve" && installMode === "symlink" ? getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent) : getCanonicalSkillsDir(isGlobal, cwd);
|
|
@@ -2698,13 +2698,13 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
2698
2698
|
success: false,
|
|
2699
2699
|
path: agentDir,
|
|
2700
2700
|
mode: installMode,
|
|
2701
|
-
error: "
|
|
2701
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2702
2702
|
};
|
|
2703
2703
|
if (!isPathSafe$1(agentBase, agentDir)) return {
|
|
2704
2704
|
success: false,
|
|
2705
2705
|
path: agentDir,
|
|
2706
2706
|
mode: installMode,
|
|
2707
|
-
error: "
|
|
2707
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2708
2708
|
};
|
|
2709
2709
|
async function writeSkillFiles(targetDir) {
|
|
2710
2710
|
for (const [filePath, content] of skill.files) {
|
|
@@ -2755,7 +2755,7 @@ async function installWellKnownSkillForAgent(skill, agentType, options = {}) {
|
|
|
2755
2755
|
success: false,
|
|
2756
2756
|
path: agentDir,
|
|
2757
2757
|
mode: installMode,
|
|
2758
|
-
error: error instanceof Error ? error.message : "
|
|
2758
|
+
error: error instanceof Error ? error.message : "未知错误"
|
|
2759
2759
|
};
|
|
2760
2760
|
}
|
|
2761
2761
|
}
|
|
@@ -2769,7 +2769,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2769
2769
|
success: false,
|
|
2770
2770
|
path: "",
|
|
2771
2771
|
mode: installMode,
|
|
2772
|
-
error: `${agent.displayName}
|
|
2772
|
+
error: `${agent.displayName} 不支持全局技能安装`
|
|
2773
2773
|
};
|
|
2774
2774
|
const skillName = sanitizeName(skill.installName);
|
|
2775
2775
|
const agentBase = getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent);
|
|
@@ -2779,7 +2779,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2779
2779
|
success: false,
|
|
2780
2780
|
path: flatSkillPath,
|
|
2781
2781
|
mode: installMode,
|
|
2782
|
-
error: "
|
|
2782
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2783
2783
|
};
|
|
2784
2784
|
try {
|
|
2785
2785
|
await mkdir(agentBase, { recursive: true });
|
|
@@ -2798,7 +2798,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2798
2798
|
success: false,
|
|
2799
2799
|
path: flatSkillPath,
|
|
2800
2800
|
mode: installMode,
|
|
2801
|
-
error: error instanceof Error ? error.message : "
|
|
2801
|
+
error: error instanceof Error ? error.message : "未知错误"
|
|
2802
2802
|
};
|
|
2803
2803
|
}
|
|
2804
2804
|
}
|
|
@@ -2809,13 +2809,13 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2809
2809
|
success: false,
|
|
2810
2810
|
path: agentDir,
|
|
2811
2811
|
mode: installMode,
|
|
2812
|
-
error: "
|
|
2812
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2813
2813
|
};
|
|
2814
2814
|
if (!isPathSafe$1(agentBase, agentDir)) return {
|
|
2815
2815
|
success: false,
|
|
2816
2816
|
path: agentDir,
|
|
2817
2817
|
mode: installMode,
|
|
2818
|
-
error: "
|
|
2818
|
+
error: "无效的技能名称:检测到潜在的路径遍历攻击"
|
|
2819
2819
|
};
|
|
2820
2820
|
async function writeSkillFiles(targetDir) {
|
|
2821
2821
|
for (const file of skill.files) {
|
|
@@ -2875,7 +2875,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
|
|
|
2875
2875
|
success: false,
|
|
2876
2876
|
path: agentDir,
|
|
2877
2877
|
mode: installMode,
|
|
2878
|
-
error: error instanceof Error ? error.message : "
|
|
2878
|
+
error: error instanceof Error ? error.message : "未知错误"
|
|
2879
2879
|
};
|
|
2880
2880
|
}
|
|
2881
2881
|
}
|
|
@@ -4056,7 +4056,7 @@ function multiselect(opts) {
|
|
|
4056
4056
|
return multiselect$1({
|
|
4057
4057
|
...opts,
|
|
4058
4058
|
options: opts.options,
|
|
4059
|
-
message: `${opts.message} ${import_picocolors.default.dim("(
|
|
4059
|
+
message: `${opts.message} ${import_picocolors.default.dim("(空格切换)")}`
|
|
4060
4060
|
});
|
|
4061
4061
|
}
|
|
4062
4062
|
async function promptForAgents(message, choices) {
|
|
@@ -4090,7 +4090,7 @@ async function selectAgentsInteractive(options) {
|
|
|
4090
4090
|
const visibleUniversalAgents = getVisibleUniversalAgents().filter(supportsGlobalFilter);
|
|
4091
4091
|
const otherAgents = getNonUniversalAgents().filter((agent) => agent !== "eve" && supportsGlobalFilter(agent));
|
|
4092
4092
|
const universalSection = {
|
|
4093
|
-
title: "
|
|
4093
|
+
title: "共享目录 (.agents/skills)",
|
|
4094
4094
|
items: visibleUniversalAgents.map((a) => ({
|
|
4095
4095
|
value: a,
|
|
4096
4096
|
label: agents[a].displayName
|
|
@@ -4107,7 +4107,7 @@ async function selectAgentsInteractive(options) {
|
|
|
4107
4107
|
lastSelected = await getLastSelectedAgents();
|
|
4108
4108
|
} catch {}
|
|
4109
4109
|
const selected = await searchMultiselect({
|
|
4110
|
-
message: "
|
|
4110
|
+
message: "请选择要安装到的 Agent:",
|
|
4111
4111
|
items: otherChoices,
|
|
4112
4112
|
initialSelected: lastSelected ? lastSelected.filter((a) => otherAgents.includes(a) && !universalAgents.includes(a)) : [],
|
|
4113
4113
|
lockedSection: universalSection
|
|
@@ -4118,29 +4118,29 @@ async function selectAgentsInteractive(options) {
|
|
|
4118
4118
|
return selected;
|
|
4119
4119
|
}
|
|
4120
4120
|
async function handleWellKnownSkills(source, url, options, spinner) {
|
|
4121
|
-
spinner.start("
|
|
4121
|
+
spinner.start("正在从 well-known 端点发现技能...");
|
|
4122
4122
|
const skills = await wellKnownProvider.fetchAllSkills(url);
|
|
4123
4123
|
if (skills.length === 0) {
|
|
4124
|
-
spinner.stop(import_picocolors.default.red("
|
|
4125
|
-
outro(import_picocolors.default.red("
|
|
4124
|
+
spinner.stop(import_picocolors.default.red("未找到技能"));
|
|
4125
|
+
outro(import_picocolors.default.red("该 URL 未找到技能。请确保服务器提供 /.well-known/agent-skills/index.json 或 /.well-known/skills/index.json 文件。"));
|
|
4126
4126
|
process.exit(1);
|
|
4127
4127
|
}
|
|
4128
4128
|
spinner.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
4129
4129
|
for (const skill of skills) {
|
|
4130
4130
|
log.info(`Skill: ${import_picocolors.default.cyan(skill.installName)}`);
|
|
4131
4131
|
log.message(import_picocolors.default.dim(skill.description));
|
|
4132
|
-
if (skill.files.size > 1) log.message(import_picocolors.default.dim(`
|
|
4132
|
+
if (skill.files.size > 1) log.message(import_picocolors.default.dim(` 文件: ${Array.from(skill.files.keys()).join(", ")}`));
|
|
4133
4133
|
}
|
|
4134
4134
|
if (options.list) {
|
|
4135
4135
|
console.log();
|
|
4136
|
-
log.step(import_picocolors.default.bold("
|
|
4136
|
+
log.step(import_picocolors.default.bold("可用技能"));
|
|
4137
4137
|
for (const skill of skills) {
|
|
4138
4138
|
log.message(` ${import_picocolors.default.cyan(skill.installName)}`);
|
|
4139
4139
|
log.message(` ${import_picocolors.default.dim(skill.description)}`);
|
|
4140
|
-
if (skill.files.size > 1) log.message(` ${import_picocolors.default.dim(
|
|
4140
|
+
if (skill.files.size > 1) log.message(` ${import_picocolors.default.dim(`文件: ${skill.files.size}`)}`);
|
|
4141
4141
|
}
|
|
4142
4142
|
console.log();
|
|
4143
|
-
outro("
|
|
4143
|
+
outro("不带 --list 参数运行即可安装");
|
|
4144
4144
|
process.exit(0);
|
|
4145
4145
|
}
|
|
4146
4146
|
let selectedSkills;
|
|
@@ -4150,8 +4150,8 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4150
4150
|
} else if (options.skill && options.skill.length > 0) {
|
|
4151
4151
|
selectedSkills = skills.filter((s) => options.skill.some((name) => s.installName.toLowerCase() === name.toLowerCase() || s.name.toLowerCase() === name.toLowerCase()));
|
|
4152
4152
|
if (selectedSkills.length === 0) {
|
|
4153
|
-
log.error(
|
|
4154
|
-
log.info("
|
|
4153
|
+
log.error(`未找到匹配技能:${options.skill.join(", ")}`);
|
|
4154
|
+
log.info("可用技能:");
|
|
4155
4155
|
for (const s of skills) log.message(` - ${s.installName}`);
|
|
4156
4156
|
process.exit(1);
|
|
4157
4157
|
}
|
|
@@ -4164,7 +4164,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4164
4164
|
log.info(`Installing all ${skills.length} skills`);
|
|
4165
4165
|
} else {
|
|
4166
4166
|
const selected = await multiselect({
|
|
4167
|
-
message: "
|
|
4167
|
+
message: "选择要安装的技能",
|
|
4168
4168
|
options: skills.map((s) => ({
|
|
4169
4169
|
value: s,
|
|
4170
4170
|
label: s.installName,
|
|
@@ -4173,7 +4173,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4173
4173
|
required: true
|
|
4174
4174
|
});
|
|
4175
4175
|
if (isCancel(selected)) {
|
|
4176
|
-
cancel("
|
|
4176
|
+
cancel("安装已取消");
|
|
4177
4177
|
process.exit(0);
|
|
4178
4178
|
}
|
|
4179
4179
|
selectedSkills = selected;
|
|
@@ -4186,27 +4186,27 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4186
4186
|
} else if (options.agent && options.agent.length > 0) {
|
|
4187
4187
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
4188
4188
|
if (invalidAgents.length > 0) {
|
|
4189
|
-
log.error(
|
|
4190
|
-
log.info(
|
|
4189
|
+
log.error(`无效 Agent:${invalidAgents.join(", ")}`);
|
|
4190
|
+
log.info(`可用 Agent:${validAgents.join(", ")}`);
|
|
4191
4191
|
process.exit(1);
|
|
4192
4192
|
}
|
|
4193
4193
|
targetAgents = options.agent;
|
|
4194
4194
|
} else {
|
|
4195
|
-
spinner.start("
|
|
4195
|
+
spinner.start("正在加载 Agent...");
|
|
4196
4196
|
const installedAgents = await detectInstalledAgents();
|
|
4197
4197
|
const totalAgents = Object.keys(agents).length;
|
|
4198
4198
|
spinner.stop(`${totalAgents} agents`);
|
|
4199
4199
|
if (installedAgents.length === 0) if (options.yes) {
|
|
4200
4200
|
targetAgents = validAgents;
|
|
4201
|
-
log.info("
|
|
4201
|
+
log.info("正在安装到全部 Agent");
|
|
4202
4202
|
} else {
|
|
4203
|
-
log.info("
|
|
4204
|
-
const selected = await promptForAgents("
|
|
4203
|
+
log.info("请选择要安装技能的 Agent");
|
|
4204
|
+
const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).map(([key, config]) => ({
|
|
4205
4205
|
value: key,
|
|
4206
4206
|
label: config.displayName
|
|
4207
4207
|
})));
|
|
4208
4208
|
if (isCancel(selected)) {
|
|
4209
|
-
cancel("
|
|
4209
|
+
cancel("安装已取消");
|
|
4210
4210
|
process.exit(0);
|
|
4211
4211
|
}
|
|
4212
4212
|
targetAgents = selected;
|
|
@@ -4220,7 +4220,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4220
4220
|
} else {
|
|
4221
4221
|
const selected = await selectAgentsInteractive({ global: options.global });
|
|
4222
4222
|
if (isCancel(selected)) {
|
|
4223
|
-
cancel("
|
|
4223
|
+
cancel("安装已取消");
|
|
4224
4224
|
process.exit(0);
|
|
4225
4225
|
}
|
|
4226
4226
|
targetAgents = selected;
|
|
@@ -4230,19 +4230,19 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4230
4230
|
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
4231
4231
|
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
4232
4232
|
const scope = await select({
|
|
4233
|
-
message: "
|
|
4233
|
+
message: "安装范围",
|
|
4234
4234
|
options: [{
|
|
4235
4235
|
value: false,
|
|
4236
|
-
label: "
|
|
4237
|
-
hint: "
|
|
4236
|
+
label: "项目",
|
|
4237
|
+
hint: "安装到当前目录(随项目一起提交)"
|
|
4238
4238
|
}, {
|
|
4239
4239
|
value: true,
|
|
4240
|
-
label: "
|
|
4241
|
-
hint: "
|
|
4240
|
+
label: "全局",
|
|
4241
|
+
hint: "安装到主目录(跨所有项目可用)"
|
|
4242
4242
|
}]
|
|
4243
4243
|
});
|
|
4244
4244
|
if (isCancel(scope)) {
|
|
4245
|
-
cancel("
|
|
4245
|
+
cancel("安装已取消");
|
|
4246
4246
|
process.exit(0);
|
|
4247
4247
|
}
|
|
4248
4248
|
installGlobally = scope;
|
|
@@ -4251,19 +4251,19 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4251
4251
|
const uniqueDirs = new Set(targetAgents.map((a) => agents[a].skillsDir));
|
|
4252
4252
|
if (!options.copy && !options.yes && uniqueDirs.size > 1) {
|
|
4253
4253
|
const modeChoice = await select({
|
|
4254
|
-
message: "
|
|
4254
|
+
message: "安装方式",
|
|
4255
4255
|
options: [{
|
|
4256
4256
|
value: "symlink",
|
|
4257
|
-
label: "
|
|
4258
|
-
hint: "
|
|
4257
|
+
label: "符号链接(推荐)",
|
|
4258
|
+
hint: "单一来源,易于更新"
|
|
4259
4259
|
}, {
|
|
4260
4260
|
value: "copy",
|
|
4261
|
-
label: "
|
|
4262
|
-
hint: "
|
|
4261
|
+
label: "复制到所有 Agent",
|
|
4262
|
+
hint: "每个 Agent 独立副本"
|
|
4263
4263
|
}]
|
|
4264
4264
|
});
|
|
4265
4265
|
if (isCancel(modeChoice)) {
|
|
4266
|
-
cancel("
|
|
4266
|
+
cancel("安装已取消");
|
|
4267
4267
|
process.exit(0);
|
|
4268
4268
|
}
|
|
4269
4269
|
installMode = modeChoice;
|
|
@@ -4292,17 +4292,17 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4292
4292
|
if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
|
|
4293
4293
|
}
|
|
4294
4294
|
console.log();
|
|
4295
|
-
note(summaryLines.join("\n"), "
|
|
4295
|
+
note(summaryLines.join("\n"), "安装摘要");
|
|
4296
4296
|
if (!options.yes) {
|
|
4297
|
-
const confirmed = await confirm({ message: "
|
|
4297
|
+
const confirmed = await confirm({ message: "确认安装?" });
|
|
4298
4298
|
if (isCancel(confirmed) || !confirmed) {
|
|
4299
|
-
cancel("
|
|
4299
|
+
cancel("安装已取消");
|
|
4300
4300
|
process.exit(0);
|
|
4301
4301
|
}
|
|
4302
4302
|
}
|
|
4303
4303
|
const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);
|
|
4304
4304
|
const wellKnownPrivacyPromise = isSourcePrivate(sourceIdentifier).catch(() => null);
|
|
4305
|
-
spinner.start("
|
|
4305
|
+
spinner.start("正在安装技能...");
|
|
4306
4306
|
const results = [];
|
|
4307
4307
|
for (const skill of selectedSkills) for (const agent of targetAgents) {
|
|
4308
4308
|
const result = await installWellKnownSkillForAgent(skill, agent, {
|
|
@@ -4315,7 +4315,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4315
4315
|
...result
|
|
4316
4316
|
});
|
|
4317
4317
|
}
|
|
4318
|
-
spinner.stop("
|
|
4318
|
+
spinner.stop("安装完成");
|
|
4319
4319
|
console.log();
|
|
4320
4320
|
const successful = results.filter((r) => r.success);
|
|
4321
4321
|
const failed = results.filter((r) => !r.success);
|
|
@@ -4378,17 +4378,17 @@ async function handleWellKnownSkills(source, url, options, spinner) {
|
|
|
4378
4378
|
const title = import_picocolors.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
4379
4379
|
note(resultLines.join("\n"), title);
|
|
4380
4380
|
if (symlinkFailures.length > 0) {
|
|
4381
|
-
log.warn(import_picocolors.default.yellow(
|
|
4382
|
-
log.message(import_picocolors.default.dim("
|
|
4381
|
+
log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$1(copiedAgents)}`));
|
|
4382
|
+
log.message(import_picocolors.default.dim(" 已改为复制文件。在 Windows 上,请启用开发者模式以支持符号链接。"));
|
|
4383
4383
|
}
|
|
4384
4384
|
}
|
|
4385
4385
|
if (failed.length > 0) {
|
|
4386
4386
|
console.log();
|
|
4387
|
-
log.error(import_picocolors.default.red(
|
|
4387
|
+
log.error(import_picocolors.default.red(`安装失败 ${failed.length} 个`));
|
|
4388
4388
|
for (const r of failed) log.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
4389
4389
|
}
|
|
4390
4390
|
console.log();
|
|
4391
|
-
outro(import_picocolors.default.green("
|
|
4391
|
+
outro(import_picocolors.default.green("完成!") + import_picocolors.default.dim(" 使用前请审阅技能;技能以 Agent 的全部权限运行。"));
|
|
4392
4392
|
await promptForFindSkills(options, targetAgents);
|
|
4393
4393
|
}
|
|
4394
4394
|
async function installFromSkillHub(parsed, options, spinner) {
|
|
@@ -4399,10 +4399,10 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4399
4399
|
let namespace;
|
|
4400
4400
|
let slug;
|
|
4401
4401
|
if (restParts.length === 0) {
|
|
4402
|
-
spinner.start(
|
|
4402
|
+
spinner.start(`正在 SkillHub 搜索 "${rawRef}"...`);
|
|
4403
4403
|
const hits = ((await api.searchSkills(rawRef)).data || []).slice(0, 20);
|
|
4404
4404
|
if (hits.length === 0) {
|
|
4405
|
-
spinner.stop(import_picocolors.default.red("
|
|
4405
|
+
spinner.stop(import_picocolors.default.red("无结果"));
|
|
4406
4406
|
outro(import_picocolors.default.red(`No skills found on SkillHub for "${rawRef}".`));
|
|
4407
4407
|
process.exit(1);
|
|
4408
4408
|
}
|
|
@@ -4411,10 +4411,10 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4411
4411
|
const hit = hits[0];
|
|
4412
4412
|
namespace = hit.namespace;
|
|
4413
4413
|
slug = hit.slug;
|
|
4414
|
-
log.info(
|
|
4414
|
+
log.info(`自动选择:${import_picocolors.default.cyan(`@${namespace}/${slug}`)} — ${hit.description || hit.name}`);
|
|
4415
4415
|
} else {
|
|
4416
4416
|
const idx = await select({
|
|
4417
|
-
message: "
|
|
4417
|
+
message: "匹配到多个技能 — 请选择一个",
|
|
4418
4418
|
options: hits.map((h, idx) => ({
|
|
4419
4419
|
value: idx,
|
|
4420
4420
|
label: `@${h.namespace}/${h.slug}`,
|
|
@@ -4422,7 +4422,7 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4422
4422
|
}))
|
|
4423
4423
|
});
|
|
4424
4424
|
if (isCancel(idx)) {
|
|
4425
|
-
cancel("
|
|
4425
|
+
cancel("安装已取消");
|
|
4426
4426
|
process.exit(0);
|
|
4427
4427
|
}
|
|
4428
4428
|
const chosen = hits[idx];
|
|
@@ -4435,13 +4435,13 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4435
4435
|
}
|
|
4436
4436
|
const canonicalSlug = toCanonicalSlug(namespace, slug);
|
|
4437
4437
|
const version = parsed.ref || "latest";
|
|
4438
|
-
spinner.start(
|
|
4438
|
+
spinner.start(`正在获取 @${namespace}/${slug} 的技能元数据...`);
|
|
4439
4439
|
let metadata;
|
|
4440
4440
|
try {
|
|
4441
4441
|
metadata = await api.getSkill(canonicalSlug);
|
|
4442
4442
|
} catch (err) {
|
|
4443
|
-
spinner.stop(import_picocolors.default.red("
|
|
4444
|
-
outro(import_picocolors.default.red(
|
|
4443
|
+
spinner.stop(import_picocolors.default.red("获取元数据失败"));
|
|
4444
|
+
outro(import_picocolors.default.red(`未在 SkillHub 上找到技能 @${namespace}/${slug}: ${err.message}`));
|
|
4445
4445
|
process.exit(1);
|
|
4446
4446
|
}
|
|
4447
4447
|
const meta = metadata;
|
|
@@ -4449,39 +4449,39 @@ async function installFromSkillHub(parsed, options, spinner) {
|
|
|
4449
4449
|
const tempDir = join(tmpdir(), `.bfi-skillhub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
|
|
4450
4450
|
mkdirSync(tempDir, { recursive: true });
|
|
4451
4451
|
const zipPath = join(tempDir, "skill.zip");
|
|
4452
|
-
spinner.start("
|
|
4452
|
+
spinner.start("正在下载技能...");
|
|
4453
4453
|
try {
|
|
4454
4454
|
await api.downloadSkill(namespace, slug, version, zipPath);
|
|
4455
4455
|
} catch (err) {
|
|
4456
|
-
spinner.stop(import_picocolors.default.red("
|
|
4456
|
+
spinner.stop(import_picocolors.default.red("下载失败"));
|
|
4457
4457
|
try {
|
|
4458
4458
|
rmSync(tempDir, {
|
|
4459
4459
|
recursive: true,
|
|
4460
4460
|
force: true
|
|
4461
4461
|
});
|
|
4462
4462
|
} catch {}
|
|
4463
|
-
outro(import_picocolors.default.red(
|
|
4463
|
+
outro(import_picocolors.default.red(`下载失败 @${namespace}/${slug}:${err.message}`));
|
|
4464
4464
|
process.exit(1);
|
|
4465
4465
|
}
|
|
4466
|
-
spinner.stop("
|
|
4467
|
-
spinner.start("
|
|
4466
|
+
spinner.stop("下载完成");
|
|
4467
|
+
spinner.start("正在解压...");
|
|
4468
4468
|
const extractDir = join(tempDir, "extracted");
|
|
4469
4469
|
mkdirSync(extractDir, { recursive: true });
|
|
4470
4470
|
try {
|
|
4471
4471
|
await extractZip(zipPath, extractDir);
|
|
4472
4472
|
} catch (err) {
|
|
4473
|
-
spinner.stop(import_picocolors.default.red("
|
|
4473
|
+
spinner.stop(import_picocolors.default.red("解压失败"));
|
|
4474
4474
|
try {
|
|
4475
4475
|
rmSync(tempDir, {
|
|
4476
4476
|
recursive: true,
|
|
4477
4477
|
force: true
|
|
4478
4478
|
});
|
|
4479
4479
|
} catch {}
|
|
4480
|
-
outro(import_picocolors.default.red(
|
|
4480
|
+
outro(import_picocolors.default.red(`解压技能压缩包失败:${err.message}`));
|
|
4481
4481
|
process.exit(1);
|
|
4482
4482
|
}
|
|
4483
|
-
spinner.stop("
|
|
4484
|
-
spinner.start("
|
|
4483
|
+
spinner.stop("解压完成");
|
|
4484
|
+
spinner.start("正在发现技能...");
|
|
4485
4485
|
const skills = await discoverSkills(extractDir, parsed.subpath, {
|
|
4486
4486
|
includeInternal: !!(options.skill && options.skill.length > 0),
|
|
4487
4487
|
fullDepth: options.fullDepth
|
|
@@ -4507,7 +4507,7 @@ async function runAdd(args, options = {}) {
|
|
|
4507
4507
|
let installTipShown = false;
|
|
4508
4508
|
const showInstallTip = () => {
|
|
4509
4509
|
if (installTipShown) return;
|
|
4510
|
-
log.message(import_picocolors.default.dim("
|
|
4510
|
+
log.message(import_picocolors.default.dim("提示:使用 --yes (-y) 和 --global (-g) 参数可跳过交互提示直接安装。"));
|
|
4511
4511
|
installTipShown = true;
|
|
4512
4512
|
};
|
|
4513
4513
|
if (!source) {
|
|
@@ -4537,14 +4537,14 @@ async function runAdd(args, options = {}) {
|
|
|
4537
4537
|
}
|
|
4538
4538
|
console.log();
|
|
4539
4539
|
if (!agentResult.isAgent) intro(import_picocolors.default.bgCyan(import_picocolors.default.black(" skills ")));
|
|
4540
|
-
if (agentResult.isAgent) log.info(import_picocolors.default.bgCyan(import_picocolors.default.black(import_picocolors.default.bold(` ${agentResult.agent.name} `))) + " Agent
|
|
4540
|
+
if (agentResult.isAgent) log.info(import_picocolors.default.bgCyan(import_picocolors.default.black(import_picocolors.default.bold(` ${agentResult.agent.name} `))) + " 已检测到 Agent — 以非交互模式安装");
|
|
4541
4541
|
else if (!process.stdin.isTTY) showInstallTip();
|
|
4542
4542
|
let tempDir = null;
|
|
4543
4543
|
try {
|
|
4544
4544
|
const spinner$2 = spinner();
|
|
4545
|
-
spinner$2.start("
|
|
4545
|
+
spinner$2.start("正在解析源...");
|
|
4546
4546
|
const parsed = parseSource(source);
|
|
4547
|
-
spinner$2.stop(
|
|
4547
|
+
spinner$2.stop(`源:${parsed.type === "local" ? parsed.localPath : parsed.url}${parsed.ref ? ` @ ${import_picocolors.default.yellow(parsed.ref)}` : ""}${parsed.subpath ? ` (${parsed.subpath})` : ""}${parsed.skillFilter ? ` ${import_picocolors.default.dim("@")}${import_picocolors.default.cyan(parsed.skillFilter)}` : ""}`);
|
|
4548
4548
|
const ownerRepoRaw = getOwnerRepo(parsed);
|
|
4549
4549
|
const repoPrivacyPromise = (() => {
|
|
4550
4550
|
if (!ownerRepoRaw) return Promise.resolve(null);
|
|
@@ -4568,14 +4568,14 @@ async function runAdd(args, options = {}) {
|
|
|
4568
4568
|
skills = result.skills;
|
|
4569
4569
|
tempDir = result.tempDir;
|
|
4570
4570
|
} else if (parsed.type === "local") {
|
|
4571
|
-
spinner$2.start("
|
|
4571
|
+
spinner$2.start("正在验证本地路径...");
|
|
4572
4572
|
if (!existsSync(parsed.localPath)) {
|
|
4573
|
-
spinner$2.stop(import_picocolors.default.red("
|
|
4574
|
-
outro(import_picocolors.default.red(
|
|
4573
|
+
spinner$2.stop(import_picocolors.default.red("路径未找到"));
|
|
4574
|
+
outro(import_picocolors.default.red(`本地路径不存在:${parsed.localPath}`));
|
|
4575
4575
|
process.exit(1);
|
|
4576
4576
|
}
|
|
4577
|
-
spinner$2.stop("
|
|
4578
|
-
spinner$2.start("
|
|
4577
|
+
spinner$2.stop("本地路径验证通过");
|
|
4578
|
+
spinner$2.start("正在发现技能...");
|
|
4579
4579
|
skills = await discoverSkills(parsed.localPath, parsed.subpath, {
|
|
4580
4580
|
includeInternal,
|
|
4581
4581
|
fullDepth: options.fullDepth
|
|
@@ -4590,7 +4590,7 @@ async function runAdd(args, options = {}) {
|
|
|
4590
4590
|
const owner = ownerRepo?.split("/")[0]?.toLowerCase();
|
|
4591
4591
|
const isSelfHostedRepo = !!ownerRepo && Object.hasOwn(BLOB_ALLOWED_REPOS, ownerRepo.toLowerCase());
|
|
4592
4592
|
if (ownerRepo && owner && (isSelfHostedRepo || BLOB_ALLOWED_OWNERS.includes(owner))) {
|
|
4593
|
-
spinner$2.start("
|
|
4593
|
+
spinner$2.start("正在获取技能...");
|
|
4594
4594
|
blobResult = await tryBlobInstall(ownerRepo, {
|
|
4595
4595
|
subpath: parsed.subpath,
|
|
4596
4596
|
skillFilter: parsed.skillFilter,
|
|
@@ -4604,35 +4604,35 @@ async function runAdd(args, options = {}) {
|
|
|
4604
4604
|
skills = blobResult.skills;
|
|
4605
4605
|
spinner$2.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
4606
4606
|
} else {
|
|
4607
|
-
spinner$2.start("
|
|
4607
|
+
spinner$2.start("正在克隆仓库...");
|
|
4608
4608
|
tempDir = await cloneRepo(parsed.url, parsed.ref);
|
|
4609
|
-
spinner$2.stop("
|
|
4610
|
-
spinner$2.start("
|
|
4609
|
+
spinner$2.stop("仓库克隆完成");
|
|
4610
|
+
spinner$2.start("正在发现技能...");
|
|
4611
4611
|
skills = await discoverSkills(tempDir, parsed.subpath, {
|
|
4612
4612
|
includeInternal,
|
|
4613
4613
|
fullDepth: options.fullDepth
|
|
4614
4614
|
});
|
|
4615
4615
|
}
|
|
4616
4616
|
} else {
|
|
4617
|
-
spinner$2.start("
|
|
4617
|
+
spinner$2.start("正在克隆仓库...");
|
|
4618
4618
|
tempDir = await cloneRepo(parsed.url, parsed.ref);
|
|
4619
|
-
spinner$2.stop("
|
|
4620
|
-
spinner$2.start("
|
|
4619
|
+
spinner$2.stop("仓库克隆完成");
|
|
4620
|
+
spinner$2.start("正在发现技能...");
|
|
4621
4621
|
skills = await discoverSkills(tempDir, parsed.subpath, {
|
|
4622
4622
|
includeInternal,
|
|
4623
4623
|
fullDepth: options.fullDepth
|
|
4624
4624
|
});
|
|
4625
4625
|
}
|
|
4626
4626
|
if (skills.length === 0) {
|
|
4627
|
-
spinner$2.stop(import_picocolors.default.red("
|
|
4628
|
-
outro(import_picocolors.default.red("
|
|
4627
|
+
spinner$2.stop(import_picocolors.default.red("未找到技能"));
|
|
4628
|
+
outro(import_picocolors.default.red("未找到有效技能。技能需要包含 name 和 description 的 SKILL.md 文件。"));
|
|
4629
4629
|
await cleanup(tempDir);
|
|
4630
4630
|
process.exit(1);
|
|
4631
4631
|
}
|
|
4632
4632
|
if (!blobResult) spinner$2.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
|
|
4633
4633
|
if (options.list) {
|
|
4634
4634
|
console.log();
|
|
4635
|
-
log.step(import_picocolors.default.bold("
|
|
4635
|
+
log.step(import_picocolors.default.bold("可用技能"));
|
|
4636
4636
|
const groupedSkills = {};
|
|
4637
4637
|
const ungroupedSkills = [];
|
|
4638
4638
|
for (const skill of skills) if (skill.pluginName) {
|
|
@@ -4658,7 +4658,7 @@ async function runAdd(args, options = {}) {
|
|
|
4658
4658
|
}
|
|
4659
4659
|
}
|
|
4660
4660
|
console.log();
|
|
4661
|
-
outro("
|
|
4661
|
+
outro("使用 --skill <name> 安装指定技能");
|
|
4662
4662
|
await cleanup(tempDir);
|
|
4663
4663
|
process.exit(0);
|
|
4664
4664
|
}
|
|
@@ -4669,8 +4669,8 @@ async function runAdd(args, options = {}) {
|
|
|
4669
4669
|
} else if (options.skill && options.skill.length > 0) {
|
|
4670
4670
|
selectedSkills = filterSkills(skills, options.skill);
|
|
4671
4671
|
if (selectedSkills.length === 0) {
|
|
4672
|
-
log.error(
|
|
4673
|
-
log.info("
|
|
4672
|
+
log.error(`未找到匹配技能:${options.skill.join(", ")}`);
|
|
4673
|
+
log.info("可用技能:");
|
|
4674
4674
|
for (const s of skills) log.message(` - ${getSkillDisplayName(s)}`);
|
|
4675
4675
|
await cleanup(tempDir);
|
|
4676
4676
|
process.exit(1);
|
|
@@ -4706,12 +4706,12 @@ async function runAdd(args, options = {}) {
|
|
|
4706
4706
|
});
|
|
4707
4707
|
}
|
|
4708
4708
|
selected = await groupMultiselect({
|
|
4709
|
-
message: `Select skills to install ${import_picocolors.default.dim("(
|
|
4709
|
+
message: `Select skills to install ${import_picocolors.default.dim("(空格切换)")}`,
|
|
4710
4710
|
options: grouped,
|
|
4711
4711
|
required: true
|
|
4712
4712
|
});
|
|
4713
4713
|
} else selected = await multiselect({
|
|
4714
|
-
message: "
|
|
4714
|
+
message: "选择要安装的技能",
|
|
4715
4715
|
options: sortedSkills.map((s) => ({
|
|
4716
4716
|
value: s,
|
|
4717
4717
|
label: getSkillDisplayName(s),
|
|
@@ -4720,7 +4720,7 @@ async function runAdd(args, options = {}) {
|
|
|
4720
4720
|
required: true
|
|
4721
4721
|
});
|
|
4722
4722
|
if (isCancel(selected)) {
|
|
4723
|
-
cancel("
|
|
4723
|
+
cancel("安装已取消");
|
|
4724
4724
|
await cleanup(tempDir);
|
|
4725
4725
|
process.exit(0);
|
|
4726
4726
|
}
|
|
@@ -4736,14 +4736,14 @@ async function runAdd(args, options = {}) {
|
|
|
4736
4736
|
} else if (options.agent && options.agent.length > 0) {
|
|
4737
4737
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
4738
4738
|
if (invalidAgents.length > 0) {
|
|
4739
|
-
log.error(
|
|
4740
|
-
log.info(
|
|
4739
|
+
log.error(`无效 Agent:${invalidAgents.join(", ")}`);
|
|
4740
|
+
log.info(`可用 Agent:${validAgents.join(", ")}`);
|
|
4741
4741
|
await cleanup(tempDir);
|
|
4742
4742
|
process.exit(1);
|
|
4743
4743
|
}
|
|
4744
4744
|
targetAgents = options.agent;
|
|
4745
4745
|
} else {
|
|
4746
|
-
spinner$2.start("
|
|
4746
|
+
spinner$2.start("正在加载 Agent...");
|
|
4747
4747
|
const installedAgents = await detectInstalledAgents();
|
|
4748
4748
|
const totalAgents = Object.keys(agents).length;
|
|
4749
4749
|
spinner$2.stop(`${totalAgents} agents`);
|
|
@@ -4753,17 +4753,17 @@ async function runAdd(args, options = {}) {
|
|
|
4753
4753
|
initialValue: true
|
|
4754
4754
|
});
|
|
4755
4755
|
if (isCancel(useEve)) {
|
|
4756
|
-
cancel("
|
|
4756
|
+
cancel("安装已取消");
|
|
4757
4757
|
await cleanup(tempDir);
|
|
4758
4758
|
process.exit(0);
|
|
4759
4759
|
}
|
|
4760
4760
|
if (useEve) {
|
|
4761
4761
|
targetAgents = ["eve"];
|
|
4762
|
-
log.info(
|
|
4762
|
+
log.info(`安装到:${import_picocolors.default.cyan(EVE_AGENT_LABEL)}`);
|
|
4763
4763
|
} else {
|
|
4764
4764
|
const selected = await selectAgentsInteractive({ global: options.global });
|
|
4765
4765
|
if (isCancel(selected)) {
|
|
4766
|
-
cancel("
|
|
4766
|
+
cancel("安装已取消");
|
|
4767
4767
|
await cleanup(tempDir);
|
|
4768
4768
|
process.exit(0);
|
|
4769
4769
|
}
|
|
@@ -4771,15 +4771,15 @@ async function runAdd(args, options = {}) {
|
|
|
4771
4771
|
}
|
|
4772
4772
|
} else if (installedAgents.length === 0) if (options.yes) {
|
|
4773
4773
|
targetAgents = validAgents;
|
|
4774
|
-
log.info("
|
|
4774
|
+
log.info("正在安装到全部 Agent");
|
|
4775
4775
|
} else {
|
|
4776
|
-
log.info("
|
|
4777
|
-
const selected = await promptForAgents("
|
|
4776
|
+
log.info("请选择要安装技能的 Agent");
|
|
4777
|
+
const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
|
|
4778
4778
|
value: key,
|
|
4779
4779
|
label: config.displayName
|
|
4780
4780
|
})));
|
|
4781
4781
|
if (isCancel(selected)) {
|
|
4782
|
-
cancel("
|
|
4782
|
+
cancel("安装已取消");
|
|
4783
4783
|
await cleanup(tempDir);
|
|
4784
4784
|
process.exit(0);
|
|
4785
4785
|
}
|
|
@@ -4794,7 +4794,7 @@ async function runAdd(args, options = {}) {
|
|
|
4794
4794
|
} else {
|
|
4795
4795
|
const selected = await selectAgentsInteractive({ global: options.global });
|
|
4796
4796
|
if (isCancel(selected)) {
|
|
4797
|
-
cancel("
|
|
4797
|
+
cancel("安装已取消");
|
|
4798
4798
|
await cleanup(tempDir);
|
|
4799
4799
|
process.exit(0);
|
|
4800
4800
|
}
|
|
@@ -4808,10 +4808,10 @@ async function runAdd(args, options = {}) {
|
|
|
4808
4808
|
if (options.subagent && options.subagent.length > 0) eveSubagentTargets = options.subagent.map((s) => s === "root" || s === "." ? void 0 : s);
|
|
4809
4809
|
else if (availableSubagents.length > 0 && !options.yes) {
|
|
4810
4810
|
const selectedSubagents = await multiselect$1({
|
|
4811
|
-
message: "
|
|
4811
|
+
message: "Eve 技能安装位置?",
|
|
4812
4812
|
options: [{
|
|
4813
4813
|
value: "",
|
|
4814
|
-
label: "
|
|
4814
|
+
label: "根 Agent",
|
|
4815
4815
|
hint: "agent/skills"
|
|
4816
4816
|
}, ...availableSubagents.map((name) => ({
|
|
4817
4817
|
value: name,
|
|
@@ -4822,7 +4822,7 @@ async function runAdd(args, options = {}) {
|
|
|
4822
4822
|
required: true
|
|
4823
4823
|
});
|
|
4824
4824
|
if (isCancel(selectedSubagents)) {
|
|
4825
|
-
cancel("
|
|
4825
|
+
cancel("安装已取消");
|
|
4826
4826
|
await cleanup(tempDir);
|
|
4827
4827
|
process.exit(0);
|
|
4828
4828
|
}
|
|
@@ -4834,19 +4834,19 @@ async function runAdd(args, options = {}) {
|
|
|
4834
4834
|
const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
|
|
4835
4835
|
if (options.global === void 0 && !options.yes && supportsGlobal) {
|
|
4836
4836
|
const scope = await select({
|
|
4837
|
-
message: "
|
|
4837
|
+
message: "安装范围",
|
|
4838
4838
|
options: [{
|
|
4839
4839
|
value: false,
|
|
4840
4840
|
label: "Project",
|
|
4841
|
-
hint: "
|
|
4841
|
+
hint: "安装到当前目录(随项目一起提交)"
|
|
4842
4842
|
}, {
|
|
4843
4843
|
value: true,
|
|
4844
4844
|
label: "Global",
|
|
4845
|
-
hint: "
|
|
4845
|
+
hint: "安装到主目录(跨所有项目可用)"
|
|
4846
4846
|
}]
|
|
4847
4847
|
});
|
|
4848
4848
|
if (isCancel(scope)) {
|
|
4849
|
-
cancel("
|
|
4849
|
+
cancel("安装已取消");
|
|
4850
4850
|
await cleanup(tempDir);
|
|
4851
4851
|
process.exit(0);
|
|
4852
4852
|
}
|
|
@@ -4857,19 +4857,19 @@ async function runAdd(args, options = {}) {
|
|
|
4857
4857
|
const uniqueDirs = new Set(installTargets.map((t) => t.subagent ? `eve:subagent:${t.subagent}` : agents[t.agent].skillsDir));
|
|
4858
4858
|
if (!options.copy && !options.yes && uniqueDirs.size > 1 && !allEve) {
|
|
4859
4859
|
const modeChoice = await select({
|
|
4860
|
-
message: "
|
|
4860
|
+
message: "安装方式",
|
|
4861
4861
|
options: [{
|
|
4862
4862
|
value: "symlink",
|
|
4863
|
-
label: "
|
|
4864
|
-
hint: "
|
|
4863
|
+
label: "符号链接(推荐)",
|
|
4864
|
+
hint: "单一来源,易于更新"
|
|
4865
4865
|
}, {
|
|
4866
4866
|
value: "copy",
|
|
4867
|
-
label: "
|
|
4868
|
-
hint: "
|
|
4867
|
+
label: "复制到所有 Agent",
|
|
4868
|
+
hint: "每个 Agent 独立副本"
|
|
4869
4869
|
}]
|
|
4870
4870
|
});
|
|
4871
4871
|
if (isCancel(modeChoice)) {
|
|
4872
|
-
cancel("
|
|
4872
|
+
cancel("安装已取消");
|
|
4873
4873
|
await cleanup(tempDir);
|
|
4874
4874
|
process.exit(0);
|
|
4875
4875
|
}
|
|
@@ -4927,7 +4927,7 @@ async function runAdd(args, options = {}) {
|
|
|
4927
4927
|
printSkillSummary(ungroupedSummary);
|
|
4928
4928
|
}
|
|
4929
4929
|
console.log();
|
|
4930
|
-
note(summaryLines.join("\n"), "
|
|
4930
|
+
note(summaryLines.join("\n"), "安装摘要");
|
|
4931
4931
|
try {
|
|
4932
4932
|
const auditData = await auditPromise;
|
|
4933
4933
|
if (auditData && ownerRepoForAudit) {
|
|
@@ -4935,18 +4935,18 @@ async function runAdd(args, options = {}) {
|
|
|
4935
4935
|
slug: getSkillDisplayName(s),
|
|
4936
4936
|
displayName: getSkillDisplayName(s)
|
|
4937
4937
|
})), ownerRepoForAudit);
|
|
4938
|
-
if (securityLines.length > 0) note(securityLines.join("\n"), "
|
|
4938
|
+
if (securityLines.length > 0) note(securityLines.join("\n"), "安全风险评估");
|
|
4939
4939
|
}
|
|
4940
4940
|
} catch {}
|
|
4941
4941
|
if (!options.yes) {
|
|
4942
|
-
const confirmed = await confirm({ message: "
|
|
4942
|
+
const confirmed = await confirm({ message: "确认安装?" });
|
|
4943
4943
|
if (isCancel(confirmed) || !confirmed) {
|
|
4944
|
-
cancel("
|
|
4944
|
+
cancel("安装已取消");
|
|
4945
4945
|
await cleanup(tempDir);
|
|
4946
4946
|
process.exit(0);
|
|
4947
4947
|
}
|
|
4948
4948
|
}
|
|
4949
|
-
spinner$2.start("
|
|
4949
|
+
spinner$2.start("正在安装技能...");
|
|
4950
4950
|
const results = [];
|
|
4951
4951
|
for (const skill of selectedSkills) for (const target of installTargets) {
|
|
4952
4952
|
const { agent, subagent } = target;
|
|
@@ -4983,7 +4983,7 @@ async function runAdd(args, options = {}) {
|
|
|
4983
4983
|
...result
|
|
4984
4984
|
});
|
|
4985
4985
|
}
|
|
4986
|
-
spinner$2.stop("
|
|
4986
|
+
spinner$2.stop("安装完成");
|
|
4987
4987
|
console.log();
|
|
4988
4988
|
const successful = results.filter((r) => r.success);
|
|
4989
4989
|
const failed = results.filter((r) => !r.success);
|
|
@@ -5073,7 +5073,7 @@ async function runAdd(args, options = {}) {
|
|
|
5073
5073
|
const skillResults = bySkill.get(entry.skill) || [];
|
|
5074
5074
|
const firstResult = skillResults[0];
|
|
5075
5075
|
if (firstResult.mode === "copy") {
|
|
5076
|
-
resultLines.push(`${import_picocolors.default.green("✓")} ${entry.skill} ${import_picocolors.default.dim("(
|
|
5076
|
+
resultLines.push(`${import_picocolors.default.green("✓")} ${entry.skill} ${import_picocolors.default.dim("(已复制)")}`);
|
|
5077
5077
|
for (const r of skillResults) {
|
|
5078
5078
|
const shortPath = shortenPath$1(r.path, cwd);
|
|
5079
5079
|
resultLines.push(` ${import_picocolors.default.dim("→")} ${shortPath}`);
|
|
@@ -5104,13 +5104,13 @@ async function runAdd(args, options = {}) {
|
|
|
5104
5104
|
const title = import_picocolors.default.green(`Installed ${skillCount} skill${skillCount !== 1 ? "s" : ""}`);
|
|
5105
5105
|
note(resultLines.join("\n"), title);
|
|
5106
5106
|
if (symlinkFailures.length > 0) {
|
|
5107
|
-
log.warn(import_picocolors.default.yellow(
|
|
5108
|
-
log.message(import_picocolors.default.dim("
|
|
5107
|
+
log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$1(copiedAgents)}`));
|
|
5108
|
+
log.message(import_picocolors.default.dim(" 已改为复制文件。在 Windows 上,请启用开发者模式以支持符号链接。"));
|
|
5109
5109
|
}
|
|
5110
5110
|
}
|
|
5111
5111
|
if (failed.length > 0) {
|
|
5112
5112
|
console.log();
|
|
5113
|
-
log.error(import_picocolors.default.red(
|
|
5113
|
+
log.error(import_picocolors.default.red(`安装失败 ${failed.length} 个`));
|
|
5114
5114
|
for (const r of failed) log.message(` ${import_picocolors.default.red("✗")} ${r.skill} → ${r.agent}: ${import_picocolors.default.dim(r.error)}`);
|
|
5115
5115
|
}
|
|
5116
5116
|
console.log();
|
|
@@ -5118,11 +5118,11 @@ async function runAdd(args, options = {}) {
|
|
|
5118
5118
|
await promptForFindSkills(options, targetAgents);
|
|
5119
5119
|
} catch (error) {
|
|
5120
5120
|
if (error instanceof GitCloneError) {
|
|
5121
|
-
log.error(import_picocolors.default.red("
|
|
5121
|
+
log.error(import_picocolors.default.red("克隆仓库失败"));
|
|
5122
5122
|
for (const line of error.message.split("\n")) log.message(import_picocolors.default.dim(line));
|
|
5123
5123
|
} else log.error(error instanceof Error ? error.message : "Unknown error occurred");
|
|
5124
5124
|
showInstallTip();
|
|
5125
|
-
outro(import_picocolors.default.red("
|
|
5125
|
+
outro(import_picocolors.default.red("安装失败"));
|
|
5126
5126
|
process.exit(1);
|
|
5127
5127
|
} finally {
|
|
5128
5128
|
await cleanup(tempDir);
|
|
@@ -5143,7 +5143,7 @@ async function promptForFindSkills(options, targetAgents) {
|
|
|
5143
5143
|
return;
|
|
5144
5144
|
}
|
|
5145
5145
|
console.log();
|
|
5146
|
-
log.message(import_picocolors.default.dim("
|
|
5146
|
+
log.message(import_picocolors.default.dim("一次性提示 - 关闭后将不再询问。"));
|
|
5147
5147
|
const install = await confirm({ message: `Install the ${import_picocolors.default.cyan("find-skills")} skill? It helps your agent discover and suggest skills.` });
|
|
5148
5148
|
if (isCancel(install)) {
|
|
5149
5149
|
await dismissPrompt("findSkillsPrompt");
|
|
@@ -5154,7 +5154,7 @@ async function promptForFindSkills(options, targetAgents) {
|
|
|
5154
5154
|
const findSkillsAgents = targetAgents?.filter((a) => a !== "replit");
|
|
5155
5155
|
if (!findSkillsAgents || findSkillsAgents.length === 0) return;
|
|
5156
5156
|
console.log();
|
|
5157
|
-
log.step("
|
|
5157
|
+
log.step("正在安装 find-skills 技能...");
|
|
5158
5158
|
try {
|
|
5159
5159
|
await runAdd(["vercel-labs/skills"], {
|
|
5160
5160
|
skill: ["find-skills"],
|
|
@@ -5163,12 +5163,12 @@ async function promptForFindSkills(options, targetAgents) {
|
|
|
5163
5163
|
agent: findSkillsAgents
|
|
5164
5164
|
});
|
|
5165
5165
|
} catch {
|
|
5166
|
-
log.warn("
|
|
5166
|
+
log.warn("安装 find-skills 失败。你可以稍后重试:");
|
|
5167
5167
|
log.message(import_picocolors.default.dim(" npx skills add vercel-labs/skills@find-skills -g -y --all"));
|
|
5168
5168
|
}
|
|
5169
5169
|
} else {
|
|
5170
5170
|
await dismissPrompt("findSkillsPrompt");
|
|
5171
|
-
log.message(import_picocolors.default.dim("
|
|
5171
|
+
log.message(import_picocolors.default.dim("你可以稍后通过以下命令安装:npx skills add vercel-labs/skills@find-skills"));
|
|
5172
5172
|
}
|
|
5173
5173
|
} catch {}
|
|
5174
5174
|
}
|
|
@@ -5204,12 +5204,12 @@ function parseAddOptions(args) {
|
|
|
5204
5204
|
i--;
|
|
5205
5205
|
} else if (arg === "--metadata") {
|
|
5206
5206
|
const metadata = args[++i];
|
|
5207
|
-
if (metadata === void 0) errors.push("--metadata
|
|
5207
|
+
if (metadata === void 0) errors.push("--metadata 需要 JSON 值");
|
|
5208
5208
|
else try {
|
|
5209
5209
|
JSON.parse(metadata);
|
|
5210
5210
|
options.metadata = metadata;
|
|
5211
5211
|
} catch {
|
|
5212
|
-
errors.push("--metadata
|
|
5212
|
+
errors.push("--metadata 必须是有效的 JSON");
|
|
5213
5213
|
}
|
|
5214
5214
|
} else if (arg === "--full-depth") options.fullDepth = true;
|
|
5215
5215
|
else if (arg === "--copy") options.copy = true;
|
|
@@ -5241,7 +5241,7 @@ function formatInstalls$1(count) {
|
|
|
5241
5241
|
if (!count || count <= 0) return "";
|
|
5242
5242
|
if (count >= 1e6) return `${(count / 1e6).toFixed(1).replace(/\.0$/, "")}M installs`;
|
|
5243
5243
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1).replace(/\.0$/, "")}K installs`;
|
|
5244
|
-
return `${count}
|
|
5244
|
+
return `${count} 次安装`;
|
|
5245
5245
|
}
|
|
5246
5246
|
const GITHUB_OWNER_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,38})$/i;
|
|
5247
5247
|
function parseFindOptions(args) {
|
|
@@ -5324,11 +5324,11 @@ async function runSearchPrompt(initialQuery = "", owner) {
|
|
|
5324
5324
|
process.stdout.write(CLEAR_DOWN);
|
|
5325
5325
|
const lines = [];
|
|
5326
5326
|
const cursor = `${BOLD$8}_${RESET$11}`;
|
|
5327
|
-
lines.push(`${TEXT$9}
|
|
5327
|
+
lines.push(`${TEXT$9}搜索技能:${RESET$11} ${query}${cursor}`);
|
|
5328
5328
|
lines.push("");
|
|
5329
|
-
if (!query || query.length < 2) lines.push(`${DIM$11}
|
|
5330
|
-
else if (results.length === 0 && loading) lines.push(`${DIM$11}
|
|
5331
|
-
else if (results.length === 0) lines.push(`${DIM$11}
|
|
5329
|
+
if (!query || query.length < 2) lines.push(`${DIM$11}输入关键词搜索(最少 2 个字符)${RESET$11}`);
|
|
5330
|
+
else if (results.length === 0 && loading) lines.push(`${DIM$11}搜索中...${RESET$11}`);
|
|
5331
|
+
else if (results.length === 0) lines.push(`${DIM$11}未找到技能${RESET$11}`);
|
|
5332
5332
|
else {
|
|
5333
5333
|
const visible = results.slice(0, 8);
|
|
5334
5334
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -5344,7 +5344,7 @@ async function runSearchPrompt(initialQuery = "", owner) {
|
|
|
5344
5344
|
}
|
|
5345
5345
|
}
|
|
5346
5346
|
lines.push("");
|
|
5347
|
-
lines.push(`${DIM$11}
|
|
5347
|
+
lines.push(`${DIM$11}上下键导航 | 回车选择 | ESC 取消${RESET$11}`);
|
|
5348
5348
|
for (const line of lines) process.stdout.write(line + "\n");
|
|
5349
5349
|
lastRenderedLines = lines.length;
|
|
5350
5350
|
}
|
|
@@ -5454,10 +5454,10 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5454
5454
|
String(results.length);
|
|
5455
5455
|
if (results.length === 0) {
|
|
5456
5456
|
const ownerSuffix = owner ? ` from owner "${owner}"` : "";
|
|
5457
|
-
console.log(`${DIM$11}
|
|
5457
|
+
console.log(`${DIM$11}未找到 "${query}" 的技能${ownerSuffix}${RESET$11}`);
|
|
5458
5458
|
return;
|
|
5459
5459
|
}
|
|
5460
|
-
console.log(`${DIM$11}
|
|
5460
|
+
console.log(`${DIM$11}安装:${RESET$11} npx skills add <owner/repo@skill>`);
|
|
5461
5461
|
console.log();
|
|
5462
5462
|
for (const skill of results.slice(0, 6)) {
|
|
5463
5463
|
const pkg = skill.source || skill.slug;
|
|
@@ -5476,14 +5476,14 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5476
5476
|
}
|
|
5477
5477
|
const selected = await runSearchPrompt("", owner);
|
|
5478
5478
|
if (!selected) {
|
|
5479
|
-
console.log(`${DIM$11}
|
|
5479
|
+
console.log(`${DIM$11}搜索已取消${RESET$11}`);
|
|
5480
5480
|
console.log();
|
|
5481
5481
|
return;
|
|
5482
5482
|
}
|
|
5483
5483
|
const pkg = selected.source || selected.slug;
|
|
5484
5484
|
const skillName = selected.name;
|
|
5485
5485
|
console.log();
|
|
5486
|
-
console.log(`${TEXT$9}
|
|
5486
|
+
console.log(`${TEXT$9}正在从 ${DIM$11}${pkg}${RESET$11} 安装 ${BOLD$8}${skillName}${RESET$11}...`);
|
|
5487
5487
|
console.log();
|
|
5488
5488
|
const { source, options: addOptions } = parseAddOptions([
|
|
5489
5489
|
pkg,
|
|
@@ -5493,8 +5493,8 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
|
|
|
5493
5493
|
await runAdd(source, addOptions);
|
|
5494
5494
|
console.log();
|
|
5495
5495
|
const info = getOwnerRepoFromString(pkg);
|
|
5496
|
-
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}
|
|
5497
|
-
else console.log(`${DIM$11}
|
|
5496
|
+
if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$9}https://skills.sh/${selected.slug}${RESET$11}`);
|
|
5497
|
+
else console.log(`${DIM$11}发现更多技能:${RESET$11} ${TEXT$9}https://skills.sh${RESET$11}`);
|
|
5498
5498
|
console.log();
|
|
5499
5499
|
}
|
|
5500
5500
|
const RESET$10 = "\x1B[0m";
|
|
@@ -5557,15 +5557,15 @@ async function runList(args) {
|
|
|
5557
5557
|
}
|
|
5558
5558
|
const lockedSkills = await getAllLockedSkills();
|
|
5559
5559
|
const cwd = process.cwd();
|
|
5560
|
-
const scopeLabel = scope ? "
|
|
5560
|
+
const scopeLabel = scope ? "全局" : "项目";
|
|
5561
5561
|
if (installedSkills.length === 0) {
|
|
5562
5562
|
if (options.json) {
|
|
5563
5563
|
console.log("[]");
|
|
5564
5564
|
return;
|
|
5565
5565
|
}
|
|
5566
|
-
console.log(`${DIM$10}
|
|
5567
|
-
if (scope) console.log(`${DIM$10}
|
|
5568
|
-
else console.log(`${DIM$10}
|
|
5566
|
+
console.log(`${DIM$10}未找到${scopeLabel}技能。${RESET$10}`);
|
|
5567
|
+
if (scope) console.log(`${DIM$10}尝试不带 -g 参数列出项目技能${RESET$10}`);
|
|
5568
|
+
else console.log(`${DIM$10}尝试带 -g 参数列出全局技能${RESET$10}`);
|
|
5569
5569
|
return;
|
|
5570
5570
|
}
|
|
5571
5571
|
function printSkill(skill, indent = false, maxNameLength = 0, maxPathLength = 0) {
|
|
@@ -5577,7 +5577,7 @@ async function runList(args) {
|
|
|
5577
5577
|
const paddedPath = shortPath.padEnd(maxPathLength);
|
|
5578
5578
|
console.log(`${prefix}${CYAN$1}${paddedName}${RESET$10} ${DIM$10}${paddedPath}${RESET$10} ${DIM$10}Agents:${RESET$10} ${agentInfo}`);
|
|
5579
5579
|
}
|
|
5580
|
-
console.log(`${BOLD$7}${scopeLabel}
|
|
5580
|
+
console.log(`${BOLD$7}${scopeLabel}技能${RESET$10}`);
|
|
5581
5581
|
console.log();
|
|
5582
5582
|
const groupedSkills = {};
|
|
5583
5583
|
const ungroupedSkills = [];
|
|
@@ -5609,7 +5609,7 @@ async function runList(args) {
|
|
|
5609
5609
|
console.log();
|
|
5610
5610
|
}
|
|
5611
5611
|
if (ungroupedSkills.length > 0) {
|
|
5612
|
-
console.log(`${BOLD$7}
|
|
5612
|
+
console.log(`${BOLD$7}通用${RESET$10}`);
|
|
5613
5613
|
let maxNameLength = 0;
|
|
5614
5614
|
let maxPathLength = 0;
|
|
5615
5615
|
for (const skill of ungroupedSkills) {
|
|
@@ -5638,12 +5638,12 @@ async function removeCommand(skillNames, options) {
|
|
|
5638
5638
|
const agentResult = await detectAgent();
|
|
5639
5639
|
if (agentResult.isAgent) {
|
|
5640
5640
|
options.yes = true;
|
|
5641
|
-
log.info(import_picocolors.default.bgCyan(import_picocolors.default.black(import_picocolors.default.bold(` ${agentResult.agent.name} `))) + " Agent
|
|
5641
|
+
log.info(import_picocolors.default.bgCyan(import_picocolors.default.black(import_picocolors.default.bold(` ${agentResult.agent.name} `))) + " 已检测到 Agent — 以非交互模式卸载");
|
|
5642
5642
|
}
|
|
5643
5643
|
const isGlobal = options.global ?? false;
|
|
5644
5644
|
const cwd = process.cwd();
|
|
5645
5645
|
const spinner$1 = spinner();
|
|
5646
|
-
spinner$1.start("
|
|
5646
|
+
spinner$1.start("正在扫描已安装的技能...");
|
|
5647
5647
|
const skillNamesSet = /* @__PURE__ */ new Set();
|
|
5648
5648
|
const scanDir = async (dir) => {
|
|
5649
5649
|
try {
|
|
@@ -5662,17 +5662,17 @@ async function removeCommand(skillNames, options) {
|
|
|
5662
5662
|
for (const subagent of getEveSubagents(cwd)) await scanDir(getEveSubagentSkillsDir(subagent, cwd));
|
|
5663
5663
|
}
|
|
5664
5664
|
const installedSkills = Array.from(skillNamesSet).sort();
|
|
5665
|
-
spinner$1.stop(
|
|
5665
|
+
spinner$1.stop(`发现 ${installedSkills.length} 个已安装技能`);
|
|
5666
5666
|
if (installedSkills.length === 0) {
|
|
5667
|
-
outro(import_picocolors.default.yellow("
|
|
5667
|
+
outro(import_picocolors.default.yellow("没有可卸载的技能。"));
|
|
5668
5668
|
return;
|
|
5669
5669
|
}
|
|
5670
5670
|
if (options.agent && options.agent.length > 0) {
|
|
5671
5671
|
const validAgents = Object.keys(agents);
|
|
5672
5672
|
const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
|
|
5673
5673
|
if (invalidAgents.length > 0) {
|
|
5674
|
-
log.error(
|
|
5675
|
-
log.info(
|
|
5674
|
+
log.error(`无效 Agent:${invalidAgents.join(", ")}`);
|
|
5675
|
+
log.info(`可用 Agent:${validAgents.join(", ")}`);
|
|
5676
5676
|
process.exit(1);
|
|
5677
5677
|
}
|
|
5678
5678
|
}
|
|
@@ -5681,7 +5681,7 @@ async function removeCommand(skillNames, options) {
|
|
|
5681
5681
|
else if (skillNames.length > 0) {
|
|
5682
5682
|
selectedSkills = installedSkills.filter((s) => skillNames.some((name) => name.toLowerCase() === s.toLowerCase()));
|
|
5683
5683
|
if (selectedSkills.length === 0) {
|
|
5684
|
-
log.error(
|
|
5684
|
+
log.error(`未找到匹配技能:${skillNames.join(", ")}`);
|
|
5685
5685
|
return;
|
|
5686
5686
|
}
|
|
5687
5687
|
} else {
|
|
@@ -5695,7 +5695,7 @@ async function removeCommand(skillNames, options) {
|
|
|
5695
5695
|
required: true
|
|
5696
5696
|
});
|
|
5697
5697
|
if (isCancel(selected)) {
|
|
5698
|
-
cancel("
|
|
5698
|
+
cancel("卸载已取消");
|
|
5699
5699
|
process.exit(0);
|
|
5700
5700
|
}
|
|
5701
5701
|
selectedSkills = selected;
|
|
@@ -5708,16 +5708,16 @@ async function removeCommand(skillNames, options) {
|
|
|
5708
5708
|
}
|
|
5709
5709
|
if (!options.yes) {
|
|
5710
5710
|
console.log();
|
|
5711
|
-
log.info("
|
|
5711
|
+
log.info("要卸载的技能:");
|
|
5712
5712
|
for (const skill of selectedSkills) log.message(` ${import_picocolors.default.red("•")} ${skill}`);
|
|
5713
5713
|
console.log();
|
|
5714
|
-
const confirmed = await confirm({ message:
|
|
5714
|
+
const confirmed = await confirm({ message: `确认要卸载 ${selectedSkills.length} 个技能?` });
|
|
5715
5715
|
if (isCancel(confirmed) || !confirmed) {
|
|
5716
|
-
cancel("
|
|
5716
|
+
cancel("卸载已取消");
|
|
5717
5717
|
process.exit(0);
|
|
5718
5718
|
}
|
|
5719
5719
|
}
|
|
5720
|
-
spinner$1.start("
|
|
5720
|
+
spinner$1.start("正在卸载技能...");
|
|
5721
5721
|
const results = [];
|
|
5722
5722
|
for (const skillName of selectedSkills) try {
|
|
5723
5723
|
const canonicalPath = getCanonicalPath(skillName, {
|
|
@@ -5779,7 +5779,7 @@ async function removeCommand(skillNames, options) {
|
|
|
5779
5779
|
error: err instanceof Error ? err.message : String(err)
|
|
5780
5780
|
});
|
|
5781
5781
|
}
|
|
5782
|
-
spinner$1.stop("
|
|
5782
|
+
spinner$1.stop("卸载完成");
|
|
5783
5783
|
const successful = results.filter((r) => r.success);
|
|
5784
5784
|
const failed = results.filter((r) => !r.success);
|
|
5785
5785
|
if (successful.length > 0) {
|
|
@@ -5793,13 +5793,13 @@ async function removeCommand(skillNames, options) {
|
|
|
5793
5793
|
}
|
|
5794
5794
|
for (const [source, data] of bySource) data.skills.join(","), targetAgents.join(","), { ...isGlobal && { global: "1" } }, data.sourceType;
|
|
5795
5795
|
}
|
|
5796
|
-
if (successful.length > 0) log.success(import_picocolors.default.green(
|
|
5796
|
+
if (successful.length > 0) log.success(import_picocolors.default.green(`已成功卸载 ${successful.length} 个技能`));
|
|
5797
5797
|
if (failed.length > 0) {
|
|
5798
|
-
log.error(import_picocolors.default.red(
|
|
5798
|
+
log.error(import_picocolors.default.red(`卸载失败 ${failed.length} 个`));
|
|
5799
5799
|
for (const r of failed) log.message(` ${import_picocolors.default.red("✗")} ${r.skill}: ${r.error}`);
|
|
5800
5800
|
}
|
|
5801
5801
|
console.log();
|
|
5802
|
-
outro(import_picocolors.default.green("
|
|
5802
|
+
outro(import_picocolors.default.green("完成!"));
|
|
5803
5803
|
}
|
|
5804
5804
|
function parseRemoveOptions(args) {
|
|
5805
5805
|
const options = {};
|
|
@@ -5916,27 +5916,27 @@ async function resolveUpdateScope(options) {
|
|
|
5916
5916
|
if (options.project) return "project";
|
|
5917
5917
|
if (options.yes || !process.stdin.isTTY) return hasProjectSkills() ? "project" : "global";
|
|
5918
5918
|
const scope = await select({
|
|
5919
|
-
message: "
|
|
5919
|
+
message: "更新范围",
|
|
5920
5920
|
options: [
|
|
5921
5921
|
{
|
|
5922
5922
|
value: "project",
|
|
5923
|
-
label: "
|
|
5924
|
-
hint: "
|
|
5923
|
+
label: "项目",
|
|
5924
|
+
hint: "更新当前目录中的技能"
|
|
5925
5925
|
},
|
|
5926
5926
|
{
|
|
5927
5927
|
value: "global",
|
|
5928
|
-
label: "
|
|
5929
|
-
hint: "
|
|
5928
|
+
label: "全局",
|
|
5929
|
+
hint: "更新主目录中的技能"
|
|
5930
5930
|
},
|
|
5931
5931
|
{
|
|
5932
5932
|
value: "both",
|
|
5933
|
-
label: "
|
|
5934
|
-
hint: "
|
|
5933
|
+
label: "全部",
|
|
5934
|
+
hint: "更新所有技能"
|
|
5935
5935
|
}
|
|
5936
5936
|
]
|
|
5937
5937
|
});
|
|
5938
5938
|
if (isCancel(scope)) {
|
|
5939
|
-
cancel("
|
|
5939
|
+
cancel("已取消");
|
|
5940
5940
|
process.exit(0);
|
|
5941
5941
|
}
|
|
5942
5942
|
return scope;
|
|
@@ -5947,12 +5947,12 @@ function matchesSkillFilter(name, filter) {
|
|
|
5947
5947
|
return filter.some((f) => f.toLowerCase() === lower);
|
|
5948
5948
|
}
|
|
5949
5949
|
function getSkipReason(entry) {
|
|
5950
|
-
if (entry.sourceType === "local") return "
|
|
5951
|
-
if (entry.sourceType === "git") return "Git
|
|
5952
|
-
if (entry.sourceType === "well-known") return "Well-known
|
|
5953
|
-
if (!entry.skillFolderHash) return "
|
|
5954
|
-
if (!entry.skillPath) return "
|
|
5955
|
-
return "
|
|
5950
|
+
if (entry.sourceType === "local") return "本地路径";
|
|
5951
|
+
if (entry.sourceType === "git") return "Git 地址";
|
|
5952
|
+
if (entry.sourceType === "well-known") return "Well-known 技能";
|
|
5953
|
+
if (!entry.skillFolderHash) return "私有或已删除的仓库";
|
|
5954
|
+
if (!entry.skillPath) return "无路径记录";
|
|
5955
|
+
return "无版本跟踪";
|
|
5956
5956
|
}
|
|
5957
5957
|
function getInstallSource(skill) {
|
|
5958
5958
|
let url = skill.sourceUrl;
|
|
@@ -5965,7 +5965,7 @@ function getInstallSource(skill) {
|
|
|
5965
5965
|
function printSkippedSkills(skipped) {
|
|
5966
5966
|
if (skipped.length === 0) return;
|
|
5967
5967
|
console.log();
|
|
5968
|
-
console.log(`${DIM$9}${skipped.length}
|
|
5968
|
+
console.log(`${DIM$9}${skipped.length} 个技能无法自动检查:${RESET$9}`);
|
|
5969
5969
|
const grouped = /* @__PURE__ */ new Map();
|
|
5970
5970
|
for (const skill of skipped) {
|
|
5971
5971
|
const source = getInstallSource(skill);
|
|
@@ -5982,7 +5982,7 @@ function printSkippedSkills(skipped) {
|
|
|
5982
5982
|
const names = skills.map((s) => sanitizeMetadata(s.name)).join(", ");
|
|
5983
5983
|
console.log(` ${TEXT$8}•${RESET$9} ${names} ${DIM$9}(${reason})${RESET$9}`);
|
|
5984
5984
|
}
|
|
5985
|
-
console.log(` ${DIM$9}
|
|
5985
|
+
console.log(` ${DIM$9}更新方法:${TEXT$8}npx skills add ${source} -g -y${RESET$9}`);
|
|
5986
5986
|
}
|
|
5987
5987
|
}
|
|
5988
5988
|
async function getProjectSkillsForUpdate(skillFilter) {
|
|
@@ -6007,13 +6007,13 @@ async function checkAndPromptForDeletions(source, allLockedForSource, lockSkills
|
|
|
6007
6007
|
});
|
|
6008
6008
|
if (deletedSkills.length > 0) {
|
|
6009
6009
|
console.log();
|
|
6010
|
-
console.log(`${DIM$9}
|
|
6010
|
+
console.log(`${DIM$9}警告:${RESET$9} 以下来自 ${DIM$9}${source}${RESET$9} 的技能似乎已在源仓库中删除:`);
|
|
6011
6011
|
for (const s of deletedSkills) console.log(` ${DIM$9}•${RESET$9} ${s}`);
|
|
6012
|
-
if (options.yes || !process.stdin.isTTY) console.log(`${DIM$9}
|
|
6012
|
+
if (options.yes || !process.stdin.isTTY) console.log(`${DIM$9}非交互模式,跳过删除。${RESET$9}`);
|
|
6013
6013
|
else {
|
|
6014
|
-
const confirmed = await confirm({ message:
|
|
6014
|
+
const confirmed = await confirm({ message: `是否删除这些已删除技能的本地副本?` });
|
|
6015
6015
|
if (confirmed && !isCancel(confirmed)) for (const s of deletedSkills) {
|
|
6016
|
-
console.log(`${DIM$9}
|
|
6016
|
+
console.log(`${DIM$9}正在卸载${RESET$9} ${s}...`);
|
|
6017
6017
|
await removeCommand([s], {
|
|
6018
6018
|
yes: true,
|
|
6019
6019
|
global: isGlobal
|
|
@@ -6030,8 +6030,8 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6030
6030
|
let failCount = 0;
|
|
6031
6031
|
if (skillNames.length === 0) {
|
|
6032
6032
|
if (!options.skills) {
|
|
6033
|
-
console.log(`${DIM$9}
|
|
6034
|
-
console.log(`${DIM$9}
|
|
6033
|
+
console.log(`${DIM$9}锁文件中没有跟踪的全局技能。${RESET$9}`);
|
|
6034
|
+
console.log(`${DIM$9}安装技能:${RESET$9} ${TEXT$8}npx skills add <package> -g${RESET$9}`);
|
|
6035
6035
|
}
|
|
6036
6036
|
return {
|
|
6037
6037
|
successCount,
|
|
@@ -6120,7 +6120,7 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6120
6120
|
if (checkable.length > 0) process.stdout.write("\r\x1B[K");
|
|
6121
6121
|
const checkedCount = checkable.length + skipped.length;
|
|
6122
6122
|
if (checkable.length === 0 && skipped.length === 0) {
|
|
6123
|
-
if (!options.skills) console.log(`${DIM$9}
|
|
6123
|
+
if (!options.skills) console.log(`${DIM$9}没有可检查的全局技能。${RESET$9}`);
|
|
6124
6124
|
return {
|
|
6125
6125
|
successCount,
|
|
6126
6126
|
failCount,
|
|
@@ -6136,18 +6136,18 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6136
6136
|
};
|
|
6137
6137
|
}
|
|
6138
6138
|
if (updates.length === 0) {
|
|
6139
|
-
console.log(`${TEXT$8}✓
|
|
6139
|
+
console.log(`${TEXT$8}✓ 所有全局技能已是最新${RESET$9}`);
|
|
6140
6140
|
return {
|
|
6141
6141
|
successCount,
|
|
6142
6142
|
failCount,
|
|
6143
6143
|
checkedCount
|
|
6144
6144
|
};
|
|
6145
6145
|
}
|
|
6146
|
-
console.log(`${TEXT$8}
|
|
6146
|
+
console.log(`${TEXT$8}发现 ${updates.length} 个可更新全局技能${RESET$9}`);
|
|
6147
6147
|
console.log();
|
|
6148
6148
|
for (const update of updates) {
|
|
6149
6149
|
const safeName = sanitizeMetadata(update.name);
|
|
6150
|
-
console.log(`${TEXT$8}
|
|
6150
|
+
console.log(`${TEXT$8}正在更新 ${safeName}...${RESET$9}`);
|
|
6151
6151
|
const installUrl = buildUpdateInstallSource(update.entry);
|
|
6152
6152
|
if (!installUrl) {
|
|
6153
6153
|
failCount++;
|
|
@@ -6176,10 +6176,10 @@ async function updateGlobalSkills(options = {}) {
|
|
|
6176
6176
|
shell: false
|
|
6177
6177
|
}).status === 0) {
|
|
6178
6178
|
successCount++;
|
|
6179
|
-
console.log(` ${TEXT$8}✓${RESET$9}
|
|
6179
|
+
console.log(` ${TEXT$8}✓${RESET$9} 已更新 ${safeName}`);
|
|
6180
6180
|
} else {
|
|
6181
6181
|
failCount++;
|
|
6182
|
-
console.log(` ${DIM$9}✗
|
|
6182
|
+
console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
|
|
6183
6183
|
}
|
|
6184
6184
|
}
|
|
6185
6185
|
printSkippedSkills(skipped);
|
|
@@ -6195,7 +6195,7 @@ async function updateProjectSkills(options = {}) {
|
|
|
6195
6195
|
let failCount = 0;
|
|
6196
6196
|
if (projectSkills.length === 0) {
|
|
6197
6197
|
if (!options.skills) {
|
|
6198
|
-
console.log(`${DIM$9}
|
|
6198
|
+
console.log(`${DIM$9}没有可更新的项目技能。${RESET$9}`);
|
|
6199
6199
|
console.log(`${DIM$9}Install project skills with${RESET$9} ${TEXT$8}npx skills add <package>${RESET$9}`);
|
|
6200
6200
|
}
|
|
6201
6201
|
return {
|
|
@@ -6227,8 +6227,8 @@ async function updateProjectSkills(options = {}) {
|
|
|
6227
6227
|
const targetParts = [];
|
|
6228
6228
|
if (hasUniversal) targetParts.push("Universal");
|
|
6229
6229
|
targetParts.push(...targetAgentNames);
|
|
6230
|
-
if (targetParts.length > 0) console.log(`${TEXT$8}
|
|
6231
|
-
console.log(`${TEXT$8}
|
|
6230
|
+
if (targetParts.length > 0) console.log(`${TEXT$8}更新目标:${targetParts.join(", ")}${RESET$9}`);
|
|
6231
|
+
console.log(`${TEXT$8}正在刷新 ${updatable.length} 个技能...${RESET$9}`);
|
|
6232
6232
|
console.log();
|
|
6233
6233
|
const bySource = /* @__PURE__ */ new Map();
|
|
6234
6234
|
for (const skill of updatable) {
|
|
@@ -6240,7 +6240,7 @@ async function updateProjectSkills(options = {}) {
|
|
|
6240
6240
|
const localLock = await readLocalLock();
|
|
6241
6241
|
const cliEntry = join(__dirname$1, "..", "bin", "cli.mjs");
|
|
6242
6242
|
if (!existsSync(cliEntry)) {
|
|
6243
|
-
console.log(`${DIM$9}✗ CLI
|
|
6243
|
+
console.log(`${DIM$9}✗ CLI 入口未找到 ${cliEntry}${RESET$9}`);
|
|
6244
6244
|
return {
|
|
6245
6245
|
successCount,
|
|
6246
6246
|
failCount: updatable.length,
|
|
@@ -6266,14 +6266,14 @@ async function updateProjectSkills(options = {}) {
|
|
|
6266
6266
|
});
|
|
6267
6267
|
deletedSkills = await checkAndPromptForDeletions(source, allLockedForSource, localLock.skills, false, options, discoveredPaths);
|
|
6268
6268
|
} catch (error) {
|
|
6269
|
-
console.log(`${DIM$9}✗
|
|
6269
|
+
console.log(`${DIM$9}✗ 检查 ${source} 已删除技能失败${RESET$9}`);
|
|
6270
6270
|
} finally {
|
|
6271
6271
|
if (tempDir) await cleanupTempDir(tempDir);
|
|
6272
6272
|
}
|
|
6273
6273
|
const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
|
|
6274
6274
|
for (const skill of remainingSkills) {
|
|
6275
6275
|
const safeName = sanitizeMetadata(skill.name);
|
|
6276
|
-
console.log(`${TEXT$8}
|
|
6276
|
+
console.log(`${TEXT$8}正在更新 ${safeName}...${RESET$9}`);
|
|
6277
6277
|
const installUrl = buildLocalUpdateSource(skill.entry);
|
|
6278
6278
|
if (!installUrl) {
|
|
6279
6279
|
failCount++;
|
|
@@ -6299,10 +6299,10 @@ async function updateProjectSkills(options = {}) {
|
|
|
6299
6299
|
shell: false
|
|
6300
6300
|
}).status === 0) {
|
|
6301
6301
|
successCount++;
|
|
6302
|
-
console.log(` ${TEXT$8}✓${RESET$9}
|
|
6302
|
+
console.log(` ${TEXT$8}✓${RESET$9} 已更新 ${safeName}`);
|
|
6303
6303
|
} else {
|
|
6304
6304
|
failCount++;
|
|
6305
|
-
console.log(` ${DIM$9}✗
|
|
6305
|
+
console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
|
|
6306
6306
|
}
|
|
6307
6307
|
}
|
|
6308
6308
|
}
|
|
@@ -6320,21 +6320,21 @@ function printLegacyProjectSkills(legacy) {
|
|
|
6320
6320
|
for (const skill of legacy) {
|
|
6321
6321
|
const reinstall = buildLocalUpdateSource(skill.entry);
|
|
6322
6322
|
console.log(` ${TEXT$8}•${RESET$9} ${sanitizeMetadata(skill.name)}`);
|
|
6323
|
-
if (reinstall) console.log(` ${DIM$9}
|
|
6323
|
+
if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$8}npx skills add ${reinstall} -y${RESET$9}`);
|
|
6324
6324
|
else console.log(` ${DIM$9}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$9}`);
|
|
6325
6325
|
}
|
|
6326
6326
|
}
|
|
6327
6327
|
async function runUpdate(args = []) {
|
|
6328
6328
|
const options = parseUpdateOptions(args);
|
|
6329
6329
|
const scope = await resolveUpdateScope(options);
|
|
6330
|
-
if (options.skills) console.log(`${TEXT$8}
|
|
6331
|
-
else console.log(`${TEXT$8}
|
|
6330
|
+
if (options.skills) console.log(`${TEXT$8}正在更新 ${options.skills.join(", ")}...${RESET$9}`);
|
|
6331
|
+
else console.log(`${TEXT$8}正在检查技能更新...${RESET$9}`);
|
|
6332
6332
|
console.log();
|
|
6333
6333
|
let totalSuccess = 0;
|
|
6334
6334
|
let totalFail = 0;
|
|
6335
6335
|
let totalFound = 0;
|
|
6336
6336
|
if (scope === "global" || scope === "both") {
|
|
6337
|
-
if (scope === "both" && !options.skills) console.log(`${BOLD$6}
|
|
6337
|
+
if (scope === "both" && !options.skills) console.log(`${BOLD$6}全局技能${RESET$9}`);
|
|
6338
6338
|
const { successCount, failCount, checkedCount } = await updateGlobalSkills(options);
|
|
6339
6339
|
totalSuccess += successCount;
|
|
6340
6340
|
totalFail += failCount;
|
|
@@ -6342,17 +6342,17 @@ async function runUpdate(args = []) {
|
|
|
6342
6342
|
if (scope === "both" && !options.skills) console.log();
|
|
6343
6343
|
}
|
|
6344
6344
|
if (scope === "project" || scope === "both") {
|
|
6345
|
-
if (scope === "both" && !options.skills) console.log(`${BOLD$6}
|
|
6345
|
+
if (scope === "both" && !options.skills) console.log(`${BOLD$6}项目技能${RESET$9}`);
|
|
6346
6346
|
const { successCount, failCount, foundCount } = await updateProjectSkills(options);
|
|
6347
6347
|
totalSuccess += successCount;
|
|
6348
6348
|
totalFail += failCount;
|
|
6349
6349
|
totalFound += foundCount;
|
|
6350
6350
|
}
|
|
6351
|
-
if (options.skills && totalFound === 0) console.log(`${DIM$9}
|
|
6351
|
+
if (options.skills && totalFound === 0) console.log(`${DIM$9}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$9}`);
|
|
6352
6352
|
console.log();
|
|
6353
|
-
if (totalSuccess > 0) console.log(`${TEXT$8}✓
|
|
6353
|
+
if (totalSuccess > 0) console.log(`${TEXT$8}✓ 已更新 ${totalSuccess} 个技能${RESET$9}`);
|
|
6354
6354
|
if (totalFail > 0) {
|
|
6355
|
-
console.log(`${DIM$9}
|
|
6355
|
+
console.log(`${DIM$9}更新失败 ${totalFail} 个技能${RESET$9}`);
|
|
6356
6356
|
process.exitCode = 1;
|
|
6357
6357
|
}
|
|
6358
6358
|
String(totalSuccess + totalFail);
|
|
@@ -6394,7 +6394,7 @@ function parseUseOptions(args) {
|
|
|
6394
6394
|
const value = args[i + 1];
|
|
6395
6395
|
if (!value || value.startsWith("-")) errors.push(`${arg} requires a skill name`);
|
|
6396
6396
|
else if (options.skill) {
|
|
6397
|
-
errors.push("
|
|
6397
|
+
errors.push("只能提供一个 --skill 值");
|
|
6398
6398
|
i++;
|
|
6399
6399
|
} else {
|
|
6400
6400
|
options.skill = value;
|
|
@@ -6412,7 +6412,7 @@ function parseUseOptions(args) {
|
|
|
6412
6412
|
}
|
|
6413
6413
|
if (options.agent.length === startCount) errors.push(`${arg} requires an agent name`);
|
|
6414
6414
|
i--;
|
|
6415
|
-
} else if (arg.startsWith("-")) errors.push(
|
|
6415
|
+
} else if (arg.startsWith("-")) errors.push(`未知选项:${arg}`);
|
|
6416
6416
|
else source.push(arg);
|
|
6417
6417
|
}
|
|
6418
6418
|
errors.push(...validateUseAgentOption(options.agent));
|
|
@@ -6454,15 +6454,15 @@ async function runUse(sourceArgs, options = {}, parseErrors = []) {
|
|
|
6454
6454
|
return;
|
|
6455
6455
|
}
|
|
6456
6456
|
if (parseErrors.length > 0) fail(parseErrors.join("\n"));
|
|
6457
|
-
if (sourceArgs.length === 0) fail(
|
|
6458
|
-
if (sourceArgs.length > 1) fail(
|
|
6457
|
+
if (sourceArgs.length === 0) fail(`缺少必要参数:source\n\n${getUseHelp()}`);
|
|
6458
|
+
if (sourceArgs.length > 1) fail(`期望一个源,收到 ${sourceArgs.length} 个:${sourceArgs.join(", ")}`);
|
|
6459
6459
|
const useAgent = options.agent?.[0];
|
|
6460
6460
|
if (useAgent && !USE_AGENT_CONFIGS[useAgent]) fail(formatUnsupportedAgentError(useAgent));
|
|
6461
6461
|
const source = sourceArgs[0];
|
|
6462
6462
|
const parsed = parseSource(source);
|
|
6463
6463
|
if (getOwnerRepo(parsed)?.split("/")[0]?.toLowerCase() === "openclaw" && !options.dangerouslyAcceptOpenclawRisks) fail([
|
|
6464
6464
|
"OpenClaw skills are unverified community submissions.",
|
|
6465
|
-
"
|
|
6465
|
+
"技能以 Agent 的全部权限运行,可能存在恶意行为。",
|
|
6466
6466
|
`If you understand the risks, re-run with: skills use ${source} --dangerously-accept-openclaw-risks`
|
|
6467
6467
|
].join("\n"));
|
|
6468
6468
|
const selector = resolveSelector(parsed.skillFilter, options.skill);
|
|
@@ -6550,7 +6550,7 @@ async function launchAgentInteractively(agent, prompt, spawnImpl = spawnAgent) {
|
|
|
6550
6550
|
if (settled) return;
|
|
6551
6551
|
settled = true;
|
|
6552
6552
|
if (error.code === "ENOENT") {
|
|
6553
|
-
reject(new UseCommandError(
|
|
6553
|
+
reject(new UseCommandError(`无法启动 ${agents[agent].displayName}:未找到命令:${config.command}`));
|
|
6554
6554
|
return;
|
|
6555
6555
|
}
|
|
6556
6556
|
reject(error);
|
|
@@ -6591,7 +6591,7 @@ function resolveSelector(sourceSelector, optionSelector) {
|
|
|
6591
6591
|
return optionSelector ?? sourceSelector;
|
|
6592
6592
|
}
|
|
6593
6593
|
function selectSkill(skills, selector, source) {
|
|
6594
|
-
if (skills.length === 0) throw new UseCommandError("
|
|
6594
|
+
if (skills.length === 0) throw new UseCommandError("未找到有效技能。技能需要包含 name 和 description 的 SKILL.md 文件。");
|
|
6595
6595
|
if (!selector) {
|
|
6596
6596
|
if (skills.length === 1) return skills[0];
|
|
6597
6597
|
throw new UseCommandError(formatMultipleSkillsError(source, skills.map(getSkillDisplayName)));
|
|
@@ -6602,7 +6602,7 @@ function selectSkill(skills, selector, source) {
|
|
|
6602
6602
|
return selected[0];
|
|
6603
6603
|
}
|
|
6604
6604
|
function selectWellKnownSkill(skills, selector, source) {
|
|
6605
|
-
if (skills.length === 0) throw new UseCommandError("
|
|
6605
|
+
if (skills.length === 0) throw new UseCommandError("该 URL 未找到技能。请确保服务器提供 /.well-known/agent-skills/index.json 或 /.well-known/skills/index.json 文件。");
|
|
6606
6606
|
let selected;
|
|
6607
6607
|
if (!selector) {
|
|
6608
6608
|
if (skills.length !== 1) throw new UseCommandError(formatMultipleSkillsError(source, skills.map((s) => s.installName)));
|
|
@@ -6623,7 +6623,7 @@ function selectWellKnownSkill(skills, selector, source) {
|
|
|
6623
6623
|
}
|
|
6624
6624
|
function formatMultipleSkillsError(source, names) {
|
|
6625
6625
|
return [
|
|
6626
|
-
"
|
|
6626
|
+
"该源包含多个技能。请指定一个技能:",
|
|
6627
6627
|
...names.map((name) => ` - ${name}`),
|
|
6628
6628
|
"",
|
|
6629
6629
|
`Examples:\n skills use ${source}@${names[0] ?? "<skill>"}\n skills use ${source} --skill ${names[0] ?? "<skill>"}`
|
|
@@ -6632,7 +6632,7 @@ function formatMultipleSkillsError(source, names) {
|
|
|
6632
6632
|
function formatNoMatchError(selector, names) {
|
|
6633
6633
|
return [
|
|
6634
6634
|
`No matching skill found for: ${selector}`,
|
|
6635
|
-
"
|
|
6635
|
+
"可用技能:",
|
|
6636
6636
|
...names.map((name) => ` - ${name}`)
|
|
6637
6637
|
].join("\n");
|
|
6638
6638
|
}
|
|
@@ -6647,7 +6647,7 @@ function validateUseAgentOption(agentValues) {
|
|
|
6647
6647
|
return errors;
|
|
6648
6648
|
}
|
|
6649
6649
|
function formatUnsupportedAgentError(agent) {
|
|
6650
|
-
return [
|
|
6650
|
+
return [`暂不支持运行 ${agents[agent].displayName}。`, `skills use --agent 支持的 Agent:${SUPPORTED_USE_AGENTS.join(", ")}`].join("\n");
|
|
6651
6651
|
}
|
|
6652
6652
|
async function writeSnapshotFiles(targetDir, files) {
|
|
6653
6653
|
for (const file of files) await writeSafeFile(targetDir, file.path, file.contents);
|
|
@@ -6724,7 +6724,7 @@ async function runLogin(args, globalOpts) {
|
|
|
6724
6724
|
const token = getOptionValue$3(args, "--token");
|
|
6725
6725
|
const { registry } = resolveConfig(globalOpts);
|
|
6726
6726
|
if (!token) {
|
|
6727
|
-
console.error("
|
|
6727
|
+
console.error("用法:bfi auth login --token <token>");
|
|
6728
6728
|
process.exit(1);
|
|
6729
6729
|
}
|
|
6730
6730
|
const api = new SkillHubAPI(registry, token);
|
|
@@ -6740,10 +6740,10 @@ async function runLogin(args, globalOpts) {
|
|
|
6740
6740
|
handle: String(userInfo.handle || "")
|
|
6741
6741
|
};
|
|
6742
6742
|
saveGlobalConfig(config);
|
|
6743
|
-
console.log(`✓
|
|
6744
|
-
console.log(`
|
|
6743
|
+
console.log(`✓ 已登录为 ${userInfo.displayName || userInfo.name || "Unknown"}`);
|
|
6744
|
+
console.log(` 注册中心:${registry}`);
|
|
6745
6745
|
} catch (error) {
|
|
6746
|
-
console.error(
|
|
6746
|
+
console.error(`登录失败:${error.message}`);
|
|
6747
6747
|
process.exit(1);
|
|
6748
6748
|
}
|
|
6749
6749
|
}
|
|
@@ -6753,21 +6753,21 @@ async function runLogout() {
|
|
|
6753
6753
|
delete config.token;
|
|
6754
6754
|
delete config.user;
|
|
6755
6755
|
saveGlobalConfig(config);
|
|
6756
|
-
console.log("✓
|
|
6757
|
-
} else console.log("
|
|
6756
|
+
console.log("✓ 已登出");
|
|
6757
|
+
} else console.log("未登录。");
|
|
6758
6758
|
}
|
|
6759
6759
|
async function runWhoami(globalOpts) {
|
|
6760
6760
|
const { registry, token } = resolveConfig(globalOpts);
|
|
6761
6761
|
if (!token) {
|
|
6762
|
-
console.error("
|
|
6762
|
+
console.error("未认证。运行:bfi auth login --token <token>");
|
|
6763
6763
|
process.exit(1);
|
|
6764
6764
|
}
|
|
6765
6765
|
const response = await new SkillHubAPI(registry, token).whoami();
|
|
6766
6766
|
const user = response.user || response;
|
|
6767
|
-
console.log(`\
|
|
6768
|
-
console.log(`
|
|
6769
|
-
console.log(`
|
|
6770
|
-
console.log(` ID
|
|
6767
|
+
console.log(`\n当前用户:`);
|
|
6768
|
+
console.log(` 名称: ${user.displayName || user.name || "N/A"}`);
|
|
6769
|
+
console.log(` 句柄: ${user.handle || "N/A"}`);
|
|
6770
|
+
console.log(` ID: ${user.id || "N/A"}`);
|
|
6771
6771
|
console.log();
|
|
6772
6772
|
}
|
|
6773
6773
|
function getOptionValue$3(args, flag) {
|
|
@@ -6784,12 +6784,12 @@ async function runSearch(args, globalOpts) {
|
|
|
6784
6784
|
const query = parseSearchQuery(args);
|
|
6785
6785
|
const namespace = args.includes("--namespace") ? getOptionValue$2(args, "--namespace") : void 0;
|
|
6786
6786
|
if (!query) {
|
|
6787
|
-
console.log("
|
|
6787
|
+
console.log("用法:bfi search <query> [--namespace <ns>] [--marketplace]");
|
|
6788
6788
|
console.log();
|
|
6789
|
-
console.log("
|
|
6790
|
-
console.log(" --namespace <ns>
|
|
6791
|
-
console.log(" --marketplace
|
|
6792
|
-
console.log(" --all
|
|
6789
|
+
console.log("选项:");
|
|
6790
|
+
console.log(" --namespace <ns> 按 SkillHub 命名空间筛选");
|
|
6791
|
+
console.log(" --marketplace 仅搜索 skills.sh 市场");
|
|
6792
|
+
console.log(" --all 同时搜索 SkillHub 和市场");
|
|
6793
6793
|
return;
|
|
6794
6794
|
}
|
|
6795
6795
|
const useMarketplace = args.includes("--marketplace");
|
|
@@ -6799,9 +6799,9 @@ async function runSearch(args, globalOpts) {
|
|
|
6799
6799
|
return;
|
|
6800
6800
|
}
|
|
6801
6801
|
if (searchAll) {
|
|
6802
|
-
console.log(`${BOLD$5}=== SkillHub
|
|
6802
|
+
console.log(`${BOLD$5}=== SkillHub 注册表 ===${RESET$8}\n`);
|
|
6803
6803
|
await searchSkillHub(query, namespace, globalOpts);
|
|
6804
|
-
console.log(`\n${BOLD$5}=== skills.sh
|
|
6804
|
+
console.log(`\n${BOLD$5}=== skills.sh 市场 ===${RESET$8}\n`);
|
|
6805
6805
|
await searchMarketplace(query);
|
|
6806
6806
|
return;
|
|
6807
6807
|
}
|
|
@@ -6831,10 +6831,10 @@ async function searchSkillHub(query, namespace, globalOpts) {
|
|
|
6831
6831
|
});
|
|
6832
6832
|
const skills = result.results || result.data || [];
|
|
6833
6833
|
if (skills.length === 0) {
|
|
6834
|
-
console.log(`${DIM$8}
|
|
6834
|
+
console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
|
|
6835
6835
|
return;
|
|
6836
6836
|
}
|
|
6837
|
-
console.log(`
|
|
6837
|
+
console.log(`SkillHub 上找到 ${skills.length} 个技能:\n`);
|
|
6838
6838
|
for (const skill of skills) {
|
|
6839
6839
|
const name = skill.displayName || skill.name || skill.slug;
|
|
6840
6840
|
const desc = skill.summary || skill.description || "";
|
|
@@ -6842,10 +6842,11 @@ async function searchSkillHub(query, namespace, globalOpts) {
|
|
|
6842
6842
|
if (desc) console.log(` ${DIM$8}${truncate$2(desc, 100)}${RESET$8}`);
|
|
6843
6843
|
console.log(` ${TEXT$7}slug: ${skill.slug}${RESET$8}`);
|
|
6844
6844
|
if (skill.version) console.log(` ${DIM$8}version: ${skill.version}${RESET$8}`);
|
|
6845
|
+
console.log(` ${DIM$8}Install: ${TEXT$7}bfi skills add ${skill.slug}${RESET$8}`);
|
|
6845
6846
|
console.log();
|
|
6846
6847
|
}
|
|
6847
6848
|
} catch (error) {
|
|
6848
|
-
console.error(`${DIM$8}SkillHub
|
|
6849
|
+
console.error(`${DIM$8}SkillHub 搜索失败:${error.message}${RESET$8}`);
|
|
6849
6850
|
}
|
|
6850
6851
|
}
|
|
6851
6852
|
async function searchMarketplace(query) {
|
|
@@ -6857,15 +6858,15 @@ async function searchMarketplace(query) {
|
|
|
6857
6858
|
const url = `${MARKETPLACE_API}/api/search?${params.toString()}`;
|
|
6858
6859
|
const res = await fetch(url);
|
|
6859
6860
|
if (!res.ok) {
|
|
6860
|
-
console.log(`${DIM$8}
|
|
6861
|
+
console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
|
|
6861
6862
|
return;
|
|
6862
6863
|
}
|
|
6863
6864
|
const skills = (await res.json()).skills || [];
|
|
6864
6865
|
if (skills.length === 0) {
|
|
6865
|
-
console.log(`${DIM$8}
|
|
6866
|
+
console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
|
|
6866
6867
|
return;
|
|
6867
6868
|
}
|
|
6868
|
-
console.log(`
|
|
6869
|
+
console.log(`skills.sh 上找到 ${skills.length} 个技能:\n`);
|
|
6869
6870
|
for (const skill of skills.slice(0, 12)) {
|
|
6870
6871
|
const installs = formatInstalls(skill.installs);
|
|
6871
6872
|
console.log(` ${BOLD$5}${skill.name}${RESET$8}`);
|
|
@@ -6875,14 +6876,14 @@ async function searchMarketplace(query) {
|
|
|
6875
6876
|
console.log();
|
|
6876
6877
|
}
|
|
6877
6878
|
} catch {
|
|
6878
|
-
console.log(`${DIM$8}skills.sh
|
|
6879
|
+
console.log(`${DIM$8}skills.sh 市场不可用${RESET$8}`);
|
|
6879
6880
|
}
|
|
6880
6881
|
}
|
|
6881
6882
|
function formatInstalls(count) {
|
|
6882
6883
|
if (!count || count <= 0) return "";
|
|
6883
6884
|
if (count >= 1e6) return `${(count / 1e6).toFixed(1).replace(/\.0$/, "")}M installs`;
|
|
6884
6885
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1).replace(/\.0$/, "")}K installs`;
|
|
6885
|
-
return `${count}
|
|
6886
|
+
return `${count} 次安装`;
|
|
6886
6887
|
}
|
|
6887
6888
|
function truncate$2(text, maxLen) {
|
|
6888
6889
|
if (text.length <= maxLen) return text;
|
|
@@ -6902,8 +6903,8 @@ const GREEN$4 = "\x1B[32m";
|
|
|
6902
6903
|
async function runInfo(args, globalOpts) {
|
|
6903
6904
|
const slug = args[0];
|
|
6904
6905
|
if (!slug) {
|
|
6905
|
-
console.log("
|
|
6906
|
-
console.log("
|
|
6906
|
+
console.log("用法:bfi info <skill-slug>");
|
|
6907
|
+
console.log("示例:bfi info global/my-skill");
|
|
6907
6908
|
process.exit(1);
|
|
6908
6909
|
}
|
|
6909
6910
|
const { registry, token } = resolveConfig(globalOpts);
|
|
@@ -6912,35 +6913,35 @@ async function runInfo(args, globalOpts) {
|
|
|
6912
6913
|
const result = await api.getSkill(slug);
|
|
6913
6914
|
const skill = result.data || result.skill || result;
|
|
6914
6915
|
if (!skill || !skill.slug) {
|
|
6915
|
-
console.log(`${DIM$7}
|
|
6916
|
+
console.log(`${DIM$7}未找到技能:${slug}${RESET$7}`);
|
|
6916
6917
|
process.exit(1);
|
|
6917
6918
|
}
|
|
6918
6919
|
console.log();
|
|
6919
6920
|
console.log(`${BOLD$4}${skill.displayName || skill.name || skill.slug}${RESET$7}`);
|
|
6920
6921
|
console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
|
|
6921
|
-
console.log(` ${BOLD$4}Slug
|
|
6922
|
-
if (skill.summary || skill.description) console.log(` ${BOLD$4}
|
|
6922
|
+
console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$6}${skill.slug}${RESET$7}`);
|
|
6923
|
+
if (skill.summary || skill.description) console.log(` ${BOLD$4}描述:${RESET$7} ${TEXT$6}${skill.summary || skill.description}${RESET$7}`);
|
|
6923
6924
|
const owner = skill.owner;
|
|
6924
6925
|
if (owner) {
|
|
6925
|
-
console.log(` ${BOLD$4}
|
|
6926
|
-
if (owner.handle) console.log(` ${BOLD$4}
|
|
6926
|
+
console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$6}${owner.displayName || owner.handle}${RESET$7}`);
|
|
6927
|
+
if (owner.handle) console.log(` ${BOLD$4}句柄:${RESET$7} ${TEXT$6}${owner.handle}${RESET$7}`);
|
|
6927
6928
|
}
|
|
6928
6929
|
const latestVersion = skill.latestVersion;
|
|
6929
6930
|
if (latestVersion) {
|
|
6930
|
-
console.log(` ${BOLD$4}
|
|
6931
|
-
if (latestVersion.license) console.log(` ${BOLD$4}
|
|
6932
|
-
if (latestVersion.changelog) console.log(` ${BOLD$4}
|
|
6931
|
+
console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$6}${latestVersion.version || "N/A"}${RESET$7}`);
|
|
6932
|
+
if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$6}${latestVersion.license}${RESET$7}`);
|
|
6933
|
+
if (latestVersion.changelog) console.log(` ${BOLD$4}变更日志:${RESET$7} ${DIM$7}${truncate$1(latestVersion.changelog, 80)}${RESET$7}`);
|
|
6933
6934
|
if (latestVersion.createdAt) {
|
|
6934
6935
|
const date = new Date(latestVersion.createdAt).toISOString().split("T")[0];
|
|
6935
|
-
console.log(` ${BOLD$4}
|
|
6936
|
+
console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
|
|
6936
6937
|
}
|
|
6937
6938
|
}
|
|
6938
6939
|
const stats = skill.stats;
|
|
6939
6940
|
if (stats) {
|
|
6940
6941
|
console.log();
|
|
6941
|
-
console.log(` ${BOLD$4}
|
|
6942
|
-
if (stats.downloads !== void 0) console.log(`
|
|
6943
|
-
if (stats.views !== void 0) console.log(`
|
|
6942
|
+
console.log(` ${BOLD$4}统计:${RESET$7}`);
|
|
6943
|
+
if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$6}${stats.downloads}${RESET$7}`);
|
|
6944
|
+
if (stats.views !== void 0) console.log(` 浏览量:${TEXT$6}${stats.views}${RESET$7}`);
|
|
6944
6945
|
}
|
|
6945
6946
|
const tags = skill.tags;
|
|
6946
6947
|
if (Array.isArray(tags) && tags.length > 0) {
|
|
@@ -6948,33 +6949,33 @@ async function runInfo(args, globalOpts) {
|
|
|
6948
6949
|
const tag = t;
|
|
6949
6950
|
return tag.name || tag;
|
|
6950
6951
|
}).join(", ");
|
|
6951
|
-
console.log(` ${BOLD$4}
|
|
6952
|
+
console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$6}${tagList}${RESET$7}`);
|
|
6952
6953
|
}
|
|
6953
6954
|
const moderation = skill.moderation;
|
|
6954
6955
|
if (moderation) {
|
|
6955
6956
|
const verdict = moderation.verdict;
|
|
6956
6957
|
if (verdict === "MALWARE_BLOCKED" || moderation.isMalwareBlocked) {
|
|
6957
6958
|
console.log();
|
|
6958
|
-
console.log(` ${RED$2}${BOLD$4}⚠
|
|
6959
|
+
console.log(` ${RED$2}${BOLD$4}⚠ 已封禁:检测到恶意软件${RESET$7}`);
|
|
6959
6960
|
if (moderation.summary) console.log(` ${RED$2}${moderation.summary}${RESET$7}`);
|
|
6960
6961
|
} else if (verdict === "SUSPICIOUS" || moderation.isSuspicious) {
|
|
6961
6962
|
console.log();
|
|
6962
|
-
console.log(` ${YELLOW$2}⚠
|
|
6963
|
+
console.log(` ${YELLOW$2}⚠ 可疑技能${RESET$7}`);
|
|
6963
6964
|
if (moderation.summary) console.log(` ${YELLOW$2}${moderation.summary}${RESET$7}`);
|
|
6964
|
-
} else if (verdict === "SAFE") console.log(` ${BOLD$4}
|
|
6965
|
+
} else if (verdict === "SAFE") console.log(` ${BOLD$4}安全:${RESET$7} ${GREEN$4}已验证安全${RESET$7}`);
|
|
6965
6966
|
}
|
|
6966
6967
|
if (skill.createdAt) {
|
|
6967
6968
|
const created = new Date(skill.createdAt).toISOString().split("T")[0];
|
|
6968
|
-
console.log(` ${BOLD$4}
|
|
6969
|
+
console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$6}${created}${RESET$7}`);
|
|
6969
6970
|
}
|
|
6970
6971
|
if (skill.updatedAt) {
|
|
6971
6972
|
const updated = new Date(skill.updatedAt).toISOString().split("T")[0];
|
|
6972
|
-
console.log(` ${BOLD$4}
|
|
6973
|
+
console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$6}${updated}${RESET$7}`);
|
|
6973
6974
|
}
|
|
6974
6975
|
console.log();
|
|
6975
6976
|
} catch (error) {
|
|
6976
|
-
if (error.status === 404) console.error(
|
|
6977
|
-
else console.error(
|
|
6977
|
+
if (error.status === 404) console.error(`未找到技能:${slug}`);
|
|
6978
|
+
else console.error(`获取技能信息失败:${error.message}`);
|
|
6978
6979
|
process.exit(1);
|
|
6979
6980
|
}
|
|
6980
6981
|
}
|
|
@@ -6996,22 +6997,22 @@ async function runConfig(args, globalOpts) {
|
|
|
6996
6997
|
}
|
|
6997
6998
|
}
|
|
6998
6999
|
function printConfigHelp() {
|
|
6999
|
-
console.log("
|
|
7000
|
-
console.log(" bfi config get [key]
|
|
7001
|
-
console.log(" bfi config set <key> <value>
|
|
7000
|
+
console.log("配置命令:");
|
|
7001
|
+
console.log(" bfi config get [key] 获取配置值");
|
|
7002
|
+
console.log(" bfi config set <key> <value> 设置配置值");
|
|
7002
7003
|
console.log();
|
|
7003
|
-
console.log("
|
|
7004
|
+
console.log("可用键(全局):");
|
|
7004
7005
|
console.log(" registry API registry URL");
|
|
7005
7006
|
console.log(" default-namespace Default namespace");
|
|
7006
7007
|
console.log(" default-ide Default IDE");
|
|
7007
7008
|
console.log();
|
|
7008
|
-
console.log("
|
|
7009
|
+
console.log("可用键(项目):");
|
|
7009
7010
|
console.log(" registry API registry URL");
|
|
7010
7011
|
console.log(" namespace Project namespace");
|
|
7011
7012
|
console.log(" ide Project IDE");
|
|
7012
7013
|
console.log();
|
|
7013
|
-
console.log("
|
|
7014
|
-
console.log(" --global
|
|
7014
|
+
console.log("标志:");
|
|
7015
|
+
console.log(" --global 全局应用设置(默认:项目)");
|
|
7015
7016
|
}
|
|
7016
7017
|
async function handleGet(args, globalOpts) {
|
|
7017
7018
|
const key = args[1];
|
|
@@ -7034,21 +7035,21 @@ async function handleGet(args, globalOpts) {
|
|
|
7034
7035
|
const projectConfigKey = projectKeyMap[key] || key;
|
|
7035
7036
|
const globalValue = globalConfig[globalConfigKey];
|
|
7036
7037
|
const projectValue = projectConfig[projectConfigKey];
|
|
7037
|
-
console.log(`\
|
|
7038
|
+
console.log(`\n配置:${key}`);
|
|
7038
7039
|
console.log("-".repeat(40));
|
|
7039
|
-
if (projectValue !== void 0) console.log(
|
|
7040
|
-
else console.log(
|
|
7041
|
-
if (globalValue !== void 0) console.log(
|
|
7042
|
-
else console.log(
|
|
7040
|
+
if (projectValue !== void 0) console.log(`项目 (.bfirc):${projectValue}`);
|
|
7041
|
+
else console.log(`项目 (.bfirc):(未设置)`);
|
|
7042
|
+
if (globalValue !== void 0) console.log(`全局 (~/.bfi/config.json):${key === "token" ? "********" : globalValue}`);
|
|
7043
|
+
else console.log(`全局 (~/.bfi/config.json):(未设置)`);
|
|
7043
7044
|
console.log();
|
|
7044
7045
|
} else {
|
|
7045
|
-
console.log("\
|
|
7046
|
+
console.log("\n项目配置 (.bfirc):");
|
|
7046
7047
|
console.log("-".repeat(40));
|
|
7047
|
-
if (Object.keys(projectConfig).length === 0) console.log("
|
|
7048
|
+
if (Object.keys(projectConfig).length === 0) console.log(" (无项目配置)");
|
|
7048
7049
|
else for (const [k, v] of Object.entries(projectConfig)) console.log(` ${k}: ${v}`);
|
|
7049
|
-
console.log("\
|
|
7050
|
+
console.log("\n全局配置 (~/.bfi/config.json):");
|
|
7050
7051
|
console.log("-".repeat(40));
|
|
7051
|
-
if (Object.keys(globalConfig).length === 0) console.log("
|
|
7052
|
+
if (Object.keys(globalConfig).length === 0) console.log(" (无全局配置)");
|
|
7052
7053
|
else for (const [k, v] of Object.entries(globalConfig)) console.log(` ${k}: ${k === "token" ? "********" : v}`);
|
|
7053
7054
|
console.log();
|
|
7054
7055
|
}
|
|
@@ -7057,9 +7058,9 @@ async function handleSet(args, _globalOpts) {
|
|
|
7057
7058
|
const key = args[1];
|
|
7058
7059
|
const value = args[2];
|
|
7059
7060
|
if (!key || value === void 0) {
|
|
7060
|
-
console.error("
|
|
7061
|
+
console.error("用法:bfi config set <key> <value>");
|
|
7061
7062
|
console.log();
|
|
7062
|
-
console.log("
|
|
7063
|
+
console.log("使用 --global 标志进行全局设置:");
|
|
7063
7064
|
console.log(" bfi config set registry https://skillhub.example.com --global");
|
|
7064
7065
|
console.log(" bfi config set namespace myteam --global");
|
|
7065
7066
|
process.exit(1);
|
|
@@ -7072,13 +7073,13 @@ async function handleSet(args, _globalOpts) {
|
|
|
7072
7073
|
"default-ide"
|
|
7073
7074
|
];
|
|
7074
7075
|
if (!validKeys.includes(key)) {
|
|
7075
|
-
console.error(
|
|
7076
|
-
console.log(
|
|
7076
|
+
console.error(`无效的键:${key}`);
|
|
7077
|
+
console.log(`有效键:${validKeys.join(", ")}`);
|
|
7077
7078
|
process.exit(1);
|
|
7078
7079
|
}
|
|
7079
7080
|
const isGlobal = args.includes("--global");
|
|
7080
7081
|
setConfigValue(key, value, isGlobal);
|
|
7081
|
-
console.log(`${DIM$6}✓${RESET$6}
|
|
7082
|
+
console.log(`${DIM$6}✓${RESET$6} 已设置 ${key} = ${value}(${(isGlobal ? "global" : "project") === "global" ? "全局" : "项目"})`);
|
|
7082
7083
|
}
|
|
7083
7084
|
const RESET$5 = "\x1B[0m";
|
|
7084
7085
|
const BOLD$3 = "\x1B[1m";
|
|
@@ -7099,12 +7100,12 @@ async function runDocs(args, globalOpts) {
|
|
|
7099
7100
|
}
|
|
7100
7101
|
}
|
|
7101
7102
|
function printDocsHelp() {
|
|
7102
|
-
console.log("
|
|
7103
|
-
console.log(" bfi docs upload <file>
|
|
7104
|
-
console.log(" bfi docs list
|
|
7105
|
-
console.log(" bfi docs info <id>
|
|
7103
|
+
console.log("文档命令:");
|
|
7104
|
+
console.log(" bfi docs upload <file> 上传文档进行解析");
|
|
7105
|
+
console.log(" bfi docs list 列出已上传文档");
|
|
7106
|
+
console.log(" bfi docs info <id> 查看文档处理状态");
|
|
7106
7107
|
console.log();
|
|
7107
|
-
console.log("
|
|
7108
|
+
console.log("示例:");
|
|
7108
7109
|
console.log(` ${DIM$5}$ ${RESET$5}bfi docs upload resume.pdf`);
|
|
7109
7110
|
console.log(` ${DIM$5}$ ${RESET$5}bfi docs list`);
|
|
7110
7111
|
console.log(` ${DIM$5}$ ${RESET$5}bfi docs info 42`);
|
|
@@ -7112,18 +7113,18 @@ function printDocsHelp() {
|
|
|
7112
7113
|
async function handleUpload(args, globalOpts) {
|
|
7113
7114
|
const filePath = args[0];
|
|
7114
7115
|
if (!filePath) {
|
|
7115
|
-
console.error("
|
|
7116
|
-
console.log("
|
|
7116
|
+
console.error("用法:bfi docs upload <file>");
|
|
7117
|
+
console.log("上传文档文件进行解析。");
|
|
7117
7118
|
process.exit(1);
|
|
7118
7119
|
}
|
|
7119
7120
|
const resolvedPath = path$1.resolve(filePath);
|
|
7120
7121
|
if (!fs.existsSync(resolvedPath)) {
|
|
7121
|
-
console.error(
|
|
7122
|
+
console.error(`文件未找到:${resolvedPath}`);
|
|
7122
7123
|
process.exit(1);
|
|
7123
7124
|
}
|
|
7124
7125
|
const stats = fs.statSync(resolvedPath);
|
|
7125
7126
|
if (!stats.isFile()) {
|
|
7126
|
-
console.error(
|
|
7127
|
+
console.error(`不是文件:${resolvedPath}`);
|
|
7127
7128
|
process.exit(1);
|
|
7128
7129
|
}
|
|
7129
7130
|
const { registry, token } = resolveConfig(globalOpts);
|
|
@@ -7131,19 +7132,19 @@ async function handleUpload(args, globalOpts) {
|
|
|
7131
7132
|
const fileName = path$1.basename(resolvedPath);
|
|
7132
7133
|
const fileSize = stats.size;
|
|
7133
7134
|
const fileSizeStr = fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`;
|
|
7134
|
-
console.log(`${DIM$5}
|
|
7135
|
+
console.log(`${DIM$5}正在上传 ${fileName} (${fileSizeStr})...${RESET$5}`);
|
|
7135
7136
|
try {
|
|
7136
7137
|
const fileBuffer = fs.readFileSync(resolvedPath);
|
|
7137
7138
|
const result = await api.uploadDoc(fileBuffer, fileName);
|
|
7138
|
-
console.log(`${TEXT$5}✓
|
|
7139
|
+
console.log(`${TEXT$5}✓ 上传成功${RESET$5}`);
|
|
7139
7140
|
console.log();
|
|
7140
|
-
if (result.id) console.log(` ${BOLD$3}ID
|
|
7141
|
-
if (result.status) console.log(` ${BOLD$3}
|
|
7142
|
-
if (result.fileName) console.log(` ${BOLD$3}
|
|
7141
|
+
if (result.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$5}${result.id}${RESET$5}`);
|
|
7142
|
+
if (result.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$5}${result.status}${RESET$5}`);
|
|
7143
|
+
if (result.fileName) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$5}${result.fileName}${RESET$5}`);
|
|
7143
7144
|
console.log();
|
|
7144
|
-
if (result.id) console.log(`${DIM$5}
|
|
7145
|
+
if (result.id) console.log(`${DIM$5}查看状态:bfi docs info ${result.id}${RESET$5}`);
|
|
7145
7146
|
} catch (error) {
|
|
7146
|
-
console.error(
|
|
7147
|
+
console.error(`上传失败:${error.message}`);
|
|
7147
7148
|
process.exit(1);
|
|
7148
7149
|
}
|
|
7149
7150
|
}
|
|
@@ -7156,11 +7157,11 @@ async function handleList$1(args, globalOpts) {
|
|
|
7156
7157
|
const result = await api.listDocs(page, size);
|
|
7157
7158
|
const docs = result.data || result.docs || result.content || [];
|
|
7158
7159
|
if (!Array.isArray(docs) || docs.length === 0) {
|
|
7159
|
-
console.log(`${DIM$5}
|
|
7160
|
+
console.log(`${DIM$5}未找到文档。${RESET$5}`);
|
|
7160
7161
|
return;
|
|
7161
7162
|
}
|
|
7162
7163
|
console.log();
|
|
7163
|
-
console.log(`${BOLD$3}
|
|
7164
|
+
console.log(`${BOLD$3}文档${RESET$5}(第 ${page} 页,共 ${docs.length} 条结果):`);
|
|
7164
7165
|
console.log(`${DIM$5}${"─".repeat(64)}${RESET$5}`);
|
|
7165
7166
|
for (const doc of docs) {
|
|
7166
7167
|
const id = doc.id || "?";
|
|
@@ -7169,26 +7170,26 @@ async function handleList$1(args, globalOpts) {
|
|
|
7169
7170
|
const createdAt = doc.createdAt || doc.created_at;
|
|
7170
7171
|
const dateStr = createdAt ? new Date(createdAt).toISOString().split("T")[0] : "N/A";
|
|
7171
7172
|
console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$5}${fileName}${RESET$5}`);
|
|
7172
|
-
console.log(` ${DIM$5}
|
|
7173
|
+
console.log(` ${DIM$5}状态:${status} | 日期:${dateStr}${RESET$5}`);
|
|
7173
7174
|
console.log();
|
|
7174
7175
|
}
|
|
7175
7176
|
const total = result.total || result.totalElements;
|
|
7176
|
-
if (total && Number(total) > (page + 1) * size) console.log(`${DIM$5}
|
|
7177
|
+
if (total && Number(total) > (page + 1) * size) console.log(`${DIM$5}下一页:bfi docs list ${page + 1}${RESET$5}`);
|
|
7177
7178
|
console.log();
|
|
7178
7179
|
} catch (error) {
|
|
7179
|
-
console.error(
|
|
7180
|
+
console.error(`列出文档失败:${error.message}`);
|
|
7180
7181
|
process.exit(1);
|
|
7181
7182
|
}
|
|
7182
7183
|
}
|
|
7183
7184
|
async function handleInfo$1(args, globalOpts) {
|
|
7184
7185
|
const docId = args[0];
|
|
7185
7186
|
if (!docId) {
|
|
7186
|
-
console.error("
|
|
7187
|
+
console.error("用法:bfi docs info <id>");
|
|
7187
7188
|
process.exit(1);
|
|
7188
7189
|
}
|
|
7189
7190
|
const id = parseInt(docId, 10);
|
|
7190
7191
|
if (isNaN(id)) {
|
|
7191
|
-
console.error(
|
|
7192
|
+
console.error(`无效的文档 ID:${docId}`);
|
|
7192
7193
|
process.exit(1);
|
|
7193
7194
|
}
|
|
7194
7195
|
const { registry, token } = resolveConfig(globalOpts);
|
|
@@ -7197,40 +7198,40 @@ async function handleInfo$1(args, globalOpts) {
|
|
|
7197
7198
|
const result = await api.getDoc(id);
|
|
7198
7199
|
const doc = result.data || result;
|
|
7199
7200
|
if (!doc || !doc.id) {
|
|
7200
|
-
console.log(`${DIM$5}
|
|
7201
|
+
console.log(`${DIM$5}未找到文档:${id}${RESET$5}`);
|
|
7201
7202
|
process.exit(1);
|
|
7202
7203
|
}
|
|
7203
7204
|
console.log();
|
|
7204
|
-
console.log(`${BOLD$3}
|
|
7205
|
+
console.log(`${BOLD$3}文档 #${doc.id}${RESET$5}`);
|
|
7205
7206
|
console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
|
|
7206
|
-
if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}
|
|
7207
|
+
if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$5}${doc.fileName || doc.file_name}${RESET$5}`);
|
|
7207
7208
|
if (doc.status) {
|
|
7208
7209
|
const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$5;
|
|
7209
|
-
console.log(` ${BOLD$3}
|
|
7210
|
+
console.log(` ${BOLD$3}状态:${RESET$5} ${statusColor}${doc.status}${RESET$5}`);
|
|
7210
7211
|
}
|
|
7211
7212
|
if (doc.createdAt || doc.created_at) {
|
|
7212
7213
|
const date = new Date(doc.createdAt || doc.created_at).toISOString().replace("T", " ").slice(0, 19);
|
|
7213
|
-
console.log(` ${BOLD$3}
|
|
7214
|
+
console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$5}${date}${RESET$5}`);
|
|
7214
7215
|
}
|
|
7215
7216
|
if (doc.updatedAt || doc.updated_at) {
|
|
7216
7217
|
const date = new Date(doc.updatedAt || doc.updated_at).toISOString().replace("T", " ").slice(0, 19);
|
|
7217
|
-
console.log(` ${BOLD$3}
|
|
7218
|
+
console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$5}${date}${RESET$5}`);
|
|
7218
7219
|
}
|
|
7219
7220
|
if (doc.result) {
|
|
7220
7221
|
console.log();
|
|
7221
|
-
console.log(` ${BOLD$3}
|
|
7222
|
+
console.log(` ${BOLD$3}结果:${RESET$5}`);
|
|
7222
7223
|
const resultStr = typeof doc.result === "string" ? doc.result : JSON.stringify(doc.result, null, 4);
|
|
7223
7224
|
for (const line of resultStr.split("\n")) console.log(` ${DIM$5}${line}${RESET$5}`);
|
|
7224
7225
|
}
|
|
7225
7226
|
if (doc.error || doc.errorMessage) {
|
|
7226
7227
|
console.log();
|
|
7227
|
-
console.log(` \x1b[31m${BOLD$3}
|
|
7228
|
+
console.log(` \x1b[31m${BOLD$3}错误:${RESET$5}`);
|
|
7228
7229
|
console.log(` \x1b[31m${doc.error || doc.errorMessage}${RESET$5}`);
|
|
7229
7230
|
}
|
|
7230
7231
|
console.log();
|
|
7231
7232
|
} catch (error) {
|
|
7232
|
-
if (error.status === 404) console.error(
|
|
7233
|
-
else console.error(
|
|
7233
|
+
if (error.status === 404) console.error(`未找到文档:${id}`);
|
|
7234
|
+
else console.error(`获取文档信息失败:${error.message}`);
|
|
7234
7235
|
process.exit(1);
|
|
7235
7236
|
}
|
|
7236
7237
|
}
|
|
@@ -7271,53 +7272,53 @@ async function runPublish(args, globalOpts) {
|
|
|
7271
7272
|
await publishFromGit(positionalArgs, api, namespace, visibility, yes, branch, directory, skillFilter);
|
|
7272
7273
|
break;
|
|
7273
7274
|
default:
|
|
7274
|
-
console.error(
|
|
7275
|
-
console.log("
|
|
7276
|
-
console.log("
|
|
7275
|
+
console.error(`未知发布模式:${mode}`);
|
|
7276
|
+
console.log("可用模式:dir, zip, git");
|
|
7277
|
+
console.log("用法:bfi publish [source] --from dir|zip|git [options]");
|
|
7277
7278
|
process.exit(1);
|
|
7278
7279
|
}
|
|
7279
7280
|
}
|
|
7280
7281
|
async function publishFromDir(positionalArgs, api, namespace, visibility) {
|
|
7281
7282
|
const dirPath = positionalArgs[0];
|
|
7282
7283
|
if (!dirPath) {
|
|
7283
|
-
console.error("
|
|
7284
|
-
console.log("
|
|
7284
|
+
console.error("用法:bfi publish <directory> --from dir");
|
|
7285
|
+
console.log("从包含 SKILL.md 的本地目录发布技能。");
|
|
7285
7286
|
process.exit(1);
|
|
7286
7287
|
}
|
|
7287
7288
|
const resolvedDir = path$1.resolve(dirPath);
|
|
7288
7289
|
if (!fs.existsSync(resolvedDir)) {
|
|
7289
|
-
console.error(
|
|
7290
|
+
console.error(`目录未找到:${resolvedDir}`);
|
|
7290
7291
|
process.exit(1);
|
|
7291
7292
|
}
|
|
7292
7293
|
if (!fs.statSync(resolvedDir).isDirectory()) {
|
|
7293
|
-
console.error(
|
|
7294
|
+
console.error(`不是目录:${resolvedDir}`);
|
|
7294
7295
|
process.exit(1);
|
|
7295
7296
|
}
|
|
7296
7297
|
const skillMdPath = path$1.join(resolvedDir, "SKILL.md");
|
|
7297
7298
|
if (!fs.existsSync(skillMdPath)) {
|
|
7298
|
-
console.error(
|
|
7299
|
-
console.log("
|
|
7299
|
+
console.error(`在 ${resolvedDir} 中未找到 SKILL.md`);
|
|
7300
|
+
console.log("需要包含 frontmatter(name, description)的 SKILL.md 文件。");
|
|
7300
7301
|
process.exit(1);
|
|
7301
7302
|
}
|
|
7302
7303
|
const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
|
|
7303
7304
|
const skillName = frontmatter.name || path$1.basename(resolvedDir);
|
|
7304
|
-
console.log(`${DIM$4}
|
|
7305
|
-
console.log(` ${BOLD$2}
|
|
7306
|
-
console.log(` ${BOLD$2}
|
|
7307
|
-
console.log(` ${BOLD$2}
|
|
7308
|
-
console.log(` ${BOLD$2}
|
|
7305
|
+
console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
|
|
7306
|
+
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$4}${skillName}${RESET$4}`);
|
|
7307
|
+
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$4}${namespace}${RESET$4}`);
|
|
7308
|
+
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$4}${visibility}${RESET$4}`);
|
|
7309
|
+
console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$4}${resolvedDir}${RESET$4}`);
|
|
7309
7310
|
console.log();
|
|
7310
|
-
console.log(`${DIM$4}
|
|
7311
|
+
console.log(`${DIM$4}正在创建 zip...${RESET$4}`);
|
|
7311
7312
|
const zipBuffer = createZipFromDir(resolvedDir);
|
|
7312
|
-
console.log(` ${GREEN$3}Zip
|
|
7313
|
-
console.log(`${DIM$4}
|
|
7313
|
+
console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
|
|
7314
|
+
console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
|
|
7314
7315
|
try {
|
|
7315
7316
|
const res = await api.publishSkill(namespace, zipBuffer, visibility);
|
|
7316
|
-
console.log(` ${GREEN$3}
|
|
7317
|
-
if (res.slug) console.log(` ${BOLD$2}Slug
|
|
7318
|
-
if (res.url) console.log(` ${BOLD$2}URL
|
|
7317
|
+
console.log(` ${GREEN$3}发布成功!${RESET$4}`);
|
|
7318
|
+
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$4}${res.slug}${RESET$4}`);
|
|
7319
|
+
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$4}${res.url}${RESET$4}`);
|
|
7319
7320
|
} catch (error) {
|
|
7320
|
-
console.error(` ${RED$1}
|
|
7321
|
+
console.error(` ${RED$1}发布失败:${error.message}${RESET$4}`);
|
|
7321
7322
|
process.exit(1);
|
|
7322
7323
|
}
|
|
7323
7324
|
console.log();
|
|
@@ -7325,43 +7326,43 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
|
|
|
7325
7326
|
async function publishFromZip(positionalArgs, api, namespace, visibility) {
|
|
7326
7327
|
const zipPath = positionalArgs[0];
|
|
7327
7328
|
if (!zipPath) {
|
|
7328
|
-
console.error("
|
|
7329
|
-
console.log("
|
|
7329
|
+
console.error("用法:bfi publish <file.zip> --from zip");
|
|
7330
|
+
console.log("从包含 SKILL.md 的 zip 文件发布技能。");
|
|
7330
7331
|
process.exit(1);
|
|
7331
7332
|
}
|
|
7332
7333
|
const resolvedZip = path$1.resolve(zipPath);
|
|
7333
7334
|
if (!fs.existsSync(resolvedZip)) {
|
|
7334
|
-
console.error(
|
|
7335
|
+
console.error(`文件未找到:${resolvedZip}`);
|
|
7335
7336
|
process.exit(1);
|
|
7336
7337
|
}
|
|
7337
|
-
console.log(`${DIM$4}
|
|
7338
|
+
console.log(`${DIM$4}正在解压 zip...${RESET$4}`);
|
|
7338
7339
|
const tmpDir = path$1.join(os$1.tmpdir(), `.bfi-publish-${Date.now()}`);
|
|
7339
7340
|
fs.mkdirSync(tmpDir, { recursive: true });
|
|
7340
7341
|
try {
|
|
7341
7342
|
await extractZip(resolvedZip, tmpDir);
|
|
7342
7343
|
const skillMdPath = findSkillMd(tmpDir);
|
|
7343
7344
|
if (!skillMdPath) {
|
|
7344
|
-
console.error(` ${RED$1}SKILL.md
|
|
7345
|
+
console.error(` ${RED$1}zip 文件中未找到 SKILL.md${RESET$4}`);
|
|
7345
7346
|
process.exit(1);
|
|
7346
7347
|
}
|
|
7347
7348
|
const skillDir = path$1.dirname(skillMdPath);
|
|
7348
|
-
console.log(` ${GREEN$3}
|
|
7349
|
+
console.log(` ${GREEN$3}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$4}`);
|
|
7349
7350
|
const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
|
|
7350
7351
|
const skillName = frontmatter.name || path$1.basename(skillDir);
|
|
7351
|
-
console.log(` ${BOLD$2}
|
|
7352
|
-
console.log(` ${BOLD$2}
|
|
7353
|
-
console.log(` ${BOLD$2}
|
|
7352
|
+
console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$4}${skillName}${RESET$4}`);
|
|
7353
|
+
console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$4}${namespace}${RESET$4}`);
|
|
7354
|
+
console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$4}${visibility}${RESET$4}`);
|
|
7354
7355
|
console.log();
|
|
7355
|
-
console.log(`${DIM$4}
|
|
7356
|
+
console.log(`${DIM$4}正在重新打包...${RESET$4}`);
|
|
7356
7357
|
const zipBuffer = createZipFromDir(skillDir);
|
|
7357
|
-
console.log(` ${GREEN$3}Zip
|
|
7358
|
-
console.log(`${DIM$4}
|
|
7358
|
+
console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
|
|
7359
|
+
console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
|
|
7359
7360
|
const res = await api.publishSkill(namespace, zipBuffer, visibility);
|
|
7360
|
-
console.log(` ${GREEN$3}
|
|
7361
|
-
if (res.slug) console.log(` ${BOLD$2}Slug
|
|
7362
|
-
if (res.url) console.log(` ${BOLD$2}URL
|
|
7361
|
+
console.log(` ${GREEN$3}发布成功!${RESET$4}`);
|
|
7362
|
+
if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$4}${res.slug}${RESET$4}`);
|
|
7363
|
+
if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$4}${res.url}${RESET$4}`);
|
|
7363
7364
|
} catch (error) {
|
|
7364
|
-
if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$1}
|
|
7365
|
+
if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$1}错误:${error.message}${RESET$4}`);
|
|
7365
7366
|
process.exit(1);
|
|
7366
7367
|
} finally {
|
|
7367
7368
|
try {
|
|
@@ -7376,10 +7377,10 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
|
|
|
7376
7377
|
async function publishFromGit(positionalArgs, api, namespace, visibility, yes, branch, directory, skillFilter) {
|
|
7377
7378
|
const repoArg = positionalArgs[0];
|
|
7378
7379
|
if (!repoArg) {
|
|
7379
|
-
console.error("
|
|
7380
|
-
console.log("
|
|
7380
|
+
console.error("用法:bfi publish <repo-url> --from git [options]");
|
|
7381
|
+
console.log("使用服务端发现从 Git 仓库发布技能。");
|
|
7381
7382
|
console.log();
|
|
7382
|
-
console.log("
|
|
7383
|
+
console.log("示例:");
|
|
7383
7384
|
console.log(` ${DIM$4}$ ${RESET$4}bfi publish https://github.com/user/repo --from git`);
|
|
7384
7385
|
console.log(` ${DIM$4}$ ${RESET$4}bfi publish user/repo --from git --branch main`);
|
|
7385
7386
|
process.exit(1);
|
|
@@ -7392,40 +7393,40 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
|
|
|
7392
7393
|
}
|
|
7393
7394
|
const effectiveBranch = branch || "main";
|
|
7394
7395
|
const effectiveDir = directory || null;
|
|
7395
|
-
console.log(`${DIM$4}
|
|
7396
|
-
console.log(` ${BOLD$2}
|
|
7397
|
-
console.log(` ${BOLD$2}
|
|
7398
|
-
if (effectiveDir) console.log(` ${BOLD$2}
|
|
7396
|
+
console.log(`${DIM$4}正在从 Git 仓库发现技能...${RESET$4}`);
|
|
7397
|
+
console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$4}${repoUrl}${RESET$4}`);
|
|
7398
|
+
console.log(` ${BOLD$2}分支:${RESET$4} ${TEXT$4}${effectiveBranch}${RESET$4}`);
|
|
7399
|
+
if (effectiveDir) console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$4}${effectiveDir}${RESET$4}`);
|
|
7399
7400
|
console.log();
|
|
7400
7401
|
let parseResult;
|
|
7401
7402
|
try {
|
|
7402
7403
|
parseResult = await api.gitParse(repoUrl, effectiveBranch, effectiveDir);
|
|
7403
7404
|
} catch (error) {
|
|
7404
|
-
console.error(` ${RED$1}Git
|
|
7405
|
+
console.error(` ${RED$1}Git 解析失败:${error.message}${RESET$4}`);
|
|
7405
7406
|
process.exit(1);
|
|
7406
7407
|
}
|
|
7407
7408
|
const sessionId = parseResult.sessionId;
|
|
7408
7409
|
const discoveredSkills = parseResult.skills || [];
|
|
7409
7410
|
const precheck = parseResult.precheck;
|
|
7410
7411
|
if (!sessionId || discoveredSkills.length === 0) {
|
|
7411
|
-
console.log(`${YELLOW$1}
|
|
7412
|
+
console.log(`${YELLOW$1}仓库中未发现技能。${RESET$4}`);
|
|
7412
7413
|
if (precheck && (precheck.errors || precheck.warnings)) {
|
|
7413
7414
|
console.log();
|
|
7414
|
-
console.log(`${BOLD$2}
|
|
7415
|
+
console.log(`${BOLD$2}预检结果:${RESET$4}`);
|
|
7415
7416
|
const errors = precheck.errors;
|
|
7416
7417
|
const warnings = precheck.warnings;
|
|
7417
7418
|
if (errors && errors.length > 0) {
|
|
7418
|
-
console.log(` ${RED$1}
|
|
7419
|
+
console.log(` ${RED$1}错误:${RESET$4}`);
|
|
7419
7420
|
for (const e of errors) console.log(` ${RED$1}- ${e}${RESET$4}`);
|
|
7420
7421
|
}
|
|
7421
7422
|
if (warnings && warnings.length > 0) {
|
|
7422
|
-
console.log(` ${YELLOW$1}
|
|
7423
|
+
console.log(` ${YELLOW$1}警告:${RESET$4}`);
|
|
7423
7424
|
for (const w of warnings) console.log(` ${YELLOW$1}- ${w}${RESET$4}`);
|
|
7424
7425
|
}
|
|
7425
7426
|
}
|
|
7426
7427
|
process.exit(1);
|
|
7427
7428
|
}
|
|
7428
|
-
console.log(`${BOLD$2}
|
|
7429
|
+
console.log(`${BOLD$2}发现 ${discoveredSkills.length} 个技能:${RESET$4}`);
|
|
7429
7430
|
console.log();
|
|
7430
7431
|
let selectedSkills = discoveredSkills;
|
|
7431
7432
|
if (skillFilter) {
|
|
@@ -7436,7 +7437,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
|
|
|
7436
7437
|
return filters.some((f) => slug.includes(f) || name.includes(f));
|
|
7437
7438
|
});
|
|
7438
7439
|
if (selectedSkills.length === 0) {
|
|
7439
|
-
console.log(`${YELLOW$1}
|
|
7440
|
+
console.log(`${YELLOW$1}没有技能匹配筛选条件:${skillFilter}${RESET$4}`);
|
|
7440
7441
|
console.log("Available skills:");
|
|
7441
7442
|
for (const s of discoveredSkills) console.log(` - ${s.slug || s.name}`);
|
|
7442
7443
|
process.exit(1);
|
|
@@ -7459,8 +7460,8 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
|
|
|
7459
7460
|
if (skillPrecheck) {
|
|
7460
7461
|
const errors = skillPrecheck.errors;
|
|
7461
7462
|
const warnings = skillPrecheck.warnings;
|
|
7462
|
-
if (errors && errors.length > 0) for (const e of errors) console.log(` ${RED$1}
|
|
7463
|
-
if (warnings && warnings.length > 0) for (const w of warnings) console.log(` ${YELLOW$1}
|
|
7463
|
+
if (errors && errors.length > 0) for (const e of errors) console.log(` ${RED$1}错误:${e}${RESET$4}`);
|
|
7464
|
+
if (warnings && warnings.length > 0) for (const w of warnings) console.log(` ${YELLOW$1}警告:${w}${RESET$4}`);
|
|
7464
7465
|
}
|
|
7465
7466
|
console.log();
|
|
7466
7467
|
}
|
|
@@ -7473,21 +7474,21 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
|
|
|
7473
7474
|
const selectedSlugs = skillFilter ? selectedSkills.map((s) => String(s.slug)) : null;
|
|
7474
7475
|
if (!yes) {
|
|
7475
7476
|
const count = selectedSlugs ? selectedSlugs.length : discoveredSkills.length;
|
|
7476
|
-
console.log(`${DIM$4}
|
|
7477
|
-
console.log(`${DIM$4}
|
|
7478
|
-
await confirmPrompt("
|
|
7477
|
+
console.log(`${DIM$4}正在将 ${count} 个技能发布到 @${namespace} (${visibility})${RESET$4}`);
|
|
7478
|
+
console.log(`${DIM$4}按 Ctrl+C 取消,或按 Enter 继续...${RESET$4}`);
|
|
7479
|
+
await confirmPrompt("确认发布?");
|
|
7479
7480
|
}
|
|
7480
|
-
console.log(`${DIM$4}
|
|
7481
|
+
console.log(`${DIM$4}正在发布到 SkillHub...${RESET$4}`);
|
|
7481
7482
|
try {
|
|
7482
7483
|
const res = await api.gitPublish(sessionId, namespace, visibility, selectedSlugs, confirmWarnings);
|
|
7483
|
-
console.log(` ${GREEN$3}
|
|
7484
|
+
console.log(` ${GREEN$3}发布成功!${RESET$4}`);
|
|
7484
7485
|
const publishedSkills = res.skills || res.published;
|
|
7485
7486
|
if (Array.isArray(publishedSkills)) for (const s of publishedSkills) {
|
|
7486
7487
|
const ps = s;
|
|
7487
7488
|
console.log(` ${GREEN$3}✓ ${ps.slug || ps.name}${RESET$4}`);
|
|
7488
7489
|
}
|
|
7489
7490
|
} catch (error) {
|
|
7490
|
-
console.error(` ${RED$1}
|
|
7491
|
+
console.error(` ${RED$1}发布失败:${error.message}${RESET$4}`);
|
|
7491
7492
|
process.exit(1);
|
|
7492
7493
|
}
|
|
7493
7494
|
console.log();
|
|
@@ -7583,21 +7584,21 @@ async function runPackage(args, globalOpts) {
|
|
|
7583
7584
|
}
|
|
7584
7585
|
function printPackageHelp() {
|
|
7585
7586
|
console.log();
|
|
7586
|
-
console.log(`${BOLD$1}
|
|
7587
|
-
console.log(` ${DIM$3}bfi package list${RESET$3}
|
|
7588
|
-
console.log(` ${DIM$3}bfi package info <ref>${RESET$3}
|
|
7589
|
-
console.log(` ${DIM$3}bfi package create <slug>${RESET$3}
|
|
7590
|
-
console.log(` ${DIM$3}bfi package add <pkg> <skills>${RESET$3}
|
|
7591
|
-
console.log(` ${DIM$3}bfi package remove <pkg> <skills>${RESET$3}
|
|
7587
|
+
console.log(`${BOLD$1}包命令:${RESET$3}`);
|
|
7588
|
+
console.log(` ${DIM$3}bfi package list${RESET$3} 列出包`);
|
|
7589
|
+
console.log(` ${DIM$3}bfi package info <ref>${RESET$3} 查看包详情`);
|
|
7590
|
+
console.log(` ${DIM$3}bfi package create <slug>${RESET$3} 创建新包`);
|
|
7591
|
+
console.log(` ${DIM$3}bfi package add <pkg> <skills>${RESET$3} 添加技能到包`);
|
|
7592
|
+
console.log(` ${DIM$3}bfi package remove <pkg> <skills>${RESET$3} 从包移除技能`);
|
|
7592
7593
|
console.log();
|
|
7593
|
-
console.log(`${BOLD$1}
|
|
7594
|
-
console.log(` --namespace <ns>
|
|
7595
|
-
console.log(` --name <name>
|
|
7596
|
-
console.log(` --description <text>
|
|
7597
|
-
console.log(` --visibility <v>
|
|
7598
|
-
console.log(` --json
|
|
7594
|
+
console.log(`${BOLD$1}选项:${RESET$3}`);
|
|
7595
|
+
console.log(` --namespace <ns> 目标命名空间`);
|
|
7596
|
+
console.log(` --name <name> 显示名称(create 时)`);
|
|
7597
|
+
console.log(` --description <text> 描述(create 时)`);
|
|
7598
|
+
console.log(` --visibility <v> 私有或公开(create 时)`);
|
|
7599
|
+
console.log(` --json 以 JSON 输出`);
|
|
7599
7600
|
console.log();
|
|
7600
|
-
console.log(`${BOLD$1}
|
|
7601
|
+
console.log(`${BOLD$1}示例:${RESET$3}`);
|
|
7601
7602
|
console.log(` ${DIM$3}$ ${RESET$3}bfi package list --namespace myteam`);
|
|
7602
7603
|
console.log(` ${DIM$3}$ ${RESET$3}bfi package info @myteam/my-package`);
|
|
7603
7604
|
console.log(` ${DIM$3}$ ${RESET$3}bfi package create my-utils --namespace myteam`);
|
|
@@ -7620,7 +7621,7 @@ async function handleList(args, api, globalOpts) {
|
|
|
7620
7621
|
return;
|
|
7621
7622
|
}
|
|
7622
7623
|
console.log();
|
|
7623
|
-
console.log(`${BOLD$1}
|
|
7624
|
+
console.log(`${BOLD$1}@${namespace} 中的包${RESET$3}(${packages.length} 个):`);
|
|
7624
7625
|
console.log();
|
|
7625
7626
|
packages.forEach((pkg, index) => {
|
|
7626
7627
|
const visibility = pkg.visibility || "private";
|
|
@@ -7633,7 +7634,7 @@ async function handleList(args, api, globalOpts) {
|
|
|
7633
7634
|
console.log();
|
|
7634
7635
|
});
|
|
7635
7636
|
} catch (error) {
|
|
7636
|
-
console.error(
|
|
7637
|
+
console.error(`列出包失败:${error.message}`);
|
|
7637
7638
|
process.exit(1);
|
|
7638
7639
|
}
|
|
7639
7640
|
}
|
|
@@ -7659,26 +7660,26 @@ async function handleInfo(args, api, globalOpts) {
|
|
|
7659
7660
|
console.log();
|
|
7660
7661
|
console.log(`${BOLD$1}${pkg.name || slug}${RESET$3}`);
|
|
7661
7662
|
console.log(`${DIM$3}${"=".repeat(48)}${RESET$3}`);
|
|
7662
|
-
console.log(` ${BOLD$1}Slug
|
|
7663
|
-
console.log(` ${BOLD$1}
|
|
7664
|
-
console.log(` ${BOLD$1}
|
|
7665
|
-
console.log(` ${BOLD$1}
|
|
7663
|
+
console.log(` ${BOLD$1}Slug:${RESET$3} ${TEXT$3}${toCanonicalSlug(namespace, slug)}${RESET$3}`);
|
|
7664
|
+
console.log(` ${BOLD$1}命名空间:${RESET$3} ${TEXT$3}@${namespace}${RESET$3}`);
|
|
7665
|
+
console.log(` ${BOLD$1}可见性:${RESET$3} ${TEXT$3}${pkg.visibility || "private"}${RESET$3}`);
|
|
7666
|
+
console.log(` ${BOLD$1}描述:${RESET$3} ${TEXT$3}${pkg.description || "N/A"}${RESET$3}`);
|
|
7666
7667
|
const skills = pkg.skills;
|
|
7667
7668
|
if (skills && skills.length > 0) {
|
|
7668
7669
|
console.log();
|
|
7669
|
-
console.log(` ${BOLD$1}
|
|
7670
|
+
console.log(` ${BOLD$1}技能(${skills.length} 个):${RESET$3}`);
|
|
7670
7671
|
for (const skill of skills) console.log(` ${DIM$3}- ${skill.slug}${skill.name ? ` (${skill.name})` : ""}${RESET$3}`);
|
|
7671
7672
|
}
|
|
7672
7673
|
console.log();
|
|
7673
7674
|
} catch (error) {
|
|
7674
|
-
console.error(
|
|
7675
|
+
console.error(`获取包信息失败:${error.message}`);
|
|
7675
7676
|
process.exit(1);
|
|
7676
7677
|
}
|
|
7677
7678
|
}
|
|
7678
7679
|
async function handleCreate(args, api, globalOpts) {
|
|
7679
7680
|
const slug = args[0];
|
|
7680
7681
|
if (!slug) {
|
|
7681
|
-
console.error("
|
|
7682
|
+
console.error("用法:bfi package create <slug> [options]");
|
|
7682
7683
|
process.exit(1);
|
|
7683
7684
|
}
|
|
7684
7685
|
const namespace = getOptionValue(args, "--namespace") || globalOpts.namespace || "global";
|
|
@@ -7692,14 +7693,14 @@ async function handleCreate(args, api, globalOpts) {
|
|
|
7692
7693
|
description: description || "",
|
|
7693
7694
|
visibility
|
|
7694
7695
|
});
|
|
7695
|
-
console.log(`${GREEN$2}✓
|
|
7696
|
+
console.log(`${GREEN$2}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$3}`);
|
|
7696
7697
|
const createdPkg = result.package;
|
|
7697
7698
|
if (createdPkg) {
|
|
7698
|
-
console.log(` ${BOLD$1}
|
|
7699
|
+
console.log(` ${BOLD$1}名称:${RESET$3} ${TEXT$3}${createdPkg.name || slug}${RESET$3}`);
|
|
7699
7700
|
console.log(` ${BOLD$1}Visibility:${RESET$3} ${TEXT$3}${createdPkg.visibility || visibility}${RESET$3}`);
|
|
7700
7701
|
}
|
|
7701
7702
|
} catch (error) {
|
|
7702
|
-
console.error(
|
|
7703
|
+
console.error(`创建包失败:${error.message}`);
|
|
7703
7704
|
process.exit(1);
|
|
7704
7705
|
}
|
|
7705
7706
|
}
|
|
@@ -7707,7 +7708,7 @@ async function handleAdd(args, api, globalOpts) {
|
|
|
7707
7708
|
const pkgRef = args[0];
|
|
7708
7709
|
const skillRefs = args.slice(1);
|
|
7709
7710
|
if (!pkgRef || skillRefs.length === 0) {
|
|
7710
|
-
console.error("
|
|
7711
|
+
console.error("用法:bfi package add <package-ref> <skill-ref...>");
|
|
7711
7712
|
process.exit(1);
|
|
7712
7713
|
}
|
|
7713
7714
|
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
@@ -7720,10 +7721,10 @@ async function handleAdd(args, api, globalOpts) {
|
|
|
7720
7721
|
});
|
|
7721
7722
|
try {
|
|
7722
7723
|
await api.addSkillsToPackage(namespace, slug, skills);
|
|
7723
|
-
console.log(`${GREEN$2}✓
|
|
7724
|
+
console.log(`${GREEN$2}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$3}`);
|
|
7724
7725
|
for (const s of skills) console.log(` ${DIM$3}- ${toSkillRefString(s.namespace, s.slug)}${RESET$3}`);
|
|
7725
7726
|
} catch (error) {
|
|
7726
|
-
console.error(
|
|
7727
|
+
console.error(`添加技能失败:${error.message}`);
|
|
7727
7728
|
process.exit(1);
|
|
7728
7729
|
}
|
|
7729
7730
|
}
|
|
@@ -7731,7 +7732,7 @@ async function handleRemove(args, api, globalOpts) {
|
|
|
7731
7732
|
const pkgRef = args[0];
|
|
7732
7733
|
const skillRefs = args.slice(1);
|
|
7733
7734
|
if (!pkgRef || skillRefs.length === 0) {
|
|
7734
|
-
console.error("
|
|
7735
|
+
console.error("用法:bfi package remove <package-ref> <skill-ref...>");
|
|
7735
7736
|
process.exit(1);
|
|
7736
7737
|
}
|
|
7737
7738
|
const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
|
|
@@ -7744,10 +7745,10 @@ async function handleRemove(args, api, globalOpts) {
|
|
|
7744
7745
|
});
|
|
7745
7746
|
try {
|
|
7746
7747
|
await api.removeSkillsFromPackage(namespace, slug, skills);
|
|
7747
|
-
console.log(`${GREEN$2}✓
|
|
7748
|
+
console.log(`${GREEN$2}✓ 已从 ${toSkillRefString(namespace, slug)} 移除 ${skills.length} 个技能${RESET$3}`);
|
|
7748
7749
|
for (const s of skills) console.log(` ${DIM$3}- ${toSkillRefString(s.namespace, s.slug)}${RESET$3}`);
|
|
7749
7750
|
} catch (error) {
|
|
7750
|
-
console.error(
|
|
7751
|
+
console.error(`移除技能失败:${error.message}`);
|
|
7751
7752
|
process.exit(1);
|
|
7752
7753
|
}
|
|
7753
7754
|
}
|
|
@@ -7763,11 +7764,11 @@ const RED = "\x1B[31m";
|
|
|
7763
7764
|
async function runLog(args, globalOpts) {
|
|
7764
7765
|
const skillRef = args[0];
|
|
7765
7766
|
if (!skillRef) {
|
|
7766
|
-
console.log("
|
|
7767
|
+
console.log("用法:bfi log <skill-ref> [summary]");
|
|
7767
7768
|
console.log();
|
|
7768
|
-
console.log("
|
|
7769
|
+
console.log("记录技能使用到 SkillHub 用于追踪和分析。");
|
|
7769
7770
|
console.log();
|
|
7770
|
-
console.log("
|
|
7771
|
+
console.log("示例:");
|
|
7771
7772
|
console.log(` ${DIM$2}$ ${RESET$2}bfi log @myteam/my-skill`);
|
|
7772
7773
|
console.log(` ${DIM$2}$ ${RESET$2}bfi log my-skill "Used for code review"`);
|
|
7773
7774
|
process.exit(1);
|
|
@@ -7777,10 +7778,10 @@ async function runLog(args, globalOpts) {
|
|
|
7777
7778
|
const api = new SkillHubAPI(registry, token);
|
|
7778
7779
|
try {
|
|
7779
7780
|
const result = await api.logSkillUsage(skillRef, summary);
|
|
7780
|
-
console.log(`${GREEN$1}✓
|
|
7781
|
+
console.log(`${GREEN$1}✓ 已记录使用 ${TEXT$2}${skillRef}${RESET$2}`);
|
|
7781
7782
|
if (result.message) console.log(` ${DIM$2}${result.message}${RESET$2}`);
|
|
7782
7783
|
} catch (error) {
|
|
7783
|
-
console.error(`${RED}
|
|
7784
|
+
console.error(`${RED}记录技能使用失败:${error.message}${RESET$2}`);
|
|
7784
7785
|
process.exit(1);
|
|
7785
7786
|
}
|
|
7786
7787
|
}
|
|
@@ -7795,14 +7796,14 @@ async function runInstall(args, globalOpts) {
|
|
|
7795
7796
|
const skillEntries = Object.entries(lock.skills);
|
|
7796
7797
|
const packageEntries = Object.entries(lock.packages);
|
|
7797
7798
|
if (skillEntries.length === 0 && packageEntries.length === 0) {
|
|
7798
|
-
console.log(`${DIM$1}
|
|
7799
|
-
console.log(`${DIM$1}
|
|
7799
|
+
console.log(`${DIM$1}锁文件 (.bfi/lock.json) 中未找到技能或包。${RESET$1}`);
|
|
7800
|
+
console.log(`${DIM$1}请先运行 'bfi skills add <source>' 安装技能。${RESET$1}`);
|
|
7800
7801
|
return;
|
|
7801
7802
|
}
|
|
7802
7803
|
console.log();
|
|
7803
|
-
console.log(`${DIM$1}
|
|
7804
|
-
console.log(`
|
|
7805
|
-
console.log(`
|
|
7804
|
+
console.log(`${DIM$1}正在从锁文件恢复...${RESET$1}`);
|
|
7805
|
+
console.log(` 技能:${skillEntries.length}`);
|
|
7806
|
+
console.log(` 包:${packageEntries.length}`);
|
|
7806
7807
|
console.log();
|
|
7807
7808
|
let installedCount = 0;
|
|
7808
7809
|
let failedCount = 0;
|
|
@@ -7817,35 +7818,35 @@ async function runInstall(args, globalOpts) {
|
|
|
7817
7818
|
if (sourceType === "skillhub" || namespace !== "global") installSource = `@${namespace}/${slug}`;
|
|
7818
7819
|
else if (source) installSource = source;
|
|
7819
7820
|
else {
|
|
7820
|
-
console.log(` ${YELLOW}
|
|
7821
|
+
console.log(` ${YELLOW}跳过 ${skillName}:未知源类型${RESET$1}`);
|
|
7821
7822
|
continue;
|
|
7822
7823
|
}
|
|
7823
|
-
console.log(` ${TEXT$1}
|
|
7824
|
+
console.log(` ${TEXT$1}正在从 ${installSource} 安装 ${skillName}...${RESET$1}`);
|
|
7824
7825
|
try {
|
|
7825
7826
|
await runAdd([installSource], { yes });
|
|
7826
7827
|
installedCount++;
|
|
7827
7828
|
console.log(` ${GREEN}✓ ${skillName}${RESET$1}`);
|
|
7828
7829
|
} catch (error) {
|
|
7829
7830
|
failedCount++;
|
|
7830
|
-
console.error(` ${YELLOW}
|
|
7831
|
+
console.error(` ${YELLOW}失败:${error.message}${RESET$1}`);
|
|
7831
7832
|
}
|
|
7832
7833
|
}
|
|
7833
7834
|
for (const [pkgRef, entry] of packageEntries) {
|
|
7834
7835
|
const pkgEntry = entry;
|
|
7835
7836
|
const installSource = `@${String(pkgEntry.namespace || "global")}/${String(pkgEntry.slug || pkgRef)}`;
|
|
7836
|
-
console.log(` ${TEXT$1}
|
|
7837
|
+
console.log(` ${TEXT$1}正在从 ${installSource} 安装包 ${pkgRef}...${RESET$1}`);
|
|
7837
7838
|
try {
|
|
7838
7839
|
await runAdd([installSource], { yes });
|
|
7839
7840
|
installedCount++;
|
|
7840
7841
|
console.log(` ${GREEN}✓ ${pkgRef}${RESET$1}`);
|
|
7841
7842
|
} catch (error) {
|
|
7842
7843
|
failedCount++;
|
|
7843
|
-
console.error(` ${YELLOW}
|
|
7844
|
+
console.error(` ${YELLOW}失败:${error.message}${RESET$1}`);
|
|
7844
7845
|
}
|
|
7845
7846
|
}
|
|
7846
7847
|
console.log();
|
|
7847
|
-
if (installedCount > 0) console.log(`${GREEN}✓
|
|
7848
|
-
if (failedCount > 0) console.log(`${YELLOW}⚠ ${failedCount}
|
|
7848
|
+
if (installedCount > 0) console.log(`${GREEN}✓ 已恢复 ${installedCount} 项${RESET$1}`);
|
|
7849
|
+
if (failedCount > 0) console.log(`${YELLOW}⚠ ${failedCount} 项恢复失败${RESET$1}`);
|
|
7849
7850
|
console.log();
|
|
7850
7851
|
}
|
|
7851
7852
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -7896,8 +7897,8 @@ function showBanner() {
|
|
|
7896
7897
|
console.log(` ${DIM}$${RESET} ${TEXT}npx bfi skills search ${DIM}[query]${RESET}`);
|
|
7897
7898
|
console.log(` ${DIM}$${RESET} ${TEXT}npx bfi skills update${RESET}`);
|
|
7898
7899
|
console.log();
|
|
7899
|
-
console.log(
|
|
7900
|
-
console.log(
|
|
7900
|
+
console.log(`发现更多技能:${TEXT}https://skills.sh/${RESET}`);
|
|
7901
|
+
console.log(`以及 ${TEXT}https://skillhub.skillhub.woa.com/${RESET}`);
|
|
7901
7902
|
console.log();
|
|
7902
7903
|
}
|
|
7903
7904
|
function showHelp() {
|
|
@@ -7977,21 +7978,21 @@ function showRemoveHelp() {
|
|
|
7977
7978
|
console.log(`
|
|
7978
7979
|
${BOLD}Usage:${RESET} bfi skills remove [skills...] [options]
|
|
7979
7980
|
|
|
7980
|
-
${BOLD}
|
|
7981
|
+
${BOLD}说明:${RESET}
|
|
7981
7982
|
Remove installed skills from agents. If no skill names are provided,
|
|
7982
7983
|
an interactive selection menu will be shown.
|
|
7983
7984
|
|
|
7984
|
-
${BOLD}
|
|
7985
|
+
${BOLD}参数:${RESET}
|
|
7985
7986
|
skills Optional skill names to remove (space-separated)
|
|
7986
7987
|
|
|
7987
|
-
${BOLD}
|
|
7988
|
+
${BOLD}选项:${RESET}
|
|
7988
7989
|
-g, --global Remove from global scope (~/) instead of project scope
|
|
7989
7990
|
-a, --agent Remove from specific agents (use '*' for all agents)
|
|
7990
7991
|
-s, --skill Specify skills to remove (use '*' for all skills)
|
|
7991
7992
|
-y, --yes Skip confirmation prompts
|
|
7992
7993
|
--all Shorthand for --skill '*' --agent '*' -y
|
|
7993
7994
|
|
|
7994
|
-
${BOLD}
|
|
7995
|
+
${BOLD}示例:${RESET}
|
|
7995
7996
|
${DIM}$${RESET} bfi skills remove ${DIM}# interactive selection${RESET}
|
|
7996
7997
|
${DIM}$${RESET} bfi skills remove my-skill ${DIM}# remove specific skill${RESET}
|
|
7997
7998
|
${DIM}$${RESET} bfi skills remove skill1 skill2 -y ${DIM}# remove multiple skills${RESET}
|
|
@@ -8012,7 +8013,7 @@ function runInit(args) {
|
|
|
8012
8013
|
const skillFile = join(skillDir, "SKILL.md");
|
|
8013
8014
|
const displayPath = hasName ? `${skillName}/SKILL.md` : "SKILL.md";
|
|
8014
8015
|
if (existsSync(skillFile)) {
|
|
8015
|
-
console.log(`${TEXT}
|
|
8016
|
+
console.log(`${TEXT}技能已存在:${DIM}${displayPath}${RESET}`);
|
|
8016
8017
|
return;
|
|
8017
8018
|
}
|
|
8018
8019
|
if (hasName) mkdirSync(skillDir, { recursive: true });
|
|
@@ -8035,16 +8036,16 @@ Describe when this skill should be used.
|
|
|
8035
8036
|
2. Second step
|
|
8036
8037
|
3. Additional steps as needed
|
|
8037
8038
|
`);
|
|
8038
|
-
console.log(`${TEXT}
|
|
8039
|
+
console.log(`${TEXT}已初始化技能:${DIM}${skillName}${RESET}`);
|
|
8039
8040
|
console.log();
|
|
8040
|
-
console.log(`${DIM}
|
|
8041
|
+
console.log(`${DIM}已创建:${RESET}`);
|
|
8041
8042
|
console.log(` ${displayPath}`);
|
|
8042
8043
|
console.log();
|
|
8043
|
-
console.log(`${DIM}
|
|
8044
|
+
console.log(`${DIM}下一步:${RESET}`);
|
|
8044
8045
|
console.log(` 1. Edit ${TEXT}${displayPath}${RESET} to define your skill instructions`);
|
|
8045
8046
|
console.log(` 2. Update the ${TEXT}name${RESET} and ${TEXT}description${RESET} in the frontmatter`);
|
|
8046
8047
|
console.log();
|
|
8047
|
-
console.log(`${DIM}
|
|
8048
|
+
console.log(`${DIM}发布方式:${RESET}`);
|
|
8048
8049
|
console.log(` ${DIM}GitHub:${RESET} Push to a repo, then ${TEXT}npx bfi skills add <owner>/<repo>${RESET}`);
|
|
8049
8050
|
console.log(` ${DIM}URL:${RESET} Host the file, then ${TEXT}npx bfi skills add https://example.com/${displayPath}${RESET}`);
|
|
8050
8051
|
console.log();
|
|
@@ -8173,10 +8174,10 @@ async function dispatchSkillSubcommand(args, globalOpts) {
|
|
|
8173
8174
|
console.log(`${BOLD}Docs:${RESET}`);
|
|
8174
8175
|
console.log(` docs <cmd> Document management`);
|
|
8175
8176
|
console.log();
|
|
8176
|
-
console.log(
|
|
8177
|
+
console.log(`运行 ${BOLD}bfi --help${RESET} 查看更多详情。`);
|
|
8177
8178
|
} else {
|
|
8178
|
-
console.log(
|
|
8179
|
-
console.log(
|
|
8179
|
+
console.log(`未知技能命令:${sub}`);
|
|
8180
|
+
console.log(`运行 ${BOLD}bfi skills --help${RESET} 查看用法。`);
|
|
8180
8181
|
}
|
|
8181
8182
|
}
|
|
8182
8183
|
}
|
|
@@ -8307,8 +8308,8 @@ async function main() {
|
|
|
8307
8308
|
console.log(VERSION);
|
|
8308
8309
|
break;
|
|
8309
8310
|
default:
|
|
8310
|
-
console.log(
|
|
8311
|
-
console.log(
|
|
8311
|
+
console.log(`未知命令:${command}`);
|
|
8312
|
+
console.log(`运行 ${BOLD}bfi --help${RESET} 查看用法。`);
|
|
8312
8313
|
}
|
|
8313
8314
|
}
|
|
8314
8315
|
main().finally(() => process.exit(process.exitCode ?? 0));
|