bfi-cli 0.1.58 → 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.
Files changed (2) hide show
  1. package/dist/cli.mjs +1618 -304
  2. package/package.json +1 -1
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
@@ -4192,10 +4337,10 @@ function parseAddOptions(args) {
4192
4337
  errors
4193
4338
  };
4194
4339
  }
4195
- const RESET$11 = "\x1B[0m";
4196
- const BOLD$8 = "\x1B[1m";
4197
- const DIM$11 = "\x1B[38;5;102m";
4198
- 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";
4199
4344
  const CYAN$2 = "\x1B[36m";
4200
4345
  const SEARCH_API_BASE = process.env.SKILLS_API_URL || "https://skills.sh";
4201
4346
  function formatInstalls$1(count) {
@@ -4284,28 +4429,28 @@ async function runSearchPrompt(initialQuery = "", owner) {
4284
4429
  if (lastRenderedLines > 0) process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));
4285
4430
  process.stdout.write(CLEAR_DOWN);
4286
4431
  const lines = [];
4287
- const cursor = `${BOLD$8}_${RESET$11}`;
4288
- lines.push(`${TEXT$8}搜索技能:${RESET$11} ${query}${cursor}`);
4432
+ const cursor = `${BOLD$10}_${RESET$13}`;
4433
+ lines.push(`${TEXT$10}搜索技能:${RESET$13} ${query}${cursor}`);
4289
4434
  lines.push("");
4290
- if (!query || query.length < 2) lines.push(`${DIM$11}输入关键词搜索(最少 2 个字符)${RESET$11}`);
4291
- else if (results.length === 0 && loading) lines.push(`${DIM$11}搜索中...${RESET$11}`);
4292
- 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}`);
4293
4438
  else {
4294
4439
  const visible = results.slice(0, 8);
4295
4440
  for (let i = 0; i < visible.length; i++) {
4296
4441
  const skill = visible[i];
4297
4442
  const isSelected = i === selectedIndex;
4298
- const arrow = isSelected ? `${BOLD$8}>${RESET$11}` : " ";
4299
- const name = isSelected ? `${BOLD$8}${skill.name}${RESET$11}` : `${TEXT$8}${skill.name}${RESET$11}`;
4300
- 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}` : "";
4301
4446
  const installs = formatInstalls$1(skill.installs);
4302
- const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$11}` : "";
4303
- 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}` : "";
4304
4449
  lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);
4305
4450
  }
4306
4451
  }
4307
4452
  lines.push("");
4308
- lines.push(`${DIM$11}上下键导航 | 回车选择 | ESC 取消${RESET$11}`);
4453
+ lines.push(`${DIM$13}上下键导航 | 回车选择 | ESC 取消${RESET$13}`);
4309
4454
  for (const line of lines) process.stdout.write(line + "\n");
4310
4455
  lastRenderedLines = lines.length;
4311
4456
  }
@@ -4402,9 +4547,9 @@ async function runFind(args) {
4402
4547
  const { query, options: findOptions, errors } = parseFindOptions(args);
4403
4548
  const owner = findOptions.owner;
4404
4549
  const isNonInteractive = !process.stdin.isTTY;
4405
- const agentTip = `${DIM$11}Tip: if running in a coding agent, follow these steps:${RESET$11}
4406
- ${DIM$11} 1) npx skills find [query] [--owner <owner>]${RESET$11}
4407
- ${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}`;
4408
4553
  if (errors.length > 0) {
4409
4554
  for (const error of errors) console.error(error);
4410
4555
  console.error("Usage: npx skills find <query> [--owner <owner>]");
@@ -4415,16 +4560,16 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4415
4560
  String(results.length);
4416
4561
  if (results.length === 0) {
4417
4562
  const ownerSuffix = owner ? ` from owner "${owner}"` : "";
4418
- console.log(`${DIM$11}未找到 "${query}" 的技能${ownerSuffix}${RESET$11}`);
4563
+ console.log(`${DIM$13}未找到 "${query}" 的技能${ownerSuffix}${RESET$13}`);
4419
4564
  return;
4420
4565
  }
4421
- 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>`);
4422
4567
  console.log();
4423
4568
  for (const skill of results.slice(0, 6)) {
4424
4569
  const pkg = skill.source || skill.slug;
4425
4570
  const installs = formatInstalls$1(skill.installs);
4426
- console.log(`${TEXT$8}${pkg}@${skill.name}${RESET$11}${installs ? ` ${CYAN$2}${installs}${RESET$11}` : ""}`);
4427
- 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}`);
4428
4573
  console.log();
4429
4574
  }
4430
4575
  return;
@@ -4432,19 +4577,19 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4432
4577
  if (isNonInteractive || await isRunningInAgent()) {
4433
4578
  console.log(agentTip);
4434
4579
  console.log();
4435
- 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}`);
4436
4581
  return;
4437
4582
  }
4438
4583
  const selected = await runSearchPrompt("", owner);
4439
4584
  if (!selected) {
4440
- console.log(`${DIM$11}搜索已取消${RESET$11}`);
4585
+ console.log(`${DIM$13}搜索已取消${RESET$13}`);
4441
4586
  console.log();
4442
4587
  return;
4443
4588
  }
4444
4589
  const pkg = selected.source || selected.slug;
4445
4590
  const skillName = selected.name;
4446
4591
  console.log();
4447
- 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}...`);
4448
4593
  console.log();
4449
4594
  const { source, options: addOptions } = parseAddOptions([
4450
4595
  pkg,
@@ -4454,13 +4599,13 @@ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4454
4599
  await runAdd(source, addOptions);
4455
4600
  console.log();
4456
4601
  const info = getOwnerRepoFromString(pkg);
4457
- if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$8}https://skills.sh/${selected.slug}${RESET$11}`);
4458
- 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}`);
4459
4604
  console.log();
4460
4605
  }
4461
- const RESET$10 = "\x1B[0m";
4462
- const BOLD$7 = "\x1B[1m";
4463
- 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";
4464
4609
  const CYAN$1 = "\x1B[36m";
4465
4610
  const YELLOW$4 = "\x1B[33m";
4466
4611
  function shortenPath(fullPath, cwd) {
@@ -4496,8 +4641,8 @@ async function runList(args) {
4496
4641
  const validAgents = Object.keys(agents);
4497
4642
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
4498
4643
  if (invalidAgents.length > 0) {
4499
- console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$10}`);
4500
- 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}`);
4501
4646
  process.exit(1);
4502
4647
  }
4503
4648
  agentFilter = options.agent;
@@ -4524,21 +4669,21 @@ async function runList(args) {
4524
4669
  console.log("[]");
4525
4670
  return;
4526
4671
  }
4527
- console.log(`${DIM$10}未找到${scopeLabel}技能。${RESET$10}`);
4528
- if (scope) console.log(`${DIM$10}尝试不带 -g 参数列出项目技能${RESET$10}`);
4529
- 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}`);
4530
4675
  return;
4531
4676
  }
4532
4677
  function printSkill(skill, indent = false, maxNameLength = 0, maxPathLength = 0) {
4533
4678
  const prefix = indent ? " " : "";
4534
4679
  const shortPath = shortenPath(skill.canonicalPath, cwd);
4535
4680
  const agentNames = skill.agents.map((a) => agents[a].displayName);
4536
- const agentInfo = skill.agents.length > 0 ? formatList$1(agentNames) : `${YELLOW$4}not linked${RESET$10}`;
4681
+ const agentInfo = skill.agents.length > 0 ? formatList$1(agentNames) : `${YELLOW$4}not linked${RESET$12}`;
4537
4682
  const paddedName = sanitizeMetadata(skill.name).padEnd(maxNameLength);
4538
4683
  const paddedPath = shortPath.padEnd(maxPathLength);
4539
- 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}`);
4540
4685
  }
4541
- console.log(`${BOLD$7}${scopeLabel}技能${RESET$10}`);
4686
+ console.log(`${BOLD$9}${scopeLabel}技能${RESET$12}`);
4542
4687
  console.log();
4543
4688
  const groupedSkills = {};
4544
4689
  const ungroupedSkills = [];
@@ -4554,7 +4699,7 @@ async function runList(args) {
4554
4699
  const sortedGroups = Object.keys(groupedSkills).sort();
4555
4700
  for (const group of sortedGroups) {
4556
4701
  const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4557
- console.log(`${BOLD$7}${title}${RESET$10}`);
4702
+ console.log(`${BOLD$9}${title}${RESET$12}`);
4558
4703
  const skills = groupedSkills[group];
4559
4704
  if (skills) {
4560
4705
  let maxNameLength = 0;
@@ -4570,7 +4715,7 @@ async function runList(args) {
4570
4715
  console.log();
4571
4716
  }
4572
4717
  if (ungroupedSkills.length > 0) {
4573
- console.log(`${BOLD$7}通用${RESET$10}`);
4718
+ console.log(`${BOLD$9}通用${RESET$12}`);
4574
4719
  let maxNameLength = 0;
4575
4720
  let maxPathLength = 0;
4576
4721
  for (const skill of ungroupedSkills) {
@@ -4844,10 +4989,10 @@ function buildLocalUpdateSource(entry) {
4844
4989
  return appendFolderAndRef(source, entry.skillPath, entry.ref);
4845
4990
  }
4846
4991
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
4847
- const RESET$9 = "\x1B[0m";
4848
- const BOLD$6 = "\x1B[1m";
4849
- const DIM$9 = "\x1B[38;5;102m";
4850
- 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";
4851
4996
  function parseUpdateOptions(args) {
4852
4997
  const options = {};
4853
4998
  const positional = [];
@@ -4940,7 +5085,7 @@ function getInstallSource(skill) {
4940
5085
  function printSkippedSkills(skipped) {
4941
5086
  if (skipped.length === 0) return;
4942
5087
  console.log();
4943
- console.log(`${DIM$9}${skipped.length} 个技能无法自动检查:${RESET$9}`);
5088
+ console.log(`${DIM$11}${skipped.length} 个技能无法自动检查:${RESET$11}`);
4944
5089
  const grouped = /* @__PURE__ */ new Map();
4945
5090
  for (const skill of skipped) {
4946
5091
  const source = getInstallSource(skill);
@@ -4951,13 +5096,13 @@ function printSkippedSkills(skipped) {
4951
5096
  for (const [source, skills] of grouped) {
4952
5097
  if (skills.length === 1) {
4953
5098
  const skill = skills[0];
4954
- 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}`);
4955
5100
  } else {
4956
5101
  const reason = skills[0].reason;
4957
5102
  const names = skills.map((s) => sanitizeMetadata(s.name)).join(", ");
4958
- 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}`);
4959
5104
  }
4960
- 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}`);
4961
5106
  }
