bfi-cli 0.1.57 → 0.1.64

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 CHANGED
@@ -22,7 +22,7 @@ import os$1 from "node:os";
22
22
  import zlib, { gunzipSync, inflateRawSync } from "node:zlib";
23
23
  import { promisify } from "util";
24
24
  import { execFile, spawn, spawnSync } from "child_process";
25
- import { access, chmod, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rm, stat, symlink, writeFile } from "fs/promises";
25
+ import { access, chmod, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "fs/promises";
26
26
  import { determineAgent } from "@vercel/detect-agent";
27
27
  var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
28
28
  const GIT_HOST = process.env.BFI_GIT_HOST || "git.yyrd.com";
@@ -506,7 +506,8 @@ var SkillHubAPI = class {
506
506
  let bodyStr;
507
507
  let bodyBuf;
508
508
  if (options.body !== void 0) if (options.body instanceof Buffer) bodyBuf = options.body;
509
- else if (options.body instanceof FormData || typeof options.body === "string") bodyStr = options.body;
509
+ else if (typeof options.body === "string") bodyStr = options.body;
510
+ else if (typeof FormData !== "undefined" && options.body instanceof FormData) return this.fetchRequest(url, requestOptions, options.body);
510
511
  else {
511
512
  requestOptions.headers["Content-Type"] = "application/json";
512
513
  bodyStr = JSON.stringify(options.body);
@@ -550,6 +551,36 @@ var SkillHubAPI = class {
550
551
  req.end();
551
552
  });
552
553
  }
554
+ async fetchRequest(url, requestOptions, formData) {
555
+ const headers = {
556
+ ...this.getHeaders(),
557
+ ...requestOptions.headers
558
+ };
559
+ const response = await fetch(url, {
560
+ method: requestOptions.method.toUpperCase(),
561
+ headers,
562
+ body: formData
563
+ });
564
+ const responseHeaders = {};
565
+ response.headers.forEach((value, key) => {
566
+ responseHeaders[key] = value;
567
+ });
568
+ const text = await response.text();
569
+ let body = text;
570
+ try {
571
+ body = JSON.parse(text);
572
+ } catch {}
573
+ if (response.ok) return {
574
+ status: response.status,
575
+ body,
576
+ headers: responseHeaders
577
+ };
578
+ const msg = body?.message || body?.msg || body?.error || `HTTP ${response.status}`;
579
+ const error = new Error(msg);
580
+ error.status = response.status;
581
+ error.body = body;
582
+ throw error;
583
+ }
553
584
  async downloadFile(urlPath, targetPath, followRedirect = true) {
554
585
  const url = new URL(this.buildUrl(urlPath));
555
586
  const isHttps = url.protocol === "https:";
@@ -650,6 +681,72 @@ var SkillHubAPI = class {
650
681
  async removeSkillsFromPackage(namespace, slug, skills) {
651
682
  return (await this.request("DELETE", `/namespaces/${namespace}/packages/${slug}/skills`, { body: { skills } })).body;
652
683
  }
684
+ async listPlugins(params) {
685
+ const body = (await this.request("GET", "/plugins", { params })).body;
686
+ return body.data || body;
687
+ }
688
+ async getPlugin(pluginId) {
689
+ const body = (await this.request("GET", `/plugins/${pluginId}`)).body;
690
+ return body.data || body;
691
+ }
692
+ async createPlugin(data) {
693
+ return (await this.request("POST", "/plugins", { body: data })).body;
694
+ }
695
+ async updatePlugin(pluginId, data) {
696
+ return (await this.request("PUT", `/plugins/${pluginId}`, { body: data })).body;
697
+ }
698
+ async deletePlugin(pluginId) {
699
+ return (await this.request("DELETE", `/plugins/${pluginId}`)).body;
700
+ }
701
+ async listPluginVersions(pluginId) {
702
+ const body = (await this.request("GET", `/plugins/${pluginId}/versions`)).body;
703
+ return body.data || body;
704
+ }
705
+ async createPluginVersion(pluginId, data) {
706
+ return (await this.request("POST", `/plugins/${pluginId}/versions`, { body: data })).body;
707
+ }
708
+ async publishPluginVersion(pluginId, versionId) {
709
+ return (await this.request("POST", `/plugins/${pluginId}/versions/${versionId}/publish`)).body;
710
+ }
711
+ async yankPluginVersion(pluginId, versionId, reason) {
712
+ return (await this.request("POST", `/plugins/${pluginId}/versions/${versionId}/yank`, { body: reason ? { changelog: reason } : void 0 })).body;
713
+ }
714
+ async downloadPluginBundle(pluginId, versionId, targetPath) {
715
+ try {
716
+ return await this.downloadFile(`/plugins/${pluginId}/versions/${versionId}/download`, targetPath);
717
+ } catch (error) {
718
+ throw new Error(`Failed to download plugin bundle: ${error.message}`);
719
+ }
720
+ }
721
+ async uploadPlugin(fileBuffer, filename, namespace, options) {
722
+ const form = new FormData();
723
+ form.append("file", new Blob([new Uint8Array(fileBuffer)]), filename);
724
+ form.append("namespace", namespace);
725
+ if (options?.visibility) form.append("visibility", options.visibility);
726
+ if (options?.summary) form.append("summary", options.summary);
727
+ if (options?.changelog) form.append("changelog", options.changelog);
728
+ return (await this.request("POST", "/plugins/upload", { body: form })).body;
729
+ }
730
+ async listMcpServers(params) {
731
+ const body = (await this.request("GET", "/mcp-servers", { params })).body;
732
+ return body.data || body;
733
+ }
734
+ async getMcpServer(mcpId) {
735
+ const body = (await this.request("GET", `/mcp-servers/${mcpId}`)).body;
736
+ return body.data || body;
737
+ }
738
+ async createMcpServer(data) {
739
+ return (await this.request("POST", "/mcp-servers", { body: data })).body;
740
+ }
741
+ async updateMcpServer(mcpId, data) {
742
+ return (await this.request("PUT", `/mcp-servers/${mcpId}`, { body: data })).body;
743
+ }
744
+ async deleteMcpServer(mcpId) {
745
+ return (await this.request("DELETE", `/mcp-servers/${mcpId}`)).body;
746
+ }
747
+ async getMcpConfig(mcpId) {
748
+ return (await this.request("GET", `/mcp-servers/${mcpId}/config`)).body.data?.config ?? "";
749
+ }
653
750
  async gitParse(repositoryUrl, branch, directory) {
654
751
  const body = {
655
752
  repositoryUrl,
@@ -1352,6 +1449,54 @@ async function cleanAndCreateDirectory(path) {
1352
1449
  force: true
1353
1450
  });
1354
1451
  } catch {}
1452
+ await ensureDirectory(path);
1453
+ }
1454
+ function isErrnoException(err) {
1455
+ return err instanceof Error && typeof err.code === "string";
1456
+ }
1457
+ async function classifyPathEntry(path) {
1458
+ try {
1459
+ return (await stat(path)).isDirectory() ? "dir" : "blocker";
1460
+ } catch {
1461
+ try {
1462
+ await lstat(path);
1463
+ return "blocker";
1464
+ } catch {
1465
+ return "missing";
1466
+ }
1467
+ }
1468
+ }
1469
+ async function findBlockingEntry(path) {
1470
+ let current = resolve(path);
1471
+ for (;;) {
1472
+ const kind = await classifyPathEntry(current);
1473
+ if (kind === "blocker") return current;
1474
+ if (kind === "dir") return null;
1475
+ const parent = dirname(current);
1476
+ if (parent === current) return null;
1477
+ current = parent;
1478
+ }
1479
+ }
1480
+ async function ensureDirectory(path) {
1481
+ try {
1482
+ await mkdir(path, { recursive: true });
1483
+ return;
1484
+ } catch (err) {
1485
+ if (!isErrnoException(err) || err.code !== "ENOTDIR" && err.code !== "EEXIST" && err.code !== "ELOOP" && err.code !== "ENOENT") throw err;
1486
+ }
1487
+ const blockingEntry = await findBlockingEntry(path);
1488
+ if (!blockingEntry) {
1489
+ await mkdir(path, { recursive: true });
1490
+ return;
1491
+ }
1492
+ const backupPath = `${blockingEntry}.bak-${Date.now()}`;
1493
+ try {
1494
+ await rename(blockingEntry, backupPath);
1495
+ } catch (renameErr) {
1496
+ const reason = renameErr instanceof Error ? renameErr.message : String(renameErr);
1497
+ throw new Error(`无法创建目录 ${path}:${blockingEntry} 存在但不是可用目录(可能是文件或失效的链接),且自动移开失败(${reason})。请手动删除或重命名该条目后重试。`);
1498
+ }
1499
+ console.warn(`检测到 ${blockingEntry} 不是可用目录(可能是文件或失效的链接),已重命名为 ${backupPath}`);
1355
1500
  await mkdir(path, { recursive: true });
1356
1501
  }
1357
1502
  async function resolveParentSymlinks(path) {
@@ -1680,7 +1825,7 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
1680
1825
  error: "无效的技能名称:检测到潜在的路径遍历攻击"
1681
1826
  };
1682
1827
  try {
1683
- await mkdir(agentBase, { recursive: true });
1828
+ await ensureDirectory(agentBase);
1684
1829
  await rm(flatSkillPath, {
1685
1830
  recursive: true,
1686
1831
  force: true
@@ -2796,12 +2941,14 @@ async function tryBlobInstall(ownerRepo, options = {}) {
2796
2941
  };
2797
2942
  }
2798
2943
  var add_exports = /* @__PURE__ */ __exportAll({
2944
+ ensureUniversalAgents: () => ensureUniversalAgents,
2799
2945
  formatEveInstallPromptMessage: () => formatEveInstallPromptMessage,
2800
2946
  getLockSource: () => getLockSource,
2801
2947
  getProjectLockSourceUrl: () => getProjectLockSourceUrl,
2802
2948
  parseAddOptions: () => parseAddOptions,
2803
2949
  promptForAgents: () => promptForAgents,
2804
- runAdd: () => runAdd
2950
+ runAdd: () => runAdd,
2951
+ selectAgentsInteractive: () => selectAgentsInteractive
2805
2952
  });
2806
2953
  const isCancelled = (value) => typeof value === "symbol";
2807
2954
  const EVE_AGENT_LABEL = "eve agent";
@@ -2876,20 +3023,20 @@ function computeSingleFileSkillHash(contents) {
2876
3023
  hash.update(contents);
2877
3024
  return hash.digest("hex");
2878
3025
  }
2879
- function formatList$1(items, maxShow = 5) {
3026
+ function formatList$2(items, maxShow = 5) {
2880
3027
  if (items.length <= maxShow) return items.join(", ");
2881
3028
  const shown = items.slice(0, maxShow);
2882
3029
  const remaining = items.length - maxShow;
2883
3030
  return `${shown.join(", ")} +${remaining} more`;
2884
3031
  }
2885
3032
  function formatSkillPromptSubject(skills) {
2886
- const namedSubject = formatList$1(skills.map((skill) => import_picocolors.default.cyan(getSkillDisplayName(skill))), 3);
3033
+ const namedSubject = formatList$2(skills.map((skill) => import_picocolors.default.cyan(getSkillDisplayName(skill))), 3);
2887
3034
  return stripTerminalEscapes(namedSubject).length <= 80 ? namedSubject : `${skills.length} selected skills`;
2888
3035
  }
2889
3036
  function formatEveInstallPromptMessage(skills) {
2890
3037
  return `Detected an eve project. Install ${formatSkillPromptSubject(skills)} for your ${EVE_AGENT_LABEL} to use?`;
2891
3038
  }
2892
- function splitAgentsByType(agentTypes) {
3039
+ function splitAgentsByType$1(agentTypes) {
2893
3040
  const universal = [];
2894
3041
  const symlinked = [];
2895
3042
  for (const a of agentTypes) if (isUniversalAgent(a)) universal.push(agents[a].displayName);
@@ -2901,29 +3048,29 @@ function splitAgentsByType(agentTypes) {
2901
3048
  }
2902
3049
  function buildAgentSummaryLines(targetAgents, installMode, selectedAgents) {
2903
3050
  const lines = [];
2904
- const { universal, symlinked } = splitAgentsByType(targetAgents);
3051
+ const { universal, symlinked } = splitAgentsByType$1(targetAgents);
2905
3052
  const selectedSet = new Set(selectedAgents || targetAgents);
2906
3053
  if (installMode === "symlink") {
2907
3054
  const selectedUniversal = universal.filter((a) => selectedSet.has(a));
2908
3055
  const selectedSymlink = symlinked.filter((a) => selectedSet.has(a));
2909
- if (selectedUniversal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$1(selectedUniversal)}`);
2910
- if (selectedSymlink.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接 →")} ${formatList$1(selectedSymlink)}`);
3056
+ if (selectedUniversal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$2(selectedUniversal)}`);
3057
+ if (selectedSymlink.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接 →")} ${formatList$2(selectedSymlink)}`);
2911
3058
  const otherUniversal = universal.filter((a) => !selectedSet.has(a));
2912
3059
  if (otherUniversal.length > 0) lines.push(` ${import_picocolors.default.dim(`(另外 ${otherUniversal.length} 个使用共享目录的 Agent 也会自动获得此技能)`)}`);
2913
3060
  } else {
2914
3061
  const allNames = targetAgents.filter((a) => selectedSet.has(a)).map((a) => agents[a].displayName);
2915
- lines.push(` ${import_picocolors.default.dim("复制 →")} ${formatList$1(allNames)}`);
3062
+ lines.push(` ${import_picocolors.default.dim("复制 →")} ${formatList$2(allNames)}`);
2916
3063
  }
2917
3064
  return lines;
2918
3065
  }
2919
- function targetDisplayName(target) {
3066
+ function targetDisplayName$1(target) {
2920
3067
  const base = agents[target.agent].displayName;
2921
3068
  return target.subagent ? `${base} (${target.subagent})` : base;
2922
3069
  }
2923
- function targetKey(target) {
3070
+ function targetKey$1(target) {
2924
3071
  return target.subagent ? `${target.agent}:${target.subagent}` : target.agent;
2925
3072
  }
2926
- function buildInstallTargets(targetAgents, eveSubagentTargets) {
3073
+ function buildInstallTargets$1(targetAgents, eveSubagentTargets) {
2927
3074
  const targets = [];
2928
3075
  for (const agent of targetAgents) if (agent === "eve") for (const subagent of eveSubagentTargets) targets.push({
2929
3076
  agent,
@@ -2932,18 +3079,18 @@ function buildInstallTargets(targetAgents, eveSubagentTargets) {
2932
3079
  else targets.push({ agent });
2933
3080
  return targets;
2934
3081
  }
2935
- function buildTargetSummaryLines(targets, installMode) {
3082
+ function buildTargetSummaryLines$1(targets, installMode) {
2936
3083
  const lines = [];
2937
3084
  const rootAgents = targets.filter((t) => !t.subagent).map((t) => t.agent);
2938
- const subagentNames = targets.filter((t) => t.subagent).map(targetDisplayName);
2939
- const { universal, symlinked } = splitAgentsByType(rootAgents);
3085
+ const subagentNames = targets.filter((t) => t.subagent).map(targetDisplayName$1);
3086
+ const { universal, symlinked } = splitAgentsByType$1(rootAgents);
2940
3087
  if (installMode === "symlink") {
2941
- if (universal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$1(universal, 3)}`);
2942
- if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接 →")} ${formatList$1(symlinked)}`);
2943
- if (subagentNames.length > 0) lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$1(subagentNames)}`);
3088
+ if (universal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$2(universal, 3)}`);
3089
+ if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接 →")} ${formatList$2(symlinked)}`);
3090
+ if (subagentNames.length > 0) lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$2(subagentNames)}`);
2944
3091
  } else {
2945
- const allNames = targets.map(targetDisplayName);
2946
- lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$1(allNames)}`);
3092
+ const allNames = targets.map(targetDisplayName$1);
3093
+ lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList$2(allNames)}`);
2947
3094
  }
2948
3095
  return lines;
2949
3096
  }
@@ -2955,12 +3102,12 @@ function ensureUniversalAgents(targetAgents) {
2955
3102
  }
2956
3103
  function buildResultLines(results, targetAgents) {
2957
3104
  const lines = [];
2958
- const { universal, symlinked: symlinkAgents } = splitAgentsByType(targetAgents);
3105
+ const { universal, symlinked: symlinkAgents } = splitAgentsByType$1(targetAgents);
2959
3106
  const successfulSymlinks = results.filter((r) => !r.symlinkFailed && !r.skipped && !universal.includes(r.agent)).map((r) => r.agent);
2960
3107
  const failedSymlinks = results.filter((r) => r.symlinkFailed && !r.skipped).map((r) => r.agent);
2961
- if (universal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$1(universal)}`);
2962
- if (successfulSymlinks.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接:")} ${formatList$1(successfulSymlinks)}`);
2963
- if (failedSymlinks.length > 0) lines.push(` ${import_picocolors.default.yellow("copied:")} ${formatList$1(failedSymlinks)}`);
3108
+ if (universal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList$2(universal)}`);
3109
+ if (successfulSymlinks.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接:")} ${formatList$2(successfulSymlinks)}`);
3110
+ if (failedSymlinks.length > 0) lines.push(` ${import_picocolors.default.yellow("copied:")} ${formatList$2(failedSymlinks)}`);
2964
3111
  return lines;
2965
3112
  }
2966
3113
  function multiselect(opts) {
@@ -3215,7 +3362,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3215
3362
  if (skill.files.size > 1) summaryLines.push(` ${import_picocolors.default.dim("files:")} ${skill.files.size}`);
3216
3363
  const skillOverwrites = overwriteStatus.get(skill.installName);
3217
3364
  const overwriteAgents = targetAgents.filter((a) => skillOverwrites?.get(a)).map((a) => agents[a].displayName);
3218
- if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
3365
+ if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$2(overwriteAgents)}`);
3219
3366
  }
3220
3367
  console.log();
3221
3368
  note(summaryLines.join("\n"), "安装摘要");
@@ -3304,7 +3451,7 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3304
3451
  const title = import_picocolors.default.green(`已安装 ${skillCount} 个技能`);
3305
3452
  note(resultLines.join("\n"), title);
3306
3453
  if (symlinkFailures.length > 0) {
3307
- log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$1(copiedAgents)}`));
3454
+ log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$2(copiedAgents)}`));
3308
3455
  log.message(import_picocolors.default.dim(" 已改为复制文件。在 Windows 上,请启用开发者模式以支持符号链接。"));
3309
3456
  }
3310
3457
  }
@@ -3500,10 +3647,10 @@ async function runAdd(args, options = {}) {
3500
3647
  else if (!process.stdin.isTTY) showInstallTip();
3501
3648
  let tempDir = null;
3502
3649
  try {
3503
- const spinner$2 = spinner();
3504
- spinner$2.start("正在解析源...");
3650
+ const spinner$3 = spinner();
3651
+ spinner$3.start("正在解析源...");
3505
3652
  const parsed = parseSource(source);
3506
- 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)}` : ""}`);
3653
+ spinner$3.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)}` : ""}`);
3507
3654
  const ownerRepoRaw = getOwnerRepo(parsed);
3508
3655
  const repoPrivacyPromise = (() => {
3509
3656
  if (!ownerRepoRaw) return Promise.resolve(null);
@@ -3512,7 +3659,7 @@ async function runAdd(args, options = {}) {
3512
3659
  return isRepoPrivate(ownerRepo.owner, ownerRepo.repo).catch(() => null);
3513
3660
  })();
3514
3661
  if (parsed.type === "well-known") {
3515
- await handleWellKnownSkills(source, parsed.url, options, spinner$2);
3662
+ await handleWellKnownSkills(source, parsed.url, options, spinner$3);
3516
3663
  return;
3517
3664
  }
3518
3665
  if (parsed.skillFilter) {
@@ -3523,18 +3670,18 @@ async function runAdd(args, options = {}) {
3523
3670
  let skills;
3524
3671
  let blobResult = null;
3525
3672
  if (parsed.type === "skillhub") {
3526
- const result = await installFromSkillHub(parsed, options, spinner$2);
3673
+ const result = await installFromSkillHub(parsed, options, spinner$3);
3527
3674
  skills = result.skills;
3528
3675
  tempDir = result.tempDir;
3529
3676
  } else if (parsed.type === "local") {
3530
- spinner$2.start("正在验证本地路径...");
3677
+ spinner$3.start("正在验证本地路径...");
3531
3678
  if (!existsSync(parsed.localPath)) {
3532
- spinner$2.stop(import_picocolors.default.red("路径未找到"));
3679
+ spinner$3.stop(import_picocolors.default.red("路径未找到"));
3533
3680
  outro(import_picocolors.default.red(`本地路径不存在:${parsed.localPath}`));
3534
3681
  process.exit(1);
3535
3682
  }
3536
- spinner$2.stop("本地路径验证通过");
3537
- spinner$2.start("正在发现技能...");
3683
+ spinner$3.stop("本地路径验证通过");
3684
+ spinner$3.start("正在发现技能...");
3538
3685
  skills = await discoverSkills(parsed.localPath, parsed.subpath, {
3539
3686
  includeInternal,
3540
3687
  fullDepth: options.fullDepth
@@ -3549,7 +3696,7 @@ async function runAdd(args, options = {}) {
3549
3696
  const owner = ownerRepo?.split("/")[0]?.toLowerCase();
3550
3697
  const isSelfHostedRepo = !!ownerRepo && Object.hasOwn(BLOB_ALLOWED_REPOS, ownerRepo.toLowerCase());
3551
3698
  if (ownerRepo && owner && (isSelfHostedRepo || BLOB_ALLOWED_OWNERS.includes(owner))) {
3552
- spinner$2.start("正在获取技能...");
3699
+ spinner$3.start("正在获取技能...");
3553
3700
  blobResult = await tryBlobInstall(ownerRepo, {
3554
3701
  subpath: parsed.subpath,
3555
3702
  skillFilter: parsed.skillFilter,
@@ -3557,36 +3704,36 @@ async function runAdd(args, options = {}) {
3557
3704
  getToken: getGitHubToken,
3558
3705
  includeInternal
3559
3706
  });
3560
- if (!blobResult) spinner$2.stop(import_picocolors.default.dim("Falling back to clone..."));
3707
+ if (!blobResult) spinner$3.stop(import_picocolors.default.dim("Falling back to clone..."));
3561
3708
  }
3562
3709
  if (blobResult) {
3563
3710
  skills = blobResult.skills;
3564
- spinner$2.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
3711
+ spinner$3.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
3565
3712
  } else {
3566
- tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$2);
3567
- spinner$2.stop("仓库克隆完成");
3568
- spinner$2.start("正在发现技能...");
3713
+ tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$3);
3714
+ spinner$3.stop("仓库克隆完成");
3715
+ spinner$3.start("正在发现技能...");
3569
3716
  skills = await discoverSkills(tempDir, parsed.subpath, {
3570
3717
  includeInternal,
3571
3718
  fullDepth: options.fullDepth
3572
3719
  });
3573
3720
  }
3574
3721
  } else {
3575
- tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$2);
3576
- spinner$2.stop("仓库克隆完成");
3577
- spinner$2.start("正在发现技能...");
3722
+ tempDir = await cloneWithGitHubFallback(parsed.url, options.branch || parsed.ref, spinner$3);
3723
+ spinner$3.stop("仓库克隆完成");
3724
+ spinner$3.start("正在发现技能...");
3578
3725
  skills = await discoverSkills(tempDir, parsed.subpath, {
3579
3726
  includeInternal,
3580
3727
  fullDepth: options.fullDepth
3581
3728
  });
3582
3729
  }
3583
3730
  if (skills.length === 0) {
3584
- spinner$2.stop(import_picocolors.default.red("未找到技能"));
3731
+ spinner$3.stop(import_picocolors.default.red("未找到技能"));
3585
3732
  outro(import_picocolors.default.red("未找到有效技能。技能需要包含 name 和 description 的 SKILL.md 文件。"));
3586
3733
  await cleanup(tempDir);
3587
3734
  process.exit(1);
3588
3735
  }
3589
- if (!blobResult) spinner$2.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
3736
+ if (!blobResult) spinner$3.stop(`Found ${import_picocolors.default.green(skills.length)} skill${skills.length > 1 ? "s" : ""}`);
3590
3737
  if (options.list) {
3591
3738
  console.log();
3592
3739
  log.step(import_picocolors.default.bold("可用技能"));
@@ -3700,10 +3847,10 @@ async function runAdd(args, options = {}) {
3700
3847
  }
3701
3848
  targetAgents = options.agent;
3702
3849
  } else {
3703
- spinner$2.start("正在加载 Agent...");
3850
+ spinner$3.start("正在加载 Agent...");
3704
3851
  const installedAgents = await detectInstalledAgents();
3705
3852
  const totalAgents = Object.keys(agents).length;
3706
- spinner$2.stop(`${totalAgents} agents`);
3853
+ spinner$3.stop(`${totalAgents} agents`);
3707
3854
  if (installedAgents.includes("eve") && (options.yes || !agentResult.isAgent)) {
3708
3855
  const useEve = options.yes ? true : await confirm({
3709
3856
  message: formatEveInstallPromptMessage(selectedSkills),
@@ -3786,7 +3933,7 @@ async function runAdd(args, options = {}) {
3786
3933
  eveSubagentTargets = selectedSubagents.map((s) => s === "" ? void 0 : s);
3787
3934
  }
3788
3935
  }
3789
- const installTargets = buildInstallTargets(targetAgents, eveSubagentTargets);
3936
+ const installTargets = buildInstallTargets$1(targetAgents, eveSubagentTargets);
3790
3937
  let installGlobally = options.global ?? false;
3791
3938
  const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
3792
3939
  if (options.global === void 0 && !options.yes && supportsGlobal) {
@@ -3845,7 +3992,7 @@ async function runAdd(args, options = {}) {
3845
3992
  const overwriteStatus = /* @__PURE__ */ new Map();
3846
3993
  for (const { skillName, target, installed } of overwriteChecks) {
3847
3994
  if (!overwriteStatus.has(skillName)) overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
3848
- overwriteStatus.get(skillName).set(targetKey(target), installed);
3995
+ overwriteStatus.get(skillName).set(targetKey$1(target), installed);
3849
3996
  }
3850
3997
  const groupedSummary = {};
3851
3998
  const ungroupedSummary = [];
@@ -3863,10 +4010,10 @@ async function runAdd(args, options = {}) {
3863
4010
  eveSubagent: installTargets[0].subagent
3864
4011
  }) : getCanonicalPath(skill.name, { global: installGlobally }), cwd);
3865
4012
  summaryLines.push(`${import_picocolors.default.cyan(shortCanonical)}`);
3866
- summaryLines.push(...buildTargetSummaryLines(installTargets, installMode));
4013
+ summaryLines.push(...buildTargetSummaryLines$1(installTargets, installMode));
3867
4014
  const skillOverwrites = overwriteStatus.get(skill.name);
3868
- const overwriteAgents = installTargets.filter((t) => skillOverwrites?.get(targetKey(t))).map(targetDisplayName);
3869
- if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$1(overwriteAgents)}`);
4015
+ const overwriteAgents = installTargets.filter((t) => skillOverwrites?.get(targetKey$1(t))).map(targetDisplayName$1);
4016
+ if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("overwrites:")} ${formatList$2(overwriteAgents)}`);
3870
4017
  }
3871
4018
  };
3872
4019
  const sortedGroups = Object.keys(groupedSummary).sort();
@@ -3903,7 +4050,7 @@ async function runAdd(args, options = {}) {
3903
4050
  process.exit(0);
3904
4051
  }
3905
4052
  }
3906
- spinner$2.start("正在安装技能...");
4053
+ spinner$3.start("正在安装技能...");
3907
4054
  const results = [];
3908
4055
  for (const skill of selectedSkills) for (const target of installTargets) {
3909
4056
  const { agent, subagent } = target;
@@ -3935,12 +4082,12 @@ async function runAdd(args, options = {}) {
3935
4082
  });
3936
4083
  results.push({
3937
4084
  skill: getSkillDisplayName(skill),
3938
- agent: targetDisplayName(target),
4085
+ agent: targetDisplayName$1(target),
3939
4086
  pluginName: skill.pluginName,
3940
4087
  ...result
3941
4088
  });
3942
4089
  }
3943
- spinner$2.stop("安装完成");
4090
+ spinner$3.stop("安装完成");
3944
4091
  console.log();
3945
4092
  const successful = results.filter((r) => r.success);
3946
4093
  const failed = results.filter((r) => !r.success);
@@ -4061,7 +4208,7 @@ async function runAdd(args, options = {}) {
4061
4208
  const title = import_picocolors.default.green(`已安装 ${skillCount} 个技能`);
4062
4209
  note(resultLines.join("\n"), title);
4063
4210
  if (symlinkFailures.length > 0) {
4064
- log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$1(copiedAgents)}`));
4211
+ log.warn(import_picocolors.default.yellow(`符号链接失败: ${formatList$2(copiedAgents)}`));
4065
4212
  log.message(import_picocolors.default.dim(" 已改为复制文件。在 Windows 上,请启用开发者模式以支持符号链接。"));