4962
5107
  }
4963
5108
  async function getProjectSkillsForUpdate(skillFilter) {
@@ -4982,13 +5127,13 @@ async function checkAndPromptForDeletions(source, allLockedForSource, lockSkills
4982
5127
  });
4983
5128
  if (deletedSkills.length > 0) {
4984
5129
  console.log();
4985
- console.log(`${DIM$9}警告:${RESET$9} 以下来自 ${DIM$9}${source}${RESET$9} 的技能似乎已在源仓库中删除:`);
4986
- for (const s of deletedSkills) console.log(` ${DIM$9}•${RESET$9} ${s}`);
4987
- 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}`);
4988
5133
  else {
4989
5134
  const confirmed = await confirm({ message: `是否删除这些已删除技能的本地副本?` });
4990
5135
  if (confirmed && !isCancel(confirmed)) for (const s of deletedSkills) {
4991
- console.log(`${DIM$9}正在卸载${RESET$9} ${s}...`);
5136
+ console.log(`${DIM$11}正在卸载${RESET$11} ${s}...`);
4992
5137
  await removeCommand([s], {
4993
5138
  yes: true,
4994
5139
  global: isGlobal
@@ -5005,8 +5150,8 @@ async function updateGlobalSkills(options = {}) {
5005
5150
  let failCount = 0;
5006
5151
  if (skillNames.length === 0) {
5007
5152
  if (!options.skills) {
5008
- console.log(`${DIM$9}锁文件中没有跟踪的全局技能。${RESET$9}`);
5009
- 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}`);
5010
5155
  }
5011
5156
  return {
5012
5157
  successCount,
@@ -5047,7 +5192,7 @@ async function updateGlobalSkills(options = {}) {
5047
5192
  const firstEntry = itemsForSource[0].entry;
5048
5193
  const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
5049
5194
  let tempDir = null;
5050
- 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`);
5051
5196
  if (firstEntry.sourceType === "skillhub") {
5052
5197
  const skillhubRef = source.replace(/^skillhub:/, "");
5053
5198
  const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
@@ -5057,7 +5202,7 @@ async function updateGlobalSkills(options = {}) {
5057
5202
  new SkillHubAPI(cfg.registry, cfg.token);
5058
5203
  for (const item of itemsForSource) {
5059
5204
  const safeName = sanitizeMetadata(item.name);
5060
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5205
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5061
5206
  try {
5062
5207
  const parts = skillhubRef.split("/");
5063
5208
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5068,7 +5213,7 @@ async function updateGlobalSkills(options = {}) {
5068
5213
  });
5069
5214
  successCount++;
5070
5215
  } catch (error) {
5071
- console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5216
+ console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5072
5217
  failCount++;
5073
5218
  }
5074
5219
  }
@@ -5078,7 +5223,7 @@ async function updateGlobalSkills(options = {}) {
5078
5223
  if (firstEntry.sourceType === "github") {
5079
5224
  const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
5080
5225
  if (!tree) {
5081
- 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}`);
5082
5227
  continue;
5083
5228
  }
5084
5229
  const discoveredPaths = findSkillMdPaths(tree);
@@ -5113,7 +5258,7 @@ async function updateGlobalSkills(options = {}) {
5113
5258
  });
5114
5259
  }
5115
5260
  } catch (error) {
5116
- 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}`);
5117
5262
  } finally {
5118
5263
  if (tempDir) await cleanupTempDir(tempDir);
5119
5264
  }
@@ -5121,7 +5266,7 @@ async function updateGlobalSkills(options = {}) {
5121
5266
  if (checkable.length > 0) process.stdout.write("\r\x1B[K");
5122
5267
  const checkedCount = checkable.length + skipped.length;
5123
5268
  if (checkable.length === 0 && skipped.length === 0) {
5124
- if (!options.skills) console.log(`${DIM$9}没有可检查的全局技能。${RESET$9}`);
5269
+ if (!options.skills) console.log(`${DIM$11}没有可检查的全局技能。${RESET$11}`);
5125
5270
  return {
5126
5271
  successCount,
5127
5272
  failCount,
@@ -5137,28 +5282,28 @@ async function updateGlobalSkills(options = {}) {
5137
5282
  };
5138
5283
  }
5139
5284
  if (updates.length === 0) {
5140
- console.log(`${TEXT$7}✓ 所有全局技能已是最新${RESET$9}`);
5285
+ console.log(`${TEXT$9}✓ 所有全局技能已是最新${RESET$11}`);
5141
5286
  return {
5142
5287
  successCount,
5143
5288
  failCount,
5144
5289
  checkedCount
5145
5290
  };
5146
5291
  }
5147
- console.log(`${TEXT$7}发现 ${updates.length} 个可更新全局技能${RESET$9}`);
5292
+ console.log(`${TEXT$9}发现 ${updates.length} 个可更新全局技能${RESET$11}`);
5148
5293
  console.log();
5149
5294
  for (const update of updates) {
5150
5295
  const safeName = sanitizeMetadata(update.name);
5151
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5296
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5152
5297
  const installUrl = buildUpdateInstallSource(update.entry);
5153
5298
  if (!installUrl) {
5154
5299
  failCount++;
5155
- 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}`);
5156
5301
  continue;
5157
5302
  }
5158
5303
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5159
5304
  if (!existsSync(cliEntry)) {
5160
5305
  failCount++;
5161
- 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}`);
5162
5307
  continue;
5163
5308
  }
5164
5309
  if (spawnSync(process.execPath, [
@@ -5177,10 +5322,10 @@ async function updateGlobalSkills(options = {}) {
5177
5322
  shell: false
5178
5323
  }).status === 0) {
5179
5324
  successCount++;
5180
- console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5325
+ console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5181
5326
  } else {
5182
5327
  failCount++;
5183
- console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5328
+ console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5184
5329
  }
5185
5330
  }
5186
5331
  printSkippedSkills(skipped);
@@ -5196,8 +5341,8 @@ async function updateProjectSkills(options = {}) {
5196
5341
  let failCount = 0;
5197
5342
  if (projectSkills.length === 0) {
5198
5343
  if (!options.skills) {
5199
- console.log(`${DIM$9}没有可更新的项目技能。${RESET$9}`);
5200
- 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}`);
5201
5346
  }
5202
5347
  return {
5203
5348
  successCount,
@@ -5208,7 +5353,7 @@ async function updateProjectSkills(options = {}) {
5208
5353
  const updatable = projectSkills.filter((s) => s.entry.skillPath);
5209
5354
  const legacy = projectSkills.filter((s) => !s.entry.skillPath);
5210
5355
  if (updatable.length === 0) {
5211
- 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}`);
5212
5357
  printLegacyProjectSkills(legacy);
5213
5358
  return {
5214
5359
  successCount,
@@ -5228,8 +5373,8 @@ async function updateProjectSkills(options = {}) {
5228
5373
  const targetParts = [];
5229
5374
  if (hasUniversal) targetParts.push("Universal");
5230
5375
  targetParts.push(...targetAgentNames);
5231
- if (targetParts.length > 0) console.log(`${TEXT$7}更新目标:${targetParts.join(", ")}${RESET$9}`);
5232
- 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}`);
5233
5378
  console.log();
5234
5379
  const bySource = /* @__PURE__ */ new Map();
5235
5380
  for (const skill of updatable) {
@@ -5241,7 +5386,7 @@ async function updateProjectSkills(options = {}) {
5241
5386
  const localLock = await readLocalLock();
5242
5387
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5243
5388
  if (!existsSync(cliEntry)) {
5244
- console.log(`${DIM$9}✗ CLI 入口未找到 ${cliEntry}${RESET$9}`);
5389
+ console.log(`${DIM$11}✗ CLI 入口未找到 ${cliEntry}${RESET$11}`);
5245
5390
  return {
5246
5391
  successCount,
5247
5392
  failCount: updatable.length,
@@ -5261,7 +5406,7 @@ async function updateProjectSkills(options = {}) {
5261
5406
  new SkillHubAPI(cfg.registry, cfg.token);
5262
5407
  for (const item of skillsForSource) {
5263
5408
  const safeName = sanitizeMetadata(item.name);
5264
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5409
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5265
5410
  try {
5266
5411
  const parts = skillhubRef.split("/");
5267
5412
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5272,7 +5417,7 @@ async function updateProjectSkills(options = {}) {
5272
5417
  });
5273
5418
  successCount++;
5274
5419
  } catch (error) {
5275
- console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5420
+ console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5276
5421
  failCount++;
5277
5422
  }
5278
5423
  }
@@ -5283,7 +5428,7 @@ async function updateProjectSkills(options = {}) {
5283
5428
  let deletedSkills = [];
5284
5429
  if (buildLocalUpdateSource(firstEntry) === null) {
5285
5430
  failCount += skillsForSource.length;
5286
- 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}`);
5287
5432
  continue;
5288
5433
  }
5289
5434
  try {
@@ -5293,18 +5438,18 @@ async function updateProjectSkills(options = {}) {
5293
5438
  });
5294
5439
  deletedSkills = await checkAndPromptForDeletions(source, allLockedForSource, localLock.skills, false, options, discoveredPaths);
5295
5440
  } catch (error) {
5296
- console.log(`${DIM$9}✗ 检查 ${source} 已删除技能失败${RESET$9}`);
5441
+ console.log(`${DIM$11}✗ 检查 ${source} 已删除技能失败${RESET$11}`);
5297
5442
  } finally {
5298
5443
  if (tempDir) await cleanupTempDir(tempDir);
5299
5444
  }
5300
5445
  const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
5301
5446
  for (const skill of remainingSkills) {
5302
5447
  const safeName = sanitizeMetadata(skill.name);
5303
- console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5448
+ console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5304
5449
  const installUrl = buildLocalUpdateSource(skill.entry);
5305
5450
  if (!installUrl) {
5306
5451
  failCount++;
5307
- 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}`);
5308
5453
  continue;
5309
5454
  }
5310
5455
  const subagentArgs = skill.entry.subagents?.length ? ["--subagent", ...skill.entry.subagents.map((s) => s === "" ? "root" : s)] : [];
@@ -5326,10 +5471,10 @@ async function updateProjectSkills(options = {}) {
5326
5471
  shell: false
5327
5472
  }).status === 0) {
5328
5473
  successCount++;
5329
- console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5474
+ console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5330
5475
  } else {
5331
5476
  failCount++;
5332
- console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5477
+ console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5333
5478
  }
5334
5479
  }
5335
5480
  }
@@ -5343,25 +5488,25 @@ async function updateProjectSkills(options = {}) {
5343
5488
  function printLegacyProjectSkills(legacy) {
5344
5489
  if (legacy.length === 0) return;
5345
5490
  console.log();
5346
- 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}`);
5347
5492
  for (const skill of legacy) {
5348
5493
  const reinstall = buildLocalUpdateSource(skill.entry);
5349
- console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)}`);
5350
- if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$7}npx skills add ${reinstall} -y${RESET$9}`);
5351
- 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}`);
5352
5497
  }
5353
5498
  }
5354
5499
  async function runUpdate(args = []) {
5355
5500
  const options = parseUpdateOptions(args);
5356
5501
  const scope = await resolveUpdateScope(options);
5357
- if (options.skills) console.log(`${TEXT$7}正在更新 ${options.skills.join(", ")}...${RESET$9}`);
5358
- 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}`);
5359
5504
  console.log();
5360
5505
  let totalSuccess = 0;
5361
5506
  let totalFail = 0;
5362
5507
  let totalFound = 0;
5363
5508
  if (scope === "global" || scope === "both") {
5364
- if (scope === "both" && !options.skills) console.log(`${BOLD$6}全局技能${RESET$9}`);
5509
+ if (scope === "both" && !options.skills) console.log(`${BOLD$8}全局技能${RESET$11}`);
5365
5510
  const { successCount, failCount, checkedCount } = await updateGlobalSkills(options);
5366
5511
  totalSuccess += successCount;
5367
5512
  totalFail += failCount;
@@ -5369,17 +5514,17 @@ async function runUpdate(args = []) {
5369
5514
  if (scope === "both" && !options.skills) console.log();
5370
5515
  }
5371
5516
  if (scope === "project" || scope === "both") {
5372
- if (scope === "both" && !options.skills) console.log(`${BOLD$6}项目技能${RESET$9}`);
5517
+ if (scope === "both" && !options.skills) console.log(`${BOLD$8}项目技能${RESET$11}`);
5373
5518
  const { successCount, failCount, foundCount } = await updateProjectSkills(options);
5374
5519
  totalSuccess += successCount;
5375
5520
  totalFail += failCount;
5376
5521
  totalFound += foundCount;
5377
5522
  }
5378
- 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}`);
5379
5524
  console.log();
5380
- if (totalSuccess > 0) console.log(`${TEXT$7}✓ 已更新 ${totalSuccess} 个技能${RESET$9}`);
5525
+ if (totalSuccess > 0) console.log(`${TEXT$9}✓ 已更新 ${totalSuccess} 个技能${RESET$11}`);
5381
5526
  if (totalFail > 0) {
5382
- console.log(`${DIM$9}更新失败 ${totalFail} 个技能${RESET$9}`);
5527
+ console.log(`${DIM$11}更新失败 ${totalFail} 个技能${RESET$11}`);
5383
5528
  process.exitCode = 1;
5384
5529
  }
5385
5530
  String(totalSuccess + totalFail);
@@ -5831,10 +5976,10 @@ function getOptionValue$3(args, flag) {
5831
5976
  const idx = args.indexOf(flag);
5832
5977
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
5833
5978
  }
5834
- const RESET$8 = "\x1B[0m";
5835
- const BOLD$5 = "\x1B[1m";
5836
- const DIM$8 = "\x1B[38;5;102m";
5837
- 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";
5838
5983
  const CYAN = "\x1B[36m";
5839
5984
  const MARKETPLACE_API = process.env.SKILLS_API_URL || "https://skills.sh";
5840
5985
  async function runSearch(args, globalOpts) {
@@ -5842,13 +5987,13 @@ async function runSearch(args, globalOpts) {
5842
5987
  const namespace = args.includes("--namespace") ? getOptionValue$2(args, "--namespace") : void 0;
5843
5988
  const json = args.includes("--json");
5844
5989
  if (!query || query.trim() === "") {
5845
- console.log(`${BOLD$5}bfi skills search <关键词> [选项]${RESET$8}`);
5990
+ console.log(`${BOLD$7}bfi skills search <关键词> [选项]${RESET$10}`);
5846
5991
  console.log();
5847
- console.log(`${DIM$8}常用命令:${RESET$8}`);
5848
- console.log(` bfi skills search react ${DIM$8}搜索 SkillHub${RESET$8}`);
5849
- console.log(` bfi skills search react --marketplace ${DIM$8}搜索 skills.sh${RESET$8}`);
5850
- console.log(` bfi skills search react --all ${DIM$8}搜索全部${RESET$8}`);
5851
- 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}`);
5852
5997
  return;
5853
5998
  }
5854
5999
  const useMarketplace = args.includes("--marketplace");
@@ -5858,9 +6003,9 @@ async function runSearch(args, globalOpts) {
5858
6003
  return;
5859
6004
  }
5860
6005
  if (searchAll) {
5861
- console.log(`${BOLD$5}=== SkillHub 注册表 ===${RESET$8}\n`);
6006
+ console.log(`${BOLD$7}=== SkillHub 注册表 ===${RESET$10}\n`);
5862
6007
  await searchSkillHub(query, namespace, globalOpts, json);
5863
- console.log(`\n${BOLD$5}=== skills.sh 市场 ===${RESET$8}\n`);
6008
+ console.log(`\n${BOLD$7}=== skills.sh 市场 ===${RESET$10}\n`);
5864
6009
  await searchMarketplace(query, json);
5865
6010
  return;
5866
6011
  }
@@ -5895,7 +6040,7 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
5895
6040
  count: 0,
5896
6041
  results: []
5897
6042
  }, null, 2));
5898
- else console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
6043
+ else console.log(`${DIM$10}SkillHub 上未找到 "${query}" 的技能${RESET$10}`);
5899
6044
  return;
5900
6045
  }
5901
6046
  if (json) {
@@ -5922,15 +6067,15 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
5922
6067
  const desc = skill.summary || skill.description || "";
5923
6068
  const canonicalSlug = skill.slug || "";
5924
6069
  const displaySlug = canonicalSlug.indexOf("--") > 0 ? canonicalSlug : `global--${canonicalSlug}`;
5925
- console.log(` ${BOLD$5}${name}${RESET$8}`);
5926
- if (desc) console.log(` ${DIM$8}${truncate$2(desc, 100)}${RESET$8}`);
5927
- console.log(` ${TEXT$6}slug: ${displaySlug}${RESET$8}`);
5928
- if (skill.version) console.log(` ${DIM$8}version: ${skill.version}${RESET$8}`);
5929
- 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}`);
5930
6075
  console.log();
5931
6076
  }