4066
4213
  }
4067
4214
  }
@@ -4190,10 +4337,10 @@ function parseAddOptions(args) {
4190
4337
  errors
4191
4338
  };
4192
4339
  }
4193
- const RESET$11 = "\x1B[0m";
4194
- const BOLD$8 = "\x1B[1m";
4195
- const DIM$11 = "\x1B[38;5;102m";
4196
- const TEXT$8 = "\x1B[38;5;145m";
4340
+ const RESET$13 = "\x1B[0m";
4341
+ const BOLD$10 = "\x1B[1m";
4342
+ const DIM$13 = "\x1B[38;5;102m";
4343
+ const TEXT$10 = "\x1B[38;5;145m";
4197
4344
  const CYAN$2 = "\x1B[36m";
4198
4345
  const SEARCH_API_BASE = process.env.SKILLS_API_URL || "https://skills.sh";
4199
4346
  function formatInstalls$1(count) {
@@ -4282,28 +4429,28 @@ async function runSearchPrompt(initialQuery = "", owner) {
4282
4429
  if (lastRenderedLines > 0) process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));
4283
4430
  process.stdout.write(CLEAR_DOWN);
4284
4431
  const lines = [];
4285
- const cursor = `${BOLD$8}_${RESET$11}`;
4286
- lines.push(`${TEXT$8}搜索技能:${RESET$11} ${query}${cursor}`);
4432
+ const cursor = `${BOLD$10}_${RESET$13}`;
4433
+ lines.push(`${TEXT$10}搜索技能:${RESET$13} ${query}${cursor}`);
4287
4434
  lines.push("");
4288
- if (!query || query.length < 2) lines.push(`${DIM$11}输入关键词搜索(最少 2 个字符)${RESET$11}`);
4289
- else if (results.length === 0 && loading) lines.push(`${DIM$11}搜索中...${RESET$11}`);
4290
- else if (results.length === 0) lines.push(`${DIM$11}未找到技能${RESET$11}`);
4435
+ if (!query || query.length < 2) lines.push(`${DIM$13}输入关键词搜索(最少 2 个字符)${RESET$13}`);
4436
+ else if (results.length === 0 && loading) lines.push(`${DIM$13}搜索中...${RESET$13}`);
4437
+ else if (results.length === 0) lines.push(`${DIM$13}未找到技能${RESET$13}`);
4291
4438
  else {
4292
4439
  const visible = results.slice(0, 8);
4293
4440
  for (let i = 0; i < visible.length; i++) {
4294
4441
  const skill = visible[i];
4295
4442
  const isSelected = i === selectedIndex;
4296
- const arrow = isSelected ? `${BOLD$8}>${RESET$11}` : " ";
4297
- const name = isSelected ? `${BOLD$8}${skill.name}${RESET$11}` : `${TEXT$8}${skill.name}${RESET$11}`;
4298
- const source = skill.source ? ` ${DIM$11}${skill.source}${RESET$11}` : "";
4443
+ const arrow = isSelected ? `${BOLD$10}>${RESET$13}` : " ";
4444
+ const name = isSelected ? `${BOLD$10}${skill.name}${RESET$13}` : `${TEXT$10}${skill.name}${RESET$13}`;
4445
+ const source = skill.source ? ` ${DIM$13}${skill.source}${RESET$13}` : "";
4299
4446
  const installs = formatInstalls$1(skill.installs);
4300
- const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$11}` : "";
4301
- const loadingIndicator = loading && i === 0 ? ` ${DIM$11}...${RESET$11}` : "";
4447
+ const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$13}` : "";
4448
+ const loadingIndicator = loading && i === 0 ? ` ${DIM$13}...${RESET$13}` : "";
4302
4449
  lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);
4303
4450
  }
4304
4451
  }
4305
4452
  lines.push("");
4306
- lines.push(`${DIM$11}上下键导航 | 回车选择 | ESC 取消${RESET$11}`);
4453
+ lines.push(`${DIM$13}上下键导航 | 回车选择 | ESC 取消${RESET$13}`);
4307
4454
  for (const line of lines) process.stdout.write(line + "\n");
4308
4455
  lastRenderedLines = lines.length;
4309
4456
  }
@@ -4400,9 +4547,9 @@ async function runFind(args) {
4400
4547
  const { query, options: findOptions, errors } = parseFindOptions(args);
4401
4548
  const owner = findOptions.owner;
4402
4549
  const isNonInteractive = !process.stdin.isTTY;
4403
- const agentTip = `${DIM$11}Tip: if running in a coding agent, follow these steps:${RESET$11}
4404
- ${DIM$11} 1) npx skills find [query] [--owner <owner>]${RESET$11}
4405
- ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4550
+ const agentTip = `${DIM$13}Tip: if running in a coding agent, follow these steps:${RESET$13}
4551
+ ${DIM$13} 1) npx skills find [query] [--owner <owner>]${RESET$13}
4552
+ ${DIM$13} 2) npx skills add <owner/repo@skill>${RESET$13}`;
4406
4553
  if (errors.length > 0) {
4407
4554
  for (const error of errors) console.error(error);
4408
4555
  console.error("Usage: npx skills find <query> [--owner <owner>]");
@@ -4413,16 +4560,16 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4413
4560
  String(results.length);
4414
4561
  if (results.length === 0) {
4415
4562
  const ownerSuffix = owner ? ` from owner "${owner}"` : "";
4416
- console.log(`${DIM$11}未找到 "${query}" 的技能${ownerSuffix}${RESET$11}`);
4563
+ console.log(`${DIM$13}未找到 "${query}" 的技能${ownerSuffix}${RESET$13}`);
4417
4564
  return;
4418
4565
  }
4419
- console.log(`${DIM$11}安装:${RESET$11} npx skills add <owner/repo@skill>`);
4566
+ console.log(`${DIM$13}安装:${RESET$13} npx skills add <owner/repo@skill>`);
4420
4567
  console.log();
4421
4568
  for (const skill of results.slice(0, 6)) {
4422
4569
  const pkg = skill.source || skill.slug;
4423
4570
  const installs = formatInstalls$1(skill.installs);
4424
- console.log(`${TEXT$8}${pkg}@${skill.name}${RESET$11}${installs ? ` ${CYAN$2}${installs}${RESET$11}` : ""}`);
4425
- console.log(`${DIM$11}└ https://skills.sh/${skill.slug}${RESET$11}`);
4571
+ console.log(`${TEXT$10}${pkg}@${skill.name}${RESET$13}${installs ? ` ${CYAN$2}${installs}${RESET$13}` : ""}`);
4572
+ console.log(`${DIM$13}└ https://skills.sh/${skill.slug}${RESET$13}`);
4426
4573
  console.log();
4427
4574
  }
4428
4575
  return;
@@ -4430,19 +4577,19 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4430
4577
  if (isNonInteractive || await isRunningInAgent()) {
4431
4578
  console.log(agentTip);
4432
4579
  console.log();
4433
- console.log(`${DIM$11}Usage: npx skills find <query> [--owner <owner>]${RESET$11}`);
4580
+ console.log(`${DIM$13}Usage: npx skills find <query> [--owner <owner>]${RESET$13}`);
4434
4581
  return;
4435
4582
  }
4436
4583
  const selected = await runSearchPrompt("", owner);
4437
4584
  if (!selected) {
4438
- console.log(`${DIM$11}搜索已取消${RESET$11}`);
4585
+ console.log(`${DIM$13}搜索已取消${RESET$13}`);
4439
4586
  console.log();
4440
4587
  return;
4441
4588
  }
4442
4589
  const pkg = selected.source || selected.slug;
4443
4590
  const skillName = selected.name;
4444
4591
  console.log();
4445
- console.log(`${TEXT$8}正在从 ${DIM$11}${pkg}${RESET$11} 安装 ${BOLD$8}${skillName}${RESET$11}...`);
4592
+ console.log(`${TEXT$10}正在从 ${DIM$13}${pkg}${RESET$13} 安装 ${BOLD$10}${skillName}${RESET$13}...`);
4446
4593
  console.log();
4447
4594
  const { source, options: addOptions } = parseAddOptions([
4448
4595
  pkg,
@@ -4452,13 +4599,13 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4452
4599
  await runAdd(source, addOptions);
4453
4600
  console.log();
4454
4601
  const info = getOwnerRepoFromString(pkg);
4455
- if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$8}https://skills.sh/${selected.slug}${RESET$11}`);
4456
- else console.log(`${DIM$11}发现更多技能:${RESET$11} ${TEXT$8}https://skills.sh${RESET$11}`);
4602
+ if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$13}查看技能:${RESET$13} ${TEXT$10}https://skills.sh/${selected.slug}${RESET$13}`);
4603
+ else console.log(`${DIM$13}发现更多技能:${RESET$13} ${TEXT$10}https://skills.sh${RESET$13}`);
4457
4604
  console.log();
4458
4605
  }
4459
- const RESET$10 = "\x1B[0m";
4460
- const BOLD$7 = "\x1B[1m";
4461
- const DIM$10 = "\x1B[38;5;102m";
4606
+ const RESET$12 = "\x1B[0m";
4607
+ const BOLD$9 = "\x1B[1m";
4608
+ const DIM$12 = "\x1B[38;5;102m";
4462
4609
  const CYAN$1 = "\x1B[36m";
4463
4610
  const YELLOW$4 = "\x1B[33m";
4464
4611
  function shortenPath(fullPath, cwd) {
@@ -4467,7 +4614,7 @@ function shortenPath(fullPath, cwd) {
4467
4614
  if (fullPath.startsWith(cwd)) return "." + fullPath.slice(cwd.length);
4468
4615
  return fullPath;
4469
4616
  }
4470
- function formatList(items, maxShow = 5) {
4617
+ function formatList$1(items, maxShow = 5) {
4471
4618
  if (items.length <= maxShow) return items.join(", ");
4472
4619
  const shown = items.slice(0, maxShow);
4473
4620
  const remaining = items.length - maxShow;
@@ -4494,8 +4641,8 @@ async function runList(args) {
4494
4641
  const validAgents = Object.keys(agents);
4495
4642
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
4496
4643
  if (invalidAgents.length > 0) {
4497
- console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$10}`);
4498
- console.log(`${DIM$10}Valid agents: ${validAgents.join(", ")}${RESET$10}`);
4644
+ console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$12}`);
4645
+ console.log(`${DIM$12}Valid agents: ${validAgents.join(", ")}${RESET$12}`);
4499
4646
  process.exit(1);
4500
4647
  }
4501
4648
  agentFilter = options.agent;
@@ -4522,21 +4669,21 @@ async function runList(args) {
4522
4669
  console.log("[]");
4523
4670
  return;
4524
4671
  }
4525
- console.log(`${DIM$10}未找到${scopeLabel}技能。${RESET$10}`);
4526
- if (scope) console.log(`${DIM$10}尝试不带 -g 参数列出项目技能${RESET$10}`);
4527
- else console.log(`${DIM$10}尝试带 -g 参数列出全局技能${RESET$10}`);
4672
+ console.log(`${DIM$12}未找到${scopeLabel}技能。${RESET$12}`);
4673
+ if (scope) console.log(`${DIM$12}尝试不带 -g 参数列出项目技能${RESET$12}`);
4674
+ else console.log(`${DIM$12}尝试带 -g 参数列出全局技能${RESET$12}`);
4528
4675
  return;
4529
4676
  }
4530
4677
  function printSkill(skill, indent = false, maxNameLength = 0, maxPathLength = 0) {
4531
4678
  const prefix = indent ? " " : "";
4532
4679
  const shortPath = shortenPath(skill.canonicalPath, cwd);
4533
4680
  const agentNames = skill.agents.map((a) => agents[a].displayName);
4534
- const agentInfo = skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW$4}not linked${RESET$10}`;
4681
+ const agentInfo = skill.agents.length > 0 ? formatList$1(agentNames) : `${YELLOW$4}not linked${RESET$12}`;
4535
4682
  const paddedName = sanitizeMetadata(skill.name).padEnd(maxNameLength);
4536
4683
  const paddedPath = shortPath.padEnd(maxPathLength);
4537
- console.log(`${prefix}${CYAN$1}${paddedName}${RESET$10} ${DIM$10}${paddedPath}${RESET$10} ${DIM$10}Agents:${RESET$10} ${agentInfo}`);
4684
+ console.log(`${prefix}${CYAN$1}${paddedName}${RESET$12} ${DIM$12}${paddedPath}${RESET$12} ${DIM$12}Agents:${RESET$12} ${agentInfo}`);
4538
4685
  }
4539
- console.log(`${BOLD$7}${scopeLabel}技能${RESET$10}`);
4686
+ console.log(`${BOLD$9}${scopeLabel}技能${RESET$12}`);
4540
4687
  console.log();
4541
4688
  const groupedSkills = {};
4542
4689
  const ungroupedSkills = [];
@@ -4552,7 +4699,7 @@ async function runList(args) {
4552
4699
  const sortedGroups = Object.keys(groupedSkills).sort();
4553
4700
  for (const group of sortedGroups) {
4554
4701
  const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4555
- console.log(`${BOLD$7}${title}${RESET$10}`);
4702
+ console.log(`${BOLD$9}${title}${RESET$12}`);
4556
4703
  const skills = groupedSkills[group];
4557
4704
  if (skills) {
4558
4705
  let maxNameLength = 0;
@@ -4568,7 +4715,7 @@ async function runList(args) {
4568
4715
  console.log();
4569
4716
  }
4570
4717
  if (ungroupedSkills.length > 0) {
4571
- console.log(`${BOLD$7}通用${RESET$10}`);
4718
+ console.log(`${BOLD$9}通用${RESET$12}`);
4572
4719
  let maxNameLength = 0;
4573
4720
  let maxPathLength = 0;
4574
4721
  for (const skill of ungroupedSkills) {
@@ -4605,8 +4752,8 @@ async function removeCommand(skillNames, options) {
4605
4752
  }
4606
4753
  const isGlobal = options.global ?? false;
4607
4754
  const cwd = process.cwd();
4608
- const spinner$1 = spinner();
4609
- spinner$1.start("正在扫描已安装的技能...");
4755
+ const spinner$2 = spinner();
4756
+ spinner$2.start("正在扫描已安装的技能...");
4610
4757
  const skillNamesSet = /* @__PURE__ */ new Set();
4611
4758
  const scanDir = async (dir) => {
4612
4759
  try {
@@ -4625,7 +4772,7 @@ async function removeCommand(skillNames, options) {
4625
4772
  for (const subagent of getEveSubagents(cwd)) await scanDir(getEveSubagentSkillsDir(subagent, cwd));
4626
4773
  }
4627
4774
  const installedSkills = Array.from(skillNamesSet).sort();
4628
- spinner$1.stop(`发现 ${installedSkills.length} 个已安装技能`);
4775
+ spinner$2.stop(`发现 ${installedSkills.length} 个已安装技能`);
4629
4776
  if (installedSkills.length === 0) {
4630
4777
  outro(import_picocolors.default.yellow("没有可卸载的技能。"));
4631
4778
  return;
@@ -4667,7 +4814,7 @@ async function removeCommand(skillNames, options) {
4667
4814
  if (options.agent && options.agent.length > 0) targetAgents = options.agent;
4668
4815
  else {
4669
4816
  targetAgents = Object.keys(agents);
4670
- spinner$1.stop(`Targeting ${targetAgents.length} potential agent(s)`);
4817
+ spinner$2.stop(`Targeting ${targetAgents.length} potential agent(s)`);
4671
4818
  }
4672
4819
  if (!options.yes) {
4673
4820
  console.log();
@@ -4680,7 +4827,7 @@ async function removeCommand(skillNames, options) {
4680
4827
  process.exit(0);
4681
4828
  }
4682
4829
  }
4683
- spinner$1.start("正在卸载技能...");
4830
+ spinner$2.start("正在卸载技能...");
4684
4831
  const results = [];
4685
4832
  for (const skillName of selectedSkills) try {
4686
4833
  const canonicalPath = getCanonicalPath(skillName, {
@@ -4742,7 +4889,7 @@ async function removeCommand(skillNames, options) {
4742
4889
  error: err instanceof Error ? err.message : String(err)
4743
4890
  });
4744
4891
  }
4745
- spinner$1.stop("卸载完成");
4892
+ spinner$2.stop("卸载完成");
4746
4893
  const successful = results.filter((r) => r.success);
4747
4894
  const failed = results.filter((r) => !r.success);
4748
4895
  if (successful.length > 0) {
@@ -4842,10 +4989,10 @@ function buildLocalUpdateSource(entry) {
4842
4989
  return appendFolderAndRef(source, entry.skillPath, entry.ref);
4843
4990
  }
4844
4991
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
4845
- const RESET$9 = "\x1B[0m";
4846
- const BOLD$6 = "\x1B[1m";
4847
- const DIM$9 = "\x1B[38;5;102m";
4848
- const TEXT$7 = "\x1B[38;5;145m";
4992
+ const RESET$11 = "\x1B[0m";
4993
+ const BOLD$8 = "\x1B[1m";
4994
+ const DIM$11 = "\x1B[38;5;102m";
4995
+ const TEXT$9 = "\x1B[38;5;145m";
4849
4996
  function parseUpdateOptions(args) {
4850
4997
  const options = {};
4851
4998
  const positional = [];
@@ -4938,7 +5085,7 @@ function getInstallSource(skill) {
4938
5085
  function printSkippedSkills(skipped) {
4939
5086
  if (skipped.length === 0) return;
4940
5087
  console.log();
4941
- console.log(`${DIM$9}${skipped.length} 个技能无法自动检查:${RESET$9}`);
5088
+ console.log(`${DIM$11}${skipped.length} 个技能无法自动检查:${RESET$11}`);
4942
5089
  const grouped = /* @__PURE__ */ new Map();
4943
5090
  for (const skill of skipped) {
4944
5091
  const source = getInstallSource(skill);
@@ -4949,13 +5096,13 @@ function printSkippedSkills(skipped) {
4949
5096
  for (const [source, skills] of grouped) {
4950
5097
  if (skills.length === 1) {
4951
5098
  const skill = skills[0];
4952
- console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)} ${DIM$9}(${skill.reason})${RESET$9}`);
5099
+ console.log(` ${TEXT$9}•${RESET$11} ${sanitizeMetadata(skill.name)} ${DIM$11}(${skill.reason})${RESET$11}`);
4953
5100
  } else {
4954
5101
  const reason = skills[0].reason;
4955
5102
  const names = skills.map((s) => sanitizeMetadata(s.name)).join(", ");
4956
- console.log(` ${TEXT$7}•${RESET$9} ${names} ${DIM$9}(${reason})${RESET$9}`);
5103
+ console.log(` ${TEXT$9}•${RESET$11} ${names} ${DIM$11}(${reason})${RESET$11}`);
4957
5104
  }
4958
- console.log(` ${DIM$9}更新方法:${TEXT$7}npx skills add ${source} -g -y${RESET$9}`);
5105
+ console.log(` ${DIM$11}更新方法:${TEXT$9}npx skills add ${source} -g -y${RESET$11}`);
4959
5106
  }
4960
5107
  }
4961
5108
  async function getProjectSkillsForUpdate(skillFilter) {
@@ -4980,13 +5127,13 @@ async function checkAndPromptForDeletions(source, allLockedForSource, lockSkills
4980
5127
  });