5932
6077
  } catch (error) {
5933
- console.error(`${DIM$8}SkillHub 搜索失败:${error.message}${RESET$8}`);
6078
+ console.error(`${DIM$10}SkillHub 搜索失败:${error.message}${RESET$10}`);
5934
6079
  }
5935
6080
  }
5936
6081
  async function searchMarketplace(query, json = false) {
@@ -5947,7 +6092,7 @@ async function searchMarketplace(query, json = false) {
5947
6092
  count: 0,
5948
6093
  results: []
5949
6094
  }, null, 2));
5950
- else console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
6095
+ else console.log(`${DIM$10}skills.sh 市场无结果${RESET$10}`);
5951
6096
  return;
5952
6097
  }
5953
6098
  const skills = (await res.json()).skills || [];
@@ -5957,7 +6102,7 @@ async function searchMarketplace(query, json = false) {
5957
6102
  count: 0,
5958
6103
  results: []
5959
6104
  }, null, 2));
5960
- else console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
6105
+ else console.log(`${DIM$10}skills.sh 上未找到 "${query}" 的技能${RESET$10}`);
5961
6106
  return;
5962
6107
  }
5963
6108
  if (json) {
@@ -5978,15 +6123,15 @@ async function searchMarketplace(query, json = false) {
5978
6123
  console.log(`skills.sh 上找到 ${skills.length} 个技能:\n`);
5979
6124
  for (const skill of skills.slice(0, 12)) {
5980
6125
  const installs = formatInstalls(skill.installs);
5981
- console.log(` ${BOLD$5}${skill.name}${RESET$8}`);
5982
- if (skill.source) console.log(` ${DIM$8}来源:${skill.source}${RESET$8}`);
5983
- if (installs) console.log(` ${CYAN}${installs}${RESET$8}`);
5984
- console.log(` ${TEXT$6}https://skills.sh/${skill.id}${RESET$8}`);
5985
- 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}`);
5986
6131
  console.log();
5987
6132
  }
5988
6133
  } catch {
5989
- console.log(`${DIM$8}skills.sh 市场不可用${RESET$8}`);
6134
+ console.log(`${DIM$10}skills.sh 市场不可用${RESET$10}`);
5990
6135
  }
5991
6136
  }
5992
6137
  function formatInstalls(count) {
@@ -6003,13 +6148,13 @@ function getOptionValue$2(args, flag) {
6003
6148
  const idx = args.indexOf(flag);
6004
6149
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
6005
6150
  }
6006
- const RESET$7 = "\x1B[0m";
6007
- const BOLD$4 = "\x1B[1m";
6008
- const DIM$7 = "\x1B[38;5;102m";
6009
- 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";
6010
6155
  const YELLOW$3 = "\x1B[33m";
6011
- const RED$3 = "\x1B[31m";
6012
- const GREEN$4 = "\x1B[32m";
6156
+ const RED$5 = "\x1B[31m";
6157
+ const GREEN$6 = "\x1B[32m";
6013
6158
  async function runInfo(args, globalOpts) {
6014
6159
  const ref = args[0];
6015
6160
  if (!ref) {
@@ -6025,35 +6170,35 @@ async function runInfo(args, globalOpts) {
6025
6170
  const result = await api.getSkill(canonical);
6026
6171
  const skill = result.data || result.skill || result;
6027
6172
  if (!skill || !skill.slug) {
6028
- console.log(`${DIM$7}未找到技能:${ref}${RESET$7}`);
6173
+ console.log(`${DIM$9}未找到技能:${ref}${RESET$9}`);
6029
6174
  process.exit(1);
6030
6175
  }
6031
6176
  console.log();
6032
- console.log(`${BOLD$4}${skill.displayName || skill.name || skill.slug}${RESET$7}`);
6033
- console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6034
- console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$5}${skill.slug}${RESET$7}`);
6035
- 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}`);
6036
6181
  const owner = skill.owner;
6037
6182
  if (owner) {
6038
- console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$5}${owner.displayName || owner.handle}${RESET$7}`);
6039
- 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}`);
6040
6185
  }
6041
6186
  const latestVersion = skill.latestVersion;
6042
6187
  if (latestVersion) {
6043
- console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$5}${latestVersion.version || "N/A"}${RESET$7}`);
6044
- if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$5}${latestVersion.license}${RESET$7}`);
6045
- 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}`);
6046
6191
  if (latestVersion.createdAt) {
6047
6192
  const date = new Date(latestVersion.createdAt).toISOString().split("T")[0];
6048
- console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$5}${date}${RESET$7}`);
6193
+ console.log(` ${BOLD$6}发布时间:${RESET$9} ${TEXT$7}${date}${RESET$9}`);
6049
6194
  }
6050
6195
  }
6051
6196
  const stats = skill.stats;
6052
6197
  if (stats) {
6053
6198
  console.log();
6054
- console.log(` ${BOLD$4}统计:${RESET$7}`);
6055
- if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$5}${stats.downloads}${RESET$7}`);
6056
- 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}`);
6057
6202
  }
6058
6203
  const tags = skill.tags;
6059
6204
  if (Array.isArray(tags) && tags.length > 0) {
@@ -6061,28 +6206,28 @@ async function runInfo(args, globalOpts) {
6061
6206
  const tag = t;
6062
6207
  return tag.name || tag;
6063
6208
  }).join(", ");
6064
- console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$5}${tagList}${RESET$7}`);
6209
+ console.log(` ${BOLD$6}标签:${RESET$9} ${TEXT$7}${tagList}${RESET$9}`);
6065
6210
  }
6066
6211
  const moderation = skill.moderation;
6067
6212
  if (moderation) {
6068
6213
  const verdict = moderation.verdict;
6069
6214
  if (verdict === "MALWARE_BLOCKED" || moderation.isMalwareBlocked) {
6070
6215
  console.log();
6071
- console.log(` ${RED$3}${BOLD$4}⚠ 已封禁:检测到恶意软件${RESET$7}`);
6072
- 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}`);
6073
6218
  } else if (verdict === "SUSPICIOUS" || moderation.isSuspicious) {
6074
6219
  console.log();
6075
- console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$7}`);
6076
- if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$7}`);
6077
- } 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}`);
6078
6223
  }
6079
6224
  if (skill.createdAt) {
6080
6225
  const created = new Date(skill.createdAt).toISOString().split("T")[0];
6081
- console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$5}${created}${RESET$7}`);
6226
+ console.log(` ${BOLD$6}创建时间:${RESET$9} ${TEXT$7}${created}${RESET$9}`);
6082
6227
  }
6083
6228
  if (skill.updatedAt) {
6084
6229
  const updated = new Date(skill.updatedAt).toISOString().split("T")[0];
6085
- console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$5}${updated}${RESET$7}`);
6230
+ console.log(` ${BOLD$6}更新时间:${RESET$9} ${TEXT$7}${updated}${RESET$9}`);
6086
6231
  }
6087
6232
  console.log();
6088
6233
  } catch (error) {
@@ -6095,8 +6240,8 @@ function truncate$1(text, maxLen) {
6095
6240
  if (text.length <= maxLen) return text;
6096
6241
  return text.slice(0, maxLen) + "...";
6097
6242
  }
6098
- const DIM$6 = "\x1B[38;5;102m";
6099
- const RESET$6 = "\x1B[0m";
6243
+ const DIM$8 = "\x1B[38;5;102m";
6244
+ const RESET$8 = "\x1B[0m";
6100
6245
  async function runConfig(args, globalOpts) {
6101
6246
  switch (args[0]) {
6102
6247
  case "get":
@@ -6191,12 +6336,12 @@ async function handleSet(args, _globalOpts) {
6191
6336
  }
6192
6337
  const isGlobal = args.includes("--global");
6193
6338
  setConfigValue(key, value, isGlobal);
6194
- 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" ? "全局" : "项目"})`);
6195
6340
  }
6196
- const RESET$5 = "\x1B[0m";
6197
- const BOLD$3 = "\x1B[1m";
6198
- const DIM$5 = "\x1B[38;5;102m";
6199
- 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";
6200
6345
  function formatFileSize(bytes) {
6201
6346
  if (bytes < 1024) return `${bytes} B`;
6202
6347
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
@@ -6223,9 +6368,9 @@ function printDocsHelp() {
6223
6368
  console.log(" bfi docs info <id> 查看文档处理状态");
6224
6369
  console.log();
6225
6370
  console.log("示例:");
6226
- console.log(` ${DIM$5}$ ${RESET$5}bfi docs upload resume.pdf`);
6227
- console.log(` ${DIM$5}$ ${RESET$5}bfi docs list`);
6228
- 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`);
6229
6374
  }
6230
6375
  async function handleUpload(args, globalOpts) {
6231
6376
  const filePath = args[0];
@@ -6248,18 +6393,18 @@ async function handleUpload(args, globalOpts) {
6248
6393
  const api = new SkillHubAPI(registry, token);
6249
6394
  const fileName = path$1.basename(resolvedPath);
6250
6395
  const fileSizeStr = formatFileSize(stats.size);
6251
- console.log(`${DIM$5}正在上传 ${fileName} (${fileSizeStr})...${RESET$5}`);
6396
+ console.log(`${DIM$7}正在上传 ${fileName} (${fileSizeStr})...${RESET$7}`);
6252
6397
  try {
6253
6398
  const fileBuffer = fs.readFileSync(resolvedPath);
6254
6399
  const result = await api.uploadDoc(fileBuffer, fileName);
6255
6400
  const doc = result.data || result;
6256
- console.log(`${TEXT$4}✓ 上传成功${RESET$5}`);
6401
+ console.log(`${TEXT$6}✓ 上传成功${RESET$7}`);
6257
6402
  console.log();
6258
- if (doc.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$4}${doc.id}${RESET$5}`);
6259
- if (doc.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$4}${doc.status}${RESET$5}`);
6260
- 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}`);
6261
6406
  console.log();
6262
- 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}`);
6263
6408
  } catch (error) {
6264
6409
  console.error(`上传失败:${error.message}`);
6265
6410
  process.exit(1);
@@ -6275,14 +6420,14 @@ async function handleList(args, globalOpts) {
6275
6420
  const data = result.data || result;
6276
6421
  const docs = data.items || data.content || data.docs || (Array.isArray(data) ? data : []);
6277
6422
  if (!Array.isArray(docs) || docs.length === 0) {
6278
- console.log(`${DIM$5}未找到文档。${RESET$5}`);
6423
+ console.log(`${DIM$7}未找到文档。${RESET$7}`);
6279
6424
  return;
6280
6425
  }
6281
6426
  const total = data.total || data.totalElements || result.total || result.totalElements;
6282
6427
  console.log();
6283
- if (total) console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${total} 条):`);
6284
- else console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${docs.length} 条结果):`);
6285
- 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}`);
6286
6431
  for (const doc of docs) {
6287
6432
  const id = doc.id || "?";
6288
6433
  const fileName = doc.fileName || doc.file_name || "unknown";
@@ -6292,11 +6437,11 @@ async function handleList(args, globalOpts) {
6292
6437
  const ip = doc.clientIp || "N/A";
6293
6438
  const createdAt = doc.createdAt || doc.created_at;
6294
6439
  const dateStr = createdAt ? new Date(createdAt).toISOString().split("T")[0] : "N/A";
6295
- console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$4}${fileName}${RESET$5}`);
6296
- 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}`);
6297
6442
  console.log();
6298
6443
  }
6299
- 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}`);
6300
6445
  console.log();
6301
6446
  } catch (error) {
6302
6447
  console.error(`列出文档失败:${error.message}`);
@@ -6320,43 +6465,43 @@ async function handleInfo(args, globalOpts) {
6320
6465
  const result = await api.getDoc(id);
6321
6466
  const doc = result.data || result;
6322
6467
  if (!doc || !doc.id) {
6323
- console.log(`${DIM$5}未找到文档:${id}${RESET$5}`);
6468
+ console.log(`${DIM$7}未找到文档:${id}${RESET$7}`);
6324
6469
  process.exit(1);
6325
6470
  }
6326
6471
  const content = doc.content;
6327
6472
  const hasContent = typeof content === "string" && content.trim().length > 0;
6328
6473
  console.log();
6329
- console.log(`${BOLD$3}文档 #${doc.id}${RESET$5}`);
6330
- console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6331
- 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}`);
6332
6477
  const fileSize = doc.fileSize || doc.file_size;
6333
- 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}`);
6334
6479
  const user = doc.userDisplayName || doc.userId;
6335
- if (user) console.log(` ${BOLD$3}上传者:${RESET$5} ${TEXT$4}${user}${RESET$5}`);
6336
- 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}`);
6337
6482
  if (doc.status) {
6338
- const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$4;
6339
- 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}`);
6340
6485
  }
6341
6486
  if (doc.createdAt || doc.created_at) {
6342
6487
  const date = new Date(doc.createdAt || doc.created_at).toISOString().replace("T", " ").slice(0, 19);
6343
- console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6488
+ console.log(` ${BOLD$5}创建时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6344
6489
  }
6345
6490
  if (doc.updatedAt || doc.updated_at) {
6346
6491
  const date = new Date(doc.updatedAt || doc.updated_at).toISOString().replace("T", " ").slice(0, 19);
6347
- console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6492
+ console.log(` ${BOLD$5}更新时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6348
6493
  }
6349
6494
  if (doc.error || doc.errorMessage) {
6350
6495
  console.log();
6351
- console.log(` \x1b[31m${BOLD$3}错误:${RESET$5}`);
6352
- 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}`);
6353
6498
  }
6354
6499
  if (hasContent) {
6355
6500
  console.log();
6356
- console.log(` ${BOLD$3}内容:${RESET$5}`);
6357
- console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6358
- for (const line of content.split("\n")) console.log(` ${TEXT$4}${line}${RESET$5}`);
6359
- 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}`);
6360
6505
  }
6361
6506
  console.log();
6362
6507
  } catch (error) {
@@ -6365,13 +6510,13 @@ async function handleInfo(args, globalOpts) {
6365
6510
  process.exit(1);
6366
6511
  }
6367
6512
  }
6368
- const RESET$4 = "\x1B[0m";
6369
- const BOLD$2 = "\x1B[1m";
6370
- const DIM$4 = "\x1B[38;5;102m";
6371
- const TEXT$3 = "\x1B[38;5;145m";
6372
- 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";
6373
6518
  const YELLOW$2 = "\x1B[33m";
6374
- const RED$2 = "\x1B[31m";
6519
+ const RED$4 = "\x1B[31m";
6375
6520
  async function runPublish(args, globalOpts) {
6376
6521
  const fromIdx = args.indexOf("--from");
6377
6522
  const mode = fromIdx !== -1 ? args[fromIdx + 1] : "dir";
@@ -6432,23 +6577,23 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
6432
6577
  }
6433
6578
  const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6434
6579
  const skillName = frontmatter.name || path$1.basename(resolvedDir);
6435
- console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
6436
- console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6437
- console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6438
- console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
6439
- 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}`);
6440
6585
  console.log();
6441
- console.log(`${DIM$4}正在创建 zip...${RESET$4}`);
6586
+ console.log(`${DIM$6}正在创建 zip...${RESET$6}`);
6442
6587
  const zipBuffer = createZipFromDir(resolvedDir);
6443
- console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6444
- 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}`);
6445
6590
  try {
6446
6591
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6447
- console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6448
- if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6449
- 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}`);
6450
6595
  } catch (error) {
6451
- console.error(` ${RED$2}发布失败:${error.message}${RESET$4}`);
6596
+ console.error(` ${RED$4}发布失败:${error.message}${RESET$6}`);
6452
6597
  process.exit(1);
6453
6598
  }
6454
6599
  console.log();
@@ -6465,34 +6610,34 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
6465
6610
  console.error(`文件未找到:${resolvedZip}`);
6466
6611
  process.exit(1);
6467
6612
  }
6468
- console.log(`${DIM$4}正在解压 zip...${RESET$4}`);
6613
+ console.log(`${DIM$6}正在解压 zip...${RESET$6}`);
6469
6614
  const tmpDir = path$1.join(os$1.tmpdir(), `.bfi-publish-${Date.now()}`);
6470
6615
  fs.mkdirSync(tmpDir, { recursive: true });
6471
6616
  try {
6472
6617
  await extractZip(resolvedZip, tmpDir);
6473
6618
  const skillMdPath = findSkillMd(tmpDir);
6474
6619
  if (!skillMdPath) {
6475
- console.error(` ${RED$2}zip 文件中未找到 SKILL.md${RESET$4}`);
6620
+ console.error(` ${RED$4}zip 文件中未找到 SKILL.md${RESET$6}`);
6476
6621
  process.exit(1);
6477
6622
  }
6478
6623
  const skillDir = path$1.dirname(skillMdPath);
6479
- 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}`);
6480
6625
  const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6481
6626
  const skillName = frontmatter.name || path$1.basename(skillDir);
6482
- console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6483
- console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6484
- 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}`);
6485
6630
  console.log();
6486
- console.log(`${DIM$4}正在重新打包...${RESET$4}`);
6631
+ console.log(`${DIM$6}正在重新打包...${RESET$6}`);
6487
6632
  const zipBuffer = createZipFromDir(skillDir);
6488
- console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6489
- 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}`);
6490
6635
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6491
- console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6492
- if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6493
- 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}`);
6494
6639
  } catch (error) {
6495
- 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}`);
6496
6641
  process.exit(1);