4981
5128
  if (deletedSkills.length > 0) {
4982
5129
  console.log();
4983
- console.log(`${DIM$9}警告:${RESET$9} 以下来自 ${DIM$9}${source}${RESET$9} 的技能似乎已在源仓库中删除:`);
4984
- for (const s of deletedSkills) console.log(` ${DIM$9}•${RESET$9} ${s}`);
4985
- if (options.yes || !process.stdin.isTTY) console.log(`${DIM$9}非交互模式,跳过删除。${RESET$9}`);
5130
+ console.log(`${DIM$11}警告:${RESET$11} 以下来自 ${DIM$11}${source}${RESET$11} 的技能似乎已在源仓库中删除:`);
5131
+ for (const s of deletedSkills) console.log(` ${DIM$11}•${RESET$11} ${s}`);
5132
+ if (options.yes || !process.stdin.isTTY) console.log(`${DIM$11}非交互模式,跳过删除。${RESET$11}`);
4986
5133
  else {
4987
5134
  const confirmed = await confirm({ message: `是否删除这些已删除技能的本地副本?` });
4988
5135
  if (confirmed && !isCancel(confirmed)) for (const s of deletedSkills) {
4989
- console.log(`${DIM$9}正在卸载${RESET$9} ${s}...`);
5136
+ console.log(`${DIM$11}正在卸载${RESET$11} ${s}...`);
4990
5137
  await removeCommand([s], {
4991
5138
  yes: true,
4992
5139
  global: isGlobal
@@ -5003,8 +5150,8 @@ async function updateGlobalSkills(options = {}) {
5003
5150
  let failCount = 0;
5004
5151
  if (skillNames.length === 0) {
5005
5152
  if (!options.skills) {
5006
- console.log(`${DIM$9}锁文件中没有跟踪的全局技能。${RESET$9}`);
5007
- console.log(`${DIM$9}安装技能:${RESET$9} ${TEXT$7}npx skills add <package> -g${RESET$9}`);
5153
+ console.log(`${DIM$11}锁文件中没有跟踪的全局技能。${RESET$11}`);
5154
+ console.log(`${DIM$11}安装技能:${RESET$11} ${TEXT$9}npx skills add <package> -g${RESET$11}`);
5008
5155
  }
5009
5156
  return {
5010
5157
  successCount,
@@ -5045,7 +5192,7 @@ async function updateGlobalSkills(options = {}) {
5045
5192
  const firstEntry = itemsForSource[0].entry;
5046
5193
  const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
5047
5194
  let tempDir = null;
5048
- process.stdout.write(`\r${DIM$9}Checking skills from source: ${source}${RESET$9}\x1b[K\n`);
5195
+ process.stdout.write(`\r${DIM$11}Checking skills from source: ${source}${RESET$11}\x1b[K\n`);
5049
5196
  if (firstEntry.sourceType === "skillhub") {
5050
5197
  const skillhubRef = source.replace(/^skillhub:/, "");
5051
5198
  const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
@@ -5055,7 +5202,7 @@ async function updateGlobalSkills(options = {}) {
5055
5202
  new SkillHubAPI(cfg.registry, cfg.token);
5056
5203
  for (const item of itemsForSource) {
5057
5204
  const safeName = sanitizeMetadata(item.name);
5058
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5205
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5059
5206
  try {
5060
5207
  const parts = skillhubRef.split("/");
5061
5208
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5066,7 +5213,7 @@ async function updateGlobalSkills(options = {}) {
5066
5213
  });
5067
5214
  successCount++;
5068
5215
  } catch (error) {
5069
- console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5216
+ console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5070
5217
  failCount++;
5071
5218
  }
5072
5219
  }
@@ -5076,7 +5223,7 @@ async function updateGlobalSkills(options = {}) {
5076
5223
  if (firstEntry.sourceType === "github") {
5077
5224
  const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
5078
5225
  if (!tree) {
5079
- console.log(` ${DIM$9}✗ Failed to fetch tree for ${source}${RESET$9}`);
5226
+ console.log(` ${DIM$11}✗ Failed to fetch tree for ${source}${RESET$11}`);
5080
5227
  continue;
5081
5228
  }
5082
5229
  const discoveredPaths = findSkillMdPaths(tree);
@@ -5111,7 +5258,7 @@ async function updateGlobalSkills(options = {}) {
5111
5258
  });
5112
5259
  }
5113
5260
  } catch (error) {
5114
- console.log(` ${DIM$9}✗ Failed to check skills from ${source}${RESET$9}`);
5261
+ console.log(` ${DIM$11}✗ Failed to check skills from ${source}${RESET$11}`);
5115
5262
  } finally {
5116
5263
  if (tempDir) await cleanupTempDir(tempDir);
5117
5264
  }
@@ -5119,7 +5266,7 @@ async function updateGlobalSkills(options = {}) {
5119
5266
  if (checkable.length > 0) process.stdout.write("\r\x1B[K");
5120
5267
  const checkedCount = checkable.length + skipped.length;
5121
5268
  if (checkable.length === 0 && skipped.length === 0) {
5122
- if (!options.skills) console.log(`${DIM$9}没有可检查的全局技能。${RESET$9}`);
5269
+ if (!options.skills) console.log(`${DIM$11}没有可检查的全局技能。${RESET$11}`);
5123
5270
  return {
5124
5271
  successCount,
5125
5272
  failCount,
@@ -5135,28 +5282,28 @@ async function updateGlobalSkills(options = {}) {
5135
5282
  };
5136
5283
  }
5137
5284
  if (updates.length === 0) {
5138
- console.log(`${TEXT$7}✓ 所有全局技能已是最新${RESET$9}`);
5285
+ console.log(`${TEXT$9}✓ 所有全局技能已是最新${RESET$11}`);
5139
5286
  return {
5140
5287
  successCount,
5141
5288
  failCount,
5142
5289
  checkedCount
5143
5290
  };
5144
5291
  }
5145
- console.log(`${TEXT$7}发现 ${updates.length} 个可更新全局技能${RESET$9}`);
5292
+ console.log(`${TEXT$9}发现 ${updates.length} 个可更新全局技能${RESET$11}`);
5146
5293
  console.log();
5147
5294
  for (const update of updates) {
5148
5295
  const safeName = sanitizeMetadata(update.name);
5149
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5296
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5150
5297
  const installUrl = buildUpdateInstallSource(update.entry);
5151
5298
  if (!installUrl) {
5152
5299
  failCount++;
5153
- console.log(` ${DIM$9}✗ Cannot update ${safeName}: lock file is missing sourceUrl for this generic Git source${RESET$9}`);
5300
+ console.log(` ${DIM$11}✗ Cannot update ${safeName}: lock file is missing sourceUrl for this generic Git source${RESET$11}`);
5154
5301
  continue;
5155
5302
  }
5156
5303
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5157
5304
  if (!existsSync(cliEntry)) {
5158
5305
  failCount++;
5159
- console.log(` ${DIM$9}✗ Failed to update ${safeName}: CLI entrypoint not found at ${cliEntry}${RESET$9}`);
5306
+ console.log(` ${DIM$11}✗ Failed to update ${safeName}: CLI entrypoint not found at ${cliEntry}${RESET$11}`);
5160
5307
  continue;
5161
5308
  }
5162
5309
  if (spawnSync(process.execPath, [
@@ -5175,10 +5322,10 @@ async function updateGlobalSkills(options = {}) {
5175
5322
  shell: false
5176
5323
  }).status === 0) {
5177
5324
  successCount++;
5178
- console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5325
+ console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5179
5326
  } else {
5180
5327
  failCount++;
5181
- console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5328
+ console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5182
5329
  }
5183
5330
  }
5184
5331
  printSkippedSkills(skipped);
@@ -5194,8 +5341,8 @@ async function updateProjectSkills(options = {}) {
5194
5341
  let failCount = 0;
5195
5342
  if (projectSkills.length === 0) {
5196
5343
  if (!options.skills) {
5197
- console.log(`${DIM$9}没有可更新的项目技能。${RESET$9}`);
5198
- console.log(`${DIM$9}Install project skills with${RESET$9} ${TEXT$7}npx skills add <package>${RESET$9}`);
5344
+ console.log(`${DIM$11}没有可更新的项目技能。${RESET$11}`);
5345
+ console.log(`${DIM$11}Install project skills with${RESET$11} ${TEXT$9}npx skills add <package>${RESET$11}`);
5199
5346
  }
5200
5347
  return {
5201
5348
  successCount,
@@ -5206,7 +5353,7 @@ async function updateProjectSkills(options = {}) {
5206
5353
  const updatable = projectSkills.filter((s) => s.entry.skillPath);
5207
5354
  const legacy = projectSkills.filter((s) => !s.entry.skillPath);
5208
5355
  if (updatable.length === 0) {
5209
- console.log(`${DIM$9}No project skills can be updated in place.${RESET$9}`);
5356
+ console.log(`${DIM$11}No project skills can be updated in place.${RESET$11}`);
5210
5357
  printLegacyProjectSkills(legacy);
5211
5358
  return {
5212
5359
  successCount,
@@ -5226,8 +5373,8 @@ async function updateProjectSkills(options = {}) {
5226
5373
  const targetParts = [];
5227
5374
  if (hasUniversal) targetParts.push("Universal");
5228
5375
  targetParts.push(...targetAgentNames);
5229
- if (targetParts.length > 0) console.log(`${TEXT$7}更新目标:${targetParts.join(", ")}${RESET$9}`);
5230
- console.log(`${TEXT$7}正在刷新 ${updatable.length} 个技能...${RESET$9}`);
5376
+ if (targetParts.length > 0) console.log(`${TEXT$9}更新目标:${targetParts.join(", ")}${RESET$11}`);
5377
+ console.log(`${TEXT$9}正在刷新 ${updatable.length} 个技能...${RESET$11}`);
5231
5378
  console.log();
5232
5379
  const bySource = /* @__PURE__ */ new Map();
5233
5380
  for (const skill of updatable) {
@@ -5239,7 +5386,7 @@ async function updateProjectSkills(options = {}) {
5239
5386
  const localLock = await readLocalLock();
5240
5387
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5241
5388
  if (!existsSync(cliEntry)) {
5242
- console.log(`${DIM$9}✗ CLI 入口未找到 ${cliEntry}${RESET$9}`);
5389
+ console.log(`${DIM$11}✗ CLI 入口未找到 ${cliEntry}${RESET$11}`);
5243
5390
  return {
5244
5391
  successCount,
5245
5392
  failCount: updatable.length,
@@ -5259,7 +5406,7 @@ async function updateProjectSkills(options = {}) {
5259
5406
  new SkillHubAPI(cfg.registry, cfg.token);
5260
5407
  for (const item of skillsForSource) {
5261
5408
  const safeName = sanitizeMetadata(item.name);
5262
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5409
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5263
5410
  try {
5264
5411
  const parts = skillhubRef.split("/");
5265
5412
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5270,7 +5417,7 @@ async function updateProjectSkills(options = {}) {
5270
5417
  });
5271
5418
  successCount++;
5272
5419
  } catch (error) {
5273
- console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5420
+ console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5274
5421
  failCount++;
5275
5422
  }
5276
5423
  }
@@ -5281,7 +5428,7 @@ async function updateProjectSkills(options = {}) {
5281
5428
  let deletedSkills = [];
5282
5429
  if (buildLocalUpdateSource(firstEntry) === null) {
5283
5430
  failCount += skillsForSource.length;
5284
- console.log(`${DIM$9}✗ Cannot update ${source}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$9}`);
5431
+ console.log(`${DIM$11}✗ Cannot update ${source}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$11}`);
5285
5432
  continue;
5286
5433
  }
5287
5434
  try {
@@ -5291,18 +5438,18 @@ async function updateProjectSkills(options = {}) {
5291
5438
  });
5292
5439
  deletedSkills = await checkAndPromptForDeletions(source, allLockedForSource, localLock.skills, false, options, discoveredPaths);
5293
5440
  } catch (error) {
5294
- console.log(`${DIM$9}✗ 检查 ${source} 已删除技能失败${RESET$9}`);
5441
+ console.log(`${DIM$11}✗ 检查 ${source} 已删除技能失败${RESET$11}`);
5295
5442
  } finally {
5296
5443
  if (tempDir) await cleanupTempDir(tempDir);
5297
5444
  }
5298
5445
  const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
5299
5446
  for (const skill of remainingSkills) {
5300
5447
  const safeName = sanitizeMetadata(skill.name);
5301
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5448
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5302
5449
  const installUrl = buildLocalUpdateSource(skill.entry);
5303
5450
  if (!installUrl) {
5304
5451
  failCount++;
5305
- console.log(` ${DIM$9}✗ Cannot update ${safeName}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$9}`);
5452
+ console.log(` ${DIM$11}✗ Cannot update ${safeName}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$11}`);
5306
5453
  continue;
5307
5454
  }
5308
5455
  const subagentArgs = skill.entry.subagents?.length ? ["--subagent", ...skill.entry.subagents.map((s) => s === "" ? "root" : s)] : [];
@@ -5324,10 +5471,10 @@ async function updateProjectSkills(options = {}) {
5324
5471
  shell: false
5325
5472
  }).status === 0) {
5326
5473
  successCount++;
5327
- console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5474
+ console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5328
5475
  } else {
5329
5476
  failCount++;
5330
- console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5477
+ console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5331
5478
  }
5332
5479
  }
5333
5480
  }
@@ -5341,25 +5488,25 @@ async function updateProjectSkills(options = {}) {
5341
5488
  function printLegacyProjectSkills(legacy) {
5342
5489
  if (legacy.length === 0) return;
5343
5490
  console.log();
5344
- console.log(`${DIM$9}${legacy.length} project skill(s) cannot be updated automatically (installed before skillPath tracking):${RESET$9}`);
5491
+ console.log(`${DIM$11}${legacy.length} project skill(s) cannot be updated automatically (installed before skillPath tracking):${RESET$11}`);
5345
5492
  for (const skill of legacy) {
5346
5493
  const reinstall = buildLocalUpdateSource(skill.entry);
5347
- console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)}`);
5348
- if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$7}npx skills add ${reinstall} -y${RESET$9}`);
5349
- else console.log(` ${DIM$9}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$9}`);
5494
+ console.log(` ${TEXT$9}•${RESET$11} ${sanitizeMetadata(skill.name)}`);
5495
+ if (reinstall) console.log(` ${DIM$11}刷新方法:${TEXT$9}npx skills add ${reinstall} -y${RESET$11}`);
5496
+ else console.log(` ${DIM$11}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$11}`);
5350
5497
  }
5351
5498
  }
5352
5499
  async function runUpdate(args = []) {
5353
5500
  const options = parseUpdateOptions(args);
5354
5501
  const scope = await resolveUpdateScope(options);
5355
- if (options.skills) console.log(`${TEXT$7}正在更新 ${options.skills.join(", ")}...${RESET$9}`);
5356
- else console.log(`${TEXT$7}正在检查技能更新...${RESET$9}`);
5502
+ if (options.skills) console.log(`${TEXT$9}正在更新 ${options.skills.join(", ")}...${RESET$11}`);
5503
+ else console.log(`${TEXT$9}正在检查技能更新...${RESET$11}`);
5357
5504
  console.log();
5358
5505
  let totalSuccess = 0;
5359
5506
  let totalFail = 0;
5360
5507
  let totalFound = 0;
5361
5508
  if (scope === "global" || scope === "both") {
5362
- if (scope === "both" && !options.skills) console.log(`${BOLD$6}全局技能${RESET$9}`);
5509
+ if (scope === "both" && !options.skills) console.log(`${BOLD$8}全局技能${RESET$11}`);
5363
5510
  const { successCount, failCount, checkedCount } = await updateGlobalSkills(options);
5364
5511
  totalSuccess += successCount;
5365
5512
  totalFail += failCount;
@@ -5367,17 +5514,17 @@ async function runUpdate(args = []) {
5367
5514
  if (scope === "both" && !options.skills) console.log();
5368
5515
  }
5369
5516
  if (scope === "project" || scope === "both") {
5370
- if (scope === "both" && !options.skills) console.log(`${BOLD$6}项目技能${RESET$9}`);
5517
+ if (scope === "both" && !options.skills) console.log(`${BOLD$8}项目技能${RESET$11}`);
5371
5518
  const { successCount, failCount, foundCount } = await updateProjectSkills(options);
5372
5519
  totalSuccess += successCount;
5373
5520
  totalFail += failCount;
5374
5521
  totalFound += foundCount;
5375
5522
  }
5376
- if (options.skills && totalFound === 0) console.log(`${DIM$9}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$9}`);
5523
+ if (options.skills && totalFound === 0) console.log(`${DIM$11}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$11}`);
5377
5524
  console.log();
5378
- if (totalSuccess > 0) console.log(`${TEXT$7}✓ 已更新 ${totalSuccess} 个技能${RESET$9}`);
5525
+ if (totalSuccess > 0) console.log(`${TEXT$9}✓ 已更新 ${totalSuccess} 个技能${RESET$11}`);
5379
5526
  if (totalFail > 0) {
5380
- console.log(`${DIM$9}更新失败 ${totalFail} 个技能${RESET$9}`);
5527
+ console.log(`${DIM$11}更新失败 ${totalFail} 个技能${RESET$11}`);
5381
5528
  process.exitCode = 1;
5382
5529
  }
5383
5530
  String(totalSuccess + totalFail);
@@ -5829,10 +5976,10 @@ function getOptionValue$3(args, flag) {
5829
5976
  const idx = args.indexOf(flag);
5830
5977
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
5831
5978
  }
5832
- const RESET$8 = "\x1B[0m";
5833
- const BOLD$5 = "\x1B[1m";
5834
- const DIM$8 = "\x1B[38;5;102m";
5835
- const TEXT$6 = "\x1B[38;5;145m";
5979
+ const RESET$10 = "\x1B[0m";
5980
+ const BOLD$7 = "\x1B[1m";
5981
+ const DIM$10 = "\x1B[38;5;102m";
5982
+ const TEXT$8 = "\x1B[38;5;145m";
5836
5983
  const CYAN = "\x1B[36m";
5837
5984
  const MARKETPLACE_API = process.env.SKILLS_API_URL || "https://skills.sh";
5838
5985
  async function runSearch(args, globalOpts) {
@@ -5840,13 +5987,13 @@ async function runSearch(args, globalOpts) {
5840
5987
  const namespace = args.includes("--namespace") ? getOptionValue$2(args, "--namespace") : void 0;
5841
5988
  const json = args.includes("--json");
5842
5989
  if (!query || query.trim() === "") {
5843
- console.log(`${BOLD$5}bfi skills search <关键词> [选项]${RESET$8}`);
5990
+ console.log(`${BOLD$7}bfi skills search <关键词> [选项]${RESET$10}`);
5844
5991
  console.log();
5845
- console.log(`${DIM$8}常用命令:${RESET$8}`);
5846
- console.log(` bfi skills search react ${DIM$8}搜索 SkillHub${RESET$8}`);
5847
- console.log(` bfi skills search react --marketplace ${DIM$8}搜索 skills.sh${RESET$8}`);
5848
- console.log(` bfi skills search react --all ${DIM$8}搜索全部${RESET$8}`);
5849
- console.log(` bfi skills search react --json ${DIM$8}JSON 输出${RESET$8}`);
5992
+ console.log(`${DIM$10}常用命令:${RESET$10}`);
5993
+ console.log(` bfi skills search react ${DIM$10}搜索 SkillHub${RESET$10}`);
5994
+ console.log(` bfi skills search react --marketplace ${DIM$10}搜索 skills.sh${RESET$10}`);
5995
+ console.log(` bfi skills search react --all ${DIM$10}搜索全部${RESET$10}`);
5996
+ console.log(` bfi skills search react --json ${DIM$10}JSON 输出${RESET$10}`);
5850
5997
  return;
5851
5998
  }
5852
5999
  const useMarketplace = args.includes("--marketplace");
@@ -5856,9 +6003,9 @@ async function runSearch(args, globalOpts) {
5856
6003
  return;
5857
6004
  }
5858
6005
  if (searchAll) {
5859
- console.log(`${BOLD$5}=== SkillHub 注册表 ===${RESET$8}\n`);
6006
+ console.log(`${BOLD$7}=== SkillHub 注册表 ===${RESET$10}\n`);
5860
6007
  await searchSkillHub(query, namespace, globalOpts, json);
5861
- console.log(`\n${BOLD$5}=== skills.sh 市场 ===${RESET$8}\n`);
6008
+ console.log(`\n${BOLD$7}=== skills.sh 市场 ===${RESET$10}\n`);
5862
6009
  await searchMarketplace(query, json);
5863
6010
  return;
5864
6011
  }
@@ -5893,7 +6040,7 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
5893
6040
  count: 0,
5894
6041
  results: []
5895
6042
  }, null, 2));
5896
- else console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
6043
+ else console.log(`${DIM$10}SkillHub 上未找到 "${query}" 的技能${RESET$10}`);
5897
6044
  return;
5898
6045
  }
5899
6046
  if (json) {
@@ -5920,15 +6067,15 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
5920
6067
  const desc = skill.summary || skill.description || "";
5921
6068
  const canonicalSlug = skill.slug || "";
5922
6069
  const displaySlug = canonicalSlug.indexOf("--") > 0 ? canonicalSlug : `global--${canonicalSlug}`;
5923
- console.log(` ${BOLD$5}${name}${RESET$8}`);
5924
- if (desc) console.log(` ${DIM$8}${truncate$2(desc, 100)}${RESET$8}`);
5925
- console.log(` ${TEXT$6}slug: ${displaySlug}${RESET$8}`);
5926
- if (skill.version) console.log(` ${DIM$8}version: ${skill.version}${RESET$8}`);
5927
- console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add ${displaySlug}${RESET$8}`);
6070
+ console.log(` ${BOLD$7}${name}${RESET$10}`);
6071
+ if (desc) console.log(` ${DIM$10}${truncate$2(desc, 100)}${RESET$10}`);
6072
+ console.log(` ${TEXT$8}slug: ${displaySlug}${RESET$10}`);
6073
+ if (skill.version) console.log(` ${DIM$10}version: ${skill.version}${RESET$10}`);
6074
+ console.log(` ${DIM$10}安装:${TEXT$8}bfi skills add ${displaySlug}${RESET$10}`);
5928
6075
  console.log();
5929
6076
  }
5930
6077
  } catch (error) {
5931
- console.error(`${DIM$8}SkillHub 搜索失败:${error.message}${RESET$8}`);
6078
+ console.error(`${DIM$10}SkillHub 搜索失败:${error.message}${RESET$10}`);
5932
6079
  }
5933
6080
  }
5934
6081
  async function searchMarketplace(query, json = false) {
@@ -5945,7 +6092,7 @@ async function searchMarketplace(query, json = false) {
5945
6092
  count: 0,
5946
6093
  results: []
5947
6094
  }, null, 2));
5948
- else console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
6095
+ else console.log(`${DIM$10}skills.sh 市场无结果${RESET$10}`);
5949
6096
  return;
5950
6097
  }
5951
6098
  const skills = (await res.json()).skills || [];
@@ -5955,7 +6102,7 @@ async function searchMarketplace(query, json = false) {
5955
6102
  count: 0,
5956
6103
  results: []
5957
6104
  }, null, 2));
5958
- else console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
6105
+ else console.log(`${DIM$10}skills.sh 上未找到 "${query}" 的技能${RESET$10}`);
5959
6106
  return;
5960
6107
  }
5961
6108
  if (json) {
@@ -5976,15 +6123,15 @@ async function searchMarketplace(query, json = false) {
5976
6123
  console.log(`skills.sh 上找到 ${skills.length} 个技能:\n`);
5977
6124
  for (const skill of skills.slice(0, 12)) {
5978
6125
  const installs = formatInstalls(skill.installs);
5979
- console.log(` ${BOLD$5}${skill.name}${RESET$8}`);
5980
- if (skill.source) console.log(` ${DIM$8}来源:${skill.source}${RESET$8}`);
5981
- if (installs) console.log(` ${CYAN}${installs}${RESET$8}`);
5982
- console.log(` ${TEXT$6}https://skills.sh/${skill.id}${RESET$8}`);
5983
- if (skill.source) console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add github:${skill.source}${RESET$8}`);
6126
+ console.log(` ${BOLD$7}${skill.name}${RESET$10}`);
6127
+ if (skill.source) console.log(` ${DIM$10}来源:${skill.source}${RESET$10}`);
6128
+ if (installs) console.log(` ${CYAN}${installs}${RESET$10}`);
6129
+ console.log(` ${TEXT$8}https://skills.sh/${skill.id}${RESET$10}`);
6130
+ if (skill.source) console.log(` ${DIM$10}安装:${TEXT$8}bfi skills add github:${skill.source}${RESET$10}`);
5984
6131
  console.log();
5985
6132
  }
5986
6133
  } catch {
5987
- console.log(`${DIM$8}skills.sh 市场不可用${RESET$8}`);
6134
+ console.log(`${DIM$10}skills.sh 市场不可用${RESET$10}`);
5988
6135
  }
5989
6136
  }
5990
6137
  function formatInstalls(count) {
@@ -6001,13 +6148,13 @@ function getOptionValue$2(args, flag) {
6001
6148
  const idx = args.indexOf(flag);
6002
6149
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
6003
6150
  }
6004
- const RESET$7 = "\x1B[0m";
6005
- const BOLD$4 = "\x1B[1m";
6006
- const DIM$7 = "\x1B[38;5;102m";
6007
- const TEXT$5 = "\x1B[38;5;145m";
6151
+ const RESET$9 = "\x1B[0m";
6152
+ const BOLD$6 = "\x1B[1m";
6153
+ const DIM$9 = "\x1B[38;5;102m";
6154
+ const TEXT$7 = "\x1B[38;5;145m";
6008
6155
  const YELLOW$3 = "\x1B[33m";
6009
- const RED$3 = "\x1B[31m";
6010
- const GREEN$4 = "\x1B[32m";
6156
+ const RED$5 = "\x1B[31m";
6157
+ const GREEN$6 = "\x1B[32m";
6011
6158
  async function runInfo(args, globalOpts) {
6012
6159
  const ref = args[0];
6013
6160
  if (!ref) {
@@ -6023,35 +6170,35 @@ async function runInfo(args, globalOpts) {
6023
6170
  const result = await api.getSkill(canonical);
6024
6171
  const skill = result.data || result.skill || result;
6025
6172
  if (!skill || !skill.slug) {
6026
- console.log(`${DIM$7}未找到技能:${ref}${RESET$7}`);
6173
+ console.log(`${DIM$9}未找到技能:${ref}${RESET$9}`);
6027
6174
  process.exit(1);
6028
6175
  }
6029
6176
  console.log();
6030
- console.log(`${BOLD$4}${skill.displayName || skill.name || skill.slug}${RESET$7}`);
6031
- console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6032
- console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$5}${skill.slug}${RESET$7}`);
6033
- if (skill.summary || skill.description) console.log(` ${BOLD$4}描述:${RESET$7} ${TEXT$5}${skill.summary || skill.description}${RESET$7}`);
6177
+ console.log(`${BOLD$6}${skill.displayName || skill.name || skill.slug}${RESET$9}`);
6178
+ console.log(`${DIM$9}${"─".repeat(48)}${RESET$9}`);
6179
+ console.log(` ${BOLD$6}Slug:${RESET$9} ${TEXT$7}${skill.slug}${RESET$9}`);
6180
+ if (skill.summary || skill.description) console.log(` ${BOLD$6}描述:${RESET$9} ${TEXT$7}${skill.summary || skill.description}${RESET$9}`);
6034
6181
  const owner = skill.owner;
6035
6182
  if (owner) {
6036
- console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$5}${owner.displayName || owner.handle}${RESET$7}`);
6037
- if (owner.handle) console.log(` ${BOLD$4}句柄:${RESET$7} ${TEXT$5}${owner.handle}${RESET$7}`);
6183
+ console.log(` ${BOLD$6}所有者:${RESET$9} ${TEXT$7}${owner.displayName || owner.handle}${RESET$9}`);
6184
+ if (owner.handle) console.log(` ${BOLD$6}句柄:${RESET$9} ${TEXT$7}${owner.handle}${RESET$9}`);
6038
6185
  }
6039
6186
  const latestVersion = skill.latestVersion;
6040
6187
  if (latestVersion) {
6041
- console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$5}${latestVersion.version || "N/A"}${RESET$7}`);
6042
- if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$5}${latestVersion.license}${RESET$7}`);
6043
- if (latestVersion.changelog) console.log(` ${BOLD$4}变更日志:${RESET$7} ${DIM$7}${truncate$1(latestVersion.changelog, 80)}${RESET$7}`);
6188
+ console.log(` ${BOLD$6}版本:${RESET$9} ${TEXT$7}${latestVersion.version || "N/A"}${RESET$9}`);
6189
+ if (latestVersion.license) console.log(` ${BOLD$6}许可证:${RESET$9} ${TEXT$7}${latestVersion.license}${RESET$9}`);
6190
+ if (latestVersion.changelog) console.log(` ${BOLD$6}变更日志:${RESET$9} ${DIM$9}${truncate$1(latestVersion.changelog, 80)}${RESET$9}`);
6044
6191
  if (latestVersion.createdAt) {
6045
6192
  const date = new Date(latestVersion.createdAt).toISOString().split("T")[0];
6046
- console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$5}${date}${RESET$7}`);
6193
+ console.log(` ${BOLD$6}发布时间:${RESET$9} ${TEXT$7}${date}${RESET$9}`);
6047
6194
  }
6048
6195
  }
6049
6196
  const stats = skill.stats;
6050
6197
  if (stats) {
6051
6198
  console.log();
6052
- console.log(` ${BOLD$4}统计:${RESET$7}`);
6053
- if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$5}${stats.downloads}${RESET$7}`);
6054
- if (stats.views !== void 0) console.log(` 浏览量:${TEXT$5}${stats.views}${RESET$7}`);
6199
+ console.log(` ${BOLD$6}统计:${RESET$9}`);
6200
+ if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$7}${stats.downloads}${RESET$9}`);
6201
+ if (stats.views !== void 0) console.log(` 浏览量:${TEXT$7}${stats.views}${RESET$9}`);
6055
6202
  }
6056
6203
  const tags = skill.tags;
6057
6204
  if (Array.isArray(tags) && tags.length > 0) {
@@ -6059,28 +6206,28 @@ async function runInfo(args, globalOpts) {
6059
6206
  const tag = t;
6060
6207
  return tag.name || tag;
6061
6208
  }).join(", ");
6062
- console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$5}${tagList}${RESET$7}`);
6209
+ console.log(` ${BOLD$6}标签:${RESET$9} ${TEXT$7}${tagList}${RESET$9}`);
6063
6210
  }
6064
6211
  const moderation = skill.moderation;
6065
6212
  if (moderation) {
6066
6213
  const verdict = moderation.verdict;
6067
6214
  if (verdict === "MALWARE_BLOCKED" || moderation.isMalwareBlocked) {
6068
6215
  console.log();
6069
- console.log(` ${RED$3}${BOLD$4}⚠ 已封禁:检测到恶意软件${RESET$7}`);
6070
- if (moderation.summary) console.log(` ${RED$3}${moderation.summary}${RESET$7}`);
6216
+ console.log(` ${RED$5}${BOLD$6}⚠ 已封禁:检测到恶意软件${RESET$9}`);
6217
+ if (moderation.summary) console.log(` ${RED$5}${moderation.summary}${RESET$9}`);
6071
6218
  } else if (verdict === "SUSPICIOUS" || moderation.isSuspicious) {
6072
6219
  console.log();
6073
- console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$7}`);
6074
- if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$7}`);
6075
- } else if (verdict === "SAFE") console.log(` ${BOLD$4}安全:${RESET$7} ${GREEN$4}已验证安全${RESET$7}`);
6220
+ console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$9}`);
6221
+ if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$9}`);
6222
+ } else if (verdict === "SAFE") console.log(` ${BOLD$6}安全:${RESET$9} ${GREEN$6}已验证安全${RESET$9}`);
6076
6223
  }
6077
6224
  if (skill.createdAt) {
6078
6225
  const created = new Date(skill.createdAt).toISOString().split("T")[0];
6079
- console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$5}${created}${RESET$7}`);
6226
+ console.log(` ${BOLD$6}创建时间:${RESET$9} ${TEXT$7}${created}${RESET$9}`);
6080
6227
  }
6081
6228
  if (skill.updatedAt) {
6082
6229
  const updated = new Date(skill.updatedAt).toISOString().split("T")[0];
6083
- console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$5}${updated}${RESET$7}`);
6230
+ console.log(` ${BOLD$6}更新时间:${RESET$9} ${TEXT$7}${updated}${RESET$9}`);
6084
6231
  }
6085
6232
  console.log();
6086
6233
  } catch (error) {
@@ -6093,8 +6240,8 @@ function truncate$1(text, maxLen) {
6093
6240
  if (text.length <= maxLen) return text;
6094
6241
  return text.slice(0, maxLen) + "...";
6095
6242
  }
6096
- const DIM$6 = "\x1B[38;5;102m";
6097
- const RESET$6 = "\x1B[0m";
6243
+ const DIM$8 = "\x1B[38;5;102m";
6244
+ const RESET$8 = "\x1B[0m";
6098
6245
  async function runConfig(args, globalOpts) {
6099
6246
  switch (args[0]) {
6100
6247
  case "get":
@@ -6189,12 +6336,12 @@ async function handleSet(args, _globalOpts) {
6189
6336
  }
6190
6337
  const isGlobal = args.includes("--global");
6191
6338
  setConfigValue(key, value, isGlobal);
6192
- console.log(`${DIM$6}✓${RESET$6} 已设置 ${key} = ${value}(${(isGlobal ? "global" : "project") === "global" ? "全局" : "项目"})`);
6339
+ console.log(`${DIM$8}✓${RESET$8} 已设置 ${key} = ${value}(${(isGlobal ? "global" : "project") === "global" ? "全局" : "项目"})`);
6193
6340
  }
6194
- const RESET$5 = "\x1B[0m";
6195
- const BOLD$3 = "\x1B[1m";
6196
- const DIM$5 = "\x1B[38;5;102m";
6197
- const TEXT$4 = "\x1B[38;5;145m";
6341
+ const RESET$7 = "\x1B[0m";
6342
+ const BOLD$5 = "\x1B[1m";
6343
+ const DIM$7 = "\x1B[38;5;102m";
6344
+ const TEXT$6 = "\x1B[38;5;145m";
6198
6345
  function formatFileSize(bytes) {
6199
6346
  if (bytes < 1024) return `${bytes} B`;
6200
6347
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -6221,9 +6368,9 @@ function printDocsHelp() {
6221
6368
  console.log(" bfi docs info <id> 查看文档处理状态");
6222
6369
  console.log();
6223
6370
  console.log("示例:");
6224
- console.log(` ${DIM$5}$ ${RESET$5}bfi docs upload resume.pdf`);
6225
- console.log(` ${DIM$5}$ ${RESET$5}bfi docs list`);
6226
- console.log(` ${DIM$5}$ ${RESET$5}bfi docs info 42`);
6371
+ console.log(` ${DIM$7}$ ${RESET$7}bfi docs upload resume.pdf`);
6372
+ console.log(` ${DIM$7}$ ${RESET$7}bfi docs list`);
6373
+ console.log(` ${DIM$7}$ ${RESET$7}bfi docs info 42`);
6227
6374
  }
6228
6375
  async function handleUpload(args, globalOpts) {
6229
6376
  const filePath = args[0];
@@ -6246,18 +6393,18 @@ async function handleUpload(args, globalOpts) {
6246
6393
  const api = new SkillHubAPI(registry, token);
6247
6394
  const fileName = path$1.basename(resolvedPath);
6248
6395
  const fileSizeStr = formatFileSize(stats.size);
6249
- console.log(`${DIM$5}正在上传 ${fileName} (${fileSizeStr})...${RESET$5}`);
6396
+ console.log(`${DIM$7}正在上传 ${fileName} (${fileSizeStr})...${RESET$7}`);
6250
6397
  try {
6251
6398
  const fileBuffer = fs.readFileSync(resolvedPath);
6252
6399
  const result = await api.uploadDoc(fileBuffer, fileName);
6253
6400
  const doc = result.data || result;
6254
- console.log(`${TEXT$4}✓ 上传成功${RESET$5}`);
6401
+ console.log(`${TEXT$6}✓ 上传成功${RESET$7}`);
6255
6402
  console.log();
6256
- if (doc.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$4}${doc.id}${RESET$5}`);
6257
- if (doc.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$4}${doc.status}${RESET$5}`);
6258
- if (doc.fileName) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${doc.fileName}${RESET$5}`);
6403
+ if (doc.id) console.log(` ${BOLD$5}ID:${RESET$7} ${TEXT$6}${doc.id}${RESET$7}`);
6404
+ if (doc.status) console.log(` ${BOLD$5}状态:${RESET$7} ${TEXT$6}${doc.status}${RESET$7}`);
6405
+ if (doc.fileName) console.log(` ${BOLD$5}文件:${RESET$7} ${TEXT$6}${doc.fileName}${RESET$7}`);
6259
6406
  console.log();
6260
- if (doc.id) console.log(`${DIM$5}查看状态:bfi docs info ${doc.id}${RESET$5}`);
6407
+ if (doc.id) console.log(`${DIM$7}查看状态:bfi docs info ${doc.id}${RESET$7}`);
6261
6408
  } catch (error) {
6262
6409
  console.error(`上传失败:${error.message}`);
6263
6410
  process.exit(1);
@@ -6273,14 +6420,14 @@ async function handleList(args, globalOpts) {
6273
6420
  const data = result.data || result;
6274
6421
  const docs = data.items || data.content || data.docs || (Array.isArray(data) ? data : []);
6275
6422
  if (!Array.isArray(docs) || docs.length === 0) {
6276
- console.log(`${DIM$5}未找到文档。${RESET$5}`);
6423
+ console.log(`${DIM$7}未找到文档。${RESET$7}`);
6277
6424
  return;
6278
6425
  }
6279
6426
  const total = data.total || data.totalElements || result.total || result.totalElements;
6280
6427
  console.log();
6281
- if (total) console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${total} 条):`);
6282
- else console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${docs.length} 条结果):`);
6283
- console.log(`${DIM$5}${"─".repeat(64)}${RESET$5}`);
6428
+ if (total) console.log(`${BOLD$5}文档${RESET$7}(第 ${page + 1} 页,共 ${total} 条):`);
6429
+ else console.log(`${BOLD$5}文档${RESET$7}(第 ${page + 1} 页,共 ${docs.length} 条结果):`);
6430
+ console.log(`${DIM$7}${"─".repeat(64)}${RESET$7}`);
6284
6431
  for (const doc of docs) {
6285
6432
  const id = doc.id || "?";
6286
6433
  const fileName = doc.fileName || doc.file_name || "unknown";
@@ -6290,11 +6437,11 @@ async function handleList(args, globalOpts) {
6290
6437
  const ip = doc.clientIp || "N/A";
6291
6438
  const createdAt = doc.createdAt || doc.created_at;
6292
6439
  const dateStr = createdAt ? new Date(createdAt).toISOString().split("T")[0] : "N/A";
6293
- console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$4}${fileName}${RESET$5}`);
6294
- console.log(` ${DIM$5}${sizeStr} | ${user} | ${ip} | ${dateStr}${RESET$5}`);
6440
+ console.log(` ${BOLD$5}#${id}${RESET$7} ${TEXT$6}${fileName}${RESET$7}`);
6441
+ console.log(` ${DIM$7}${sizeStr} | ${user} | ${ip} | ${dateStr}${RESET$7}`);
6295
6442
  console.log();
6296
6443
  }
6297
- if (total && Number(total) > (page + 1) * size) console.log(`${DIM$5}下一页:bfi docs list ${page + 1}${RESET$5}`);
6444
+ if (total && Number(total) > (page + 1) * size) console.log(`${DIM$7}下一页:bfi docs list ${page + 1}${RESET$7}`);
6298
6445
  console.log();
6299
6446
  } catch (error) {
6300
6447
  console.error(`列出文档失败:${error.message}`);
@@ -6318,43 +6465,43 @@ async function handleInfo(args, globalOpts) {
6318
6465
  const result = await api.getDoc(id);
6319
6466
  const doc = result.data || result;
6320
6467
  if (!doc || !doc.id) {
6321
- console.log(`${DIM$5}未找到文档:${id}${RESET$5}`);
6468
+ console.log(`${DIM$7}未找到文档:${id}${RESET$7}`);
6322
6469
  process.exit(1);
6323
6470
  }
6324
6471
  const content = doc.content;
6325
6472
  const hasContent = typeof content === "string" && content.trim().length > 0;
6326
6473
  console.log();
6327
- console.log(`${BOLD$3}文档 #${doc.id}${RESET$5}`);
6328
- console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6329
- if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${doc.fileName || doc.file_name}${RESET$5}`);
6474
+ console.log(`${BOLD$5}文档 #${doc.id}${RESET$7}`);
6475
+ console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6476
+ if (doc.fileName || doc.file_name) console.log(` ${BOLD$5}文件:${RESET$7} ${TEXT$6}${doc.fileName || doc.file_name}${RESET$7}`);
6330
6477
  const fileSize = doc.fileSize || doc.file_size;
6331
- if (fileSize) console.log(` ${BOLD$3}大小:${RESET$5} ${TEXT$4}${formatFileSize(Number(fileSize))}${RESET$5}`);
6478
+ if (fileSize) console.log(` ${BOLD$5}大小:${RESET$7} ${TEXT$6}${formatFileSize(Number(fileSize))}${RESET$7}`);
6332
6479
  const user = doc.userDisplayName || doc.userId;
6333
- if (user) console.log(` ${BOLD$3}上传者:${RESET$5} ${TEXT$4}${user}${RESET$5}`);
6334
- if (doc.clientIp) console.log(` ${BOLD$3}IP:${RESET$5} ${TEXT$4}${doc.clientIp}${RESET$5}`);
6480
+ if (user) console.log(` ${BOLD$5}上传者:${RESET$7} ${TEXT$6}${user}${RESET$7}`);
6481
+ if (doc.clientIp) console.log(` ${BOLD$5}IP:${RESET$7} ${TEXT$6}${doc.clientIp}${RESET$7}`);
6335
6482
  if (doc.status) {
6336
- const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$4;
6337
- console.log(` ${BOLD$3}状态:${RESET$5} ${statusColor}${doc.status}${RESET$5}`);
6483
+ const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$6;
6484
+ console.log(` ${BOLD$5}状态:${RESET$7} ${statusColor}${doc.status}${RESET$7}`);
6338
6485
  }
6339
6486
  if (doc.createdAt || doc.created_at) {
6340
6487
  const date = new Date(doc.createdAt || doc.created_at).toISOString().replace("T", " ").slice(0, 19);
6341
- console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6488
+ console.log(` ${BOLD$5}创建时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6342
6489
  }
6343
6490
  if (doc.updatedAt || doc.updated_at) {
6344
6491
  const date = new Date(doc.updatedAt || doc.updated_at).toISOString().replace("T", " ").slice(0, 19);
6345
- console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6492
+ console.log(` ${BOLD$5}更新时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6346
6493
  }
6347
6494
  if (doc.error || doc.errorMessage) {
6348
6495
  console.log();
6349
- console.log(` \x1b[31m${BOLD$3}错误:${RESET$5}`);
6350
- console.log(` \x1b[31m${doc.error || doc.errorMessage}${RESET$5}`);
6496
+ console.log(` \x1b[31m${BOLD$5}错误:${RESET$7}`);
6497
+ console.log(` \x1b[31m${doc.error || doc.errorMessage}${RESET$7}`);
6351
6498
  }
6352
6499
  if (hasContent) {
6353
6500
  console.log();
6354
- console.log(` ${BOLD$3}内容:${RESET$5}`);
6355
- console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6356
- for (const line of content.split("\n")) console.log(` ${TEXT$4}${line}${RESET$5}`);
6357
- console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6501
+ console.log(` ${BOLD$5}内容:${RESET$7}`);
6502
+ console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6503
+ for (const line of content.split("\n")) console.log(` ${TEXT$6}${line}${RESET$7}`);
6504
+ console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6358
6505
  }
6359
6506
  console.log();
6360
6507
  } catch (error) {
@@ -6363,13 +6510,13 @@ async function handleInfo(args, globalOpts) {
6363
6510
  process.exit(1);
6364
6511
  }
6365
6512
  }
6366
- const RESET$4 = "\x1B[0m";
6367
- const BOLD$2 = "\x1B[1m";
6368
- const DIM$4 = "\x1B[38;5;102m";
6369
- const TEXT$3 = "\x1B[38;5;145m";
6370
- const GREEN$3 = "\x1B[32m";
6513
+ const RESET$6 = "\x1B[0m";
6514
+ const BOLD$4 = "\x1B[1m";
6515
+ const DIM$6 = "\x1B[38;5;102m";
6516
+ const TEXT$5 = "\x1B[38;5;145m";
6517
+ const GREEN$5 = "\x1B[32m";
6371
6518
  const YELLOW$2 = "\x1B[33m";
6372
- const RED$2 = "\x1B[31m";
6519
+ const RED$4 = "\x1B[31m";
6373
6520
  async function runPublish(args, globalOpts) {
6374
6521
  const fromIdx = args.indexOf("--from");
6375
6522
  const mode = fromIdx !== -1 ? args[fromIdx + 1] : "dir";
@@ -6430,23 +6577,23 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
6430
6577
  }
6431
6578
  const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6432
6579
  const skillName = frontmatter.name || path$1.basename(resolvedDir);
6433
- console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
6434
- console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6435
- console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6436
- console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
6437
- console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$3}${resolvedDir}${RESET$4}`);
6580
+ console.log(`${DIM$6}正在从目录发布技能...${RESET$6}`);
6581
+ console.log(` ${BOLD$4}名称:${RESET$6} ${TEXT$5}${skillName}${RESET$6}`);
6582
+ console.log(` ${BOLD$4}命名空间:${RESET$6} ${TEXT$5}${namespace}${RESET$6}`);
6583
+ console.log(` ${BOLD$4}可见性:${RESET$6} ${TEXT$5}${visibility}${RESET$6}`);
6584
+ console.log(` ${BOLD$4}目录:${RESET$6} ${TEXT$5}${resolvedDir}${RESET$6}`);
6438
6585
  console.log();
6439
- console.log(`${DIM$4}正在创建 zip...${RESET$4}`);
6586
+ console.log(`${DIM$6}正在创建 zip...${RESET$6}`);
6440
6587
  const zipBuffer = createZipFromDir(resolvedDir);
6441
- console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6442
- console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
6588
+ console.log(` ${GREEN$5}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$6}`);
6589
+ console.log(`${DIM$6}正在上传到 SkillHub...${RESET$6}`);
6443
6590
  try {
6444
6591
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6445
- console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6446
- if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6447
- if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
6592
+ console.log(` ${GREEN$5}发布成功!${RESET$6}`);
6593
+ if (res.slug) console.log(` ${BOLD$4}Slug:${RESET$6} ${TEXT$5}${res.slug}${RESET$6}`);
6594
+ if (res.url) console.log(` ${BOLD$4}URL:${RESET$6} ${TEXT$5}${res.url}${RESET$6}`);
6448
6595
  } catch (error) {
6449
- console.error(` ${RED$2}发布失败:${error.message}${RESET$4}`);
6596
+ console.error(` ${RED$4}发布失败:${error.message}${RESET$6}`);
6450
6597
  process.exit(1);
6451
6598
  }
6452
6599
  console.log();
@@ -6463,34 +6610,34 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
6463
6610
  console.error(`文件未找到:${resolvedZip}`);
6464
6611
  process.exit(1);
6465
6612
  }
6466
- console.log(`${DIM$4}正在解压 zip...${RESET$4}`);
6613
+ console.log(`${DIM$6}正在解压 zip...${RESET$6}`);
6467
6614
  const tmpDir = path$1.join(os$1.tmpdir(), `.bfi-publish-${Date.now()}`);
6468
6615
  fs.mkdirSync(tmpDir, { recursive: true });
6469
6616
  try {
6470
6617
  await extractZip(resolvedZip, tmpDir);
6471
6618
  const skillMdPath = findSkillMd(tmpDir);
6472
6619
  if (!skillMdPath) {
6473
- console.error(` ${RED$2}zip 文件中未找到 SKILL.md${RESET$4}`);
6620
+ console.error(` ${RED$4}zip 文件中未找到 SKILL.md${RESET$6}`);
6474
6621
  process.exit(1);
6475
6622
  }
6476
6623
  const skillDir = path$1.dirname(skillMdPath);
6477
- console.log(` ${GREEN$3}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$4}`);
6624
+ console.log(` ${GREEN$5}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$6}`);
6478
6625
  const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6479
6626
  const skillName = frontmatter.name || path$1.basename(skillDir);
6480
- console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6481
- console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6482
- console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
6627
+ console.log(` ${BOLD$4}名称:${RESET$6} ${TEXT$5}${skillName}${RESET$6}`);
6628
+ console.log(` ${BOLD$4}命名空间:${RESET$6} ${TEXT$5}${namespace}${RESET$6}`);
6629
+ console.log(` ${BOLD$4}可见性:${RESET$6} ${TEXT$5}${visibility}${RESET$6}`);
6483
6630
  console.log();
6484
- console.log(`${DIM$4}正在重新打包...${RESET$4}`);
6631
+ console.log(`${DIM$6}正在重新打包...${RESET$6}`);
6485
6632
  const zipBuffer = createZipFromDir(skillDir);
6486
- console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6487
- console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
6633
+ console.log(` ${GREEN$5}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$6}`);
6634
+ console.log(`${DIM$6}正在上传到 SkillHub...${RESET$6}`);
6488
6635
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6489
- console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6490
- if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6491
- if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
6636
+ console.log(` ${GREEN$5}发布成功!${RESET$6}`);
6637
+ if (res.slug) console.log(` ${BOLD$4}Slug:${RESET$6} ${TEXT$5}${res.slug}${RESET$6}`);
6638
+ if (res.url) console.log(` ${BOLD$4}URL:${RESET$6} ${TEXT$5}${res.url}${RESET$6}`);
6492
6639
  } catch (error) {
6493
- if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$2}错误:${error.message}${RESET$4}`);
6640
+ if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$4}错误:${error.message}${RESET$6}`);
6494
6641
  process.exit(1);
6495
6642
  } finally {
6496
6643
  try {
@@ -6519,18 +6666,18 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6519
6666
  }
6520
6667
  const effectiveBranch = branch || parsedRef || "main";
6521
6668
  const effectiveSubpath = directory || null;
6522
- console.log(`${DIM$4}正在从 Git 仓库发现技能...${RESET$4}`);
6523
- console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$3}${repoUrl}${RESET$4}`);
6524
- console.log(` ${BOLD$2}分支:${RESET$4} ${TEXT$3}${effectiveBranch}${RESET$4}`);
6669
+ console.log(`${DIM$6}正在从 Git 仓库发现技能...${RESET$6}`);
6670
+ console.log(` ${BOLD$4}仓库:${RESET$6} ${TEXT$5}${repoUrl}${RESET$6}`);
6671
+ console.log(` ${BOLD$4}分支:${RESET$6} ${TEXT$5}${effectiveBranch}${RESET$6}`);
6525
6672
  console.log();