6497
6642
  } finally {
6498
6643
  try {
@@ -6521,18 +6666,18 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6521
6666
  }
6522
6667
  const effectiveBranch = branch || parsedRef || "main";
6523
6668
  const effectiveSubpath = directory || null;
6524
- console.log(`${DIM$4}正在从 Git 仓库发现技能...${RESET$4}`);
6525
- console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$3}${repoUrl}${RESET$4}`);
6526
- 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}`);
6527
6672
  console.log();
6528
6673
  let tmpDir = null;
6529
6674
  let skills = [];
6530
6675
  try {
6531
- console.log(`${DIM$4}正在克隆仓库...${RESET$4}`);
6676
+ console.log(`${DIM$6}正在克隆仓库...${RESET$6}`);
6532
6677
  const { cloneRepo } = await Promise.resolve().then(() => git_exports);
6533
6678
  tmpDir = await cloneRepo(repoUrl, effectiveBranch);
6534
- console.log(` ${GREEN$3}仓库克隆完成${RESET$4}`);
6535
- console.log(`${DIM$4}正在发现技能...${RESET$4}`);
6679
+ console.log(` ${GREEN$5}仓库克隆完成${RESET$6}`);
6680
+ console.log(`${DIM$6}正在发现技能...${RESET$6}`);
6536
6681
  const { discoverSkills } = await import("./_chunks/skills.mjs").then((n) => n.skills_exports);
6537
6682
  skills = (await discoverSkills(tmpDir, effectiveSubpath || void 0)).map((s) => ({
6538
6683
  path: s.path,
@@ -6540,7 +6685,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6540
6685
  description: s.description || ""
6541
6686
  }));
6542
6687
  } catch (error) {
6543
- console.error(` ${RED$2}克隆或发现失败:${error.message}${RESET$4}`);
6688
+ console.error(` ${RED$4}克隆或发现失败:${error.message}${RESET$6}`);
6544
6689
  if (tmpDir) try {
6545
6690
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6546
6691
  await cleanupTempDir(tmpDir);
@@ -6548,7 +6693,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6548
6693
  process.exit(1);
6549
6694
  }
6550
6695
  if (skills.length === 0) {
6551
- console.log(`${YELLOW$2}仓库中未发现技能。${RESET$4}`);
6696
+ console.log(`${YELLOW$2}仓库中未发现技能。${RESET$6}`);
6552
6697
  if (tmpDir) try {
6553
6698
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6554
6699
  await cleanupTempDir(tmpDir);
@@ -6560,7 +6705,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6560
6705
  const filters = skillFilter.split(",").map((s) => s.trim().toLowerCase());
6561
6706
  selectedSkills = skills.filter((s) => filters.some((f) => s.name.toLowerCase().includes(f)));
6562
6707
  if (selectedSkills.length === 0) {
6563
- console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$4}`);
6708
+ console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$6}`);
6564
6709
  console.log(`可用:${skills.map((s) => s.name).join(", ")}`);
6565
6710
  try {
6566
6711
  fs.rmSync(tmpDir, {
@@ -6571,12 +6716,12 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6571
6716
  process.exit(1);
6572
6717
  }
6573
6718
  }
6574
- 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`);
6575
6720
  for (const skill of selectedSkills) {
6576
6721
  const relPath = path$1.relative(tmpDir, skill.path) || ".";
6577
- console.log(` ${BOLD$2}${skill.name}${RESET$4}`);
6578
- console.log(` ${DIM$4}📁 ${relPath.split("/").join(" ▸ ")}${RESET$4}`);
6579
- 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}`);
6580
6725
  console.log();
6581
6726
  }
6582
6727
  if (!yes) {
@@ -6595,17 +6740,17 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6595
6740
  const { createZipFromDir } = await Promise.resolve().then(() => zip_exports);
6596
6741
  let successCount = 0;
6597
6742
  for (const skill of selectedSkills) {
6598
- console.log(`${DIM$4}正在发布 ${skill.name}...${RESET$4}`);
6743
+ console.log(`${DIM$6}正在发布 ${skill.name}...${RESET$6}`);
6599
6744
  try {
6600
6745
  const zipBuffer = createZipFromDir(skill.path);
6601
6746
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6602
- console.log(` ${GREEN$3}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$4}`);
6747
+ console.log(` ${GREEN$5}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$6}`);
6603
6748
  successCount++;
6604
6749
  } catch (error) {
6605
- console.error(` ${RED$2}✗ ${skill.name}:${error.message}${RESET$4}`);
6750
+ console.error(` ${RED$4}✗ ${skill.name}:${error.message}${RESET$6}`);
6606
6751
  }
6607
6752
  }
6608
- console.log(`\n${GREEN$3}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$4}`);
6753
+ console.log(`\n${GREEN$5}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$6}`);
6609
6754
  if (tmpDir) try {
6610
6755
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6611
6756
  await cleanupTempDir(tmpDir);
@@ -6655,11 +6800,11 @@ function truncate(text, maxLen) {
6655
6800
  return text.slice(0, maxLen) + "...";
6656
6801
  }
6657
6802
  var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
6658
- const RESET$3 = "\x1B[0m";
6659
- const BOLD$1 = "\x1B[1m";
6660
- const DIM$3 = "\x1B[38;5;102m";
6661
- const GREEN$2 = "\x1B[32m";
6662
- 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";
6663
6808
  const YELLOW$1 = "\x1B[33m";
6664
6809
  async function runPackage(args, globalOpts) {
6665
6810
  const subcommand = args[0];
@@ -6705,21 +6850,21 @@ function getWorkdir(globalOpts, args) {
6705
6850
  return globalOpts.workdir || process.cwd();
6706
6851
  }
6707
6852
  function printPackageHelp() {
6708
- console.log(`${BOLD$1}包命令:${RESET$3}`);
6853
+ console.log(`${BOLD$3}包命令:${RESET$5}`);
6709
6854
  console.log();
6710
- console.log(`${BOLD$1}本地操作:${RESET$3}`);
6711
- console.log(` ${DIM$3}bfi skills package list${RESET$3} 列出已安装的包`);
6712
- console.log(` ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包(含全部技能)`);
6713
- console.log(` ${DIM$3}bfi skills package uninstall <ref>${RESET$3} 卸载包(含全部技能)`);
6714
- console.log(` ${DIM$3}bfi skills package update [ref]${RESET$3} 更新包中技能`);
6715
- 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} 搜索包`);
6716
6861
  console.log();
6717
- console.log(`${BOLD$1}服务端管理:${RESET$3}`);
6718
- console.log(` ${DIM$3}bfi skills package create <slug>${RESET$3} 创建包`);
6719
- console.log(` ${DIM$3}bfi skills package add-skills <ref> [skills...]${RESET$3} 添加技能到包`);
6720
- 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} 从包移除技能`);
6721
6866
  console.log();
6722
- console.log(`${BOLD$1}选项:${RESET$3}`);
6867
+ console.log(`${BOLD$3}选项:${RESET$5}`);
6723
6868
  console.log(` --namespace <ns> 目标命名空间`);
6724
6869
  console.log(` --name <name> 显示名称(create 时)`);
6725
6870
  console.log(` --description <t> 描述(create 时)`);
@@ -6736,18 +6881,18 @@ async function handleLocalList(args, globalOpts) {
6736
6881
  }
6737
6882
  if (entries.length === 0) {
6738
6883
  console.log("没有已安装的包。");
6739
- console.log(`使用 ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包。`);
6884
+ console.log(`使用 ${DIM$5}bfi skills package install <ref>${RESET$5} 安装包。`);
6740
6885
  return;
6741
6886
  }
6742
6887
  console.log();
6743
- console.log(`${BOLD$1}已安装的包(${entries.length} 个):${RESET$3}`);
6888
+ console.log(`${BOLD$3}已安装的包(${entries.length} 个):${RESET$5}`);
6744
6889
  console.log();
6745
6890
  for (const [ref, info] of entries) {
6746
6891
  const pkg = info;
6747
6892
  const skills = lock.skills || {};
6748
6893
  const pkgSkills = Object.entries(skills).filter(([, s]) => s.package?.slug === pkg.slug);
6749
- console.log(` ${BOLD$1}${pkg.name || pkg.slug}${RESET$3}`);
6750
- 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}`);
6751
6896
  console.log();
6752
6897
  }
6753
6898
  }
@@ -6806,25 +6951,25 @@ async function handleInstall(args, api, globalOpts) {
6806
6951
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
6807
6952
  const isYes = args.includes("-y") || args.includes("--yes") || globalOpts.yes;
6808
6953
  const isGlobal = args.includes("-g") || args.includes("--global");
6809
- console.log(`${DIM$3}正在获取包信息...${RESET$3}`);
6954
+ console.log(`${DIM$5}正在获取包信息...${RESET$5}`);
6810
6955
  let pkgInfo;
6811
6956
  try {
6812
6957
  pkgInfo = await api.getPackage(namespace, slug);
6813
6958
  pkgInfo = pkgInfo.data || pkgInfo;
6814
6959
  } catch (error) {
6815
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
6960
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
6816
6961
  process.exit(1);
6817
6962
  }
6818
6963
  const skills = pkgInfo.skills || [];
6819
6964
  if (skills.length === 0) {
6820
- console.log(`${YELLOW$1}包中没有技能。${RESET$3}`);
6965
+ console.log(`${YELLOW$1}包中没有技能。${RESET$5}`);
6821
6966
  return;
6822
6967
  }
6823
- console.log(`${BOLD$1}${pkgInfo.name || slug}${RESET$3}(${skills.length} 个技能):`);
6968
+ console.log(`${BOLD$3}${pkgInfo.name || slug}${RESET$5}(${skills.length} 个技能):`);
6824
6969
  console.log();
6825
6970
  for (const skill of skills) {
6826
6971
  const ref = `@${skill.namespace || namespace}/${skill.slug}`;
6827
- console.log(` ${DIM$3}• ${skill.displayName || skill.slug}${RESET$3} ${DIM$3}${ref}${RESET$3}`);
6972
+ console.log(` ${DIM$5}• ${skill.displayName || skill.slug}${RESET$5} ${DIM$5}${ref}${RESET$5}`);
6828
6973
  }
6829
6974
  console.log();
6830
6975
  let targetAgents;
@@ -6837,8 +6982,8 @@ async function handleInstall(args, api, globalOpts) {
6837
6982
  targetAgents = ensureUniversalAgents(installed.length > 0 ? installed : validAgents);
6838
6983
  installGlobally = isGlobal;
6839
6984
  installMode = "symlink";
6840
- console.log(`${DIM$3}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$3}`);
6841
- console.log(`${DIM$3}范围:${installGlobally ? "全局" : "项目"} | 方式:${installMode === "symlink" ? "符号链接" : "复制"}${RESET$3}`);
6985
+ console.log(`${DIM$5}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$5}`);
6986
+ console.log(`${DIM$5}范围:${installGlobally ? "全局" : "项目"} | 方式:${installMode === "symlink" ? "符号链接" : "复制"}${RESET$5}`);
6842
6987
  console.log();
6843
6988
  } else {
6844
6989
  const spinner$1 = spinner();
@@ -6859,7 +7004,7 @@ async function handleInstall(args, api, globalOpts) {
6859
7004
  }
6860
7005
  if (useEve) {
6861
7006
  targetAgents = ["eve"];
6862
- console.log(`${DIM$3}安装到:eve agent${RESET$3}`);
7007
+ console.log(`${DIM$5}安装到:eve agent${RESET$5}`);
6863
7008
  } else {
6864
7009
  const selected = await selectAgentsInteractive({ global: false });
6865
7010
  if (isCancel(selected)) {
@@ -6881,7 +7026,7 @@ async function handleInstall(args, api, globalOpts) {
6881
7026
  } else if (installedAgents.length === 1) {
6882
7027
  targetAgents = ensureUniversalAgents(installedAgents);
6883
7028
  const firstAgent = installedAgents[0];
6884
- console.log(`${DIM$3}安装到:${agents[firstAgent].displayName}${RESET$3}`);
7029
+ console.log(`${DIM$5}安装到:${agents[firstAgent].displayName}${RESET$5}`);
6885
7030
  } else {
6886
7031
  const selected = await selectAgentsInteractive({ global: false });
6887
7032
  if (isCancel(selected)) {
@@ -6998,13 +7143,13 @@ async function handleInstall(args, api, globalOpts) {
6998
7143
  if (targetAgents.includes("eve")) runAddBaseOpts.subagent = eveSubagentTargets.map((s) => s ?? "root");
6999
7144
  for (const skill of skills) {
7000
7145
  const skillRef = `@${skill.namespace || namespace}/${skill.slug}`;
7001
- console.log(` ${DIM$3}正在安装 ${skillRef}...${RESET$3}`);
7146
+ console.log(` ${DIM$5}正在安装 ${skillRef}...${RESET$5}`);
7002
7147
  try {
7003
7148
  await runAdd([skillRef], runAddBaseOpts);
7004
- console.log(` ${GREEN$2}✓ ${skill.slug}${RESET$3}`);
7149
+ console.log(` ${GREEN$4}✓ ${skill.slug}${RESET$5}`);
7005
7150
  installedSkills.push(skill.slug);
7006
7151
  } catch (error) {
7007
- console.log(` ${RED$1}✗ ${skill.slug}:${error.message}${RESET$3}`);
7152
+ console.log(` ${RED$3}✗ ${skill.slug}:${error.message}${RESET$5}`);
7008
7153
  }
7009
7154
  }
7010
7155
  const cwd = getWorkdir(globalOpts, args);
@@ -7031,7 +7176,7 @@ async function handleInstall(args, api, globalOpts) {
7031
7176
  }
7032
7177
  saveLockfile(cwd, lock);
7033
7178
  console.log();
7034
- console.log(`${GREEN$2}✓ 包安装完成${RESET$3}`);
7179
+ console.log(`${GREEN$4}✓ 包安装完成${RESET$5}`);
7035
7180
  }
7036
7181
  async function handleUninstall(args, globalOpts) {
7037
7182
  const pkgRef = args[0];
@@ -7044,7 +7189,7 @@ async function handleUninstall(args, globalOpts) {
7044
7189
  const cwd = getWorkdir(globalOpts, args);
7045
7190
  const lock = loadLockfile(cwd);
7046
7191
  if (!lock.packages || !lock.packages[pkgKey]) {
7047
- console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$3}`);
7192
+ console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$5}`);
7048
7193
  return;
7049
7194
  }
7050
7195
  const skills = lock.skills || {};
@@ -7065,7 +7210,7 @@ async function handleUninstall(args, globalOpts) {
7065
7210
  delete lock.packages[pkgKey];
7066
7211
  const { saveLockfile } = await Promise.resolve().then(() => config_exports);
7067
7212
  saveLockfile(cwd, lock);
7068
- console.log(`${GREEN$2}✓ 已卸载包,移除 ${removed} 个技能${RESET$3}`);
7213
+ console.log(`${GREEN$4}✓ 已卸载包,移除 ${removed} 个技能${RESET$5}`);
7069
7214
  }
7070
7215
  async function handleUpdate(args, api, globalOpts) {
7071
7216
  const pkgRef = args[0];
@@ -7075,7 +7220,7 @@ async function handleUpdate(args, api, globalOpts) {
7075
7220
  if (pkgRef) {
7076
7221
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7077
7222
  if (!pkgs[`@${namespace}/${slug}`]) {
7078
- console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$3}`);
7223
+ console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$5}`);
7079
7224
  return;
7080
7225
  }
7081
7226
  packagesToUpdate.push({
@@ -7090,11 +7235,11 @@ async function handleUpdate(args, api, globalOpts) {
7090
7235
  console.log("没有已安装的包需要更新。");
7091
7236
  return;
7092
7237
  }
7093
- console.log(`${DIM$3}正在更新 ${packagesToUpdate.length} 个包...${RESET$3}`);
7238
+ console.log(`${DIM$5}正在更新 ${packagesToUpdate.length} 个包...${RESET$5}`);
7094
7239
  for (const pkg of packagesToUpdate) try {
7095
7240
  const pkgInfo = await api.getPackage(pkg.namespace, pkg.slug);
7096
7241
  const skills = (pkgInfo.data || pkgInfo).skills || [];
7097
- 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}`);
7098
7243
  for (const skill of skills) {
7099
7244
  const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
7100
7245
  const { runAdd } = await Promise.resolve().then(() => add_exports);
@@ -7106,9 +7251,9 @@ async function handleUpdate(args, api, globalOpts) {
7106
7251
  } catch {}
7107
7252
  }
7108
7253
  } catch (error) {
7109
- 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}`);
7110
7255
  }
7111
- console.log(`${GREEN$2}✓ 包更新完成${RESET$3}`);
7256
+ console.log(`${GREEN$4}✓ 包更新完成${RESET$5}`);
7112
7257
  }
7113
7258
  async function handleSearch(args, api, globalOpts) {
7114
7259
  const query = args.filter((a) => !a.startsWith("--")).join(" ") || void 0;
@@ -7128,11 +7273,11 @@ async function handleSearch(args, api, globalOpts) {
7128
7273
  }, null, 2));
7129
7274
  return;
7130
7275
  }
7131
- console.log(`\n${BOLD$1}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$3}\n`);
7276
+ console.log(`\n${BOLD$3}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$5}\n`);
7132
7277
  for (const [ns, sk] of namespaces) {
7133
- console.log(` ${BOLD$1}@${ns}${RESET$3}(${sk.length} 个技能)`);
7134
- for (const s of sk.slice(0, 5)) console.log(` ${DIM$3}- ${s.displayName || s.name} (${s.slug})${RESET$3}`);
7135
- 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}`);
7136
7281
  console.log();
7137
7282
  }
7138
7283
  } else {
@@ -7171,11 +7316,11 @@ async function handleSearch(args, api, globalOpts) {
7171
7316
  };
7172
7317
  const maxName = Math.max(...allPackages.map((p) => dw(p.displayName || p.name || p.slug || "")), 4);
7173
7318
  const maxSlug = Math.max(...allPackages.map((p) => dw(`@${p._namespace}/${p.slug}`)), 4);
7174
- console.log(`\n${BOLD$1}所有技能包(${allPackages.length} 个):${RESET$3}\n`);
7319
+ console.log(`\n${BOLD$3}所有技能包(${allPackages.length} 个):${RESET$5}\n`);
7175
7320
  for (const pkg of allPackages) {
7176
7321
  const name = pad(pkg.displayName || pkg.name || pkg.slug || "", maxName);
7177
7322
  const ref = pad(`@${pkg._namespace}/${pkg.slug}`, maxSlug);
7178
- 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}`);
7179
7324
  }
7180
7325
  }
7181
7326
  }
@@ -7196,11 +7341,11 @@ async function handleCreate(args, api, globalOpts) {
7196
7341
  description: description || "",
7197
7342
  visibility: visibility.toUpperCase()
7198
7343
  });
7199
- console.log(`${GREEN$2}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7344
+ console.log(`${GREEN$4}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$5}`);
7200
7345
  const pkg = result.package || result.data || result;
7201
- 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}`);
7202
7347
  } catch (error) {
7203
- console.error(`${RED$1}创建包失败:${error.message}${RESET$3}`);
7348
+ console.error(`${RED$3}创建包失败:${error.message}${RESET$5}`);
7204
7349
  process.exit(1);
7205
7350
  }
7206
7351
  }
@@ -7226,11 +7371,11 @@ async function handleAddSkills(args, api, globalOpts) {
7226
7371
  };
7227
7372
  });
7228
7373
  if (skills.length === 0) {
7229
- console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$3}`);
7374
+ console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$5}`);
7230
7375
  return;
7231
7376
  }
7232
7377
  } catch (error) {
7233
- console.error(`${RED$1}获取技能列表失败:${error.message}${RESET$3}`);
7378
+ console.error(`${RED$3}获取技能列表失败:${error.message}${RESET$5}`);
7234
7379
  process.exit(1);
7235
7380
  }
7236
7381
  else skills = skillRefs.map((ref) => {
@@ -7242,9 +7387,9 @@ async function handleAddSkills(args, api, globalOpts) {
7242
7387
  });
7243
7388
  try {
7244
7389
  await api.addSkillsToPackage(namespace, slug, skills);
7245
- console.log(`${GREEN$2}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7390
+ console.log(`${GREEN$4}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$5}`);
7246
7391
  } catch (error) {
7247
- console.error(`${RED$1}添加失败:${error.message}${RESET$3}`);
7392
+ console.error(`${RED$3}添加失败:${error.message}${RESET$5}`);
7248
7393
  process.exit(1);
7249
7394
  }