6526
6673
  let tmpDir = null;
6527
6674
  let skills = [];
6528
6675
  try {
6529
- console.log(`${DIM$4}正在克隆仓库...${RESET$4}`);
6676
+ console.log(`${DIM$6}正在克隆仓库...${RESET$6}`);
6530
6677
  const { cloneRepo } = await Promise.resolve().then(() => git_exports);
6531
6678
  tmpDir = await cloneRepo(repoUrl, effectiveBranch);
6532
- console.log(` ${GREEN$3}仓库克隆完成${RESET$4}`);
6533
- console.log(`${DIM$4}正在发现技能...${RESET$4}`);
6679
+ console.log(` ${GREEN$5}仓库克隆完成${RESET$6}`);
6680
+ console.log(`${DIM$6}正在发现技能...${RESET$6}`);
6534
6681
  const { discoverSkills } = await import("./_chunks/skills.mjs").then((n) => n.skills_exports);
6535
6682
  skills = (await discoverSkills(tmpDir, effectiveSubpath || void 0)).map((s) => ({
6536
6683
  path: s.path,
@@ -6538,7 +6685,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6538
6685
  description: s.description || ""
6539
6686
  }));
6540
6687
  } catch (error) {
6541
- console.error(` ${RED$2}克隆或发现失败:${error.message}${RESET$4}`);
6688
+ console.error(` ${RED$4}克隆或发现失败:${error.message}${RESET$6}`);
6542
6689
  if (tmpDir) try {
6543
6690
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6544
6691
  await cleanupTempDir(tmpDir);
@@ -6546,7 +6693,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6546
6693
  process.exit(1);
6547
6694
  }
6548
6695
  if (skills.length === 0) {
6549
- console.log(`${YELLOW$2}仓库中未发现技能。${RESET$4}`);
6696
+ console.log(`${YELLOW$2}仓库中未发现技能。${RESET$6}`);
6550
6697
  if (tmpDir) try {
6551
6698
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6552
6699
  await cleanupTempDir(tmpDir);
@@ -6558,7 +6705,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6558
6705
  const filters = skillFilter.split(",").map((s) => s.trim().toLowerCase());
6559
6706
  selectedSkills = skills.filter((s) => filters.some((f) => s.name.toLowerCase().includes(f)));
6560
6707
  if (selectedSkills.length === 0) {
6561
- console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$4}`);
6708
+ console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$6}`);
6562
6709
  console.log(`可用:${skills.map((s) => s.name).join(", ")}`);
6563
6710
  try {
6564
6711
  fs.rmSync(tmpDir, {
@@ -6569,12 +6716,12 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6569
6716
  process.exit(1);
6570
6717
  }
6571
6718
  }
6572
- console.log(`\n${BOLD$2}发现 ${skills.length} 个技能,将发布 ${selectedSkills.length} 个:${RESET$4}\n`);
6719
+ console.log(`\n${BOLD$4}发现 ${skills.length} 个技能,将发布 ${selectedSkills.length} 个:${RESET$6}\n`);
6573
6720
  for (const skill of selectedSkills) {
6574
6721
  const relPath = path$1.relative(tmpDir, skill.path) || ".";
6575
- console.log(` ${BOLD$2}${skill.name}${RESET$4}`);
6576
- console.log(` ${DIM$4}📁 ${relPath.split("/").join(" ▸ ")}${RESET$4}`);
6577
- if (skill.description) console.log(` ${DIM$4}${truncate(skill.description, 80)}${RESET$4}`);
6722
+ console.log(` ${BOLD$4}${skill.name}${RESET$6}`);
6723
+ console.log(` ${DIM$6}📁 ${relPath.split("/").join(" ▸ ")}${RESET$6}`);
6724
+ if (skill.description) console.log(` ${DIM$6}${truncate(skill.description, 80)}${RESET$6}`);
6578
6725
  console.log();
6579
6726
  }
6580
6727
  if (!yes) {
@@ -6593,17 +6740,17 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6593
6740
  const { createZipFromDir } = await Promise.resolve().then(() => zip_exports);
6594
6741
  let successCount = 0;
6595
6742
  for (const skill of selectedSkills) {
6596
- console.log(`${DIM$4}正在发布 ${skill.name}...${RESET$4}`);
6743
+ console.log(`${DIM$6}正在发布 ${skill.name}...${RESET$6}`);
6597
6744
  try {
6598
6745
  const zipBuffer = createZipFromDir(skill.path);
6599
6746
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6600
- console.log(` ${GREEN$3}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$4}`);
6747
+ console.log(` ${GREEN$5}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$6}`);
6601
6748
  successCount++;
6602
6749
  } catch (error) {
6603
- console.error(` ${RED$2}✗ ${skill.name}:${error.message}${RESET$4}`);
6750
+ console.error(` ${RED$4}✗ ${skill.name}:${error.message}${RESET$6}`);
6604
6751
  }
6605
6752
  }
6606
- console.log(`\n${GREEN$3}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$4}`);
6753
+ console.log(`\n${GREEN$5}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$6}`);
6607
6754
  if (tmpDir) try {
6608
6755
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6609
6756
  await cleanupTempDir(tmpDir);
@@ -6653,11 +6800,11 @@ function truncate(text, maxLen) {
6653
6800
  return text.slice(0, maxLen) + "...";
6654
6801
  }
6655
6802
  var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
6656
- const RESET$3 = "\x1B[0m";
6657
- const BOLD$1 = "\x1B[1m";
6658
- const DIM$3 = "\x1B[38;5;102m";
6659
- const GREEN$2 = "\x1B[32m";
6660
- const RED$1 = "\x1B[31m";
6803
+ const RESET$5 = "\x1B[0m";
6804
+ const BOLD$3 = "\x1B[1m";
6805
+ const DIM$5 = "\x1B[38;5;102m";
6806
+ const GREEN$4 = "\x1B[32m";
6807
+ const RED$3 = "\x1B[31m";
6661
6808
  const YELLOW$1 = "\x1B[33m";
6662
6809
  async function runPackage(args, globalOpts) {
6663
6810
  const subcommand = args[0];
@@ -6703,21 +6850,21 @@ function getWorkdir(globalOpts, args) {
6703
6850
  return globalOpts.workdir || process.cwd();
6704
6851
  }
6705
6852
  function printPackageHelp() {
6706
- console.log(`${BOLD$1}包命令:${RESET$3}`);
6853
+ console.log(`${BOLD$3}包命令:${RESET$5}`);
6707
6854
  console.log();
6708
- console.log(`${BOLD$1}本地操作:${RESET$3}`);
6709
- console.log(` ${DIM$3}bfi skills package list${RESET$3} 列出已安装的包`);
6710
- console.log(` ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包(含全部技能)`);
6711
- console.log(` ${DIM$3}bfi skills package uninstall <ref>${RESET$3} 卸载包(含全部技能)`);
6712
- console.log(` ${DIM$3}bfi skills package update [ref]${RESET$3} 更新包中技能`);
6713
- console.log(` ${DIM$3}bfi skills package search <query>${RESET$3} 搜索包`);
6855
+ console.log(`${BOLD$3}本地操作:${RESET$5}`);
6856
+ console.log(` ${DIM$5}bfi skills package list${RESET$5} 列出已安装的包`);
6857
+ console.log(` ${DIM$5}bfi skills package install <ref>${RESET$5} 安装包(含全部技能)`);
6858
+ console.log(` ${DIM$5}bfi skills package uninstall <ref>${RESET$5} 卸载包(含全部技能)`);
6859
+ console.log(` ${DIM$5}bfi skills package update [ref]${RESET$5} 更新包中技能`);
6860
+ console.log(` ${DIM$5}bfi skills package search <query>${RESET$5} 搜索包`);
6714
6861
  console.log();
6715
- console.log(`${BOLD$1}服务端管理:${RESET$3}`);
6716
- console.log(` ${DIM$3}bfi skills package create <slug>${RESET$3} 创建包`);
6717
- console.log(` ${DIM$3}bfi skills package add-skills <ref> [skills...]${RESET$3} 添加技能到包`);
6718
- console.log(` ${DIM$3}bfi skills package remove-skills <ref> [skills...]${RESET$3} 从包移除技能`);
6862
+ console.log(`${BOLD$3}服务端管理:${RESET$5}`);
6863
+ console.log(` ${DIM$5}bfi skills package create <slug>${RESET$5} 创建包`);
6864
+ console.log(` ${DIM$5}bfi skills package add-skills <ref> [skills...]${RESET$5} 添加技能到包`);
6865
+ console.log(` ${DIM$5}bfi skills package remove-skills <ref> [skills...]${RESET$5} 从包移除技能`);
6719
6866
  console.log();
6720
- console.log(`${BOLD$1}选项:${RESET$3}`);
6867
+ console.log(`${BOLD$3}选项:${RESET$5}`);
6721
6868
  console.log(` --namespace <ns> 目标命名空间`);
6722
6869
  console.log(` --name <name> 显示名称(create 时)`);
6723
6870
  console.log(` --description <t> 描述(create 时)`);
@@ -6734,21 +6881,66 @@ async function handleLocalList(args, globalOpts) {
6734
6881
  }
6735
6882
  if (entries.length === 0) {
6736
6883
  console.log("没有已安装的包。");
6737
- console.log(`使用 ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包。`);
6884
+ console.log(`使用 ${DIM$5}bfi skills package install <ref>${RESET$5} 安装包。`);
6738
6885
  return;
6739
6886
  }
6740
6887
  console.log();
6741
- console.log(`${BOLD$1}已安装的包(${entries.length} 个):${RESET$3}`);
6888
+ console.log(`${BOLD$3}已安装的包(${entries.length} 个):${RESET$5}`);
6742
6889
  console.log();
6743
6890
  for (const [ref, info] of entries) {
6744
6891
  const pkg = info;
6745
6892
  const skills = lock.skills || {};
6746
6893
  const pkgSkills = Object.entries(skills).filter(([, s]) => s.package?.slug === pkg.slug);
6747
- console.log(` ${BOLD$1}${pkg.name || pkg.slug}${RESET$3}`);
6748
- console.log(` ${DIM$3}命名空间:@${pkg.namespace} | 版本:${pkg.version || "latest"} | 技能数:${pkgSkills.length}${RESET$3}`);
6894
+ console.log(` ${BOLD$3}${pkg.name || pkg.slug}${RESET$5}`);
6895
+ console.log(` ${DIM$5}命名空间:@${pkg.namespace} | 版本:${pkg.version || "latest"} | 技能数:${pkgSkills.length}${RESET$5}`);
6749
6896
  console.log();
6750
6897
  }
6751
6898
  }
6899
+ function targetDisplayName(target) {
6900
+ const base = agents[target.agent].displayName;
6901
+ return target.subagent ? `${base} (${target.subagent})` : base;
6902
+ }
6903
+ function targetKey(target) {
6904
+ return target.subagent ? `${target.agent}:${target.subagent}` : target.agent;
6905
+ }
6906
+ function buildInstallTargets(targetAgents, eveSubagentTargets) {
6907
+ const targets = [];
6908
+ for (const agent of targetAgents) if (agent === "eve") for (const subagent of eveSubagentTargets) targets.push({
6909
+ agent,
6910
+ subagent
6911
+ });
6912
+ else targets.push({ agent });
6913
+ return targets;
6914
+ }
6915
+ function splitAgentsByType(agentTypes) {
6916
+ const universal = [];
6917
+ const symlinked = [];
6918
+ for (const a of agentTypes) if (isUniversalAgent(a)) universal.push(agents[a].displayName);
6919
+ else symlinked.push(agents[a].displayName);
6920
+ return {
6921
+ universal,
6922
+ symlinked
6923
+ };
6924
+ }
6925
+ function formatList(items, maxShow = 5) {
6926
+ if (items.length <= maxShow) return items.join(", ");
6927
+ return `${items.slice(0, maxShow).join(", ")} +${items.length - maxShow} more`;
6928
+ }
6929
+ function buildTargetSummaryLines(targets, installMode) {
6930
+ const lines = [];
6931
+ const rootAgents = targets.filter((t) => !t.subagent).map((t) => t.agent);
6932
+ const subagentNames = targets.filter((t) => t.subagent).map(targetDisplayName);
6933
+ const { universal, symlinked } = splitAgentsByType(rootAgents);
6934
+ if (installMode === "symlink") {
6935
+ if (universal.length > 0) lines.push(` ${import_picocolors.default.green("共享目录:")} ${formatList(universal, 3)}`);
6936
+ if (symlinked.length > 0) lines.push(` ${import_picocolors.default.dim("符号链接 →")} ${formatList(symlinked)}`);
6937
+ if (subagentNames.length > 0) lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList(subagentNames)}`);
6938
+ } else {
6939
+ const allNames = targets.map(targetDisplayName);
6940
+ lines.push(` ${import_picocolors.default.dim("copy →")} ${formatList(allNames)}`);
6941
+ }
6942
+ return lines;
6943
+ }
6752
6944
  async function handleInstall(args, api, globalOpts) {
6753
6945
  const pkgRef = args[0];
6754
6946
  if (!pkgRef) {
@@ -6757,126 +6949,297 @@ async function handleInstall(args, api, globalOpts) {
6757
6949
  process.exit(1);
6758
6950
  }
6759
6951
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
6760
- console.log(`${DIM$3}正在获取包信息...${RESET$3}`);
6952
+ const isYes = args.includes("-y") || args.includes("--yes") || globalOpts.yes;
6953
+ const isGlobal = args.includes("-g") || args.includes("--global");
6954
+ console.log(`${DIM$5}正在获取包信息...${RESET$5}`);
6761
6955
  let pkgInfo;
6762
6956
  try {
6763
6957
  pkgInfo = await api.getPackage(namespace, slug);
6764
6958
  pkgInfo = pkgInfo.data || pkgInfo;
6765
6959
  } catch (error) {
6766
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
6960
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
6767
6961
  process.exit(1);
6768
6962
  }
6769
6963
  const skills = pkgInfo.skills || [];
6770
6964
  if (skills.length === 0) {
6771
- console.log(`${YELLOW$1}包中没有技能。${RESET$3}`);
6965
+ console.log(`${YELLOW$1}包中没有技能。${RESET$5}`);
6772
6966
  return;
6773
6967
  }
6774
- console.log(`${BOLD$1}${pkgInfo.name || slug}${RESET$3}(${skills.length} 个技能):`);
6968
+ console.log(`${BOLD$3}${pkgInfo.name || slug}${RESET$5}(${skills.length} 个技能):`);
6775
6969
  console.log();
6776
- const { runAdd } = await Promise.resolve().then(() => add_exports);
6777
- const installedSkills = [];
6778
6970
  for (const skill of skills) {
6779
- const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
6780
- console.log(` ${DIM$3}正在安装 ${skillRef}...${RESET$3}`);
6781
- try {
6782
- await runAdd([skillRef], {
6783
- ...globalOpts,
6784
- yes: true
6785
- });
6786
- console.log(` ${GREEN$2}✓ ${skill.slug}${RESET$3}`);
6787
- installedSkills.push(skill.slug);
6788
- } catch (error) {
6789
- console.log(` ${RED$1}✗ ${skill.slug}:${error.message}${RESET$3}`);
6790
- }
6791
- }
6792
- const cwd = getWorkdir(globalOpts, args);
6793
- const lock = loadLockfile(cwd);
6794
- const pkgKey = `@${namespace}/${slug}`;
6795
- if (!lock.packages) lock.packages = {};
6796
- lock.packages[pkgKey] = {
6797
- namespace,
6798
- slug,
6799
- name: pkgInfo.displayName || pkgInfo.name || slug,
6800
- version: pkgInfo.version || "latest",
6801
- skillCount: installedSkills.length
6802
- };
6803
- for (const skillSlug of installedSkills) {
6804
- if (!lock.skills[skillSlug]) lock.skills[skillSlug] = {
6805
- namespace,
6806
- slug,
6807
- version: "latest"
6808
- };
6809
- lock.skills[skillSlug].package = {
6810
- namespace,
6811
- slug
6812
- };
6971
+ const ref = `@${skill.namespace || namespace}/${skill.slug}`;
6972
+ console.log(` ${DIM$5}• ${skill.displayName || skill.slug}${RESET$5} ${DIM$5}${ref}${RESET$5}`);
6813
6973
  }
6814
- saveLockfile(cwd, lock);
6815
6974
  console.log();
6816
- console.log(`${GREEN$2}✓ 包安装完成${RESET$3}`);
6817
- }
6818
- async function handleUninstall(args, globalOpts) {
6819
- const pkgRef = args[0];
6820
- if (!pkgRef) {
6821
- console.error("用法:bfi skills package uninstall <package-ref>");
6822
- process.exit(1);
6823
- }
6824
- const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
6825
- const pkgKey = `@${namespace}/${slug}`;
6826
- const cwd = getWorkdir(globalOpts, args);
6827
- const lock = loadLockfile(cwd);
6828
- if (!lock.packages || !lock.packages[pkgKey]) {
6829
- console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$3}`);
6830
- return;
6831
- }
6832
- const skills = lock.skills || {};
6833
- let removed = 0;
6834
- for (const [skillName, info] of Object.entries(skills)) {
6835
- const skillInfo = info;
6836
- if (skillInfo.package?.slug === slug && skillInfo.package?.namespace === namespace) {
6837
- const { removeCommand } = await Promise.resolve().then(() => remove_exports);
6838
- try {
6839
- await removeCommand([skillName], {
6840
- global: false,
6841
- yes: true
6842
- });
6843
- removed++;
6844
- } catch {}
6845
- }
6846
- }
6847
- delete lock.packages[pkgKey];
6848
- const { saveLockfile } = await Promise.resolve().then(() => config_exports);
6849
- saveLockfile(cwd, lock);
6850
- console.log(`${GREEN$2}✓ 已卸载包,移除 ${removed} 个技能${RESET$3}`);
6851
- }
6852
- async function handleUpdate(args, api, globalOpts) {
6853
- const pkgRef = args[0];
6854
- const lock = loadLockfile(getWorkdir(globalOpts, args));
6855
- let packagesToUpdate = [];
6856
- const pkgs = lock.packages || {};
6857
- if (pkgRef) {
6858
- const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
6859
- if (!pkgs[`@${namespace}/${slug}`]) {
6860
- console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$3}`);
6861
- return;
6862
- }
6863
- packagesToUpdate.push({
6864
- namespace,
6865
- slug
6866
- });
6867
- } else packagesToUpdate = Object.values(pkgs).map((p) => ({
6868
- namespace: p.namespace,
6869
- slug: p.slug
6870
- }));
6975
+ let targetAgents;
6976
+ let installGlobally;
6977
+ let installMode;
6978
+ let eveSubagentTargets = [void 0];
6979
+ if (isYes) {
6980
+ const installed = await detectInstalledAgents();
6981
+ const validAgents = Object.keys(agents);
6982
+ targetAgents = ensureUniversalAgents(installed.length > 0 ? installed : validAgents);
6983
+ installGlobally = isGlobal;
6984
+ installMode = "symlink";
6985
+ console.log(`${DIM$5}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$5}`);
6986
+ console.log(`${DIM$5}范围:${installGlobally ? "全局" : "项目"} | 方式:${installMode === "symlink" ? "符号链接" : "复制"}${RESET$5}`);
6987
+ console.log();
6988
+ } else {
6989
+ const spinner$1 = spinner();
6990
+ spinner$1.start("正在加载 Agent...");
6991
+ const installedAgents = await detectInstalledAgents();
6992
+ const totalAgents = Object.keys(agents).length;
6993
+ spinner$1.stop(`${totalAgents} agents`);
6994
+ const skillNames = skills.map((s) => s.displayName || s.slug);
6995
+ const skillSubject = skillNames.length <= 3 ? skillNames.map((n) => import_picocolors.default.cyan(n)).join(", ") : `${skills.length} 个技能`;
6996
+ if (installedAgents.includes("eve")) {
6997
+ const useEve = await confirm({
6998
+ message: `检测到 Eve 项目。为您的 eve agent 安装 ${skillSubject}?`,
6999
+ initialValue: true
7000
+ });
7001
+ if (isCancel(useEve)) {
7002
+ cancel("安装已取消");
7003
+ process.exit(0);
7004
+ }
7005
+ if (useEve) {
7006
+ targetAgents = ["eve"];
7007
+ console.log(`${DIM$5}安装到:eve agent${RESET$5}`);
7008
+ } else {
7009
+ const selected = await selectAgentsInteractive({ global: false });
7010
+ if (isCancel(selected)) {
7011
+ cancel("安装已取消");
7012
+ process.exit(0);
7013
+ }
7014
+ targetAgents = selected;
7015
+ }
7016
+ } else if (installedAgents.length === 0) {
7017
+ const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
7018
+ value: key,
7019
+ label: config.displayName
7020
+ })));
7021
+ if (isCancel(selected)) {
7022
+ cancel("安装已取消");
7023
+ process.exit(0);
7024
+ }
7025
+ targetAgents = selected;
7026
+ } else if (installedAgents.length === 1) {
7027
+ targetAgents = ensureUniversalAgents(installedAgents);
7028
+ const firstAgent = installedAgents[0];
7029
+ console.log(`${DIM$5}安装到:${agents[firstAgent].displayName}${RESET$5}`);
7030
+ } else {
7031
+ const selected = await selectAgentsInteractive({ global: false });
7032
+ if (isCancel(selected)) {
7033
+ cancel("安装已取消");
7034
+ process.exit(0);
7035
+ }
7036
+ targetAgents = selected;
7037
+ }
7038
+ if (targetAgents.includes("eve")) {
7039
+ const availableSubagents = getEveSubagents(process.cwd());
7040
+ if (availableSubagents.length > 0) {
7041
+ const selectedSubagents = await multiselect$1({
7042
+ message: "Eve 技能安装位置?",
7043
+ options: [{
7044
+ value: "",
7045
+ label: "根 Agent",
7046
+ hint: "agent/skills"
7047
+ }, ...availableSubagents.map((name) => ({
7048
+ value: name,
7049
+ label: name,
7050
+ hint: `agent/subagents/${name}/skills`
7051
+ }))],
7052
+ initialValues: [""],
7053
+ required: true
7054
+ });
7055
+ if (isCancel(selectedSubagents)) {
7056
+ cancel("安装已取消");
7057
+ process.exit(0);
7058
+ }
7059
+ eveSubagentTargets = selectedSubagents.map((s) => s === "" ? void 0 : s);
7060
+ }
7061
+ }
7062
+ const installTargets = buildInstallTargets(targetAgents, eveSubagentTargets);
7063
+ installGlobally = isGlobal;
7064
+ const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== void 0);
7065
+ if (!isGlobal && supportsGlobal) {
7066
+ const scope = await select({
7067
+ message: "安装范围",
7068
+ options: [{
7069
+ value: false,
7070
+ label: "项目",
7071
+ hint: "安装到当前目录(随项目一起提交)"
7072
+ }, {
7073
+ value: true,
7074
+ label: "全局",
7075
+ hint: "安装到主目录(跨所有项目可用)"
7076
+ }]
7077
+ });
7078
+ if (isCancel(scope)) {
7079
+ cancel("安装已取消");
7080
+ process.exit(0);
7081
+ }
7082
+ installGlobally = scope;
7083
+ }
7084
+ const allEve = installTargets.every((t) => t.agent === "eve");
7085
+ if (new Set(installTargets.map((t) => t.subagent ? `eve:subagent:${t.subagent}` : agents[t.agent].skillsDir)).size > 1 && !allEve) {
7086
+ const modeChoice = await select({
7087
+ message: "安装方式",
7088
+ options: [{
7089
+ value: "symlink",
7090
+ label: "符号链接(推荐)",
7091
+ hint: "单一来源,易于更新"
7092
+ }, {
7093
+ value: "copy",
7094
+ label: "复制到所有 Agent",
7095
+ hint: "每个 Agent 独立副本"
7096
+ }]
7097
+ });
7098
+ if (isCancel(modeChoice)) {
7099
+ cancel("安装已取消");
7100
+ process.exit(0);
7101
+ }
7102
+ installMode = modeChoice;
7103
+ } else installMode = "copy";
7104
+ const overwriteChecks = await Promise.all(skills.flatMap((skill) => installTargets.map(async (target) => ({
7105
+ skillName: skill.slug,
7106
+ target,
7107
+ installed: await isSkillInstalled(skill.slug, target.agent, {
7108
+ global: installGlobally,
7109
+ eveSubagent: target.subagent
7110
+ })
7111
+ }))));
7112
+ const overwriteStatus = /* @__PURE__ */ new Map();
7113
+ for (const { skillName, target, installed } of overwriteChecks) {
7114
+ if (!overwriteStatus.has(skillName)) overwriteStatus.set(skillName, /* @__PURE__ */ new Map());
7115
+ overwriteStatus.get(skillName).set(targetKey(target), installed);
7116
+ }
7117
+ const summaryLines = [];
7118
+ for (const skill of skills) {
7119
+ if (summaryLines.length > 0) summaryLines.push("");
7120
+ const skillOverwrites = overwriteStatus.get(skill.slug);
7121
+ const overwriteAgents = installTargets.filter((t) => skillOverwrites?.get(targetKey(t))).map(targetDisplayName);
7122
+ summaryLines.push(`${import_picocolors.default.cyan(skill.displayName || skill.slug)}`);
7123
+ summaryLines.push(...buildTargetSummaryLines(installTargets, installMode));
7124
+ if (overwriteAgents.length > 0) summaryLines.push(` ${import_picocolors.default.yellow("覆盖:")} ${overwriteAgents.join(", ")}`);
7125
+ }
7126
+ console.log();
7127
+ note(summaryLines.join("\n"), "安装摘要");
7128
+ const confirmed = await confirm({ message: "确认安装?" });
7129
+ if (isCancel(confirmed) || !confirmed) {
7130
+ cancel("安装已取消");
7131
+ process.exit(0);
7132
+ }
7133
+ }
7134
+ const { runAdd } = await Promise.resolve().then(() => add_exports);
7135
+ const installedSkills = [];
7136
+ const nonEveAgents = targetAgents.filter((a) => a !== "eve");
7137
+ const runAddBaseOpts = {
7138
+ global: installGlobally,
7139
+ copy: installMode === "copy",
7140
+ yes: true
7141
+ };
7142
+ if (nonEveAgents.length > 0) runAddBaseOpts.agent = nonEveAgents;
7143
+ if (targetAgents.includes("eve")) runAddBaseOpts.subagent = eveSubagentTargets.map((s) => s ?? "root");
7144
+ for (const skill of skills) {
7145
+ const skillRef = `@${skill.namespace || namespace}/${skill.slug}`;
7146
+ console.log(` ${DIM$5}正在安装 ${skillRef}...${RESET$5}`);
7147
+ try {
7148
+ await runAdd([skillRef], runAddBaseOpts);
7149
+ console.log(` ${GREEN$4}✓ ${skill.slug}${RESET$5}`);
7150
+ installedSkills.push(skill.slug);
7151
+ } catch (error) {
7152
+ console.log(` ${RED$3}✗ ${skill.slug}:${error.message}${RESET$5}`);
7153
+ }
7154
+ }
7155
+ const cwd = getWorkdir(globalOpts, args);
7156
+ const lock = loadLockfile(cwd);
7157
+ const pkgKey = `@${namespace}/${slug}`;
7158
+ if (!lock.packages) lock.packages = {};
7159
+ lock.packages[pkgKey] = {
7160
+ namespace,
7161
+ slug,
7162
+ name: pkgInfo.displayName || pkgInfo.name || slug,
7163
+ version: pkgInfo.version || "latest",
7164
+ skillCount: installedSkills.length
7165
+ };
7166
+ for (const skillSlug of installedSkills) {
7167
+ if (!lock.skills[skillSlug]) lock.skills[skillSlug] = {
7168
+ namespace,
7169
+ slug,
7170
+ version: "latest"
7171
+ };
7172
+ lock.skills[skillSlug].package = {
7173
+ namespace,
7174
+ slug
7175
+ };
7176
+ }
7177
+ saveLockfile(cwd, lock);
7178
+ console.log();
7179
+ console.log(`${GREEN$4}✓ 包安装完成${RESET$5}`);
7180
+ }
7181
+ async function handleUninstall(args, globalOpts) {
7182
+ const pkgRef = args[0];
7183
+ if (!pkgRef) {
7184
+ console.error("用法:bfi skills package uninstall <package-ref>");
7185
+ process.exit(1);
7186
+ }
7187
+ const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7188
+ const pkgKey = `@${namespace}/${slug}`;
7189
+ const cwd = getWorkdir(globalOpts, args);
7190
+ const lock = loadLockfile(cwd);
7191
+ if (!lock.packages || !lock.packages[pkgKey]) {
7192
+ console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$5}`);
7193
+ return;
7194
+ }
7195
+ const skills = lock.skills || {};
7196
+ let removed = 0;
7197
+ for (const [skillName, info] of Object.entries(skills)) {
7198
+ const skillInfo = info;
7199
+ if (skillInfo.package?.slug === slug && skillInfo.package?.namespace === namespace) {
7200
+ const { removeCommand } = await Promise.resolve().then(() => remove_exports);
7201
+ try {
7202
+ await removeCommand([skillName], {
7203
+ global: false,
7204
+ yes: true
7205
+ });
7206
+ removed++;
7207
+ } catch {}
7208
+ }
7209
+ }
7210
+ delete lock.packages[pkgKey];
7211
+ const { saveLockfile } = await Promise.resolve().then(() => config_exports);
7212
+ saveLockfile(cwd, lock);
7213
+ console.log(`${GREEN$4}✓ 已卸载包,移除 ${removed} 个技能${RESET$5}`);
7214
+ }
7215
+ async function handleUpdate(args, api, globalOpts) {
7216
+ const pkgRef = args[0];
7217
+ const lock = loadLockfile(getWorkdir(globalOpts, args));
7218
+ let packagesToUpdate = [];
7219
+ const pkgs = lock.packages || {};
7220
+ if (pkgRef) {
7221
+ const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7222
+ if (!pkgs[`@${namespace}/${slug}`]) {
7223
+ console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$5}`);
7224
+ return;
7225
+ }
7226
+ packagesToUpdate.push({
7227
+ namespace,
7228
+ slug
7229
+ });
7230
+ } else packagesToUpdate = Object.values(pkgs).map((p) => ({
7231
+ namespace: p.namespace,
7232
+ slug: p.slug
7233
+ }));
6871
7234
  if (packagesToUpdate.length === 0) {
6872
7235
  console.log("没有已安装的包需要更新。");
6873
7236
  return;
6874
7237
  }
6875
- console.log(`${DIM$3}正在更新 ${packagesToUpdate.length} 个包...${RESET$3}`);
7238
+ console.log(`${DIM$5}正在更新 ${packagesToUpdate.length} 个包...${RESET$5}`);
6876
7239
  for (const pkg of packagesToUpdate) try {
6877
7240
  const pkgInfo = await api.getPackage(pkg.namespace, pkg.slug);
6878
7241
  const skills = (pkgInfo.data || pkgInfo).skills || [];
6879
- console.log(` ${DIM$3}更新 @${pkg.namespace}/${pkg.slug}(${skills.length} 个技能)...${RESET$3}`);
7242
+ console.log(` ${DIM$5}更新 @${pkg.namespace}/${pkg.slug}(${skills.length} 个技能)...${RESET$5}`);
6880
7243
  for (const skill of skills) {
6881
7244
  const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
6882
7245
  const { runAdd } = await Promise.resolve().then(() => add_exports);
@@ -6888,9 +7251,9 @@ async function handleUpdate(args, api, globalOpts) {
6888
7251
  } catch {}
6889
7252
  }
6890
7253
  } catch (error) {
6891
- console.log(` ${RED$1}✗ @${pkg.namespace}/${pkg.slug}:${error.message}${RESET$3}`);
7254
+ console.log(` ${RED$3}✗ @${pkg.namespace}/${pkg.slug}:${error.message}${RESET$5}`);
6892
7255
  }
6893
- console.log(`${GREEN$2}✓ 包更新完成${RESET$3}`);
7256
+ console.log(`${GREEN$4}✓ 包更新完成${RESET$5}`);
6894
7257
  }
6895
7258
  async function handleSearch(args, api, globalOpts) {
6896
7259
  const query = args.filter((a) => !a.startsWith("--")).join(" ") || void 0;
@@ -6910,11 +7273,11 @@ async function handleSearch(args, api, globalOpts) {
6910
7273
  }, null, 2));
6911
7274
  return;
6912
7275
  }
6913
- console.log(`\n${BOLD$1}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$3}\n`);
7276
+ console.log(`\n${BOLD$3}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$5}\n`);
6914
7277
  for (const [ns, sk] of namespaces) {
6915
- console.log(` ${BOLD$1}@${ns}${RESET$3}(${sk.length} 个技能)`);
6916
- for (const s of sk.slice(0, 5)) console.log(` ${DIM$3}- ${s.displayName || s.name} (${s.slug})${RESET$3}`);
6917
- if (sk.length > 5) console.log(` ${DIM$3}... 还有 ${sk.length - 5} 个${RESET$3}`);
7278
+ console.log(` ${BOLD$3}@${ns}${RESET$5}(${sk.length} 个技能)`);
7279
+ for (const s of sk.slice(0, 5)) console.log(` ${DIM$5}- ${s.displayName || s.name} (${s.slug})${RESET$5}`);
7280
+ if (sk.length > 5) console.log(` ${DIM$5}... 还有 ${sk.length - 5} 个${RESET$5}`);
6918
7281
  console.log();
6919
7282
  }
6920
7283
  } else {
@@ -6953,11 +7316,11 @@ async function handleSearch(args, api, globalOpts) {
6953
7316
  };
6954
7317
  const maxName = Math.max(...allPackages.map((p) => dw(p.displayName || p.name || p.slug || "")), 4);
6955
7318
  const maxSlug = Math.max(...allPackages.map((p) => dw(`@${p._namespace}/${p.slug}`)), 4);
6956
- console.log(`\n${BOLD$1}所有技能包(${allPackages.length} 个):${RESET$3}\n`);
7319
+ console.log(`\n${BOLD$3}所有技能包(${allPackages.length} 个):${RESET$5}\n`);
6957
7320
  for (const pkg of allPackages) {
6958
7321
  const name = pad(pkg.displayName || pkg.name || pkg.slug || "", maxName);
6959
7322
  const ref = pad(`@${pkg._namespace}/${pkg.slug}`, maxSlug);
6960
- console.log(` ${BOLD$1}${name}${RESET$3} ${DIM$3}${ref} ${pkg.visibility === "PUBLIC" ? "公开" : "私有"}${RESET$3}`);
7323
+ console.log(` ${BOLD$3}${name}${RESET$5} ${DIM$5}${ref} ${pkg.visibility === "PUBLIC" ? "公开" : "私有"}${RESET$5}`);
6961
7324
  }
6962
7325
  }
6963
7326
  }
@@ -6978,11 +7341,11 @@ async function handleCreate(args, api, globalOpts) {
6978
7341
  description: description || "",
6979
7342
  visibility: visibility.toUpperCase()
6980
7343
  });
6981
- console.log(`${GREEN$2}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7344
+ console.log(`${GREEN$4}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$5}`);
6982
7345
  const pkg = result.package || result.data || result;
6983
- if (pkg) console.log(` ${DIM$3}名称:${pkg.name || slug} | 可见性:${pkg.visibility || visibility}${RESET$3}`);
7346
+ if (pkg) console.log(` ${DIM$5}名称:${pkg.name || slug} | 可见性:${pkg.visibility || visibility}${RESET$5}`);
6984
7347
  } catch (error) {
6985
- console.error(`${RED$1}创建包失败:${error.message}${RESET$3}`);
7348
+ console.error(`${RED$3}创建包失败:${error.message}${RESET$5}`);
6986
7349
  process.exit(1);
6987
7350
  }
6988
7351
  }
@@ -7008,11 +7371,11 @@ async function handleAddSkills(args, api, globalOpts) {
7008
7371
  };
7009
7372
  });
7010
7373
  if (skills.length === 0) {
7011
- console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$3}`);
7374
+ console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$5}`);
7012
7375
  return;
7013
7376
  }
7014
7377
  } catch (error) {
7015
- console.error(`${RED$1}获取技能列表失败:${error.message}${RESET$3}`);
7378
+ console.error(`${RED$3}获取技能列表失败:${error.message}${RESET$5}`);
7016
7379
  process.exit(1);
7017
7380
  }
7018
7381
  else skills = skillRefs.map((ref) => {
@@ -7024,85 +7387,487 @@ async function handleAddSkills(args, api, globalOpts) {
7024
7387
  });
7025
7388
  try {
7026
7389
  await api.addSkillsToPackage(namespace, slug, skills);
7027
- console.log(`${GREEN$2}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7390
+ console.log(`${GREEN$4}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$5}`);
7028
7391
  } catch (error) {
7029
- console.error(`${RED$1}添加失败:${error.message}${RESET$3}`);
7392
+ console.error(`${RED$3}添加失败:${error.message}${RESET$5}`);
7393
+ process.exit(1);
7394
+ }
7395
+ }
7396
+ async function handleRemoveSkills(args, api, globalOpts) {
7397
+ const pkgRef = args[0];
7398
+ const skillRefs = args.slice(1);
7399
+ if (!pkgRef) {
7400
+ console.error("用法:bfi skills package remove-skills <package-ref> [skill-ref...]");
7401
+ console.error(" 不指定技能时,移除包中全部技能");
7402
+ process.exit(1);
7403
+ }
7404
+ const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7405
+ let skills;
7406
+ if (skillRefs.length === 0) try {
7407
+ const pkgInfo = await api.getPackage(namespace, slug);
7408
+ skills = ((pkgInfo.data || pkgInfo).skills || []).map((s) => ({
7409
+ namespace: s.namespace || namespace,
7410
+ slug: s.slug
7411
+ }));
7412
+ if (skills.length === 0) {
7413
+ console.log("包中没有技能。");
7414
+ return;
7415
+ }
7416
+ } catch (error) {
7417
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7418
+ process.exit(1);
7419
+ }
7420
+ else skills = skillRefs.map((ref) => {
7421
+ const { namespace: ns, slug: s } = parseSkillRef(ref, namespace);
7422
+ return {
7423
+ namespace: ns,
7424
+ slug: s
7425
+ };
7426
+ });
7427
+ try {
7428
+ await api.removeSkillsFromPackage(namespace, slug, skills);
7429
+ console.log(`${GREEN$4}✓ 已从包移除 ${skills.length} 个技能${RESET$5}`);
7430
+ } catch (error) {
7431
+ console.error(`${RED$3}移除失败:${error.message}${RESET$5}`);
7432
+ process.exit(1);
7433
+ }
7434
+ }
7435
+ async function handleServerInfo(args, api, globalOpts) {
7436
+ const pkgRef = args[0];
7437
+ if (!pkgRef) {
7438
+ console.error("用法:bfi skills package info <package-ref>");
7439
+ process.exit(1);
7440
+ }
7441
+ const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7442
+ const json = args.includes("--json");
7443
+ try {
7444
+ const result = await api.getPackage(namespace, slug);
7445
+ const pkg = result.data || result;
7446
+ if (json) {
7447
+ console.log(JSON.stringify(pkg, null, 2));
7448
+ return;
7449
+ }
7450
+ console.log(`\n${BOLD$3}${pkg.displayName || pkg.name || slug}${RESET$5}`);
7451
+ console.log(`${DIM$5}${"=".repeat(48)}${RESET$5}`);
7452
+ console.log(` ${BOLD$3}Slug:${RESET$5} ${toCanonicalSlug(namespace, slug)}`);
7453
+ console.log(` ${BOLD$3}命名空间:${RESET$5} @${namespace}`);
7454
+ console.log(` ${BOLD$3}可见性:${RESET$5} ${pkg.visibility || "PRIVATE"}`);
7455
+ const skills = pkg.skills || [];
7456
+ if (skills.length > 0) {
7457
+ console.log(`\n ${BOLD$3}技能(${skills.length} 个):${RESET$5}`);
7458
+ for (const s of skills) console.log(` ${DIM$5}- ${s.displayName || s.slug} (${s.namespace || namespace}--${s.slug})${RESET$5}`);
7459
+ }
7460
+ console.log();
7461
+ } catch (error) {
7462
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7463
+ process.exit(1);
7464
+ }
7465
+ }
7466
+ function getOptionValue(args, flag) {
7467
+ const idx = args.indexOf(flag);
7468
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
7469
+ }
7470
+ const RESET$4 = "\x1B[0m";
7471
+ const BOLD$2 = "\x1B[1m";
7472
+ const DIM$4 = "\x1B[38;5;102m";
7473
+ const TEXT$4 = "\x1B[38;5;145m";
7474
+ const GREEN$3 = "\x1B[32m";
7475
+ const RED$2 = "\x1B[31m";
7476
+ async function runPlugin(args, globalOpts) {
7477
+ const sub = args[0];
7478
+ const subArgs = args.slice(1);
7479
+ switch (sub) {
7480
+ case "create":
7481
+ case "new":
7482
+ await createScaffold(subArgs);
7483
+ break;
7484
+ case "validate":
7485
+ await validate(subArgs);
7486
+ break;
7487
+ case "publish":
7488
+ await publish(subArgs, globalOpts);
7489
+ break;
7490
+ case "list":
7491
+ case "ls":
7492
+ await list$1(subArgs, globalOpts);
7493
+ break;
7494
+ case "info":
7495
+ await info$1(subArgs, globalOpts);
7496
+ break;
7497
+ case "install":
7498
+ await install(subArgs, globalOpts);
7499
+ break;
7500
+ case "--help":
7501
+ case "-h":
7502
+ case void 0:
7503
+ showHelp$2();
7504
+ break;
7505
+ default:
7506
+ console.log(`未知 plugin 命令:${sub}`);
7507
+ showHelp$2();
7508
+ }
7509
+ }
7510
+ function showHelp$2() {
7511
+ console.log();
7512
+ console.log(`${BOLD$2}bfi plugin <command>${RESET$4} — Claude Code plugin 管理`);
7513
+ console.log();
7514
+ console.log(`${BOLD$2}Commands:${RESET$4}`);
7515
+ console.log(` create <name> Scaffold a plugin directory (skills/, agents/, hooks/, mcp/)`);
7516
+ console.log(` validate [path] Validate plugin.json and directory layout`);
7517
+ console.log(` publish <path> Publish a plugin to SkillHub`);
7518
+ console.log(` list, ls List plugins on SkillHub`);
7519
+ console.log(` info <id> Show plugin details`);
7520
+ console.log(` install <ref> Install a plugin (SkillHub id or local .zip)`);
7521
+ console.log();
7522
+ }
7523
+ async function createScaffold(args) {
7524
+ const name = args.find((a, i) => i === 0 || args[i - 1] !== "--with" && !a.startsWith("-"));
7525
+ if (!name || name.startsWith("-")) {
7526
+ console.error("用法:bfi plugin create <name> [--with skills agents hooks mcp]");
7527
+ process.exit(1);
7528
+ }
7529
+ const withIdx = args.indexOf("--with");
7530
+ const components = withIdx !== -1 ? args.slice(withIdx + 1) : [];
7531
+ const target = path$1.resolve(name);
7532
+ if (fs.existsSync(path$1.join(target, ".claude-plugin", "plugin.json"))) {
7533
+ console.error(`plugin 已存在:${target}`);
7534
+ process.exit(1);
7535
+ }
7536
+ fs.mkdirSync(path$1.join(target, ".claude-plugin"), { recursive: true });
7537
+ const manifest = {
7538
+ $schema: "https://anthropic.com/claude-code/plugin.schema.json",
7539
+ name: path$1.basename(target),
7540
+ version: "0.1.0",
7541
+ description: "",
7542
+ author: { name: "" },
7543
+ ...components.includes("skills") ? { skills: ["./skills"] } : {}
7544
+ };
7545
+ fs.writeFileSync(path$1.join(target, ".claude-plugin", "plugin.json"), JSON.stringify(manifest, null, 2) + "\n");
7546
+ if (components.includes("skills")) fs.mkdirSync(path$1.join(target, "skills"), { recursive: true });
7547
+ if (components.includes("agents")) fs.mkdirSync(path$1.join(target, "agents"), { recursive: true });
7548
+ if (components.includes("hooks")) {
7549
+ fs.mkdirSync(path$1.join(target, "hooks"), { recursive: true });
7550
+ fs.writeFileSync(path$1.join(target, "hooks", "hooks.json"), JSON.stringify({ hooks: {} }, null, 2) + "\n");
7551
+ }
7552
+ if (components.includes("mcp")) fs.writeFileSync(path$1.join(target, ".mcp.json"), JSON.stringify({ mcpServers: {} }, null, 2) + "\n");
7553
+ console.log(`${GREEN$3}✓${RESET$4} Created plugin ${TEXT$4}${path$1.basename(target)}${RESET$4}`);
7554
+ console.log(` ${DIM$4}${target}${RESET$4}`);
7555
+ }
7556
+ async function validate(args) {
7557
+ const target = path$1.resolve(args[0] ?? ".");
7558
+ const standardManifest = path$1.join(target, ".claude-plugin", "plugin.json");
7559
+ const bfiManifest = path$1.join(target, "plugin.json");
7560
+ const manifestPath = fs.existsSync(standardManifest) ? standardManifest : fs.existsSync(bfiManifest) ? bfiManifest : standardManifest;
7561
+ const isBfiLayout = manifestPath === bfiManifest;
7562
+ const errors = [];
7563
+ const warnings = [];
7564
+ if (!fs.existsSync(manifestPath)) errors.push(`未找到 ${manifestPath}`);
7565
+ else try {
7566
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
7567
+ if (!manifest.name) errors.push("plugin.json 缺少 name 字段");
7568
+ if (!manifest.version) warnings.push("plugin.json 缺少 version 字段");
7569
+ if (!manifest.description) warnings.push("plugin.json 缺少 description 字段");
7570
+ const skillPaths = manifest.skills ?? manifest.provides?.skills ?? [];
7571
+ for (const skillPath of skillPaths) {
7572
+ const normalized = skillPath.startsWith("./") ? skillPath.slice(2) : skillPath;
7573
+ if (!isBfiLayout && !skillPath.startsWith("./")) errors.push(`skills 路径必须以 ./ 开头:${skillPath}`);
7574
+ else if (!fs.existsSync(path$1.join(target, normalized))) errors.push(`skills 路径不存在:${skillPath}`);
7575
+ }
7576
+ } catch (e) {
7577
+ errors.push(`plugin.json 解析失败:${e.message}`);
7578
+ }
7579
+ if (fs.existsSync(path$1.join(target, ".mcp.json"))) try {
7580
+ JSON.parse(fs.readFileSync(path$1.join(target, ".mcp.json"), "utf-8"));
7581
+ } catch (e) {
7582
+ errors.push(`.mcp.json 解析失败:${e.message}`);
7583
+ }
7584
+ if (fs.existsSync(path$1.join(target, "hooks", "hooks.json"))) try {
7585
+ JSON.parse(fs.readFileSync(path$1.join(target, "hooks", "hooks.json"), "utf-8"));
7586
+ } catch (e) {
7587
+ errors.push(`hooks/hooks.json 解析失败:${e.message}`);
7588
+ }
7589
+ for (const error of errors) console.log(`${RED$2}✗${RESET$4} ${error}`);
7590
+ for (const warning of warnings) console.log(`${DIM$4}⚠${RESET$4} ${warning}`);
7591
+ if (errors.length === 0) console.log(`${GREEN$3}✓${RESET$4} Validation passed${warnings.length > 0 ? ` with ${warnings.length} warning(s)` : ""}`);
7592
+ else process.exitCode = 1;
7593
+ }
7594
+ async function publish(args, globalOpts) {
7595
+ const target = args[0];
7596
+ if (!target) {
7597
+ console.error("用法:bfi plugin publish <directory|file.zip|file.tgz>");
7598
+ process.exit(1);
7599
+ }
7600
+ const resolved = path$1.resolve(target);
7601
+ const namespace = getOption$1(args, "--namespace") || globalOpts.namespace || "global";
7602
+ const visibility = getOption$1(args, "--visibility") || "public";
7603
+ const { registry, token } = resolveConfig(globalOpts);
7604
+ if (!token) {
7605
+ console.error("未登录。请先运行:bfi auth login --token <token>");
7606
+ process.exit(1);
7607
+ }
7608
+ const api = new SkillHubAPI(registry, token);
7609
+ if (/\.(tgz|tar\.gz|zip)$/i.test(resolved)) {
7610
+ if (!fs.existsSync(resolved)) {
7611
+ console.error(`文件未找到:${resolved}`);
7612
+ process.exit(1);
7613
+ }
7614
+ console.log(`上传 ${TEXT$4}${path$1.basename(resolved)}${RESET$4} → ${DIM$4}${registry}${RESET$4}`);
7615
+ try {
7616
+ const created = await api.uploadPlugin(fs.readFileSync(resolved), path$1.basename(resolved), namespace, { visibility: visibility.toUpperCase() });
7617
+ const plugin = created?.data ?? created;
7618
+ console.log(`${GREEN$3}✓${RESET$4} Published ${TEXT$4}${plugin.slug}${RESET$4} (id=${plugin.id})`);
7619
+ } catch (e) {
7620
+ console.error(`发布失败:${e.message}`);
7621
+ process.exit(1);
7622
+ }
7623
+ return;
7624
+ }
7625
+ const standardManifest = path$1.join(resolved, ".claude-plugin", "plugin.json");
7626
+ const bfiManifest = path$1.join(resolved, "plugin.json");
7627
+ const manifestPath = fs.existsSync(standardManifest) ? standardManifest : fs.existsSync(bfiManifest) ? bfiManifest : null;
7628
+ if (!manifestPath) {
7629
+ console.error(`不是有效 plugin 目录(缺少 .claude-plugin/plugin.json 或 plugin.json):${resolved}`);
7630
+ process.exit(1);
7631
+ }
7632
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
7633
+ const namespaces = await api.myNamespaces();
7634
+ const ns = (Array.isArray(namespaces) ? namespaces : namespaces?.data ?? []).find((n) => n.slug === namespace);
7635
+ if (!ns) {
7636
+ console.error(`命名空间不存在:${namespace}`);
7637
+ process.exit(1);
7638
+ }
7639
+ const zipBuffer = createZipFromDir(resolved);
7640
+ const versionMatch = manifest.version ?? "0.1.0";
7641
+ console.log(`发布 ${TEXT$4}${manifest.name}@${versionMatch}${RESET$4} → ${DIM$4}${registry}${RESET$4}`);
7642
+ const created = await api.createPlugin({
7643
+ namespaceId: ns.id,
7644
+ slug: manifest.name,
7645
+ displayName: manifest.name,
7646
+ summary: manifest.description ?? "",
7647
+ description: manifest.description ?? "",
7648
+ visibility: visibility.toUpperCase()
7649
+ });
7650
+ const plugin = created?.data ?? created;
7651
+ const version = await api.createPluginVersion(plugin.id, {
7652
+ version: versionMatch,
7653
+ changelog: "Published via bfi plugin publish"
7654
+ });
7655
+ const versionBody = version?.data ?? version;
7656
+ const tmpZip = path$1.join(os$1.tmpdir(), `${manifest.name}-${versionMatch}.zip`);
7657
+ fs.writeFileSync(tmpZip, zipBuffer);
7658
+ console.log(`${GREEN$3}✓${RESET$4} Plugin created (id=${plugin.id}, version=${versionBody.version})`);
7659
+ console.log(` ${DIM$4}zip: ${tmpZip}${RESET$4}`);
7660
+ }
7661
+ async function list$1(_args, globalOpts) {
7662
+ const { registry, token } = resolveConfig(globalOpts);
7663
+ const result = await new SkillHubAPI(registry, token).listPlugins();
7664
+ const plugins = Array.isArray(result) ? result : result?.content ?? result?.data ?? [];
7665
+ if (plugins.length === 0) {
7666
+ console.log("暂无 plugin。");
7667
+ return;
7668
+ }
7669
+ console.log();
7670
+ for (const p of plugins) {
7671
+ console.log(` ${TEXT$4}${p.slug}${RESET$4} ${DIM$4}${p.latestVersionId ? "v" + p.latestVersionId : ""}${RESET$4}`);
7672
+ console.log(` ${p.summary ?? ""}`);
7673
+ console.log(` ${DIM$4}下载 ${p.downloadCount ?? 0} · star ${p.starCount ?? 0}${RESET$4}`);
7674
+ }
7675
+ console.log();
7676
+ }
7677
+ async function info$1(args, globalOpts) {
7678
+ const idArg = args[0];
7679
+ if (!idArg) {
7680
+ console.error("用法:bfi plugin info <pluginId>");
7681
+ process.exit(1);
7682
+ }
7683
+ const { registry, token } = resolveConfig(globalOpts);
7684
+ const plugin = await new SkillHubAPI(registry, token).getPlugin(Number(idArg));
7685
+ console.log();
7686
+ console.log(`${BOLD$2}${plugin.displayName ?? plugin.slug}${RESET$4} (id=${plugin.id})`);
7687
+ console.log(` ${plugin.summary ?? ""}`);
7688
+ console.log(` ${DIM$4}visibility=${plugin.visibility} status=${plugin.status}${RESET$4}`);
7689
+ console.log(` ${DIM$4}下载 ${plugin.downloadCount ?? 0} · star ${plugin.starCount ?? 0}${RESET$4}`);
7690
+ console.log();
7691
+ }
7692
+ async function install(args, globalOpts) {
7693
+ const ref = args[0];
7694
+ if (!ref) {
7695
+ console.error("用法:bfi plugin install <pluginId|./plugin.zip>");
7696
+ process.exit(1);
7697
+ }
7698
+ const homeSkills = path$1.join(os$1.homedir(), ".claude", "skills");
7699
+ if (ref.endsWith(".zip") || fs.existsSync(ref)) {
7700
+ const resolved = path$1.resolve(ref);
7701
+ extractZip(resolved, homeSkills);
7702
+ console.log(`${GREEN$3}✓${RESET$4} Installed from ${resolved}`);
7703
+ console.log(` ${DIM$4}${homeSkills}${RESET$4}`);
7704
+ console.log(` ${DIM$4}重启 Claude Code 会话后生效${RESET$4}`);
7705
+ return;
7706
+ }
7707
+ const { registry, token } = resolveConfig(globalOpts);
7708
+ const api = new SkillHubAPI(registry, token);
7709
+ const plugin = await api.getPlugin(Number(ref));
7710
+ const slug = plugin.slug ?? `plugin-${plugin.id}`;
7711
+ if (!plugin.latestVersionId) {
7712
+ console.error(`插件 ${slug} 尚无已发布版本,无法安装`);
7713
+ process.exit(1);
7714
+ }
7715
+ const tmpZip = path$1.join(os$1.tmpdir(), `${slug}-install.zip`);
7716
+ console.log(`下载 ${TEXT$4}${slug}${RESET$4} ← ${DIM$4}${registry}${RESET$4}`);
7717
+ await api.downloadPluginBundle(plugin.id, plugin.latestVersionId, tmpZip);
7718
+ extractZip(tmpZip, homeSkills);
7719
+ fs.unlinkSync(tmpZip);
7720
+ console.log(`${GREEN$3}✓${RESET$4} Installed ${TEXT$4}${slug}${RESET$4}`);
7721
+ console.log(` ${DIM$4}${homeSkills}${RESET$4}`);
7722
+ console.log(` ${DIM$4}重启 Claude Code 会话后生效${RESET$4}`);
7723
+ }
7724
+ function getOption$1(args, flag) {
7725
+ const idx = args.indexOf(flag);
7726
+ return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
7727
+ }
7728
+ const RESET$3 = "\x1B[0m";
7729
+ const BOLD$1 = "\x1B[1m";
7730
+ const DIM$3 = "\x1B[38;5;102m";
7731
+ const TEXT$3 = "\x1B[38;5;145m";
7732
+ const GREEN$2 = "\x1B[32m";
7733
+ const RED$1 = "\x1B[31m";
7734
+ async function runMcp(args, globalOpts) {
7735
+ const sub = args[0];
7736
+ const subArgs = args.slice(1);
7737
+ switch (sub) {
7738
+ case "list":
7739
+ case "ls":
7740
+ await list(subArgs, globalOpts);
7741
+ break;
7742
+ case "info":
7743
+ await info(subArgs, globalOpts);
7744
+ break;
7745
+ case "config":
7746
+ await config(subArgs, globalOpts);
7747
+ break;
7748
+ case "add":
7749
+ await add(subArgs, globalOpts);
7750
+ break;
7751
+ case "remove":
7752
+ case "rm":
7753
+ await remove(subArgs);
7754
+ break;
7755
+ case "--help":
7756
+ case "-h":
7757
+ case void 0:
7758
+ showHelp$1();
7759
+ break;
7760
+ default:
7761
+ console.log(`未知 mcp 命令:${sub}`);
7762
+ showHelp$1();
7763
+ }
7764
+ }
7765
+ function showHelp$1() {
7766
+ console.log();
7767
+ console.log(`${BOLD$1}bfi mcp <command>${RESET$3} — MCP 服务器管理`);
7768
+ console.log();
7769
+ console.log(`${BOLD$1}Commands:${RESET$3}`);
7770
+ console.log(` list, ls List MCP servers on SkillHub`);
7771
+ console.log(` info <id> Show MCP server details`);
7772
+ console.log(` config <id> Print .mcp.json config fragment`);
7773
+ console.log(` add <id> Write server into local .mcp.json (user scope)`);
7774
+ console.log(` remove <name> Remove a server from local .mcp.json`);
7775
+ console.log();
7776
+ }
7777
+ async function list(_args, globalOpts) {
7778
+ const { registry, token } = resolveConfig(globalOpts);
7779
+ const result = await new SkillHubAPI(registry, token).listMcpServers();
7780
+ const servers = Array.isArray(result) ? result : result?.content ?? result?.data ?? [];
7781
+ if (servers.length === 0) {
7782
+ console.log("暂无 MCP 服务器。");
7783
+ return;
7784
+ }
7785
+ console.log();
7786
+ for (const s of servers) {
7787
+ console.log(` ${TEXT$3}${s.slug}${RESET$3} ${DIM$3}[${s.transportType}]${RESET$3}`);
7788
+ console.log(` ${s.summary ?? ""}`);
7789
+ console.log(` ${DIM$3}下载 ${s.downloadCount ?? 0} · star ${s.starCount ?? 0}${RESET$3}`);
7790
+ }
7791
+ console.log();
7792
+ }
7793
+ async function info(args, globalOpts) {
7794
+ const idArg = args[0];
7795
+ if (!idArg) {
7796
+ console.error("用法:bfi mcp info <mcpId>");
7030
7797
  process.exit(1);
7031
7798
  }
7799
+ const { registry, token } = resolveConfig(globalOpts);
7800
+ const server = await new SkillHubAPI(registry, token).getMcpServer(Number(idArg));
7801
+ console.log();
7802
+ console.log(`${BOLD$1}${server.displayName ?? server.slug}${RESET$3} (id=${server.id})`);
7803
+ console.log(` transport: ${server.transportType}`);
7804
+ if (server.serverUrl) console.log(` url: ${server.serverUrl}`);
7805
+ if (server.command) console.log(` command: ${server.command}`);
7806
+ console.log(` ${DIM$3}visibility=${server.visibility} status=${server.status}${RESET$3}`);
7807
+ console.log();
7032
7808
  }
7033
- async function handleRemoveSkills(args, api, globalOpts) {
7034
- const pkgRef = args[0];
7035
- const skillRefs = args.slice(1);
7036
- if (!pkgRef) {
7037
- console.error("用法:bfi skills package remove-skills <package-ref> [skill-ref...]");
7038
- console.error(" 不指定技能时,移除包中全部技能");
7809
+ async function config(args, globalOpts) {
7810
+ const idArg = args[0];
7811
+ if (!idArg) {
7812
+ console.error("用法:bfi mcp config <mcpId>");
7039
7813
  process.exit(1);
7040
7814
  }
7041
- const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7042
- let skills;
7043
- if (skillRefs.length === 0) try {
7044
- const pkgInfo = await api.getPackage(namespace, slug);
7045
- skills = ((pkgInfo.data || pkgInfo).skills || []).map((s) => ({
7046
- namespace: s.namespace || namespace,
7047
- slug: s.slug
7048
- }));
7049
- if (skills.length === 0) {
7050
- console.log("包中没有技能。");
7051
- return;
7052
- }
7053
- } catch (error) {
7054
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7815
+ const { registry, token } = resolveConfig(globalOpts);
7816
+ const configJson = await new SkillHubAPI(registry, token).getMcpConfig(Number(idArg));
7817
+ console.log(configJson);
7818
+ }
7819
+ async function add(args, globalOpts) {
7820
+ const idArg = args[0];
7821
+ if (!idArg) {
7822
+ console.error("用法:bfi mcp add <mcpId>");
7055
7823
  process.exit(1);
7056
7824
  }
7057
- else skills = skillRefs.map((ref) => {
7058
- const { namespace: ns, slug: s } = parseSkillRef(ref, namespace);
7059
- return {
7060
- namespace: ns,
7061
- slug: s
7062
- };
7063
- });
7064
- try {
7065
- await api.removeSkillsFromPackage(namespace, slug, skills);
7066
- console.log(`${GREEN$2}✓ 已从包移除 ${skills.length} 个技能${RESET$3}`);
7067
- } catch (error) {
7068
- console.error(`${RED$1}移除失败:${error.message}${RESET$3}`);
7825
+ const { registry, token } = resolveConfig(globalOpts);
7826
+ const api = new SkillHubAPI(registry, token);
7827
+ const server = await api.getMcpServer(Number(idArg));
7828
+ const configJson = JSON.parse(await api.getMcpConfig(Number(idArg)));
7829
+ const mcpPath = resolveMcpPath(getOption(args, "--scope") ?? "user");
7830
+ let existing = { mcpServers: {} };
7831
+ if (fs.existsSync(mcpPath)) {
7832
+ existing = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
7833
+ if (!existing.mcpServers) existing.mcpServers = {};
7834
+ }
7835
+ const serverName = server.slug ?? `mcp-${server.id}`;
7836
+ existing.mcpServers[serverName] = configJson.mcpServers[Object.keys(configJson.mcpServers)[0]];
7837
+ fs.mkdirSync(path$1.dirname(mcpPath), { recursive: true });
7838
+ fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + "\n");
7839
+ console.log(`${GREEN$2}✓${RESET$3} Added ${TEXT$3}${serverName}${RESET$3} → ${DIM$3}${mcpPath}${RESET$3}`);
7840
+ }
7841
+ async function remove(args) {
7842
+ const name = args[0];
7843
+ if (!name) {
7844
+ console.error("用法:bfi mcp remove <name> [--scope user|project|local]");
7069
7845
  process.exit(1);
7070
7846
  }
7071
- }
7072
- async function handleServerInfo(args, api, globalOpts) {
7073
- const pkgRef = args[0];
7074
- if (!pkgRef) {
7075
- console.error("用法:bfi skills package info <package-ref>");
7847
+ const mcpPath = resolveMcpPath(getOption(args, "--scope") ?? "user");
7848
+ if (!fs.existsSync(mcpPath)) {
7849
+ console.error(`配置文件不存在:${mcpPath}`);
7076
7850
  process.exit(1);
7077
7851
  }
7078
- const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7079
- const json = args.includes("--json");
7080
- try {
7081
- const result = await api.getPackage(namespace, slug);
7082
- const pkg = result.data || result;
7083
- if (json) {
7084
- console.log(JSON.stringify(pkg, null, 2));
7085
- return;
7086
- }
7087
- console.log(`\n${BOLD$1}${pkg.displayName || pkg.name || slug}${RESET$3}`);
7088
- console.log(`${DIM$3}${"=".repeat(48)}${RESET$3}`);
7089
- console.log(` ${BOLD$1}Slug:${RESET$3} ${toCanonicalSlug(namespace, slug)}`);
7090
- console.log(` ${BOLD$1}命名空间:${RESET$3} @${namespace}`);
7091
- console.log(` ${BOLD$1}可见性:${RESET$3} ${pkg.visibility || "PRIVATE"}`);
7092
- const skills = pkg.skills || [];
7093
- if (skills.length > 0) {
7094
- console.log(`\n ${BOLD$1}技能(${skills.length} 个):${RESET$3}`);
7095
- for (const s of skills) console.log(` ${DIM$3}- ${s.displayName || s.slug} (${s.namespace || namespace}--${s.slug})${RESET$3}`);
7096
- }
7097
- console.log();
7098
- } catch (error) {
7099
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7852
+ const existing = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
7853
+ if (!existing.mcpServers?.[name]) {
7854
+ console.error(`${RED$1}未找到服务器:${name}${RESET$3}`);
7100
7855
  process.exit(1);
7101
7856
  }
7857
+ delete existing.mcpServers[name];
7858
+ fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + "\n");
7859
+ console.log(`${GREEN$2}✓${RESET$3} Removed ${TEXT$3}${name}${RESET$3}`);
7102
7860
  }
7103
- function getOptionValue(args, flag) {
7861
+ function resolveMcpPath(scope) {
7862
+ switch (scope) {
7863
+ case "project": return path$1.join(process.cwd(), ".mcp.json");
7864
+ case "local": return path$1.join(process.cwd(), ".claude", ".mcp.json.local");
7865
+ default: return path$1.join(os$1.homedir(), ".claude", ".mcp.json");
7866
+ }
7867
+ }
7868
+ function getOption(args, flag) {
7104
7869
  const idx = args.indexOf(flag);
7105
- return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
7870
+ return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
7106
7871
  }
7107
7872
  const RESET$2 = "\x1B[0m";
7108
7873
  const DIM$2 = "\x1B[38;5;102m";
@@ -7217,6 +7982,735 @@ async function runInstall(args, globalOpts) {
7217
7982
  if (failedCount > 0) console.log(`${YELLOW}⚠ ${failedCount} 项恢复失败${RESET$1}`);
7218
7983
  console.log();
7219
7984
  }
7985
+ const YMC_DEFAULT_BASE = process.env.BFI_YMC_BASE || "http://172.20.35.178:8901/bficli/api/v2";
7986
+ var YmcApi = class {
7987
+ baseUrl;
7988
+ token;
7989
+ constructor(token = null, baseUrl) {
7990
+ this.baseUrl = (baseUrl || YMC_DEFAULT_BASE).replace(/\/$/, "");
7991
+ if (token) {
7992
+ this.token = token;
7993
+ return;
7994
+ }
7995
+ this.token = loadGlobalConfig()?.token ?? null;
7996
+ }
7997
+ async call(path, body = {}, timeoutMs = 9e4) {
7998
+ const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
7999
+ const payload = JSON.stringify(body);
8000
+ const mod = url.startsWith("https://") ? https : http;
8001
+ const raw = await new Promise((resolve, reject) => {
8002
+ const req = mod.request(url, {
8003
+ method: "POST",
8004
+ headers: {
8005
+ "Content-Type": "application/json",
8006
+ Accept: "application/json",
8007
+ ...this.token ? { Authorization: `Bearer ${this.token}` } : {},
8008
+ "Content-Length": Buffer.byteLength(payload)
8009
+ },
8010
+ timeout: timeoutMs
8011
+ }, (res) => {
8012
+ const chunks = [];
8013
+ res.on("data", (c) => chunks.push(c));
8014
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
8015
+ });
8016
+ req.on("timeout", () => {
8017
+ req.destroy(/* @__PURE__ */ new Error(`请求超时(${timeoutMs}ms)`));
8018
+ });
8019
+ req.on("error", reject);
8020
+ req.write(payload);
8021
+ req.end();
8022
+ });
8023
+ let parsed;
8024
+ try {
8025
+ parsed = JSON.parse(raw);
8026
+ } catch {
8027
+ throw new Error(`非 JSON 响应(HTTP):${raw.slice(0, 200)}`);
8028
+ }
8029
+ if (parsed.detail && parsed.code === void 0) throw new Error(String(parsed.detail));
8030
+ return {
8031
+ code: typeof parsed.code === "number" ? parsed.code : -1,
8032
+ msg: String(parsed.msg ?? ""),
8033
+ data: parsed.data ?? null,
8034
+ raw: parsed
8035
+ };
8036
+ }
8037
+ async download(path, body, outFile, timeoutMs = 18e4) {
8038
+ const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
8039
+ const payload = JSON.stringify(body);
8040
+ const mod = url.startsWith("https://") ? https : http;
8041
+ const raw = await new Promise((resolve, reject) => {
8042
+ const req = mod.request(url, {
8043
+ method: "POST",
8044
+ headers: {
8045
+ "Content-Type": "application/json",
8046
+ Accept: "*/*",
8047
+ Authorization: `Bearer ${this.token}`,
8048
+ "Content-Length": Buffer.byteLength(payload)
8049
+ },
8050
+ timeout: timeoutMs
8051
+ }, (res) => {
8052
+ const chunks = [];
8053
+ res.on("data", (c) => chunks.push(c));
8054
+ res.on("end", () => resolve(Buffer.concat(chunks)));
8055
+ });
8056
+ req.on("timeout", () => {
8057
+ req.destroy(/* @__PURE__ */ new Error(`下载超时(${timeoutMs}ms)`));
8058
+ });
8059
+ req.on("error", reject);
8060
+ req.write(payload);
8061
+ req.end();
8062
+ });
8063
+ if (raw.length > 0 && raw[0] === 123) {
8064
+ const msg = JSON.parse(raw.toString("utf-8"));
8065
+ throw new Error(String(msg.msg ?? "下载失败"));
8066
+ }
8067
+ (await import("fs")).writeFileSync(outFile, raw);
8068
+ return raw.length;
8069
+ }
8070
+ async get(path, timeoutMs = 3e4) {
8071
+ const url = `${this.baseUrl}/${path.replace(/^\//, "")}`;
8072
+ const mod = url.startsWith("https://") ? https : http;
8073
+ const raw = await new Promise((resolve, reject) => {
8074
+ const req = mod.request(url, {
8075
+ method: "GET",
8076
+ headers: {
8077
+ Accept: "application/json",
8078
+ ...this.token ? { Authorization: `Bearer ${this.token}` } : {}
8079
+ },
8080
+ timeout: timeoutMs
8081
+ }, (res) => {
8082
+ const chunks = [];
8083
+ res.on("data", (c) => chunks.push(c));
8084
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
8085
+ });
8086
+ req.on("timeout", () => {
8087
+ req.destroy(/* @__PURE__ */ new Error(`请求超时(${timeoutMs}ms)`));
8088
+ });
8089
+ req.on("error", reject);
8090
+ req.end();
8091
+ });
8092
+ const parsed = JSON.parse(raw);
8093
+ if (parsed.detail && parsed.code === void 0) throw new Error(String(parsed.detail));
8094
+ return {
8095
+ code: typeof parsed.code === "number" ? parsed.code : -1,
8096
+ msg: String(parsed.msg ?? ""),
8097
+ data: parsed.data ?? null,
8098
+ raw: parsed
8099
+ };
8100
+ }
8101
+ };
8102
+ function opt(args, ...names) {
8103
+ for (const name of names) {
8104
+ const idx = args.indexOf(name);
8105
+ if (idx !== -1 && idx + 1 < args.length) return args[idx + 1];
8106
+ const eq = args.find((a) => a.startsWith(`${name}=`));
8107
+ if (eq) return eq.slice(name.length + 1);
8108
+ }
8109
+ }
8110
+ function flag(args, ...names) {
8111
+ return names.some((n) => args.includes(n));
8112
+ }
8113
+ function positionals(args) {
8114
+ const out = [];
8115
+ for (let i = 0; i < args.length; i++) {
8116
+ if (args[i].startsWith("-")) {
8117
+ if (!args[i].includes("=") && i + 1 < args.length && !args[i + 1].startsWith("-")) i++;
8118
+ continue;
8119
+ }
8120
+ out.push(args[i]);
8121
+ }
8122
+ return out;
8123
+ }
8124
+ function emit(result, jsonMode, summarize) {
8125
+ if (jsonMode) {
8126
+ console.log(JSON.stringify(result.raw, null, 2));
8127
+ return;
8128
+ }
8129
+ if (result.code !== 0) {
8130
+ console.error(`✗ ${result.msg || "请求失败"}`);
8131
+ process.exit(1);
8132
+ }
8133
+ console.log(summarize ? summarize(result.data) : JSON.stringify(result.data, null, 2));
8134
+ }
8135
+ function raw0(text) {
8136
+ return text || "{}";
8137
+ }
8138
+ const ENV_DOC = "环境: test/daily/pre/core1-4/commldev";
8139
+ function requireEnv(args) {
8140
+ const env = opt(args, "-e", "--env", "--env-name");
8141
+ if (!env) {
8142
+ console.error(`缺少环境参数:-e <${ENV_DOC}>`);
8143
+ process.exit(1);
8144
+ }
8145
+ return { env_name: env };
8146
+ }
8147
+ function timeOf(args, required = true) {
8148
+ const t = opt(args, "-t", "--time");
8149
+ if (!t && required) {
8150
+ console.error("缺少时间参数:-t <简写>(如 1h/3d/10m/4w,表示过去 N 单位到现在)");
8151
+ process.exit(1);
8152
+ }
8153
+ return t ? { time: t } : {};
8154
+ }
8155
+ function timeOpts(args) {
8156
+ const out = {};
8157
+ const t = opt(args, "-t", "--time");
8158
+ if (t) out.time = t;
8159
+ const st = opt(args, "--start-time");
8160
+ if (st) out.start_time = st;
8161
+ const et = opt(args, "--end-time");
8162
+ if (et) out.end_time = et;
8163
+ return out;
8164
+ }
8165
+ function requireToken(api) {
8166
+ if (!api.token) {
8167
+ console.error("未认证。先运行:bfi auth login --token <sk-token>(或传 --token)");
8168
+ process.exit(1);
8169
+ }
8170
+ }
8171
+ function rowsSummary(label) {
8172
+ return (data) => {
8173
+ const d = data;
8174
+ const rows = d.rows ?? d;
8175
+ return `✓ ${label}: ${Array.isArray(rows) ? rows.length : 0} 条`;
8176
+ };
8177
+ }
8178
+ async function runYmc(args, globalOpts) {
8179
+ const sub = args[0];
8180
+ const rest = args.slice(1);
8181
+ const jsonMode = flag(rest, "--json");
8182
+ const token = globalOpts.token;
8183
+ const api = new YmcApi(token ?? null);
8184
+ requireToken(api);
8185
+ if (!sub || sub === "--help" || sub === "-h") {
8186
+ printHelp();
8187
+ return;
8188
+ }
8189
+ switch (sub) {
8190
+ case "status":
8191
+ emit(await api.get("ymc/auth/status"), jsonMode, (data) => {
8192
+ const s = data;
8193
+ const line = (g) => {
8194
+ const x = s[g];
8195
+ if (!x?.logged_in) return `${g}: 未登录`;
8196
+ return `${g}: 已登录(至 ${(/* @__PURE__ */ new Date(Number(x.expires_at) * 1e3)).toLocaleString("zh-CN")})`;
8197
+ };
8198
+ return `${line("dev")}\n${line("prod")}`;
8199
+ });
8200
+ break;
8201
+ case "trace": {
8202
+ const id = positionals(rest)[0];
8203
+ if (!id) {
8204
+ console.error("用法:bfi ymc trace <trace_id> -e <env>");
8205
+ process.exit(1);
8206
+ }
8207
+ emit(await api.call("trace", {
8208
+ trace_id: id,
8209
+ ...requireEnv(rest)
8210
+ }), jsonMode, (data) => {
8211
+ const d = data;
8212
+ const lines = [];
8213
+ const wc = d.warning_chain;
8214
+ const s = wc?.Summary ?? {};
8215
+ lines.push(`✓ 三源查询完成 ts=${d.ts}(${d.ts_source})`);
8216
+ lines.push(`概览: span=${s.TraceCount ?? "?"} 异常=${s.AppExceptionCount ?? 0} 最大耗时=${s.MaxCostTime ?? "?"}ms 慢调用告警=${s.WarningCallCount ?? 0} 慢SQL告警=${s.WarningSqlCount ?? 0}`);
8217
+ const mw = wc?.MWSummary ?? [];
8218
+ if (Array.isArray(mw) && mw.length) lines.push("Top慢span: " + mw.slice().sort((a, b) => Number(b.CostTime ?? 0) - Number(a.CostTime ?? 0)).slice(0, 3).map((x) => `${x.CurAppCode}=${x.CostTime}ms(sql${x.SqlNum}/rpc${x.RpcCount})`).join(" | "));
8219
+ const ae = wc?.AppException ?? [];
8220
+ if (Array.isArray(ae) && ae.length) {
8221
+ const first = ae[0];
8222
+ const le = first.LogEntry ?? {};
8223
+ const msg = String(le.Message ?? "").replace(/\s+/g, " ").slice(0, 180);
8224
+ lines.push(`异常[0]: ${first.AppCode} ${le.Logger ?? ""}\n ${msg}`);
8225
+ }
8226
+ const ing = d.ingress_logs ?? [];
8227
+ if (Array.isArray(ing) && ing.length) {
8228
+ const st = ing.reduce((m, x) => {
8229
+ const k = String(x.status);
8230
+ m[k] = (m[k] ?? 0) + 1;
8231
+ return m;
8232
+ }, {});
8233
+ lines.push(`ingress: ${ing.length} 条 ${JSON.stringify(st)} 入口=${(ing[0].url ?? "?").toString().slice(0, 60)}`);
8234
+ }
8235
+ return lines.join("\n");
8236
+ });
8237
+ break;
8238
+ }
8239
+ case "chain": {
8240
+ const id = positionals(rest)[0];
8241
+ if (!id) {
8242
+ console.error("用法:bfi ymc chain <trace_id> -e <env>");
8243
+ process.exit(1);
8244
+ }
8245
+ emit(await api.call("chain", {
8246
+ trace_id: id,
8247
+ ...requireEnv(rest)
8248
+ }), jsonMode, (data) => {
8249
+ const d = data;
8250
+ return `✓ 链路查询: ts=${d.ts}(${d.ts_source})chain=${d.warning_chain ? "有" : "无"}`;
8251
+ });
8252
+ break;
8253
+ }
8254
+ case "sls-raw": {
8255
+ const query = positionals(rest)[0];
8256
+ if (!query) {
8257
+ console.error("用法:bfi ymc sls-raw \"<查询语句>\" -e <env> [-t time | --start-time <s> --end-time <e> | --days N] [--line N]");
8258
+ console.error("例:bfi ymc sls-raw '* | SELECT applicationName, count(*) AS c GROUP BY applicationName' -e daily -t 3d");
8259
+ console.error("例:bfi ymc sls-raw '* | SELECT * WHERE level=''ERROR''' -e pre --start-time \"2026-08-31 15:00:00\" --end-time \"2026-08-31 16:00:00\"");
8260
+ console.error("说明:--start-time/--end-time(yyyy-MM-dd HH:mm:ss 北京时间)为精确窗口,优先于 -t/--days");
8261
+ process.exit(1);
8262
+ }
8263
+ const body = {
8264
+ query,
8265
+ ...requireEnv(rest),
8266
+ ...timeOpts(rest),
8267
+ ...opt(rest, "--days") ? { days: Number(opt(rest, "--days")) } : {},
8268
+ ...opt(rest, "--line") ? { line: Number(opt(rest, "--line")) } : {}
8269
+ };
8270
+ emit(await api.call("sls/raw", body), jsonMode, rowsSummary("SLS 原始查询"));
8271
+ break;
8272
+ }
8273
+ case "sls-grep": {
8274
+ const kw = positionals(rest)[0];
8275
+ if (!kw) {
8276
+ console.error("用法:bfi ymc sls-grep \"<关键词>\" -e <env> [-t time] [--group-by applicationName|message|requestURL]");
8277
+ console.error("例:bfi ymc sls-grep \"ClassCastException\" -e daily -t 3d");
8278
+ console.error("⚠️ 输出为聚合统计行(每组计数,计数上限 100,可能被封顶)——非明细。");
8279
+ console.error(" 需要真实条数/明细/精确时间窗时改用 sls-raw + GROUP BY + --start-time/--end-time");
8280
+ process.exit(1);
8281
+ }
8282
+ const groupBy = opt(rest, "--group-by") || "applicationName";
8283
+ const query = `"${kw.replace(/"/g, "")}" | SELECT ${groupBy}, count(*) AS count GROUP BY ${groupBy} ORDER BY count DESC`;
8284
+ emit(await api.call("sls/raw", {
8285
+ query,
8286
+ ...requireEnv(rest),
8287
+ ...timeOf(rest, false),
8288
+ line: Number(opt(rest, "--line") || 50)
8289
+ }), jsonMode, rowsSummary(`SLS 全文检索 "${kw}"`));
8290
+ break;
8291
+ }
8292
+ case "sls-logs": {
8293
+ const id = positionals(rest)[0];
8294
+ if (!id) {
8295
+ console.error("用法:bfi ymc sls-logs <trace_id> -e <env>");
8296
+ process.exit(1);
8297
+ }
8298
+ emit(await api.call("sls/logs", {
8299
+ trace_id: id,
8300
+ ...requireEnv(rest)
8301
+ }), jsonMode, rowsSummary("SLS 日志"));
8302
+ break;
8303
+ }
8304
+ case "slowsql": {
8305
+ const body = {
8306
+ ...requireEnv(rest),
8307
+ ...timeOpts(rest),
8308
+ page: Number(opt(rest, "--page") || 1),
8309
+ pageSize: Number(opt(rest, "--page-size") || 20)
8310
+ };
8311
+ for (const [k, name] of [
8312
+ ["sqlStr", "--sql-str"],
8313
+ ["md5Sql", "--md5"],
8314
+ ["traceId", "--trace-id"],
8315
+ ["curAppCode", "--app"],
8316
+ ["enableProfiler", "--profiler"]
8317
+ ]) {
8318
+ const v = opt(rest, name);
8319
+ if (v) body[k] = v;
8320
+ }
8321
+ emit(await api.call("ymc/warningSql", body), jsonMode, rowsSummary("慢 SQL"));
8322
+ break;
8323
+ }
8324
+ case "slowcall": {
8325
+ const body = {
8326
+ ...requireEnv(rest),
8327
+ ...timeOpts(rest),
8328
+ page: Number(opt(rest, "--page") || 1),
8329
+ pageSize: Number(opt(rest, "--page-size") || 20)
8330
+ };
8331
+ for (const [k, name] of [
8332
+ ["traceId", "--trace-id"],
8333
+ ["curAppCode", "--app"],
8334
+ ["remoteCallMethod", "--method"],
8335
+ ["enableProfiler", "--profiler"]
8336
+ ]) {
8337
+ const v = opt(rest, name);
8338
+ if (v) body[k] = v;
8339
+ }
8340
+ const cost = opt(rest, "--min-cost");
8341
+ if (cost) body.costTime = [Number(cost), 999999];
8342
+ emit(await api.call("ymc/warningCall", body), jsonMode, rowsSummary("慢调用"));
8343
+ break;
8344
+ }
8345
+ case "exceptions": {
8346
+ const body = {
8347
+ ...requireEnv(rest),
8348
+ ...timeOpts(rest),
8349
+ appCode: opt(rest, "--app") || ""
8350
+ };
8351
+ emit(await api.call("ymc/exceptionHistory", body), jsonMode, rowsSummary("异常聚合"));
8352
+ break;
8353
+ }
8354
+ case "alerts": {
8355
+ const body = {
8356
+ ...requireEnv(rest),
8357
+ ...timeOpts(rest),
8358
+ pageSize: Number(opt(rest, "--page-size") || 10),
8359
+ ...opt(rest, "--level") ? { level: opt(rest, "--level") } : {}
8360
+ };
8361
+ emit(await api.call("ymc/alert/detail", body), jsonMode, rowsSummary("告警"));
8362
+ break;
8363
+ }
8364
+ case "url-stats": {
8365
+ const uri = positionals(rest)[0];
8366
+ if (!uri) {
8367
+ console.error("用法:bfi ymc url-stats </uri> -e <env> [-t <time> | --start-time <t> [--end-time <t>]]");
8368
+ process.exit(1);
8369
+ }
8370
+ emit(await api.call("kibana/stats", {
8371
+ uri,
8372
+ ...requireEnv(rest),
8373
+ ...timeOpts(rest)
8374
+ }), jsonMode, (data) => {
8375
+ const d = data;
8376
+ const a = d.aggs;
8377
+ return `✓ URL 统计: QPS=${a.qps} avg=${a.avg_rt?.value ?? "-"} 慢请求Top=${Array.isArray(d.slow_top) ? d.slow_top.length : 0}`;
8378
+ });
8379
+ break;
8380
+ }
8381
+ case "ingress": {
8382
+ const body = {
8383
+ ...requireEnv(rest),
8384
+ ...timeOpts(rest),
8385
+ size: Number(opt(rest, "--size") || 100)
8386
+ };
8387
+ const id = opt(rest, "--trace-id");
8388
+ const uri = opt(rest, "--uri");
8389
+ if (id) body.trace_id = id;
8390
+ else if (uri) {
8391
+ body.uri = uri;
8392
+ body.fuzzy = !flag(rest, "--exact");
8393
+ } else {
8394
+ console.error("用法:bfi ymc ingress --trace-id <id> | --uri </path> -e <env> [-t time]");
8395
+ process.exit(1);
8396
+ }
8397
+ emit(await api.call("kibana/search", body), jsonMode, rowsSummary("ingress 日志"));
8398
+ break;
8399
+ }
8400
+ case "dump-list": {
8401
+ const body = {
8402
+ ...requireEnv(rest),
8403
+ ...timeOpts(rest),
8404
+ monitorType: opt(rest, "--type") || "profiler",
8405
+ appIdList: opt(rest, "--app") ? [opt(rest, "--app")] : []
8406
+ };
8407
+ emit(await api.call("ymc/tool/list", body), jsonMode, rowsSummary("诊断文件"));
8408
+ break;
8409
+ }
8410
+ case "cases": {
8411
+ const sub2 = rest[0] || "search";
8412
+ const rest2 = rest.slice(1);
8413
+ if (sub2 === "search") {
8414
+ const body = {};
8415
+ for (const [k, name] of [
8416
+ ["type", "--type"],
8417
+ ["fingerprint", "--finger"],
8418
+ ["service", "--service"],
8419
+ ["keyword", "--kw"]
8420
+ ]) {
8421
+ const v = opt(rest2, name);
8422
+ if (v) body[k] = v;
8423
+ }
8424
+ if (opt(rest2, "--limit")) body.limit = Number(opt(rest2, "--limit"));
8425
+ emit(await api.call("cases/search", body), jsonMode, (data) => {
8426
+ const d = data;
8427
+ const list = d.cases || [];
8428
+ if (!list.length) return "(无命中案例)";
8429
+ return `✓ 命中 ${d.count} 条:\n` + list.map((x) => ` [${x.case_id}] (${x.type}/${x.confidence}) ${x.title}\n 指纹: ${JSON.stringify(x.fingerprint)} ${x.env || ""} ${x.service || ""} by ${x.author}`).join("\n");
8430
+ });
8431
+ } else if (sub2 === "show") {
8432
+ const id = positionals(rest2)[0];
8433
+ if (!id) {
8434
+ console.error("用法:bfi ymc cases show <case_id>");
8435
+ process.exit(1);
8436
+ }
8437
+ emit(await api.get(`cases/${id}`), jsonMode);
8438
+ } else if (sub2 === "upload") {
8439
+ const file = opt(rest2, "--file");
8440
+ if (!file) {
8441
+ console.error("用法:bfi ymc cases upload --file <case.md> [--type] [--finger \"a,b\"] [--env] [--service]");
8442
+ process.exit(1);
8443
+ }
8444
+ const { readFileSync } = await import("node:fs");
8445
+ const body = {
8446
+ type: opt(rest2, "--type") || "review",
8447
+ fingerprint: (opt(rest2, "--finger") || "").split(",").map((s) => s.trim()).filter(Boolean),
8448
+ content: readFileSync(file, "utf-8")
8449
+ };
8450
+ for (const [k, name] of [
8451
+ ["env", "--env"],
8452
+ ["service", "--service"],
8453
+ ["confidence", "--confidence"],
8454
+ ["title", "--title"]
8455
+ ]) {
8456
+ const v = opt(rest2, name);
8457
+ if (v) body[k] = v;
8458
+ }
8459
+ emit(await api.call("cases", body), jsonMode, (data) => `✓ 案例已上传: ${data.case_id}`);
8460
+ } else if (sub2 === "index") emit(await api.get("cases/index/overview"), jsonMode, (data) => {
8461
+ const d = data;
8462
+ const byType = Object.entries(d.by_type || {}).map(([k, v]) => `${k}=${v}`).join(", ");
8463
+ const fps = (d.top_fingerprints || []).map((x) => `${x.fingerprint}(${x.count})`).join(", ");
8464
+ return `✓ 案例总数: ${d.total}\n 类型分布: ${byType}\n 高频指纹: ${fps}`;
8465
+ });
8466
+ else {
8467
+ console.error("用法:bfi ymc cases <search|show|upload|index>");
8468
+ process.exit(1);
8469
+ }
8470
+ break;
8471
+ }
8472
+ case "wiki": {
8473
+ const sub2 = rest[0] || "search";
8474
+ const rest2 = rest.slice(1);
8475
+ const searchBase = (process.env.BFI_WIKI_BASE || YMC_DEFAULT_BASE.replace(/\/api\/v2$/, "/api/v1")) + "/search/";
8476
+ if (sub2 === "search") {
8477
+ const kw = positionals(rest2)[0];
8478
+ if (!kw) {
8479
+ console.error("用法:bfi ymc wiki search \"<关键词>\" [--source confluence|jira|ecfile] [--limit N] [--titles]");
8480
+ process.exit(1);
8481
+ }
8482
+ const body = {
8483
+ query: kw,
8484
+ limit: Number(opt(rest2, "--limit") || 20)
8485
+ };
8486
+ const src = opt(rest2, "--source");
8487
+ if (src) body.sources = [src];
8488
+ if (flag(rest2, "--titles")) body.titles_only = true;
8489
+ const resp = await new Promise((resolve, reject) => {
8490
+ const mod = searchBase.startsWith("https://") ? https : http;
8491
+ const payload = JSON.stringify(body);
8492
+ const req = mod.request(searchBase + "unified", {
8493
+ method: "POST",
8494
+ headers: {
8495
+ "Content-Type": "application/json",
8496
+ Accept: "application/json",
8497
+ "Content-Length": Buffer.byteLength(payload)
8498
+ },
8499
+ timeout: 6e4
8500
+ }, (res) => {
8501
+ const chunks = [];
8502
+ res.on("data", (c) => chunks.push(c));
8503
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
8504
+ });
8505
+ req.on("timeout", () => req.destroy(/* @__PURE__ */ new Error("超时")));
8506
+ req.on("error", reject);
8507
+ req.write(payload);
8508
+ req.end();
8509
+ });
8510
+ if (jsonMode) {
8511
+ console.log(JSON.stringify(JSON.parse(raw0(resp)), null, 2));
8512
+ break;
8513
+ }
8514
+ const parsed = JSON.parse(raw0(resp));
8515
+ if (parsed.code !== 0) {
8516
+ console.error(`✗ ${parsed.msg}`);
8517
+ process.exit(1);
8518
+ }
8519
+ console.log(JSON.stringify(parsed.data, null, 2));
8520
+ } else if (sub2 === "show") {
8521
+ const id = positionals(rest2)[0];
8522
+ const sourceName = opt(rest2, "--source") || "gfjira";
8523
+ if (!id) {
8524
+ console.error("用法:bfi ymc wiki show <id> [--source wiki|uap-wiki|gfwiki|gfjira|ecfile]");
8525
+ process.exit(1);
8526
+ }
8527
+ const resp = await new Promise((resolve, reject) => {
8528
+ const mod = searchBase.startsWith("https://") ? https : http;
8529
+ const payload = JSON.stringify({
8530
+ source_name: sourceName,
8531
+ id,
8532
+ offset: 0
8533
+ });
8534
+ const req = mod.request(searchBase + "detail", {
8535
+ method: "POST",
8536
+ headers: {
8537
+ "Content-Type": "application/json",
8538
+ Accept: "application/json",
8539
+ "Content-Length": Buffer.byteLength(payload)
8540
+ },
8541
+ timeout: 6e4
8542
+ }, (res) => {
8543
+ const chunks = [];
8544
+ res.on("data", (c) => chunks.push(c));
8545
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
8546
+ });
8547
+ req.on("timeout", () => req.destroy(/* @__PURE__ */ new Error("超时")));
8548
+ req.on("error", reject);
8549
+ req.write(payload);
8550
+ req.end();
8551
+ });
8552
+ if (jsonMode) {
8553
+ console.log(JSON.stringify(JSON.parse(raw0(resp)), null, 2));
8554
+ break;
8555
+ }
8556
+ const parsed = JSON.parse(raw0(resp));
8557
+ if (parsed.code !== 0) {
8558
+ console.error(`✗ ${parsed.msg}`);
8559
+ process.exit(1);
8560
+ }
8561
+ const d = parsed.data;
8562
+ const text = String(d.content ?? d.text ?? JSON.stringify(d));
8563
+ console.log(text.length > 4e3 ? `${text.slice(0, 4e3)}\n…(截断,--json 看全量)` : text);
8564
+ } else {
8565
+ console.error("用法:bfi ymc wiki <search|show>");
8566
+ process.exit(1);
8567
+ }
8568
+ break;
8569
+ }
8570
+ case "callstat":
8571
+ emit(await api.call("ymc/warningCallstat", {
8572
+ ...requireEnv(rest),
8573
+ ...timeOpts(rest),
8574
+ page: Number(opt(rest, "--page") || 1),
8575
+ pageSize: Number(opt(rest, "--page-size") || 20)
8576
+ }), jsonMode, rowsSummary("慢调用统计"));
8577
+ break;
8578
+ case "sqlstat":
8579
+ emit(await api.call("ymc/warningSqlstat", {
8580
+ ...requireEnv(rest),
8581
+ ...timeOpts(rest),
8582
+ page: Number(opt(rest, "--page") || 1),
8583
+ pageSize: Number(opt(rest, "--page-size") || 20)
8584
+ }), jsonMode, rowsSummary("慢 SQL 统计"));
8585
+ break;
8586
+ case "events": {
8587
+ const body = {
8588
+ ...requireEnv(rest),
8589
+ type: opt(rest, "--type") || "",
8590
+ startTime: opt(rest, "--start-time") || "",
8591
+ endTime: opt(rest, "--end-time") || "",
8592
+ page: Number(opt(rest, "--page") || 1),
8593
+ pageSize: Number(opt(rest, "--page-size") || 10),
8594
+ appCode: opt(rest, "--app") || "",
8595
+ pipelineCode: opt(rest, "--pipeline") || ""
8596
+ };
8597
+ const realPath = flag(rest, "--histogram") ? "ymc/eventHistograms" : "ymc/eventLogs";
8598
+ emit(await api.call(realPath, body), jsonMode, rowsSummary(flag(rest, "--histogram") ? "事件直方图" : "集群事件"));
8599
+ break;
8600
+ }
8601
+ case "log-url": {
8602
+ const body = {
8603
+ ...requireEnv(rest),
8604
+ type: opt(rest, "--type") || "ingressLog",
8605
+ appId: opt(rest, "--app") || ""
8606
+ };
8607
+ const ids = opt(rest, "--filter-app");
8608
+ if (ids) body.filterCondition = { appIds: ids.split(",").map((s) => s.trim()) };
8609
+ emit(await api.call("ymc/aliyun-log/url", body), jsonMode, (data) => `✓ 日志直通 URL 已生成(data 内含 url,浏览器可直接打开)`);
8610
+ break;
8611
+ }
8612
+ case "sample-list":
8613
+ emit(await api.call("ymc/sample/list", {
8614
+ ...requireEnv(rest),
8615
+ ...timeOpts(rest)
8616
+ }), jsonMode, rowsSummary("采样数据"));
8617
+ break;
8618
+ case "rca": {
8619
+ const body = {
8620
+ ...requireEnv(rest),
8621
+ ...timeOpts(rest)
8622
+ };
8623
+ for (const [k, name] of [["appId", "--app"], ["appCode", "--app-code"]]) {
8624
+ const v = opt(rest, name);
8625
+ if (v) body[k] = v;
8626
+ }
8627
+ emit(await api.call("ymc/rca/full-report", body, 3e5), jsonMode, () => "✓ RCA 报告已生成(--json 查看全文)");
8628
+ break;
8629
+ }
8630
+ case "bpr-download": {
8631
+ const pk = positionals(rest)[0];
8632
+ if (!pk) {
8633
+ console.error("用法:bfi ymc bpr-download <pk> -e <env> [-o 输出文件]");
8634
+ console.error("例:bfi ymc bpr-download eopppmokijpjoflfmodjffojcohiflgm -e pre -o ~/bpr.html");
8635
+ console.error("pk 来源:bfi ymc call bpr/list --data '{\"page\":1,\"pageSize\":10}' -e <env>");
8636
+ process.exit(1);
8637
+ }
8638
+ const out = opt(rest, "-o", "--out") || `bpr_${pk.slice(0, 16)}.html`;
8639
+ try {
8640
+ const n = await api.download("ymc/bpr/download", {
8641
+ ...requireEnv(rest),
8642
+ pk
8643
+ }, out);
8644
+ console.log(`✓ 已下载 ${n} 字节 → ${out}`);
8645
+ } catch (e) {
8646
+ console.error(`✗ ${e.message}`);
8647
+ process.exit(1);
8648
+ }
8649
+ break;
8650
+ }
8651
+ case "call": {
8652
+ const route = positionals(rest)[0];
8653
+ const dataStr = opt(rest, "--data") || "{}";
8654
+ if (!route) {
8655
+ console.error("用法:bfi ymc call <route> -e <env> [--data '{\"k\":\"v\"}'] [--timeout 秒] [-t time | --start-time <s> --end-time <e>]");
8656
+ console.error("route 例:warningCall/warningSql/exceptionHistory/bpr/list/alert/detail/uba/query/tool/list/environment ...");
8657
+ console.error("完整清单见 http://172.20.35.178:8901/docs");
8658
+ process.exit(1);
8659
+ }
8660
+ let extra;
8661
+ try {
8662
+ extra = JSON.parse(dataStr);
8663
+ } catch {
8664
+ console.error("--data 不是合法 JSON");
8665
+ process.exit(1);
8666
+ }
8667
+ const timeoutArg = opt(rest, "--timeout");
8668
+ const timeoutMs = timeoutArg ? Number(timeoutArg) * 1e3 : void 0;
8669
+ emit(await api.call(`ymc/${route}`, {
8670
+ ...requireEnv(rest),
8671
+ ...timeOpts(rest),
8672
+ ...extra
8673
+ }, timeoutMs), jsonMode);
8674
+ break;
8675
+ }
8676
+ default:
8677
+ console.error(`未知子命令:${sub}`);
8678
+ printHelp();
8679
+ process.exit(1);
8680
+ }
8681
+ }
8682
+ function printHelp() {
8683
+ console.log(`
8684
+ bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
8685
+
8686
+ 命令:
8687
+ status 登录会话状态(dev/prod)
8688
+ trace <trace_id> -e <env> 三源合一(SLS+链路+ingress)
8689
+ chain <trace_id> -e <env> 原子源:warningChain 链路
8690
+ sls-logs <trace_id> -e <env> 原子源:SLS 业务日志
8691
+ sls-raw "<查询>" -e <env> SLS 原始查询(完整查询语法透传)
8692
+ sls-grep "<关键词>" -e <env> SLS 全文检索聚合(异常历史分布取证)
8693
+ slowsql -t <time> [-e] [--sql-str] [--md5] [--trace-id] [--app] [--profiler]
8694
+ slowcall -t <time> [-e] [--trace-id] [--app] [--method] [--min-cost ms] [--profiler]
8695
+ exceptions -t <time> [-e] [--app]
8696
+ alerts -t <time> [-e] [--level error|warn|info]
8697
+ url-stats </uri> -t <time> -e <env>
8698
+ ingress --trace-id <id> | --uri </path> [-t <time>] -e <env> [--exact]
8699
+ dump-list [-t <time>] -e <env> [--app] [--type profiler]
8700
+ cases <search|show|upload|index> 案例库(KEDB)
8701
+ wiki search "<kw>" [--source] [--titles] 知识库统一检索(wiki/jira/文库)
8702
+ wiki show <id> [--source] 知识条目全文
8703
+ call <route> -e <env> [--data '<json>'] 通用透传(全部注册表端点)
8704
+
8705
+ 通用参数:
8706
+ -e, --env 环境(${ENV_DOC})
8707
+ -t, --time 时间简写(10m/2h/3d/4w = 过去 N 单位到现在)
8708
+ --start-time <t> 开始时间 yyyy-MM-dd HH:mm:ss(与 -t 二选一;只传它=到当前)
8709
+ --end-time <t> 结束时间(须与 --start-time 同传)
8710
+ --json 输出原始 JSON
8711
+ --token 覆盖已登录 token(默认用 bfi auth login 的)
8712
+ `);
8713
+ }
7220
8714
  const __dirname = dirname(fileURLToPath(import.meta.url));
7221
8715
  function getVersion() {
7222
8716
  try {
@@ -7309,11 +8803,37 @@ ${BOLD}━━━ 技能包管理 ━━━${RESET}
7309
8803
  skills package add <pkg> <skill...> 添加技能到包
7310
8804
  skills package remove <pkg> <skill...> 从包移除技能
7311
8805
 
8806
+ ${BOLD}━━━ 插件管理 ━━━${RESET}
8807
+ plugin create <name> [--with ...] 脚手架一个插件目录
8808
+ plugin validate [path] 校验插件结构
8809
+ plugin publish <dir|zip|tgz> 发布插件到 SkillHub
8810
+ plugin list 列出插件
8811
+ plugin info <id> 查看插件详情
8812
+ plugin install <id|file.zip> 安装插件(SkillHub id 或本地 zip)
8813
+
8814
+ ${BOLD}━━━ MCP 服务器 ━━━${RESET}
8815
+ mcp list 列出 MCP 服务器
8816
+ mcp info <id> 查看详情
8817
+ mcp config <id> 打印 .mcp.json 配置
8818
+ mcp add <id> 写入本地 .mcp.json
8819
+ mcp remove <name> 从本地 .mcp.json 移除
8820
+
7312
8821
  ${BOLD}━━━ 文档 ━━━${RESET}
7313
8822
  docs upload <file> 上传文档
7314
8823
  docs list 列出文档
7315
8824
  docs info <id> 查看文档详情
7316
8825
 
8826
+ ${BOLD}━━━ 观测查询(ymc)━━━${RESET}
8827
+ ymc status 登录会话状态
8828
+ ymc trace <trace_id> -e <env> traceId 三源合一(SLS+链路+ingress)
8829
+ ymc chain / sls-logs <id> 原子源:链路 / SLS 日志
8830
+ ymc slowsql / slowcall 慢 SQL / 慢调用(-t 时间简写)
8831
+ ymc exceptions / alerts 异常聚合 / 告警明细
8832
+ ymc url-stats <uri> -t <time> URL 性能统计
8833
+ ymc ingress --trace-id|--uri ingress 访问日志
8834
+ ymc dump-list / call <route> 诊断文件 / 通用端点透传
8835
+ (-e env: test/daily/pre/core1-4/commldev;-t: 10m/2h/3d/4w)
8836
+
7317
8837
  ${BOLD}━━━ 配置 ━━━${RESET}
7318
8838
  config get [key] 查看配置
7319
8839
  config set <key> <value> [--global] 设置配置
@@ -7578,6 +9098,9 @@ async function main() {
7578
9098
  setAgents(await resolveAgents(cfg.token ? new SkillHubAPI(cfg.registry, cfg.token) : void 0));
7579
9099
  } catch {}
7580
9100
  switch (command) {
9101
+ case "ymc":
9102
+ await runYmc(restArgs, globalOpts);
9103
+ break;
7581
9104
  case "auth":
7582
9105
  if (restArgs[0] === "logout") await runLogout();
7583
9106
  else if (restArgs[0] === "whoami") await runWhoami(globalOpts);
@@ -7610,6 +9133,12 @@ async function main() {
7610
9133
  case "pkg":
7611
9134
  await runPackage(restArgs, globalOpts);
7612
9135
  break;
9136
+ case "plugin":
9137
+ await runPlugin(restArgs, globalOpts);
9138
+ break;
9139
+ case "mcp":
9140
+ await runMcp(restArgs, globalOpts);
9141
+ break;
7613
9142
  case "log":
7614
9143
  await runLog(restArgs, globalOpts);
7615
9144
  break;
@@ -7688,5 +9217,8 @@ async function main() {
7688
9217
  console.log(`运行 ${BOLD}bfi --help${RESET} 查看用法。`);
7689
9218
  }
7690
9219
  }
7691
- main().finally(() => process.exit(process.exitCode ?? 0));
9220
+ main().catch((e) => {
9221
+ console.error(`✗ ${e?.message || e}`);
9222
+ process.exit(1);
9223
+ });
7692
9224
  export { loadGlobalConfig };