7250
7395
  }
@@ -7269,7 +7414,7 @@ async function handleRemoveSkills(args, api, globalOpts) {
7269
7414
  return;
7270
7415
  }
7271
7416
  } catch (error) {
7272
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7417
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7273
7418
  process.exit(1);
7274
7419
  }
7275
7420
  else skills = skillRefs.map((ref) => {
@@ -7281,9 +7426,9 @@ async function handleRemoveSkills(args, api, globalOpts) {
7281
7426
  });
7282
7427
  try {
7283
7428
  await api.removeSkillsFromPackage(namespace, slug, skills);
7284
- console.log(`${GREEN$2}✓ 已从包移除 ${skills.length} 个技能${RESET$3}`);
7429
+ console.log(`${GREEN$4}✓ 已从包移除 ${skills.length} 个技能${RESET$5}`);
7285
7430
  } catch (error) {
7286
- console.error(`${RED$1}移除失败:${error.message}${RESET$3}`);
7431
+ console.error(`${RED$3}移除失败:${error.message}${RESET$5}`);
7287
7432
  process.exit(1);
7288
7433
  }
7289
7434
  }
@@ -7302,19 +7447,19 @@ async function handleServerInfo(args, api, globalOpts) {
7302
7447
  console.log(JSON.stringify(pkg, null, 2));
7303
7448
  return;
7304
7449
  }
7305
- console.log(`\n${BOLD$1}${pkg.displayName || pkg.name || slug}${RESET$3}`);
7306
- console.log(`${DIM$3}${"=".repeat(48)}${RESET$3}`);
7307
- console.log(` ${BOLD$1}Slug:${RESET$3} ${toCanonicalSlug(namespace, slug)}`);
7308
- console.log(` ${BOLD$1}命名空间:${RESET$3} @${namespace}`);
7309
- console.log(` ${BOLD$1}可见性:${RESET$3} ${pkg.visibility || "PRIVATE"}`);
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"}`);
7310
7455
  const skills = pkg.skills || [];
7311
7456
  if (skills.length > 0) {
7312
- console.log(`\n ${BOLD$1}技能(${skills.length} 个):${RESET$3}`);
7313
- for (const s of skills) console.log(` ${DIM$3}- ${s.displayName || s.slug} (${s.namespace || namespace}--${s.slug})${RESET$3}`);
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}`);
7314
7459
  }
7315
7460
  console.log();
7316
7461
  } catch (error) {
7317
- console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7462
+ console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7318
7463
  process.exit(1);
7319
7464
  }
7320
7465
  }
@@ -7322,6 +7467,408 @@ function getOptionValue(args, flag) {
7322
7467
  const idx = args.indexOf(flag);
7323
7468
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
7324
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>");
7797
+ process.exit(1);
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();
7808
+ }
7809
+ async function config(args, globalOpts) {
7810
+ const idArg = args[0];
7811
+ if (!idArg) {
7812
+ console.error("用法:bfi mcp config <mcpId>");
7813
+ process.exit(1);
7814
+ }
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>");
7823
+ process.exit(1);
7824
+ }
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]");
7845
+ process.exit(1);
7846
+ }
7847
+ const mcpPath = resolveMcpPath(getOption(args, "--scope") ?? "user");
7848
+ if (!fs.existsSync(mcpPath)) {
7849
+ console.error(`配置文件不存在:${mcpPath}`);
7850
+ process.exit(1);
7851
+ }
7852
+ const existing = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
7853
+ if (!existing.mcpServers?.[name]) {
7854
+ console.error(`${RED$1}未找到服务器:${name}${RESET$3}`);
7855
+ process.exit(1);
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}`);
7860
+ }
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) {
7869
+ const idx = args.indexOf(flag);
7870
+ return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
7871
+ }
7325
7872
  const RESET$2 = "\x1B[0m";
7326
7873
  const DIM$2 = "\x1B[38;5;102m";
7327
7874
  const TEXT$2 = "\x1B[38;5;145m";
@@ -7435,6 +7982,735 @@ async function runInstall(args, globalOpts) {
7435
7982
  if (failedCount > 0) console.log(`${YELLOW}⚠ ${failedCount} 项恢复失败${RESET$1}`);
7436
7983
  console.log();
7437
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
+ }
7438
8714
  const __dirname = dirname(fileURLToPath(import.meta.url));
7439
8715
  function getVersion() {
7440
8716
  try {
@@ -7527,11 +8803,37 @@ ${BOLD}━━━ 技能包管理 ━━━${RESET}
7527
8803
  skills package add <pkg> <skill...> 添加技能到包
7528
8804
  skills package remove <pkg> <skill...> 从包移除技能
7529
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
+
7530
8821
  ${BOLD}━━━ 文档 ━━━${RESET}
7531
8822
  docs upload <file> 上传文档
7532
8823
  docs list 列出文档
7533
8824
  docs info <id> 查看文档详情
7534
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
+
7535
8837
  ${BOLD}━━━ 配置 ━━━${RESET}
7536
8838
  config get [key] 查看配置
7537
8839
  config set <key> <value> [--global] 设置配置
@@ -7796,6 +9098,9 @@ async function main() {
7796
9098
  setAgents(await resolveAgents(cfg.token ? new SkillHubAPI(cfg.registry, cfg.token) : void 0));
7797
9099
  } catch {}
7798
9100
  switch (command) {
9101
+ case "ymc":
9102
+ await runYmc(restArgs, globalOpts);
9103
+ break;
7799
9104
  case "auth":
7800
9105
  if (restArgs[0] === "logout") await runLogout();
7801
9106
  else if (restArgs[0] === "whoami") await runWhoami(globalOpts);
@@ -7828,6 +9133,12 @@ async function main() {
7828
9133
  case "pkg":
7829
9134
  await runPackage(restArgs, globalOpts);
7830
9135
  break;
9136
+ case "plugin":
9137
+ await runPlugin(restArgs, globalOpts);
9138
+ break;
9139
+ case "mcp":
9140
+ await runMcp(restArgs, globalOpts);
9141
+ break;
7831
9142
  case "log":
7832
9143
  await runLog(restArgs, globalOpts);
7833
9144
  break;
@@ -7906,5 +9217,8 @@ async function main() {
7906
9217
  console.log(`运行 ${BOLD}bfi --help${RESET} 查看用法。`);
7907
9218
  }
7908
9219
  }
7909
- main().finally(() => process.exit(process.exitCode ?? 0));
9220
+ main().catch((e) => {
9221
+ console.error(`✗ ${e?.message || e}`);
9222
+ process.exit(1);
9223
+ });
7910
9224
  export { loadGlobalConfig };