bfi-cli 0.1.89 → 0.1.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -4,13 +4,16 @@ import { isCancel } from "./_chunks/libs/@clack/core.mjs";
4
4
  import { cancel, confirm, groupMultiselect, intro, log, multiselect as multiselect$1, note, outro, select, spinner } from "./_chunks/libs/@clack/prompts.mjs";
5
5
  import { require_picocolors } from "./_chunks/libs/picocolors.mjs";
6
6
  import { addSkillToLocalLock, addSkillToLock, computeSkillFolderHash, discoverSkills, dismissPrompt, filterSkills, getAllLockedSkills, getGitHubToken, getLastSelectedAgents, getSkillDisplayName, getSkillFromLock, isPromptDismissed, parseFrontmatter, parseSkillMd, readLocalLock, readSkillLock, removeSkillFromLock, sanitizeMetadata, saveSelectedAgents, stripTerminalEscapes } from "./_chunks/skills.mjs";
7
+ import { PluginRegistryClient } from "./_chunks/registry-client.mjs";
8
+ import { loadGlobalConfig, loadLockfile, loadProjectConfig, resolveConfig, saveGlobalConfig as saveGlobalConfig$1, saveLockfile, setConfigValue } from "./_chunks/config.mjs";
7
9
  import { esm_default } from "./_chunks/libs/simple-git.mjs";
8
10
  import { EVE_SUBAGENTS_DIR, agents, detectInstalledAgents, getEveSubagents, getNonUniversalAgents, getUniversalAgents, getVisibleUniversalAgents, isUniversalAgent } from "./_chunks/agents.mjs";
11
+ import { packageSkillName } from "./_chunks/package-skill-identity.mjs";
9
12
  import { createRequire } from "node:module";
10
13
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
11
14
  import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep } from "path";
12
15
  import { fileURLToPath } from "url";
13
- import { createHash } from "node:crypto";
16
+ import { createHash, randomUUID } from "node:crypto";
14
17
  import { stripVTControlCharacters } from "node:util";
15
18
  import fs from "node:fs";
16
19
  import path$1 from "node:path";
@@ -19,8 +22,8 @@ import * as readline from "readline";
19
22
  import { Writable } from "stream";
20
23
  import https from "node:https";
21
24
  import http from "node:http";
22
- import os$1 from "node:os";
23
25
  import zlib, { gunzipSync, inflateRawSync } from "node:zlib";
26
+ import os$1 from "node:os";
24
27
  import { promisify } from "util";
25
28
  import { execFile, spawn, spawnSync } from "child_process";
26
29
  import { access, chmod, cp, lstat, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "fs/promises";
@@ -448,8 +451,10 @@ async function searchMultiselect(options) {
448
451
  }
449
452
  if (key.name === "space") {
450
453
  const item = filtered[cursor];
451
- if (item) if (selected.has(item.value)) selected.delete(item.value);
452
- else selected.add(item.value);
454
+ if (item) {
455
+ if (selected.has(item.value)) selected.delete(item.value);
456
+ else selected.add(item.value);
457
+ }
453
458
  render();
454
459
  return;
455
460
  }
@@ -476,6 +481,9 @@ var SkillHubAPI = class {
476
481
  token;
477
482
  mockUserId;
478
483
  rejectUnauthorized;
484
+ pluginRegistry() {
485
+ return new PluginRegistryClient(this.registry, this.token);
486
+ }
479
487
  constructor(registry, token = null, mockUserId = null) {
480
488
  this.registry = registry || "https://bfi.yyuap.com:811";
481
489
  this.token = token;
@@ -506,12 +514,14 @@ var SkillHubAPI = class {
506
514
  if (url.protocol === "https:") requestOptions.rejectUnauthorized = this.rejectUnauthorized;
507
515
  let bodyStr;
508
516
  let bodyBuf;
509
- if (options.body !== void 0) if (options.body instanceof Buffer) bodyBuf = options.body;
510
- else if (typeof options.body === "string") bodyStr = options.body;
511
- else if (typeof FormData !== "undefined" && options.body instanceof FormData) return this.fetchRequest(url, requestOptions, options.body);
512
- else {
513
- requestOptions.headers["Content-Type"] = "application/json";
514
- bodyStr = JSON.stringify(options.body);
517
+ if (options.body !== void 0) {
518
+ if (options.body instanceof Buffer) bodyBuf = options.body;
519
+ else if (typeof options.body === "string") bodyStr = options.body;
520
+ else if (typeof FormData !== "undefined" && options.body instanceof FormData) return this.fetchRequest(url, requestOptions, options.body);
521
+ else {
522
+ requestOptions.headers["Content-Type"] = "application/json";
523
+ bodyStr = JSON.stringify(options.body);
524
+ }
515
525
  }
516
526
  return new Promise((resolve, reject) => {
517
527
  const req = (url.protocol === "https:" ? https : http).request(url, requestOptions, (res) => {
@@ -653,6 +663,13 @@ var SkillHubAPI = class {
653
663
  async whoami() {
654
664
  return (await this.request("GET", "/whoami")).body;
655
665
  }
666
+ async reportInstallEvent(payload) {
667
+ return (await this.request("POST", "/install-events", { body: payload })).body;
668
+ }
669
+ async getBlocklist() {
670
+ const body = (await this.request("GET", "/registry/blocklist")).body;
671
+ return body.data || body;
672
+ }
656
673
  async myNamespaces() {
657
674
  return (await this.request("GET", "/me/namespaces")).body;
658
675
  }
@@ -664,6 +681,30 @@ var SkillHubAPI = class {
664
681
  const body = (await this.request("GET", `/namespaces/${namespace}/packages/${slug}`)).body;
665
682
  return body.data || body;
666
683
  }
684
+ async listComponentFiles(namespace, slug, componentId) {
685
+ const body = (await this.request("GET", `/namespaces/${namespace}/packages/${slug}/components/${componentId}/files`)).body;
686
+ return body.data || body;
687
+ }
688
+ async readComponentFile(namespace, slug, componentId, filePath) {
689
+ const target = `/namespaces/${namespace}/packages/${slug}/components/${componentId}/files/content?path=${encodeURIComponent(filePath)}`;
690
+ const url = new URL(this.buildUrl(target));
691
+ const isHttps = url.protocol === "https:";
692
+ const client = isHttps ? https : http;
693
+ const options = { headers: this.getHeaders() };
694
+ if (isHttps) options.rejectUnauthorized = this.rejectUnauthorized;
695
+ return new Promise((resolve, reject) => {
696
+ client.get(url.toString(), options, (res) => {
697
+ if (!res.statusCode || res.statusCode >= 400) {
698
+ reject(/* @__PURE__ */ new Error(`读取组件文件失败:HTTP ${res.statusCode}(${filePath})`));
699
+ res.resume();
700
+ return;
701
+ }
702
+ const chunks = [];
703
+ res.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
704
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
705
+ }).on("error", reject);
706
+ });
707
+ }
667
708
  async downloadPackage(namespace, slug, targetPath) {
668
709
  const path = `/namespaces/${namespace}/packages/${slug}/download`;
669
710
  try {
@@ -682,72 +723,6 @@ var SkillHubAPI = class {
682
723
  async removeSkillsFromPackage(namespace, slug, skills) {
683
724
  return (await this.request("DELETE", `/namespaces/${namespace}/packages/${slug}/skills`, { body: { skills } })).body;
684
725
  }
685
- async listPlugins(params) {
686
- const body = (await this.request("GET", "/plugins", { params })).body;
687
- return body.data || body;
688
- }
689
- async getPlugin(pluginId) {
690
- const body = (await this.request("GET", `/plugins/${pluginId}`)).body;
691
- return body.data || body;
692
- }
693
- async createPlugin(data) {
694
- return (await this.request("POST", "/plugins", { body: data })).body;
695
- }
696
- async updatePlugin(pluginId, data) {
697
- return (await this.request("PUT", `/plugins/${pluginId}`, { body: data })).body;
698
- }
699
- async deletePlugin(pluginId) {
700
- return (await this.request("DELETE", `/plugins/${pluginId}`)).body;
701
- }
702
- async listPluginVersions(pluginId) {
703
- const body = (await this.request("GET", `/plugins/${pluginId}/versions`)).body;
704
- return body.data || body;
705
- }
706
- async createPluginVersion(pluginId, data) {
707
- return (await this.request("POST", `/plugins/${pluginId}/versions`, { body: data })).body;
708
- }
709
- async publishPluginVersion(pluginId, versionId) {
710
- return (await this.request("POST", `/plugins/${pluginId}/versions/${versionId}/publish`)).body;
711
- }
712
- async yankPluginVersion(pluginId, versionId, reason) {
713
- return (await this.request("POST", `/plugins/${pluginId}/versions/${versionId}/yank`, { body: reason ? { changelog: reason } : void 0 })).body;
714
- }
715
- async downloadPluginBundle(pluginId, versionId, targetPath) {
716
- try {
717
- return await this.downloadFile(`/plugins/${pluginId}/versions/${versionId}/download`, targetPath);
718
- } catch (error) {
719
- throw new Error(`Failed to download plugin bundle: ${error.message}`);
720
- }
721
- }
722
- async uploadPlugin(fileBuffer, filename, namespace, options) {
723
- const form = new FormData();
724
- form.append("file", new Blob([new Uint8Array(fileBuffer)]), filename);
725
- form.append("namespace", namespace);
726
- if (options?.visibility) form.append("visibility", options.visibility);
727
- if (options?.summary) form.append("summary", options.summary);
728
- if (options?.changelog) form.append("changelog", options.changelog);
729
- return (await this.request("POST", "/plugins/upload", { body: form })).body;
730
- }
731
- async listMcpServers(params) {
732
- const body = (await this.request("GET", "/mcp-servers", { params })).body;
733
- return body.data || body;
734
- }
735
- async getMcpServer(mcpId) {
736
- const body = (await this.request("GET", `/mcp-servers/${mcpId}`)).body;
737
- return body.data || body;
738
- }
739
- async createMcpServer(data) {
740
- return (await this.request("POST", "/mcp-servers", { body: data })).body;
741
- }
742
- async updateMcpServer(mcpId, data) {
743
- return (await this.request("PUT", `/mcp-servers/${mcpId}`, { body: data })).body;
744
- }
745
- async deleteMcpServer(mcpId) {
746
- return (await this.request("DELETE", `/mcp-servers/${mcpId}`)).body;
747
- }
748
- async getMcpConfig(mcpId) {
749
- return (await this.request("GET", `/mcp-servers/${mcpId}/config`)).body.data?.config ?? "";
750
- }
751
726
  async gitParse(repositoryUrl, branch, directory) {
752
727
  const body = {
753
728
  repositoryUrl,
@@ -907,142 +882,6 @@ var SkillHubAPI = class {
907
882
  });
908
883
  }
909
884
  };
910
- var config_exports = /* @__PURE__ */ __exportAll({
911
- GLOBAL_CONFIG_DIR: () => GLOBAL_CONFIG_DIR,
912
- GLOBAL_CONFIG_FILE: () => GLOBAL_CONFIG_FILE,
913
- LOCK_FILE: () => LOCK_FILE,
914
- PROJECT_CONFIG_FILE: () => PROJECT_CONFIG_FILE,
915
- getConfigValue: () => getConfigValue,
916
- loadGlobalConfig: () => loadGlobalConfig,
917
- loadLockfile: () => loadLockfile,
918
- loadProjectConfig: () => loadProjectConfig,
919
- resolveConfig: () => resolveConfig,
920
- saveGlobalConfig: () => saveGlobalConfig,
921
- saveLockfile: () => saveLockfile,
922
- saveProjectConfig: () => saveProjectConfig,
923
- setConfigValue: () => setConfigValue
924
- });
925
- const GLOBAL_CONFIG_DIR = path$1.join(os$1.homedir(), ".bfi");
926
- const GLOBAL_CONFIG_FILE = path$1.join(GLOBAL_CONFIG_DIR, "config.json");
927
- const PROJECT_CONFIG_FILE = ".bfirc";
928
- const LOCK_FILE_DIR = ".bfi";
929
- const LOCK_FILE = path$1.join(LOCK_FILE_DIR, "lock.json");
930
- function resolveConfig(globalOpts = {}) {
931
- return {
932
- registry: getConfigValue("registry", globalOpts) || "https://bfi.yyuap.com:811",
933
- token: getConfigValue("token", globalOpts) || null,
934
- namespace: getConfigValue("namespace", globalOpts) || "global",
935
- ide: getConfigValue("ide", globalOpts) || null
936
- };
937
- }
938
- function loadGlobalConfig() {
939
- try {
940
- if (fs.existsSync(GLOBAL_CONFIG_FILE)) {
941
- const content = fs.readFileSync(GLOBAL_CONFIG_FILE, "utf8");
942
- return JSON.parse(content);
943
- }
944
- } catch (error) {
945
- console.warn(`Warning: Failed to load global config: ${error.message}`);
946
- }
947
- return null;
948
- }
949
- function saveGlobalConfig(config) {
950
- try {
951
- if (!fs.existsSync(GLOBAL_CONFIG_DIR)) fs.mkdirSync(GLOBAL_CONFIG_DIR, {
952
- recursive: true,
953
- mode: 448
954
- });
955
- const content = JSON.stringify(config, null, 2);
956
- fs.writeFileSync(GLOBAL_CONFIG_FILE, content, { mode: 384 });
957
- return true;
958
- } catch (error) {
959
- throw new Error(`Failed to save global config: ${error.message}`);
960
- }
961
- }
962
- function loadProjectConfig(workdir) {
963
- try {
964
- const configPath = path$1.join(workdir, PROJECT_CONFIG_FILE);
965
- if (fs.existsSync(configPath)) {
966
- const content = fs.readFileSync(configPath, "utf8");
967
- return JSON.parse(content);
968
- }
969
- } catch (error) {
970
- console.warn(`Warning: Failed to load project config: ${error.message}`);
971
- }
972
- return null;
973
- }
974
- function saveProjectConfig(workdir, config) {
975
- try {
976
- const configPath = path$1.join(workdir, PROJECT_CONFIG_FILE);
977
- const content = JSON.stringify(config, null, 2);
978
- fs.writeFileSync(configPath, content);
979
- return true;
980
- } catch (error) {
981
- throw new Error(`Failed to save project config: ${error.message}`);
982
- }
983
- }
984
- function loadLockfile(workdir) {
985
- try {
986
- const lockPath = path$1.join(workdir, LOCK_FILE);
987
- if (fs.existsSync(lockPath)) {
988
- const content = fs.readFileSync(lockPath, "utf8");
989
- return JSON.parse(content);
990
- }
991
- } catch (error) {
992
- console.warn(`Warning: Failed to load lockfile: ${error.message}`);
993
- }
994
- return {
995
- version: 1,
996
- skills: {},
997
- packages: {}
998
- };
999
- }
1000
- function saveLockfile(workdir, lock) {
1001
- try {
1002
- const lockDir = path$1.join(workdir, LOCK_FILE_DIR);
1003
- if (!fs.existsSync(lockDir)) fs.mkdirSync(lockDir, { recursive: true });
1004
- const lockPath = path$1.join(workdir, LOCK_FILE);
1005
- const content = JSON.stringify(lock, null, 2);
1006
- fs.writeFileSync(lockPath, content);
1007
- return true;
1008
- } catch (error) {
1009
- throw new Error(`Failed to save lockfile: ${error.message}`);
1010
- }
1011
- }
1012
- function getConfigValue(key, globalOpts = {}) {
1013
- const projectConfig = loadProjectConfig(globalOpts.workdir || process.cwd());
1014
- const globalConfig = loadGlobalConfig();
1015
- const configMap = {
1016
- registry: globalOpts.registry || projectConfig && projectConfig.registry || globalConfig && globalConfig.registry || null,
1017
- token: globalOpts.token || projectConfig && projectConfig.token || globalConfig && globalConfig.token || null,
1018
- namespace: globalOpts.namespace || projectConfig && projectConfig.namespace || globalConfig && globalConfig.defaultNamespace || "global",
1019
- ide: globalOpts.ide || projectConfig && projectConfig.ide || globalConfig && globalConfig.defaultIDE || null
1020
- };
1021
- return key ? configMap[key] : void 0;
1022
- }
1023
- function setConfigValue(key, value, isGlobal = false) {
1024
- if (isGlobal) {
1025
- const config = loadGlobalConfig() || { version: 1 };
1026
- const configKey = {
1027
- "registry": "registry",
1028
- "token": "token",
1029
- "default-namespace": "defaultNamespace",
1030
- "default-ide": "defaultIDE"
1031
- }[key] || key;
1032
- config[configKey] = value;
1033
- saveGlobalConfig(config);
1034
- } else {
1035
- const workdir = process.cwd();
1036
- const config = loadProjectConfig(workdir) || {};
1037
- const configKey = {
1038
- "registry": "registry",
1039
- "namespace": "namespace",
1040
- "ide": "ide"
1041
- }[key] || key;
1042
- config[configKey] = value;
1043
- saveProjectConfig(workdir, config);
1044
- }
1045
- }
1046
885
  var skill_ref_exports = /* @__PURE__ */ __exportAll({
1047
886
  parseSkillRef: () => parseSkillRef,
1048
887
  toCanonicalSlug: () => toCanonicalSlug,
@@ -1458,10 +1297,12 @@ async function isDirEntryOrSymlinkToDir(entry, entryPath) {
1458
1297
  }
1459
1298
  }
1460
1299
  function getCanonicalSkillsDir(global, cwd) {
1461
- return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR, SKILLS_SUBDIR);
1300
+ const baseDir = global ? homedir() : cwd || process.cwd();
1301
+ return join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
1462
1302
  }
1463
1303
  function getEveSubagentSkillsDir(subagent, cwd) {
1464
- return join(cwd || process.cwd(), EVE_SUBAGENTS_DIR, sanitizeName(subagent), "skills");
1304
+ const baseDir = cwd || process.cwd();
1305
+ return join(baseDir, EVE_SUBAGENTS_DIR, sanitizeName(subagent), "skills");
1465
1306
  }
1466
1307
  function getAgentBaseDir(agentType, global, cwd, eveSubagent) {
1467
1308
  if (isUniversalAgent(agentType)) return getCanonicalSkillsDir(global, cwd);
@@ -1539,7 +1380,8 @@ async function resolveParentSymlinks(path) {
1539
1380
  const dir = dirname(resolved);
1540
1381
  const base = basename(resolved);
1541
1382
  try {
1542
- return join(await realpath(dir), base);
1383
+ const realDir = await realpath(dir);
1384
+ return join(realDir, base);
1543
1385
  } catch {
1544
1386
  return resolved;
1545
1387
  }
@@ -1563,7 +1405,8 @@ async function createSymlink(target, linkPath) {
1563
1405
  }
1564
1406
  const linkDir = dirname(linkPath);
1565
1407
  await mkdir(linkDir, { recursive: true });
1566
- const relativePath = relative(await resolveParentSymlinks(linkDir), target);
1408
+ const realLinkDir = await resolveParentSymlinks(linkDir);
1409
+ const relativePath = relative(realLinkDir, target);
1567
1410
  const symlinkType = platform() === "win32" ? "junction" : void 0;
1568
1411
  await symlink(symlinkType === "junction" ? resolvedTarget : relativePath, linkPath, symlinkType);
1569
1412
  return true;
@@ -1632,7 +1475,8 @@ async function installSkillForAgent(skill, agentType, options = {}) {
1632
1475
  mode: "symlink"
1633
1476
  };
1634
1477
  if (!isGlobal && !isUniversalAgent(agentType)) {
1635
- if (!existsSync(join(cwd, agents[agentType].skillsDir.split("/")[0])) && agentType !== "claude-code") return {
1478
+ const agentRootDir = join(cwd, agents[agentType].skillsDir.split("/")[0]);
1479
+ if (!existsSync(agentRootDir) && agentType !== "claude-code") return {
1636
1480
  success: true,
1637
1481
  path: canonicalDir,
1638
1482
  canonicalPath: canonicalDir,
@@ -1706,7 +1550,8 @@ async function copyDirectory(src, dest, agentType) {
1706
1550
  dereference: true,
1707
1551
  recursive: true
1708
1552
  });
1709
- await chmod(destPath, (await stat(srcPath)).mode & 511);
1553
+ const sourceStats = await stat(srcPath);
1554
+ await chmod(destPath, sourceStats.mode & 511);
1710
1555
  } catch (err) {
1711
1556
  if (err instanceof Error && "code" in err && err.code === "ENOENT" && entry.isSymbolicLink()) console.warn(`Skipping broken symlink: ${srcPath}`);
1712
1557
  else throw err;
@@ -1923,7 +1768,8 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
1923
1768
  mode: "symlink"
1924
1769
  };
1925
1770
  if (!isGlobal && !isUniversalAgent(agentType)) {
1926
- if (!existsSync(join(cwd, agents[agentType].skillsDir.split("/")[0]))) return {
1771
+ const agentRootDir = join(cwd, agents[agentType].skillsDir.split("/")[0]);
1772
+ if (!existsSync(agentRootDir)) return {
1927
1773
  success: true,
1928
1774
  path: canonicalDir,
1929
1775
  canonicalPath: canonicalDir,
@@ -2151,7 +1997,7 @@ var ProviderRegistryImpl = class {
2151
1997
  };
2152
1998
  new ProviderRegistryImpl();
2153
1999
  const DISCOVERY_SCHEMA_V2 = "https://schemas.agentskills.io/discovery/0.2.0/schema.json";
2154
- const MAX_ARCHIVE_UNPACKED_BYTES = 50 * 1024 * 1024;
2000
+ const MAX_ARCHIVE_UNPACKED_BYTES = 52428800;
2155
2001
  const MAX_ARCHIVE_FILES = 1e3;
2156
2002
  var WellKnownProvider = class {
2157
2003
  id = "well-known";
@@ -3304,22 +3150,23 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3304
3150
  const installedAgents = await detectInstalledAgents();
3305
3151
  const totalAgents = Object.keys(agents).length;
3306
3152
  spinner.stop(`${totalAgents} agents`);
3307
- if (installedAgents.length === 0) if (options.yes) {
3308
- targetAgents = validAgents;
3309
- log.info("正在安装到全部 Agent");
3310
- } else {
3311
- log.info("请选择要安装技能的 Agent");
3312
- const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).map(([key, config]) => ({
3313
- value: key,
3314
- label: config.displayName
3315
- })));
3316
- if (isCancel(selected)) {
3317
- cancel("安装已取消");
3318
- process.exit(0);
3153
+ if (installedAgents.length === 0) {
3154
+ if (options.yes) {
3155
+ targetAgents = validAgents;
3156
+ log.info("正在安装到全部 Agent");
3157
+ } else {
3158
+ log.info("请选择要安装技能的 Agent");
3159
+ const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).map(([key, config]) => ({
3160
+ value: key,
3161
+ label: config.displayName
3162
+ })));
3163
+ if (isCancel(selected)) {
3164
+ cancel("安装已取消");
3165
+ process.exit(0);
3166
+ }
3167
+ targetAgents = selected;
3319
3168
  }
3320
- targetAgents = selected;
3321
- }
3322
- else if (installedAgents.length === 1 || options.yes) {
3169
+ } else if (installedAgents.length === 1 || options.yes) {
3323
3170
  targetAgents = ensureUniversalAgents(installedAgents);
3324
3171
  if (installedAgents.length === 1) {
3325
3172
  const firstAgent = installedAgents[0];
@@ -3513,7 +3360,7 @@ async function cloneWithGitHubFallback(url, ref, spinner) {
3513
3360
  }
3514
3361
  async function installFromSkillHub(parsed, options, spinner) {
3515
3362
  let tempDir = null;
3516
- const config = resolveConfig();
3363
+ const config = resolveConfig(options);
3517
3364
  const api = new SkillHubAPI(config.registry, config.token);
3518
3365
  const rawRef = parsed.url.startsWith("skillhub:") ? parsed.url.slice(9) : parsed.url;
3519
3366
  const [firstPart, ...restParts] = rawRef.split("/");
@@ -3554,13 +3401,14 @@ async function installFromSkillHub(parsed, options, spinner) {
3554
3401
  slug = hit.slug;
3555
3402
  log.info(`自动选择:${import_picocolors.default.cyan(`@${namespace}/${slug}`)} — ${hit.description || hit.name}`);
3556
3403
  } else {
3404
+ const choices = hits.map((h, idx) => ({
3405
+ value: idx,
3406
+ label: `@${h.namespace}/${h.slug}`,
3407
+ hint: h.description || h.name
3408
+ }));
3557
3409
  const idx = await select({
3558
3410
  message: "匹配到多个技能 — 请选择一个",
3559
- options: hits.map((h, idx) => ({
3560
- value: idx,
3561
- label: `@${h.namespace}/${h.slug}`,
3562
- hint: h.description || h.name
3563
- }))
3411
+ options: choices
3564
3412
  });
3565
3413
  if (isCancel(idx)) {
3566
3414
  cancel("安装已取消");
@@ -3587,7 +3435,8 @@ async function installFromSkillHub(parsed, options, spinner) {
3587
3435
  }
3588
3436
  const meta = metadata;
3589
3437
  spinner.stop(`Skill: ${import_picocolors.default.cyan(`@${namespace}/${slug}`)}${meta.description ? ` — ${import_picocolors.default.dim(meta.description)}` : ""}`);
3590
- tempDir = join(tmpdir(), `.skillhub-skillshub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
3438
+ const tmpRoot = tmpdir();
3439
+ tempDir = join(tmpRoot, `.skillhub-skillshub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
3591
3440
  mkdirSync(tempDir, { recursive: true });
3592
3441
  const zipPath = join(tempDir, "skill.zip");
3593
3442
  spinner.start("正在下载技能...");
@@ -3638,6 +3487,21 @@ async function installFromSkillHub(parsed, options, spinner) {
3638
3487
  } catch {}
3639
3488
  process.exit(1);
3640
3489
  }
3490
+ if (options.packageSkill) {
3491
+ const { scopePackageSkill } = await import("./_chunks/package-skill-identity.mjs").then((n) => n.package_skill_identity_exports);
3492
+ try {
3493
+ return {
3494
+ skills: scopePackageSkill(skills, namespace, slug),
3495
+ tempDir
3496
+ };
3497
+ } catch (error) {
3498
+ rmSync(tempDir, {
3499
+ recursive: true,
3500
+ force: true
3501
+ });
3502
+ throw error;
3503
+ }
3504
+ }
3641
3505
  return {
3642
3506
  skills,
3643
3507
  tempDir
@@ -3908,23 +3772,24 @@ async function runAdd(args, options = {}) {
3908
3772
  }
3909
3773
  targetAgents = selected;
3910
3774
  }
3911
- } else if (installedAgents.length === 0) if (options.yes) {
3912
- targetAgents = validAgents;
3913
- log.info("正在安装到全部 Agent");
3914
- } else {
3915
- log.info("请选择要安装技能的 Agent");
3916
- const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
3917
- value: key,
3918
- label: config.displayName
3919
- })));
3920
- if (isCancel(selected)) {
3921
- cancel("安装已取消");
3922
- await cleanup(tempDir);
3923
- process.exit(0);
3775
+ } else if (installedAgents.length === 0) {
3776
+ if (options.yes) {
3777
+ targetAgents = validAgents;
3778
+ log.info("正在安装到全部 Agent");
3779
+ } else {
3780
+ log.info("请选择要安装技能的 Agent");
3781
+ const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
3782
+ value: key,
3783
+ label: config.displayName
3784
+ })));
3785
+ if (isCancel(selected)) {
3786
+ cancel("安装已取消");
3787
+ await cleanup(tempDir);
3788
+ process.exit(0);
3789
+ }
3790
+ targetAgents = selected;
3924
3791
  }
3925
- targetAgents = selected;
3926
- }
3927
- else if (installedAgents.length === 1 || options.yes) {
3792
+ } else if (installedAgents.length === 1 || options.yes) {
3928
3793
  targetAgents = ensureUniversalAgents(installedAgents);
3929
3794
  if (installedAgents.length === 1) {
3930
3795
  const firstAgent = installedAgents[0];
@@ -3946,17 +3811,18 @@ async function runAdd(args, options = {}) {
3946
3811
  const availableSubagents = getEveSubagents(process.cwd());
3947
3812
  if (options.subagent && options.subagent.length > 0) eveSubagentTargets = options.subagent.map((s) => s === "root" || s === "." ? void 0 : s);
3948
3813
  else if (availableSubagents.length > 0 && !options.yes) {
3814
+ const subagentChoices = [{
3815
+ value: "",
3816
+ label: "根 Agent",
3817
+ hint: "agent/skills"
3818
+ }, ...availableSubagents.map((name) => ({
3819
+ value: name,
3820
+ label: name,
3821
+ hint: `agent/subagents/${name}/skills`
3822
+ }))];
3949
3823
  const selectedSubagents = await multiselect$1({
3950
3824
  message: "Eve 技能安装位置?",
3951
- options: [{
3952
- value: "",
3953
- label: "根 Agent",
3954
- hint: "agent/skills"
3955
- }, ...availableSubagents.map((name) => ({
3956
- value: name,
3957
- label: name,
3958
- hint: `agent/subagents/${name}/skills`
3959
- }))],
3825
+ options: subagentChoices,
3960
3826
  initialValues: [""],
3961
3827
  required: true
3962
3828
  });
@@ -4134,9 +4000,11 @@ async function runAdd(args, options = {}) {
4134
4000
  const normalizedSource = getOwnerRepo(parsed);
4135
4001
  const lockSource = getLockSource(parsed.url, normalizedSource);
4136
4002
  const projectLockSourceUrl = getProjectLockSourceUrl(parsed.type, parsed.url);
4137
- if (normalizedSource) if (parseOwnerRepo(normalizedSource)) {
4138
- if (await repoPrivacyPromise === false) selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4139
- } else selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4003
+ if (normalizedSource) {
4004
+ if (parseOwnerRepo(normalizedSource)) {
4005
+ if (await repoPrivacyPromise === false) selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4006
+ } else selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4007
+ }
4140
4008
  if (successful.length > 0 && installGlobally && (normalizedSource || parsed.type === "skillhub")) {
4141
4009
  const successfulSkillNames = new Set(successful.map((r) => r.skill));
4142
4010
  let cachedTree;
@@ -4153,7 +4021,8 @@ async function runAdd(args, options = {}) {
4153
4021
  const hash = getSkillFolderHashFromTree(cachedTree, skillPathValue);
4154
4022
  if (hash) skillFolderHash = hash;
4155
4023
  } else if (skillPathValue && tempDir) {
4156
- const hash = await computeSkillFolderHash(join(tempDir, dirname(skillPathValue)));
4024
+ const skillDir = join(tempDir, dirname(skillPathValue));
4025
+ const hash = await computeSkillFolderHash(skillDir);
4157
4026
  if (hash) skillFolderHash = hash;
4158
4027
  }
4159
4028
  await addSkillToLock(skill.name, {
@@ -4197,11 +4066,13 @@ async function runAdd(args, options = {}) {
4197
4066
  const skillResults = bySkill.get(r.skill) || [];
4198
4067
  skillResults.push(r);
4199
4068
  bySkill.set(r.skill, skillResults);
4200
- if (skillResults.length === 1) if (r.pluginName) {
4201
- const group = r.pluginName;
4202
- if (!groupedResults[group]) groupedResults[group] = [];
4203
- groupedResults[group].push(r);
4204
- } else ungroupedResults.push(r);
4069
+ if (skillResults.length === 1) {
4070
+ if (r.pluginName) {
4071
+ const group = r.pluginName;
4072
+ if (!groupedResults[group]) groupedResults[group] = [];
4073
+ groupedResults[group].push(r);
4074
+ } else ungroupedResults.push(r);
4075
+ }
4205
4076
  }
4206
4077
  const skillCount = bySkill.size;
4207
4078
  const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
@@ -4372,10 +4243,10 @@ function parseAddOptions(args) {
4372
4243
  errors
4373
4244
  };
4374
4245
  }
4375
- const RESET$13 = "\x1B[0m";
4376
- const BOLD$10 = "\x1B[1m";
4377
- const DIM$13 = "\x1B[38;5;102m";
4378
- const TEXT$10 = "\x1B[38;5;145m";
4246
+ const RESET$11 = "\x1B[0m";
4247
+ const BOLD$8 = "\x1B[1m";
4248
+ const DIM$11 = "\x1B[38;5;102m";
4249
+ const TEXT$8 = "\x1B[38;5;145m";
4379
4250
  const CYAN$2 = "\x1B[36m";
4380
4251
  const SEARCH_API_BASE = process.env.SKILLS_API_URL || "https://skills.sh";
4381
4252
  function formatInstalls$1(count) {
@@ -4464,28 +4335,28 @@ async function runSearchPrompt(initialQuery = "", owner) {
4464
4335
  if (lastRenderedLines > 0) process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));
4465
4336
  process.stdout.write(CLEAR_DOWN);
4466
4337
  const lines = [];
4467
- const cursor = `${BOLD$10}_${RESET$13}`;
4468
- lines.push(`${TEXT$10}搜索技能:${RESET$13} ${query}${cursor}`);
4338
+ const cursor = `${BOLD$8}_${RESET$11}`;
4339
+ lines.push(`${TEXT$8}搜索技能:${RESET$11} ${query}${cursor}`);
4469
4340
  lines.push("");
4470
- if (!query || query.length < 2) lines.push(`${DIM$13}输入关键词搜索(最少 2 个字符)${RESET$13}`);
4471
- else if (results.length === 0 && loading) lines.push(`${DIM$13}搜索中...${RESET$13}`);
4472
- else if (results.length === 0) lines.push(`${DIM$13}未找到技能${RESET$13}`);
4341
+ if (!query || query.length < 2) lines.push(`${DIM$11}输入关键词搜索(最少 2 个字符)${RESET$11}`);
4342
+ else if (results.length === 0 && loading) lines.push(`${DIM$11}搜索中...${RESET$11}`);
4343
+ else if (results.length === 0) lines.push(`${DIM$11}未找到技能${RESET$11}`);
4473
4344
  else {
4474
4345
  const visible = results.slice(0, 8);
4475
4346
  for (let i = 0; i < visible.length; i++) {
4476
4347
  const skill = visible[i];
4477
4348
  const isSelected = i === selectedIndex;
4478
- const arrow = isSelected ? `${BOLD$10}>${RESET$13}` : " ";
4479
- const name = isSelected ? `${BOLD$10}${skill.name}${RESET$13}` : `${TEXT$10}${skill.name}${RESET$13}`;
4480
- const source = skill.source ? ` ${DIM$13}${skill.source}${RESET$13}` : "";
4349
+ const arrow = isSelected ? `${BOLD$8}>${RESET$11}` : " ";
4350
+ const name = isSelected ? `${BOLD$8}${skill.name}${RESET$11}` : `${TEXT$8}${skill.name}${RESET$11}`;
4351
+ const source = skill.source ? ` ${DIM$11}${skill.source}${RESET$11}` : "";
4481
4352
  const installs = formatInstalls$1(skill.installs);
4482
- const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$13}` : "";
4483
- const loadingIndicator = loading && i === 0 ? ` ${DIM$13}...${RESET$13}` : "";
4353
+ const installsBadge = installs ? ` ${CYAN$2}${installs}${RESET$11}` : "";
4354
+ const loadingIndicator = loading && i === 0 ? ` ${DIM$11}...${RESET$11}` : "";
4484
4355
  lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);
4485
4356
  }
4486
4357
  }
4487
4358
  lines.push("");
4488
- lines.push(`${DIM$13}上下键导航 | 回车选择 | ESC 取消${RESET$13}`);
4359
+ lines.push(`${DIM$11}上下键导航 | 回车选择 | ESC 取消${RESET$11}`);
4489
4360
  for (const line of lines) process.stdout.write(line + "\n");
4490
4361
  lastRenderedLines = lines.length;
4491
4362
  }
@@ -4582,9 +4453,9 @@ async function runFind(args) {
4582
4453
  const { query, options: findOptions, errors } = parseFindOptions(args);
4583
4454
  const owner = findOptions.owner;
4584
4455
  const isNonInteractive = !process.stdin.isTTY;
4585
- const agentTip = `${DIM$13}Tip: if running in a coding agent, follow these steps:${RESET$13}
4586
- ${DIM$13} 1) npx skills find [query] [--owner <owner>]${RESET$13}
4587
- ${DIM$13} 2) npx skills add <owner/repo@skill>${RESET$13}`;
4456
+ const agentTip = `${DIM$11}Tip: if running in a coding agent, follow these steps:${RESET$11}
4457
+ ${DIM$11} 1) npx skills find [query] [--owner <owner>]${RESET$11}
4458
+ ${DIM$11} 2) npx skills add <owner/repo@skill>${RESET$11}`;
4588
4459
  if (errors.length > 0) {
4589
4460
  for (const error of errors) console.error(error);
4590
4461
  console.error("Usage: npx skills find <query> [--owner <owner>]");
@@ -4595,16 +4466,16 @@ ${DIM$13} 2) npx skills add <owner/repo@skill>${RESET$13}`;
4595
4466
  String(results.length);
4596
4467
  if (results.length === 0) {
4597
4468
  const ownerSuffix = owner ? ` from owner "${owner}"` : "";
4598
- console.log(`${DIM$13}未找到 "${query}" 的技能${ownerSuffix}${RESET$13}`);
4469
+ console.log(`${DIM$11}未找到 "${query}" 的技能${ownerSuffix}${RESET$11}`);
4599
4470
  return;
4600
4471
  }
4601
- console.log(`${DIM$13}安装:${RESET$13} npx skills add <owner/repo@skill>`);
4472
+ console.log(`${DIM$11}安装:${RESET$11} npx skills add <owner/repo@skill>`);
4602
4473
  console.log();
4603
4474
  for (const skill of results.slice(0, 6)) {
4604
4475
  const pkg = skill.source || skill.slug;
4605
4476
  const installs = formatInstalls$1(skill.installs);
4606
- console.log(`${TEXT$10}${pkg}@${skill.name}${RESET$13}${installs ? ` ${CYAN$2}${installs}${RESET$13}` : ""}`);
4607
- console.log(`${DIM$13}└ https://skills.sh/${skill.slug}${RESET$13}`);
4477
+ console.log(`${TEXT$8}${pkg}@${skill.name}${RESET$11}${installs ? ` ${CYAN$2}${installs}${RESET$11}` : ""}`);
4478
+ console.log(`${DIM$11}└ https://skills.sh/${skill.slug}${RESET$11}`);
4608
4479
  console.log();
4609
4480
  }
4610
4481
  return;
@@ -4612,19 +4483,19 @@ ${DIM$13} 2) npx skills add <owner/repo@skill>${RESET$13}`;
4612
4483
  if (isNonInteractive || await isRunningInAgent()) {
4613
4484
  console.log(agentTip);
4614
4485
  console.log();
4615
- console.log(`${DIM$13}Usage: npx skills find <query> [--owner <owner>]${RESET$13}`);
4486
+ console.log(`${DIM$11}Usage: npx skills find <query> [--owner <owner>]${RESET$11}`);
4616
4487
  return;
4617
4488
  }
4618
4489
  const selected = await runSearchPrompt("", owner);
4619
4490
  if (!selected) {
4620
- console.log(`${DIM$13}搜索已取消${RESET$13}`);
4491
+ console.log(`${DIM$11}搜索已取消${RESET$11}`);
4621
4492
  console.log();
4622
4493
  return;
4623
4494
  }
4624
4495
  const pkg = selected.source || selected.slug;
4625
4496
  const skillName = selected.name;
4626
4497
  console.log();
4627
- console.log(`${TEXT$10}正在从 ${DIM$13}${pkg}${RESET$13} 安装 ${BOLD$10}${skillName}${RESET$13}...`);
4498
+ console.log(`${TEXT$8}正在从 ${DIM$11}${pkg}${RESET$11} 安装 ${BOLD$8}${skillName}${RESET$11}...`);
4628
4499
  console.log();
4629
4500
  const { source, options: addOptions } = parseAddOptions([
4630
4501
  pkg,
@@ -4634,13 +4505,13 @@ ${DIM$13} 2) npx skills add <owner/repo@skill>${RESET$13}`;
4634
4505
  await runAdd(source, addOptions);
4635
4506
  console.log();
4636
4507
  const info = getOwnerRepoFromString(pkg);
4637
- if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$13}查看技能:${RESET$13} ${TEXT$10}https://skills.sh/${selected.slug}${RESET$13}`);
4638
- else console.log(`${DIM$13}发现更多技能:${RESET$13} ${TEXT$10}https://skills.sh${RESET$13}`);
4508
+ if (info && await isRepoPublic(info.owner, info.repo)) console.log(`${DIM$11}查看技能:${RESET$11} ${TEXT$8}https://skills.sh/${selected.slug}${RESET$11}`);
4509
+ else console.log(`${DIM$11}发现更多技能:${RESET$11} ${TEXT$8}https://skills.sh${RESET$11}`);
4639
4510
  console.log();
4640
4511
  }
4641
- const RESET$12 = "\x1B[0m";
4642
- const BOLD$9 = "\x1B[1m";
4643
- const DIM$12 = "\x1B[38;5;102m";
4512
+ const RESET$10 = "\x1B[0m";
4513
+ const BOLD$7 = "\x1B[1m";
4514
+ const DIM$10 = "\x1B[38;5;102m";
4644
4515
  const CYAN$1 = "\x1B[36m";
4645
4516
  const YELLOW$4 = "\x1B[33m";
4646
4517
  function shortenPath(fullPath, cwd) {
@@ -4676,8 +4547,8 @@ async function runList(args) {
4676
4547
  const validAgents = Object.keys(agents);
4677
4548
  const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));
4678
4549
  if (invalidAgents.length > 0) {
4679
- console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$12}`);
4680
- console.log(`${DIM$12}Valid agents: ${validAgents.join(", ")}${RESET$12}`);
4550
+ console.log(`${YELLOW$4}Invalid agents: ${invalidAgents.join(", ")}${RESET$10}`);
4551
+ console.log(`${DIM$10}Valid agents: ${validAgents.join(", ")}${RESET$10}`);
4681
4552
  process.exit(1);
4682
4553
  }
4683
4554
  agentFilter = options.agent;
@@ -4704,21 +4575,21 @@ async function runList(args) {
4704
4575
  console.log("[]");
4705
4576
  return;
4706
4577
  }
4707
- console.log(`${DIM$12}未找到${scopeLabel}技能。${RESET$12}`);
4708
- if (scope) console.log(`${DIM$12}尝试不带 -g 参数列出项目技能${RESET$12}`);
4709
- else console.log(`${DIM$12}尝试带 -g 参数列出全局技能${RESET$12}`);
4578
+ console.log(`${DIM$10}未找到${scopeLabel}技能。${RESET$10}`);
4579
+ if (scope) console.log(`${DIM$10}尝试不带 -g 参数列出项目技能${RESET$10}`);
4580
+ else console.log(`${DIM$10}尝试带 -g 参数列出全局技能${RESET$10}`);
4710
4581
  return;
4711
4582
  }
4712
4583
  function printSkill(skill, indent = false, maxNameLength = 0, maxPathLength = 0) {
4713
4584
  const prefix = indent ? " " : "";
4714
4585
  const shortPath = shortenPath(skill.canonicalPath, cwd);
4715
4586
  const agentNames = skill.agents.map((a) => agents[a].displayName);
4716
- const agentInfo = skill.agents.length > 0 ? formatList$1(agentNames) : `${YELLOW$4}not linked${RESET$12}`;
4587
+ const agentInfo = skill.agents.length > 0 ? formatList$1(agentNames) : `${YELLOW$4}not linked${RESET$10}`;
4717
4588
  const paddedName = sanitizeMetadata(skill.name).padEnd(maxNameLength);
4718
4589
  const paddedPath = shortPath.padEnd(maxPathLength);
4719
- console.log(`${prefix}${CYAN$1}${paddedName}${RESET$12} ${DIM$12}${paddedPath}${RESET$12} ${DIM$12}Agents:${RESET$12} ${agentInfo}`);
4590
+ console.log(`${prefix}${CYAN$1}${paddedName}${RESET$10} ${DIM$10}${paddedPath}${RESET$10} ${DIM$10}Agents:${RESET$10} ${agentInfo}`);
4720
4591
  }
4721
- console.log(`${BOLD$9}${scopeLabel}技能${RESET$12}`);
4592
+ console.log(`${BOLD$7}${scopeLabel}技能${RESET$10}`);
4722
4593
  console.log();
4723
4594
  const groupedSkills = {};
4724
4595
  const ungroupedSkills = [];
@@ -4734,7 +4605,7 @@ async function runList(args) {
4734
4605
  const sortedGroups = Object.keys(groupedSkills).sort();
4735
4606
  for (const group of sortedGroups) {
4736
4607
  const title = group.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4737
- console.log(`${BOLD$9}${title}${RESET$12}`);
4608
+ console.log(`${BOLD$7}${title}${RESET$10}`);
4738
4609
  const skills = groupedSkills[group];
4739
4610
  if (skills) {
4740
4611
  let maxNameLength = 0;
@@ -4750,7 +4621,7 @@ async function runList(args) {
4750
4621
  console.log();
4751
4622
  }
4752
4623
  if (ungroupedSkills.length > 0) {
4753
- console.log(`${BOLD$9}通用${RESET$12}`);
4624
+ console.log(`${BOLD$7}通用${RESET$10}`);
4754
4625
  let maxNameLength = 0;
4755
4626
  let maxPathLength = 0;
4756
4627
  for (const skill of ungroupedSkills) {
@@ -4810,7 +4681,7 @@ async function removeCommand(skillNames, options) {
4810
4681
  spinner$2.stop(`发现 ${installedSkills.length} 个已安装技能`);
4811
4682
  if (installedSkills.length === 0) {
4812
4683
  outro(import_picocolors.default.yellow("没有可卸载的技能。"));
4813
- return;
4684
+ return { removed: [] };
4814
4685
  }
4815
4686
  if (options.agent && options.agent.length > 0) {
4816
4687
  const validAgents = Object.keys(agents);
@@ -4827,7 +4698,7 @@ async function removeCommand(skillNames, options) {
4827
4698
  selectedSkills = installedSkills.filter((s) => skillNames.some((name) => name.toLowerCase() === s.toLowerCase()));
4828
4699
  if (selectedSkills.length === 0) {
4829
4700
  log.error(`未找到匹配技能:${skillNames.join(", ")}`);
4830
- return;
4701
+ return { removed: [] };
4831
4702
  }
4832
4703
  } else {
4833
4704
  const choices = installedSkills.map((s) => ({
@@ -4891,17 +4762,21 @@ async function removeCommand(skillNames, options) {
4891
4762
  });
4892
4763
  } catch (err) {
4893
4764
  log.warn(`Could not remove skill from ${agent.displayName}: ${err instanceof Error ? err.message : String(err)}`);
4765
+ throw err;
4894
4766
  }
4895
4767
  }
4896
4768
  }
4897
4769
  const remainingAgents = (await detectInstalledAgents()).filter((a) => !targetAgents.includes(a));
4898
4770
  let isStillUsed = false;
4899
- for (const agentKey of remainingAgents) if (await lstat(getInstallPath(skillName, agentKey, {
4900
- global: isGlobal,
4901
- cwd
4902
- })).catch(() => null)) {
4903
- isStillUsed = true;
4904
- break;
4771
+ for (const agentKey of remainingAgents) {
4772
+ const path = getInstallPath(skillName, agentKey, {
4773
+ global: isGlobal,
4774
+ cwd
4775
+ });
4776
+ if (await lstat(path).catch(() => null)) {
4777
+ isStillUsed = true;
4778
+ break;
4779
+ }
4905
4780
  }
4906
4781
  if (!isStillUsed) await rm(canonicalPath, {
4907
4782
  recursive: true,
@@ -4945,6 +4820,7 @@ async function removeCommand(skillNames, options) {
4945
4820
  }
4946
4821
  console.log();
4947
4822
  outro(import_picocolors.default.green("完成!"));
4823
+ return { removed: successful.map((result) => result.skill) };
4948
4824
  }
4949
4825
  function parseRemoveOptions(args) {
4950
4826
  const options = {};
@@ -5024,10 +4900,10 @@ function buildLocalUpdateSource(entry) {
5024
4900
  return appendFolderAndRef(source, entry.skillPath, entry.ref);
5025
4901
  }
5026
4902
  const __dirname$1 = dirname(fileURLToPath(import.meta.url));
5027
- const RESET$11 = "\x1B[0m";
5028
- const BOLD$8 = "\x1B[1m";
5029
- const DIM$11 = "\x1B[38;5;102m";
5030
- const TEXT$9 = "\x1B[38;5;145m";
4903
+ const RESET$9 = "\x1B[0m";
4904
+ const BOLD$6 = "\x1B[1m";
4905
+ const DIM$9 = "\x1B[38;5;102m";
4906
+ const TEXT$7 = "\x1B[38;5;145m";
5031
4907
  function parseUpdateOptions(args) {
5032
4908
  const options = {};
5033
4909
  const positional = [];
@@ -5040,12 +4916,14 @@ function parseUpdateOptions(args) {
5040
4916
  }
5041
4917
  function hasProjectSkills(cwd) {
5042
4918
  const dir = cwd || process.cwd();
5043
- if (existsSync(join(dir, "skills-lock.json"))) return true;
4919
+ const lockPath = join(dir, "skills-lock.json");
4920
+ if (existsSync(lockPath)) return true;
5044
4921
  const skillsDir = join(dir, ".agents", "skills");
5045
4922
  try {
5046
4923
  const entries = readdirSync(skillsDir, { withFileTypes: true });
5047
4924
  for (const entry of entries) if (entry.isDirectory()) {
5048
- if (existsSync(join(skillsDir, entry.name, "SKILL.md"))) return true;
4925
+ const skillMd = join(skillsDir, entry.name, "SKILL.md");
4926
+ if (existsSync(skillMd)) return true;
5049
4927
  }
5050
4928
  } catch {}
5051
4929
  return false;
@@ -5120,7 +4998,7 @@ function getInstallSource(skill) {
5120
4998
  function printSkippedSkills(skipped) {
5121
4999
  if (skipped.length === 0) return;
5122
5000
  console.log();
5123
- console.log(`${DIM$11}${skipped.length} 个技能无法自动检查:${RESET$11}`);
5001
+ console.log(`${DIM$9}${skipped.length} 个技能无法自动检查:${RESET$9}`);
5124
5002
  const grouped = /* @__PURE__ */ new Map();
5125
5003
  for (const skill of skipped) {
5126
5004
  const source = getInstallSource(skill);
@@ -5131,13 +5009,13 @@ function printSkippedSkills(skipped) {
5131
5009
  for (const [source, skills] of grouped) {
5132
5010
  if (skills.length === 1) {
5133
5011
  const skill = skills[0];
5134
- console.log(` ${TEXT$9}•${RESET$11} ${sanitizeMetadata(skill.name)} ${DIM$11}(${skill.reason})${RESET$11}`);
5012
+ console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)} ${DIM$9}(${skill.reason})${RESET$9}`);
5135
5013
  } else {
5136
5014
  const reason = skills[0].reason;
5137
5015
  const names = skills.map((s) => sanitizeMetadata(s.name)).join(", ");
5138
- console.log(` ${TEXT$9}•${RESET$11} ${names} ${DIM$11}(${reason})${RESET$11}`);
5016
+ console.log(` ${TEXT$7}•${RESET$9} ${names} ${DIM$9}(${reason})${RESET$9}`);
5139
5017
  }
5140
- console.log(` ${DIM$11}更新方法:${TEXT$9}npx skills add ${source} -g -y${RESET$11}`);
5018
+ console.log(` ${DIM$9}更新方法:${TEXT$7}npx skills add ${source} -g -y${RESET$9}`);
5141
5019
  }
5142
5020
  }
5143
5021
  async function getProjectSkillsForUpdate(skillFilter) {
@@ -5162,13 +5040,13 @@ async function checkAndPromptForDeletions(source, allLockedForSource, lockSkills
5162
5040
  });
5163
5041
  if (deletedSkills.length > 0) {
5164
5042
  console.log();
5165
- console.log(`${DIM$11}警告:${RESET$11} 以下来自 ${DIM$11}${source}${RESET$11} 的技能似乎已在源仓库中删除:`);
5166
- for (const s of deletedSkills) console.log(` ${DIM$11}•${RESET$11} ${s}`);
5167
- if (options.yes || !process.stdin.isTTY) console.log(`${DIM$11}非交互模式,跳过删除。${RESET$11}`);
5043
+ console.log(`${DIM$9}警告:${RESET$9} 以下来自 ${DIM$9}${source}${RESET$9} 的技能似乎已在源仓库中删除:`);
5044
+ for (const s of deletedSkills) console.log(` ${DIM$9}•${RESET$9} ${s}`);
5045
+ if (options.yes || !process.stdin.isTTY) console.log(`${DIM$9}非交互模式,跳过删除。${RESET$9}`);
5168
5046
  else {
5169
5047
  const confirmed = await confirm({ message: `是否删除这些已删除技能的本地副本?` });
5170
5048
  if (confirmed && !isCancel(confirmed)) for (const s of deletedSkills) {
5171
- console.log(`${DIM$11}正在卸载${RESET$11} ${s}...`);
5049
+ console.log(`${DIM$9}正在卸载${RESET$9} ${s}...`);
5172
5050
  await removeCommand([s], {
5173
5051
  yes: true,
5174
5052
  global: isGlobal
@@ -5185,8 +5063,8 @@ async function updateGlobalSkills(options = {}) {
5185
5063
  let failCount = 0;
5186
5064
  if (skillNames.length === 0) {
5187
5065
  if (!options.skills) {
5188
- console.log(`${DIM$11}锁文件中没有跟踪的全局技能。${RESET$11}`);
5189
- console.log(`${DIM$11}安装技能:${RESET$11} ${TEXT$9}npx skills add <package> -g${RESET$11}`);
5066
+ console.log(`${DIM$9}锁文件中没有跟踪的全局技能。${RESET$9}`);
5067
+ console.log(`${DIM$9}安装技能:${RESET$9} ${TEXT$7}npx skills add <package> -g${RESET$9}`);
5190
5068
  }
5191
5069
  return {
5192
5070
  successCount,
@@ -5227,17 +5105,17 @@ async function updateGlobalSkills(options = {}) {
5227
5105
  const firstEntry = itemsForSource[0].entry;
5228
5106
  const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
5229
5107
  let tempDir = null;
5230
- process.stdout.write(`\r${DIM$11}Checking skills from source: ${source}${RESET$11}\x1b[K\n`);
5108
+ process.stdout.write(`\r${DIM$9}Checking skills from source: ${source}${RESET$9}\x1b[K\n`);
5231
5109
  if (firstEntry.sourceType === "skillhub") {
5232
5110
  const skillhubRef = source.replace(/^skillhub:/, "");
5233
5111
  const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
5234
5112
  const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
5235
- const { resolveConfig } = await Promise.resolve().then(() => config_exports);
5113
+ const { resolveConfig } = await import("./_chunks/config.mjs").then((n) => n.config_exports);
5236
5114
  const cfg = resolveConfig({});
5237
5115
  new SkillHubAPI(cfg.registry, cfg.token);
5238
5116
  for (const item of itemsForSource) {
5239
5117
  const safeName = sanitizeMetadata(item.name);
5240
- console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5118
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5241
5119
  try {
5242
5120
  const parts = skillhubRef.split("/");
5243
5121
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5248,7 +5126,7 @@ async function updateGlobalSkills(options = {}) {
5248
5126
  });
5249
5127
  successCount++;
5250
5128
  } catch (error) {
5251
- console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5129
+ console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5252
5130
  failCount++;
5253
5131
  }
5254
5132
  }
@@ -5258,7 +5136,7 @@ async function updateGlobalSkills(options = {}) {
5258
5136
  if (firstEntry.sourceType === "github") {
5259
5137
  const tree = await fetchRepoTree(source, firstEntry.ref, getGitHubToken);
5260
5138
  if (!tree) {
5261
- console.log(` ${DIM$11}✗ Failed to fetch tree for ${source}${RESET$11}`);
5139
+ console.log(` ${DIM$9}✗ Failed to fetch tree for ${source}${RESET$9}`);
5262
5140
  continue;
5263
5141
  }
5264
5142
  const discoveredPaths = findSkillMdPaths(tree);
@@ -5293,7 +5171,7 @@ async function updateGlobalSkills(options = {}) {
5293
5171
  });
5294
5172
  }
5295
5173
  } catch (error) {
5296
- console.log(` ${DIM$11}✗ Failed to check skills from ${source}${RESET$11}`);
5174
+ console.log(` ${DIM$9}✗ Failed to check skills from ${source}${RESET$9}`);
5297
5175
  } finally {
5298
5176
  if (tempDir) await cleanupTempDir(tempDir);
5299
5177
  }
@@ -5301,7 +5179,7 @@ async function updateGlobalSkills(options = {}) {
5301
5179
  if (checkable.length > 0) process.stdout.write("\r\x1B[K");
5302
5180
  const checkedCount = checkable.length + skipped.length;
5303
5181
  if (checkable.length === 0 && skipped.length === 0) {
5304
- if (!options.skills) console.log(`${DIM$11}没有可检查的全局技能。${RESET$11}`);
5182
+ if (!options.skills) console.log(`${DIM$9}没有可检查的全局技能。${RESET$9}`);
5305
5183
  return {
5306
5184
  successCount,
5307
5185
  failCount,
@@ -5317,28 +5195,28 @@ async function updateGlobalSkills(options = {}) {
5317
5195
  };
5318
5196
  }
5319
5197
  if (updates.length === 0) {
5320
- console.log(`${TEXT$9}✓ 所有全局技能已是最新${RESET$11}`);
5198
+ console.log(`${TEXT$7}✓ 所有全局技能已是最新${RESET$9}`);
5321
5199
  return {
5322
5200
  successCount,
5323
5201
  failCount,
5324
5202
  checkedCount
5325
5203
  };
5326
5204
  }
5327
- console.log(`${TEXT$9}发现 ${updates.length} 个可更新全局技能${RESET$11}`);
5205
+ console.log(`${TEXT$7}发现 ${updates.length} 个可更新全局技能${RESET$9}`);
5328
5206
  console.log();
5329
5207
  for (const update of updates) {
5330
5208
  const safeName = sanitizeMetadata(update.name);
5331
- console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5209
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5332
5210
  const installUrl = buildUpdateInstallSource(update.entry);
5333
5211
  if (!installUrl) {
5334
5212
  failCount++;
5335
- console.log(` ${DIM$11}✗ Cannot update ${safeName}: lock file is missing sourceUrl for this generic Git source${RESET$11}`);
5213
+ console.log(` ${DIM$9}✗ Cannot update ${safeName}: lock file is missing sourceUrl for this generic Git source${RESET$9}`);
5336
5214
  continue;
5337
5215
  }
5338
5216
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5339
5217
  if (!existsSync(cliEntry)) {
5340
5218
  failCount++;
5341
- console.log(` ${DIM$11}✗ Failed to update ${safeName}: CLI entrypoint not found at ${cliEntry}${RESET$11}`);
5219
+ console.log(` ${DIM$9}✗ Failed to update ${safeName}: CLI entrypoint not found at ${cliEntry}${RESET$9}`);
5342
5220
  continue;
5343
5221
  }
5344
5222
  if (spawnSync(process.execPath, [
@@ -5357,10 +5235,10 @@ async function updateGlobalSkills(options = {}) {
5357
5235
  shell: false
5358
5236
  }).status === 0) {
5359
5237
  successCount++;
5360
- console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5238
+ console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5361
5239
  } else {
5362
5240
  failCount++;
5363
- console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5241
+ console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5364
5242
  }
5365
5243
  }
5366
5244
  printSkippedSkills(skipped);
@@ -5376,8 +5254,8 @@ async function updateProjectSkills(options = {}) {
5376
5254
  let failCount = 0;
5377
5255
  if (projectSkills.length === 0) {
5378
5256
  if (!options.skills) {
5379
- console.log(`${DIM$11}没有可更新的项目技能。${RESET$11}`);
5380
- console.log(`${DIM$11}Install project skills with${RESET$11} ${TEXT$9}npx skills add <package>${RESET$11}`);
5257
+ console.log(`${DIM$9}没有可更新的项目技能。${RESET$9}`);
5258
+ console.log(`${DIM$9}Install project skills with${RESET$9} ${TEXT$7}npx skills add <package>${RESET$9}`);
5381
5259
  }
5382
5260
  return {
5383
5261
  successCount,
@@ -5388,7 +5266,7 @@ async function updateProjectSkills(options = {}) {
5388
5266
  const updatable = projectSkills.filter((s) => s.entry.skillPath);
5389
5267
  const legacy = projectSkills.filter((s) => !s.entry.skillPath);
5390
5268
  if (updatable.length === 0) {
5391
- console.log(`${DIM$11}No project skills can be updated in place.${RESET$11}`);
5269
+ console.log(`${DIM$9}No project skills can be updated in place.${RESET$9}`);
5392
5270
  printLegacyProjectSkills(legacy);
5393
5271
  return {
5394
5272
  successCount,
@@ -5408,8 +5286,8 @@ async function updateProjectSkills(options = {}) {
5408
5286
  const targetParts = [];
5409
5287
  if (hasUniversal) targetParts.push("Universal");
5410
5288
  targetParts.push(...targetAgentNames);
5411
- if (targetParts.length > 0) console.log(`${TEXT$9}更新目标:${targetParts.join(", ")}${RESET$11}`);
5412
- console.log(`${TEXT$9}正在刷新 ${updatable.length} 个技能...${RESET$11}`);
5289
+ if (targetParts.length > 0) console.log(`${TEXT$7}更新目标:${targetParts.join(", ")}${RESET$9}`);
5290
+ console.log(`${TEXT$7}正在刷新 ${updatable.length} 个技能...${RESET$9}`);
5413
5291
  console.log();
5414
5292
  const bySource = /* @__PURE__ */ new Map();
5415
5293
  for (const skill of updatable) {
@@ -5421,7 +5299,7 @@ async function updateProjectSkills(options = {}) {
5421
5299
  const localLock = await readLocalLock();
5422
5300
  const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
5423
5301
  if (!existsSync(cliEntry)) {
5424
- console.log(`${DIM$11}✗ CLI 入口未找到 ${cliEntry}${RESET$11}`);
5302
+ console.log(`${DIM$9}✗ CLI 入口未找到 ${cliEntry}${RESET$9}`);
5425
5303
  return {
5426
5304
  successCount,
5427
5305
  failCount: updatable.length,
@@ -5436,12 +5314,12 @@ async function updateProjectSkills(options = {}) {
5436
5314
  const skillhubRef = source.replace(/^skillhub:/, "");
5437
5315
  const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
5438
5316
  const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
5439
- const { resolveConfig } = await Promise.resolve().then(() => config_exports);
5317
+ const { resolveConfig } = await import("./_chunks/config.mjs").then((n) => n.config_exports);
5440
5318
  const cfg = resolveConfig({});
5441
5319
  new SkillHubAPI(cfg.registry, cfg.token);
5442
5320
  for (const item of skillsForSource) {
5443
5321
  const safeName = sanitizeMetadata(item.name);
5444
- console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5322
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5445
5323
  try {
5446
5324
  const parts = skillhubRef.split("/");
5447
5325
  const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
@@ -5452,7 +5330,7 @@ async function updateProjectSkills(options = {}) {
5452
5330
  });
5453
5331
  successCount++;
5454
5332
  } catch (error) {
5455
- console.log(` ${DIM$11}✗ ${safeName}: ${error.message}${RESET$11}`);
5333
+ console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5456
5334
  failCount++;
5457
5335
  }
5458
5336
  }
@@ -5463,28 +5341,29 @@ async function updateProjectSkills(options = {}) {
5463
5341
  let deletedSkills = [];
5464
5342
  if (buildLocalUpdateSource(firstEntry) === null) {
5465
5343
  failCount += skillsForSource.length;
5466
- console.log(`${DIM$11}✗ Cannot update ${source}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$11}`);
5344
+ console.log(`${DIM$9}✗ Cannot update ${source}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$9}`);
5467
5345
  continue;
5468
5346
  }
5469
5347
  try {
5470
5348
  tempDir = await cloneRepo(sourceUrl, ref);
5471
5349
  const discoveredPaths = (await discoverSkills(tempDir)).map((s) => {
5472
- return join(relative(tempDir, s.path), "SKILL.md").split(sep).join("/");
5350
+ const relPath = relative(tempDir, s.path);
5351
+ return join(relPath, "SKILL.md").split(sep).join("/");
5473
5352
  });
5474
5353
  deletedSkills = await checkAndPromptForDeletions(source, allLockedForSource, localLock.skills, false, options, discoveredPaths);
5475
5354
  } catch (error) {
5476
- console.log(`${DIM$11}✗ 检查 ${source} 已删除技能失败${RESET$11}`);
5355
+ console.log(`${DIM$9}✗ 检查 ${source} 已删除技能失败${RESET$9}`);
5477
5356
  } finally {
5478
5357
  if (tempDir) await cleanupTempDir(tempDir);
5479
5358
  }
5480
5359
  const remainingSkills = skillsForSource.filter((s) => !deletedSkills.includes(s.name));
5481
5360
  for (const skill of remainingSkills) {
5482
5361
  const safeName = sanitizeMetadata(skill.name);
5483
- console.log(`${TEXT$9}正在更新 ${safeName}...${RESET$11}`);
5362
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5484
5363
  const installUrl = buildLocalUpdateSource(skill.entry);
5485
5364
  if (!installUrl) {
5486
5365
  failCount++;
5487
- console.log(` ${DIM$11}✗ Cannot update ${safeName}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$11}`);
5366
+ console.log(` ${DIM$9}✗ Cannot update ${safeName}: skills-lock.json is missing sourceUrl for this generic Git source${RESET$9}`);
5488
5367
  continue;
5489
5368
  }
5490
5369
  const subagentArgs = skill.entry.subagents?.length ? ["--subagent", ...skill.entry.subagents.map((s) => s === "" ? "root" : s)] : [];
@@ -5506,10 +5385,10 @@ async function updateProjectSkills(options = {}) {
5506
5385
  shell: false
5507
5386
  }).status === 0) {
5508
5387
  successCount++;
5509
- console.log(` ${TEXT$9}✓${RESET$11} 已更新 ${safeName}`);
5388
+ console.log(` ${TEXT$7}✓${RESET$9} 已更新 ${safeName}`);
5510
5389
  } else {
5511
5390
  failCount++;
5512
- console.log(` ${DIM$11}✗ 更新 ${safeName} 失败${RESET$11}`);
5391
+ console.log(` ${DIM$9}✗ 更新 ${safeName} 失败${RESET$9}`);
5513
5392
  }
5514
5393
  }
5515
5394
  }
@@ -5523,25 +5402,25 @@ async function updateProjectSkills(options = {}) {
5523
5402
  function printLegacyProjectSkills(legacy) {
5524
5403
  if (legacy.length === 0) return;
5525
5404
  console.log();
5526
- console.log(`${DIM$11}${legacy.length} project skill(s) cannot be updated automatically (installed before skillPath tracking):${RESET$11}`);
5405
+ console.log(`${DIM$9}${legacy.length} project skill(s) cannot be updated automatically (installed before skillPath tracking):${RESET$9}`);
5527
5406
  for (const skill of legacy) {
5528
5407
  const reinstall = buildLocalUpdateSource(skill.entry);
5529
- console.log(` ${TEXT$9}•${RESET$11} ${sanitizeMetadata(skill.name)}`);
5530
- if (reinstall) console.log(` ${DIM$11}刷新方法:${TEXT$9}npx skills add ${reinstall} -y${RESET$11}`);
5531
- else console.log(` ${DIM$11}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$11}`);
5408
+ console.log(` ${TEXT$7}•${RESET$9} ${sanitizeMetadata(skill.name)}`);
5409
+ if (reinstall) console.log(` ${DIM$9}刷新方法:${TEXT$7}npx skills add ${reinstall} -y${RESET$9}`);
5410
+ else console.log(` ${DIM$9}To refresh: reinstall using the original full Git URL; this lock entry only has an ambiguous shorthand.${RESET$9}`);
5532
5411
  }
5533
5412
  }
5534
5413
  async function runUpdate(args = []) {
5535
5414
  const options = parseUpdateOptions(args);
5536
5415
  const scope = await resolveUpdateScope(options);
5537
- if (options.skills) console.log(`${TEXT$9}正在更新 ${options.skills.join(", ")}...${RESET$11}`);
5538
- else console.log(`${TEXT$9}正在检查技能更新...${RESET$11}`);
5416
+ if (options.skills) console.log(`${TEXT$7}正在更新 ${options.skills.join(", ")}...${RESET$9}`);
5417
+ else console.log(`${TEXT$7}正在检查技能更新...${RESET$9}`);
5539
5418
  console.log();
5540
5419
  let totalSuccess = 0;
5541
5420
  let totalFail = 0;
5542
5421
  let totalFound = 0;
5543
5422
  if (scope === "global" || scope === "both") {
5544
- if (scope === "both" && !options.skills) console.log(`${BOLD$8}全局技能${RESET$11}`);
5423
+ if (scope === "both" && !options.skills) console.log(`${BOLD$6}全局技能${RESET$9}`);
5545
5424
  const { successCount, failCount, checkedCount } = await updateGlobalSkills(options);
5546
5425
  totalSuccess += successCount;
5547
5426
  totalFail += failCount;
@@ -5549,17 +5428,17 @@ async function runUpdate(args = []) {
5549
5428
  if (scope === "both" && !options.skills) console.log();
5550
5429
  }
5551
5430
  if (scope === "project" || scope === "both") {
5552
- if (scope === "both" && !options.skills) console.log(`${BOLD$8}项目技能${RESET$11}`);
5431
+ if (scope === "both" && !options.skills) console.log(`${BOLD$6}项目技能${RESET$9}`);
5553
5432
  const { successCount, failCount, foundCount } = await updateProjectSkills(options);
5554
5433
  totalSuccess += successCount;
5555
5434
  totalFail += failCount;
5556
5435
  totalFound += foundCount;
5557
5436
  }
5558
- if (options.skills && totalFound === 0) console.log(`${DIM$11}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$11}`);
5437
+ if (options.skills && totalFound === 0) console.log(`${DIM$9}未找到匹配的已安装技能:${options.skills.join(", ")}${RESET$9}`);
5559
5438
  console.log();
5560
- if (totalSuccess > 0) console.log(`${TEXT$9}✓ 已更新 ${totalSuccess} 个技能${RESET$11}`);
5439
+ if (totalSuccess > 0) console.log(`${TEXT$7}✓ 已更新 ${totalSuccess} 个技能${RESET$9}`);
5561
5440
  if (totalFail > 0) {
5562
- console.log(`${DIM$11}更新失败 ${totalFail} 个技能${RESET$11}`);
5441
+ console.log(`${DIM$9}更新失败 ${totalFail} 个技能${RESET$9}`);
5563
5442
  process.exitCode = 1;
5564
5443
  }
5565
5444
  String(totalSuccess + totalFail);
@@ -5946,7 +5825,7 @@ async function runLogin(args, globalOpts) {
5946
5825
  name: String(userInfo.displayName || userInfo.name || ""),
5947
5826
  handle: String(userInfo.handle || "")
5948
5827
  };
5949
- saveGlobalConfig(config);
5828
+ saveGlobalConfig$1(config);
5950
5829
  console.log(`✓ 已登录为 ${userInfo.displayName || userInfo.name || "Unknown"}`);
5951
5830
  console.log(` 注册中心:${registry}`);
5952
5831
  } catch (error) {
@@ -5959,7 +5838,7 @@ async function runLogout() {
5959
5838
  if (config?.token) {
5960
5839
  delete config.token;
5961
5840
  delete config.user;
5962
- saveGlobalConfig(config);
5841
+ saveGlobalConfig$1(config);
5963
5842
  console.log("✓ 已登出");
5964
5843
  } else console.log("未登录。");
5965
5844
  }
@@ -6011,10 +5890,10 @@ function getOptionValue$3(args, flag) {
6011
5890
  const idx = args.indexOf(flag);
6012
5891
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
6013
5892
  }
6014
- const RESET$10 = "\x1B[0m";
6015
- const BOLD$7 = "\x1B[1m";
6016
- const DIM$10 = "\x1B[38;5;102m";
6017
- const TEXT$8 = "\x1B[38;5;145m";
5893
+ const RESET$8 = "\x1B[0m";
5894
+ const BOLD$5 = "\x1B[1m";
5895
+ const DIM$8 = "\x1B[38;5;102m";
5896
+ const TEXT$6 = "\x1B[38;5;145m";
6018
5897
  const CYAN = "\x1B[36m";
6019
5898
  const MARKETPLACE_API = process.env.SKILLS_API_URL || "https://skills.sh";
6020
5899
  async function runSearch(args, globalOpts) {
@@ -6022,13 +5901,13 @@ async function runSearch(args, globalOpts) {
6022
5901
  const namespace = args.includes("--namespace") ? getOptionValue$2(args, "--namespace") : void 0;
6023
5902
  const json = args.includes("--json");
6024
5903
  if (!query || query.trim() === "") {
6025
- console.log(`${BOLD$7}bfi skills search <关键词> [选项]${RESET$10}`);
5904
+ console.log(`${BOLD$5}bfi skills search <关键词> [选项]${RESET$8}`);
6026
5905
  console.log();
6027
- console.log(`${DIM$10}常用命令:${RESET$10}`);
6028
- console.log(` bfi skills search react ${DIM$10}搜索 SkillHub${RESET$10}`);
6029
- console.log(` bfi skills search react --marketplace ${DIM$10}搜索 skills.sh${RESET$10}`);
6030
- console.log(` bfi skills search react --all ${DIM$10}搜索全部${RESET$10}`);
6031
- console.log(` bfi skills search react --json ${DIM$10}JSON 输出${RESET$10}`);
5906
+ console.log(`${DIM$8}常用命令:${RESET$8}`);
5907
+ console.log(` bfi skills search react ${DIM$8}搜索 SkillHub${RESET$8}`);
5908
+ console.log(` bfi skills search react --marketplace ${DIM$8}搜索 skills.sh${RESET$8}`);
5909
+ console.log(` bfi skills search react --all ${DIM$8}搜索全部${RESET$8}`);
5910
+ console.log(` bfi skills search react --json ${DIM$8}JSON 输出${RESET$8}`);
6032
5911
  return;
6033
5912
  }
6034
5913
  const useMarketplace = args.includes("--marketplace");
@@ -6038,9 +5917,9 @@ async function runSearch(args, globalOpts) {
6038
5917
  return;
6039
5918
  }
6040
5919
  if (searchAll) {
6041
- console.log(`${BOLD$7}=== SkillHub 注册表 ===${RESET$10}\n`);
5920
+ console.log(`${BOLD$5}=== SkillHub 注册表 ===${RESET$8}\n`);
6042
5921
  await searchSkillHub(query, namespace, globalOpts, json);
6043
- console.log(`\n${BOLD$7}=== skills.sh 市场 ===${RESET$10}\n`);
5922
+ console.log(`\n${BOLD$5}=== skills.sh 市场 ===${RESET$8}\n`);
6044
5923
  await searchMarketplace(query, json);
6045
5924
  return;
6046
5925
  }
@@ -6075,7 +5954,7 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
6075
5954
  count: 0,
6076
5955
  results: []
6077
5956
  }, null, 2));
6078
- else console.log(`${DIM$10}SkillHub 上未找到 "${query}" 的技能${RESET$10}`);
5957
+ else console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
6079
5958
  return;
6080
5959
  }
6081
5960
  if (json) {
@@ -6102,15 +5981,15 @@ async function searchSkillHub(query, namespace, globalOpts, json = false) {
6102
5981
  const desc = skill.summary || skill.description || "";
6103
5982
  const canonicalSlug = skill.slug || "";
6104
5983
  const displaySlug = canonicalSlug.indexOf("--") > 0 ? canonicalSlug : `global--${canonicalSlug}`;
6105
- console.log(` ${BOLD$7}${name}${RESET$10}`);
6106
- if (desc) console.log(` ${DIM$10}${truncate$2(desc, 100)}${RESET$10}`);
6107
- console.log(` ${TEXT$8}slug: ${displaySlug}${RESET$10}`);
6108
- if (skill.version) console.log(` ${DIM$10}version: ${skill.version}${RESET$10}`);
6109
- console.log(` ${DIM$10}安装:${TEXT$8}bfi skills add ${displaySlug}${RESET$10}`);
5984
+ console.log(` ${BOLD$5}${name}${RESET$8}`);
5985
+ if (desc) console.log(` ${DIM$8}${truncate$2(desc, 100)}${RESET$8}`);
5986
+ console.log(` ${TEXT$6}slug: ${displaySlug}${RESET$8}`);
5987
+ if (skill.version) console.log(` ${DIM$8}version: ${skill.version}${RESET$8}`);
5988
+ console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add ${displaySlug}${RESET$8}`);
6110
5989
  console.log();
6111
5990
  }
6112
5991
  } catch (error) {
6113
- console.error(`${DIM$10}SkillHub 搜索失败:${error.message}${RESET$10}`);
5992
+ console.error(`${DIM$8}SkillHub 搜索失败:${error.message}${RESET$8}`);
6114
5993
  }
6115
5994
  }
6116
5995
  async function searchMarketplace(query, json = false) {
@@ -6127,7 +6006,7 @@ async function searchMarketplace(query, json = false) {
6127
6006
  count: 0,
6128
6007
  results: []
6129
6008
  }, null, 2));
6130
- else console.log(`${DIM$10}skills.sh 市场无结果${RESET$10}`);
6009
+ else console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
6131
6010
  return;
6132
6011
  }
6133
6012
  const skills = (await res.json()).skills || [];
@@ -6137,7 +6016,7 @@ async function searchMarketplace(query, json = false) {
6137
6016
  count: 0,
6138
6017
  results: []
6139
6018
  }, null, 2));
6140
- else console.log(`${DIM$10}skills.sh 上未找到 "${query}" 的技能${RESET$10}`);
6019
+ else console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
6141
6020
  return;
6142
6021
  }
6143
6022
  if (json) {
@@ -6158,15 +6037,15 @@ async function searchMarketplace(query, json = false) {
6158
6037
  console.log(`skills.sh 上找到 ${skills.length} 个技能:\n`);
6159
6038
  for (const skill of skills.slice(0, 12)) {
6160
6039
  const installs = formatInstalls(skill.installs);
6161
- console.log(` ${BOLD$7}${skill.name}${RESET$10}`);
6162
- if (skill.source) console.log(` ${DIM$10}来源:${skill.source}${RESET$10}`);
6163
- if (installs) console.log(` ${CYAN}${installs}${RESET$10}`);
6164
- console.log(` ${TEXT$8}https://skills.sh/${skill.id}${RESET$10}`);
6165
- if (skill.source) console.log(` ${DIM$10}安装:${TEXT$8}bfi skills add github:${skill.source}${RESET$10}`);
6040
+ console.log(` ${BOLD$5}${skill.name}${RESET$8}`);
6041
+ if (skill.source) console.log(` ${DIM$8}来源:${skill.source}${RESET$8}`);
6042
+ if (installs) console.log(` ${CYAN}${installs}${RESET$8}`);
6043
+ console.log(` ${TEXT$6}https://skills.sh/${skill.id}${RESET$8}`);
6044
+ if (skill.source) console.log(` ${DIM$8}安装:${TEXT$6}bfi skills add github:${skill.source}${RESET$8}`);
6166
6045
  console.log();
6167
6046
  }
6168
6047
  } catch {
6169
- console.log(`${DIM$10}skills.sh 市场不可用${RESET$10}`);
6048
+ console.log(`${DIM$8}skills.sh 市场不可用${RESET$8}`);
6170
6049
  }
6171
6050
  }
6172
6051
  function formatInstalls(count) {
@@ -6183,13 +6062,13 @@ function getOptionValue$2(args, flag) {
6183
6062
  const idx = args.indexOf(flag);
6184
6063
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
6185
6064
  }
6186
- const RESET$9 = "\x1B[0m";
6187
- const BOLD$6 = "\x1B[1m";
6188
- const DIM$9 = "\x1B[38;5;102m";
6189
- const TEXT$7 = "\x1B[38;5;145m";
6065
+ const RESET$7 = "\x1B[0m";
6066
+ const BOLD$4 = "\x1B[1m";
6067
+ const DIM$7 = "\x1B[38;5;102m";
6068
+ const TEXT$5 = "\x1B[38;5;145m";
6190
6069
  const YELLOW$3 = "\x1B[33m";
6191
- const RED$5 = "\x1B[31m";
6192
- const GREEN$6 = "\x1B[32m";
6070
+ const RED$3 = "\x1B[31m";
6071
+ const GREEN$4 = "\x1B[32m";
6193
6072
  async function runInfo(args, globalOpts) {
6194
6073
  const ref = args[0];
6195
6074
  if (!ref) {
@@ -6205,35 +6084,35 @@ async function runInfo(args, globalOpts) {
6205
6084
  const result = await api.getSkill(canonical);
6206
6085
  const skill = result.data || result.skill || result;
6207
6086
  if (!skill || !skill.slug) {
6208
- console.log(`${DIM$9}未找到技能:${ref}${RESET$9}`);
6087
+ console.log(`${DIM$7}未找到技能:${ref}${RESET$7}`);
6209
6088
  process.exit(1);
6210
6089
  }
6211
6090
  console.log();
6212
- console.log(`${BOLD$6}${skill.displayName || skill.name || skill.slug}${RESET$9}`);
6213
- console.log(`${DIM$9}${"─".repeat(48)}${RESET$9}`);
6214
- console.log(` ${BOLD$6}Slug:${RESET$9} ${TEXT$7}${skill.slug}${RESET$9}`);
6215
- if (skill.summary || skill.description) console.log(` ${BOLD$6}描述:${RESET$9} ${TEXT$7}${skill.summary || skill.description}${RESET$9}`);
6091
+ console.log(`${BOLD$4}${skill.displayName || skill.name || skill.slug}${RESET$7}`);
6092
+ console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6093
+ console.log(` ${BOLD$4}Slug:${RESET$7} ${TEXT$5}${skill.slug}${RESET$7}`);
6094
+ if (skill.summary || skill.description) console.log(` ${BOLD$4}描述:${RESET$7} ${TEXT$5}${skill.summary || skill.description}${RESET$7}`);
6216
6095
  const owner = skill.owner;
6217
6096
  if (owner) {
6218
- console.log(` ${BOLD$6}所有者:${RESET$9} ${TEXT$7}${owner.displayName || owner.handle}${RESET$9}`);
6219
- if (owner.handle) console.log(` ${BOLD$6}句柄:${RESET$9} ${TEXT$7}${owner.handle}${RESET$9}`);
6097
+ console.log(` ${BOLD$4}所有者:${RESET$7} ${TEXT$5}${owner.displayName || owner.handle}${RESET$7}`);
6098
+ if (owner.handle) console.log(` ${BOLD$4}句柄:${RESET$7} ${TEXT$5}${owner.handle}${RESET$7}`);
6220
6099
  }
6221
6100
  const latestVersion = skill.latestVersion;
6222
6101
  if (latestVersion) {
6223
- console.log(` ${BOLD$6}版本:${RESET$9} ${TEXT$7}${latestVersion.version || "N/A"}${RESET$9}`);
6224
- if (latestVersion.license) console.log(` ${BOLD$6}许可证:${RESET$9} ${TEXT$7}${latestVersion.license}${RESET$9}`);
6225
- if (latestVersion.changelog) console.log(` ${BOLD$6}变更日志:${RESET$9} ${DIM$9}${truncate$1(latestVersion.changelog, 80)}${RESET$9}`);
6102
+ console.log(` ${BOLD$4}版本:${RESET$7} ${TEXT$5}${latestVersion.version || "N/A"}${RESET$7}`);
6103
+ if (latestVersion.license) console.log(` ${BOLD$4}许可证:${RESET$7} ${TEXT$5}${latestVersion.license}${RESET$7}`);
6104
+ if (latestVersion.changelog) console.log(` ${BOLD$4}变更日志:${RESET$7} ${DIM$7}${truncate$1(latestVersion.changelog, 80)}${RESET$7}`);
6226
6105
  if (latestVersion.createdAt) {
6227
6106
  const date = new Date(latestVersion.createdAt).toISOString().split("T")[0];
6228
- console.log(` ${BOLD$6}发布时间:${RESET$9} ${TEXT$7}${date}${RESET$9}`);
6107
+ console.log(` ${BOLD$4}发布时间:${RESET$7} ${TEXT$5}${date}${RESET$7}`);
6229
6108
  }
6230
6109
  }
6231
6110
  const stats = skill.stats;
6232
6111
  if (stats) {
6233
6112
  console.log();
6234
- console.log(` ${BOLD$6}统计:${RESET$9}`);
6235
- if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$7}${stats.downloads}${RESET$9}`);
6236
- if (stats.views !== void 0) console.log(` 浏览量:${TEXT$7}${stats.views}${RESET$9}`);
6113
+ console.log(` ${BOLD$4}统计:${RESET$7}`);
6114
+ if (stats.downloads !== void 0) console.log(` 下载量:${TEXT$5}${stats.downloads}${RESET$7}`);
6115
+ if (stats.views !== void 0) console.log(` 浏览量:${TEXT$5}${stats.views}${RESET$7}`);
6237
6116
  }
6238
6117
  const tags = skill.tags;
6239
6118
  if (Array.isArray(tags) && tags.length > 0) {
@@ -6241,28 +6120,28 @@ async function runInfo(args, globalOpts) {
6241
6120
  const tag = t;
6242
6121
  return tag.name || tag;
6243
6122
  }).join(", ");
6244
- console.log(` ${BOLD$6}标签:${RESET$9} ${TEXT$7}${tagList}${RESET$9}`);
6123
+ console.log(` ${BOLD$4}标签:${RESET$7} ${TEXT$5}${tagList}${RESET$7}`);
6245
6124
  }
6246
6125
  const moderation = skill.moderation;
6247
6126
  if (moderation) {
6248
6127
  const verdict = moderation.verdict;
6249
6128
  if (verdict === "MALWARE_BLOCKED" || moderation.isMalwareBlocked) {
6250
6129
  console.log();
6251
- console.log(` ${RED$5}${BOLD$6}⚠ 已封禁:检测到恶意软件${RESET$9}`);
6252
- if (moderation.summary) console.log(` ${RED$5}${moderation.summary}${RESET$9}`);
6130
+ console.log(` ${RED$3}${BOLD$4}⚠ 已封禁:检测到恶意软件${RESET$7}`);
6131
+ if (moderation.summary) console.log(` ${RED$3}${moderation.summary}${RESET$7}`);
6253
6132
  } else if (verdict === "SUSPICIOUS" || moderation.isSuspicious) {
6254
6133
  console.log();
6255
- console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$9}`);
6256
- if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$9}`);
6257
- } else if (verdict === "SAFE") console.log(` ${BOLD$6}安全:${RESET$9} ${GREEN$6}已验证安全${RESET$9}`);
6134
+ console.log(` ${YELLOW$3}⚠ 可疑技能${RESET$7}`);
6135
+ if (moderation.summary) console.log(` ${YELLOW$3}${moderation.summary}${RESET$7}`);
6136
+ } else if (verdict === "SAFE") console.log(` ${BOLD$4}安全:${RESET$7} ${GREEN$4}已验证安全${RESET$7}`);
6258
6137
  }
6259
6138
  if (skill.createdAt) {
6260
6139
  const created = new Date(skill.createdAt).toISOString().split("T")[0];
6261
- console.log(` ${BOLD$6}创建时间:${RESET$9} ${TEXT$7}${created}${RESET$9}`);
6140
+ console.log(` ${BOLD$4}创建时间:${RESET$7} ${TEXT$5}${created}${RESET$7}`);
6262
6141
  }
6263
6142
  if (skill.updatedAt) {
6264
6143
  const updated = new Date(skill.updatedAt).toISOString().split("T")[0];
6265
- console.log(` ${BOLD$6}更新时间:${RESET$9} ${TEXT$7}${updated}${RESET$9}`);
6144
+ console.log(` ${BOLD$4}更新时间:${RESET$7} ${TEXT$5}${updated}${RESET$7}`);
6266
6145
  }
6267
6146
  console.log();
6268
6147
  } catch (error) {
@@ -6275,8 +6154,8 @@ function truncate$1(text, maxLen) {
6275
6154
  if (text.length <= maxLen) return text;
6276
6155
  return text.slice(0, maxLen) + "...";
6277
6156
  }
6278
- const DIM$8 = "\x1B[38;5;102m";
6279
- const RESET$8 = "\x1B[0m";
6157
+ const DIM$6 = "\x1B[38;5;102m";
6158
+ const RESET$6 = "\x1B[0m";
6280
6159
  async function runConfig(args, globalOpts) {
6281
6160
  switch (args[0]) {
6282
6161
  case "get":
@@ -6285,6 +6164,9 @@ async function runConfig(args, globalOpts) {
6285
6164
  case "set":
6286
6165
  await handleSet(args, globalOpts);
6287
6166
  break;
6167
+ case "analytics":
6168
+ handleAnalytics(args);
6169
+ break;
6288
6170
  default: printConfigHelp();
6289
6171
  }
6290
6172
  }
@@ -6303,6 +6185,9 @@ function printConfigHelp() {
6303
6185
  console.log(" namespace Project namespace");
6304
6186
  console.log(" ide Project IDE");
6305
6187
  console.log();
6188
+ console.log("匿名上报:");
6189
+ console.log(" bfi config analytics on|off|status 匿名安装上报开关(默认开)");
6190
+ console.log();
6306
6191
  console.log("标志:");
6307
6192
  console.log(" --global 全局应用设置(默认:项目)");
6308
6193
  }
@@ -6371,16 +6256,34 @@ async function handleSet(args, _globalOpts) {
6371
6256
  }
6372
6257
  const isGlobal = args.includes("--global");
6373
6258
  setConfigValue(key, value, isGlobal);
6374
- console.log(`${DIM$8}✓${RESET$8} 已设置 ${key} = ${value}(${(isGlobal ? "global" : "project") === "global" ? "全局" : "项目"})`);
6259
+ console.log(`${DIM$6}✓${RESET$6} 已设置 ${key} = ${value}(${(isGlobal ? "global" : "project") === "global" ? "全局" : "项目"})`);
6260
+ }
6261
+ function handleAnalytics(args) {
6262
+ const action = args[1];
6263
+ if (action === "status") {
6264
+ const enabled = (loadGlobalConfig() || {}).analytics !== false;
6265
+ console.log(`匿名安装上报:${enabled ? "开" : "关"}(默认开)`);
6266
+ console.log("只上报本地随机安装 id 与技能 id,不含用户名、主机名、IP。");
6267
+ console.log("也可用环境变量 BFI_ANALYTICS=off 临时关闭。");
6268
+ return;
6269
+ }
6270
+ if (action !== "on" && action !== "off") {
6271
+ console.error("用法:bfi config analytics on|off|status");
6272
+ process.exit(1);
6273
+ }
6274
+ const config = loadGlobalConfig() || { version: 1 };
6275
+ config.analytics = action === "on";
6276
+ saveGlobalConfig(config);
6277
+ console.log(action === "on" ? "已开启匿名安装上报(bfi config analytics off 可关闭)。" : "已关闭匿名安装上报(bfi config analytics on 可重新开启)。");
6375
6278
  }
6376
- const RESET$7 = "\x1B[0m";
6377
- const BOLD$5 = "\x1B[1m";
6378
- const DIM$7 = "\x1B[38;5;102m";
6379
- const TEXT$6 = "\x1B[38;5;145m";
6279
+ const RESET$5 = "\x1B[0m";
6280
+ const BOLD$3 = "\x1B[1m";
6281
+ const DIM$5 = "\x1B[38;5;102m";
6282
+ const TEXT$4 = "\x1B[38;5;145m";
6380
6283
  function formatFileSize(bytes) {
6381
6284
  if (bytes < 1024) return `${bytes} B`;
6382
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
6383
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6285
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
6286
+ return `${(bytes / 1048576).toFixed(1)} MB`;
6384
6287
  }
6385
6288
  async function runDocs(args, globalOpts) {
6386
6289
  switch (args[0]) {
@@ -6407,11 +6310,11 @@ function printDocsHelp() {
6407
6310
  console.log(" bfi docs download <id> 下载原始文档文件");
6408
6311
  console.log();
6409
6312
  console.log("示例:");
6410
- console.log(` ${DIM$7}$ ${RESET$7}bfi docs upload notes.md`);
6411
- console.log(` ${DIM$7}$ ${RESET$7}bfi docs upload bundle.zip`);
6412
- console.log(` ${DIM$7}$ ${RESET$7}bfi docs list`);
6413
- console.log(` ${DIM$7}$ ${RESET$7}bfi docs info 42`);
6414
- console.log(` ${DIM$7}$ ${RESET$7}bfi docs download 42`);
6313
+ console.log(` ${DIM$5}$ ${RESET$5}bfi docs upload notes.md`);
6314
+ console.log(` ${DIM$5}$ ${RESET$5}bfi docs upload bundle.zip`);
6315
+ console.log(` ${DIM$5}$ ${RESET$5}bfi docs list`);
6316
+ console.log(` ${DIM$5}$ ${RESET$5}bfi docs info 42`);
6317
+ console.log(` ${DIM$5}$ ${RESET$5}bfi docs download 42`);
6415
6318
  }
6416
6319
  async function handleUpload(args, globalOpts) {
6417
6320
  const filePath = args[0];
@@ -6434,18 +6337,18 @@ async function handleUpload(args, globalOpts) {
6434
6337
  const api = new SkillHubAPI(registry, token);
6435
6338
  const fileName = path$1.basename(resolvedPath);
6436
6339
  const fileSizeStr = formatFileSize(stats.size);
6437
- console.log(`${DIM$7}正在上传 ${fileName} (${fileSizeStr})...${RESET$7}`);
6340
+ console.log(`${DIM$5}正在上传 ${fileName} (${fileSizeStr})...${RESET$5}`);
6438
6341
  try {
6439
6342
  const fileBuffer = fs.readFileSync(resolvedPath);
6440
6343
  const result = await api.uploadDoc(fileBuffer, fileName);
6441
6344
  const doc = result.data || result;
6442
- console.log(`${TEXT$6}✓ 上传成功${RESET$7}`);
6345
+ console.log(`${TEXT$4}✓ 上传成功${RESET$5}`);
6443
6346
  console.log();
6444
- if (doc.id) console.log(` ${BOLD$5}ID:${RESET$7} ${TEXT$6}${doc.id}${RESET$7}`);
6445
- if (doc.status) console.log(` ${BOLD$5}状态:${RESET$7} ${TEXT$6}${doc.status}${RESET$7}`);
6446
- if (doc.fileName) console.log(` ${BOLD$5}文件:${RESET$7} ${TEXT$6}${doc.fileName}${RESET$7}`);
6347
+ if (doc.id) console.log(` ${BOLD$3}ID:${RESET$5} ${TEXT$4}${doc.id}${RESET$5}`);
6348
+ if (doc.status) console.log(` ${BOLD$3}状态:${RESET$5} ${TEXT$4}${doc.status}${RESET$5}`);
6349
+ if (doc.fileName) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${doc.fileName}${RESET$5}`);
6447
6350
  console.log();
6448
- if (doc.id) console.log(`${DIM$7}查看状态:bfi docs info ${doc.id}${RESET$7}`);
6351
+ if (doc.id) console.log(`${DIM$5}查看状态:bfi docs info ${doc.id}${RESET$5}`);
6449
6352
  } catch (error) {
6450
6353
  console.error(`上传失败:${error.message}`);
6451
6354
  process.exit(1);
@@ -6461,14 +6364,14 @@ async function handleList(args, globalOpts) {
6461
6364
  const data = result.data || result;
6462
6365
  const docs = data.items || data.content || data.docs || (Array.isArray(data) ? data : []);
6463
6366
  if (!Array.isArray(docs) || docs.length === 0) {
6464
- console.log(`${DIM$7}未找到文档。${RESET$7}`);
6367
+ console.log(`${DIM$5}未找到文档。${RESET$5}`);
6465
6368
  return;
6466
6369
  }
6467
6370
  const total = data.total || data.totalElements || result.total || result.totalElements;
6468
6371
  console.log();
6469
- if (total) console.log(`${BOLD$5}文档${RESET$7}(第 ${page + 1} 页,共 ${total} 条):`);
6470
- else console.log(`${BOLD$5}文档${RESET$7}(第 ${page + 1} 页,共 ${docs.length} 条结果):`);
6471
- console.log(`${DIM$7}${"─".repeat(64)}${RESET$7}`);
6372
+ if (total) console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${total} 条):`);
6373
+ else console.log(`${BOLD$3}文档${RESET$5}(第 ${page + 1} 页,共 ${docs.length} 条结果):`);
6374
+ console.log(`${DIM$5}${"─".repeat(64)}${RESET$5}`);
6472
6375
  for (const doc of docs) {
6473
6376
  const id = doc.id || "?";
6474
6377
  const fileName = doc.fileName || doc.file_name || "unknown";
@@ -6478,11 +6381,11 @@ async function handleList(args, globalOpts) {
6478
6381
  const ip = doc.clientIp || "N/A";
6479
6382
  const createdAt = doc.createdAt || doc.created_at;
6480
6383
  const dateStr = createdAt ? new Date(createdAt).toISOString().split("T")[0] : "N/A";
6481
- console.log(` ${BOLD$5}#${id}${RESET$7} ${TEXT$6}${fileName}${RESET$7}`);
6482
- console.log(` ${DIM$7}${sizeStr} | ${user} | ${ip} | ${dateStr}${RESET$7}`);
6384
+ console.log(` ${BOLD$3}#${id}${RESET$5} ${TEXT$4}${fileName}${RESET$5}`);
6385
+ console.log(` ${DIM$5}${sizeStr} | ${user} | ${ip} | ${dateStr}${RESET$5}`);
6483
6386
  console.log();
6484
6387
  }
6485
- if (total && Number(total) > (page + 1) * size) console.log(`${DIM$7}下一页:bfi docs list ${page + 1}${RESET$7}`);
6388
+ if (total && Number(total) > (page + 1) * size) console.log(`${DIM$5}下一页:bfi docs list ${page + 1}${RESET$5}`);
6486
6389
  console.log();
6487
6390
  } catch (error) {
6488
6391
  console.error(`列出文档失败:${error.message}`);
@@ -6506,46 +6409,46 @@ async function handleInfo(args, globalOpts) {
6506
6409
  const result = await api.getDoc(id);
6507
6410
  const doc = result.data || result;
6508
6411
  if (!doc || !doc.id) {
6509
- console.log(`${DIM$7}未找到文档:${id}${RESET$7}`);
6412
+ console.log(`${DIM$5}未找到文档:${id}${RESET$5}`);
6510
6413
  process.exit(1);
6511
6414
  }
6512
6415
  const content = doc.content;
6513
6416
  const hasContent = typeof content === "string" && content.trim().length > 0;
6514
6417
  console.log();
6515
- console.log(`${BOLD$5}文档 #${doc.id}${RESET$7}`);
6516
- console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6517
- if (doc.fileName || doc.file_name) console.log(` ${BOLD$5}文件:${RESET$7} ${TEXT$6}${doc.fileName || doc.file_name}${RESET$7}`);
6418
+ console.log(`${BOLD$3}文档 #${doc.id}${RESET$5}`);
6419
+ console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6420
+ if (doc.fileName || doc.file_name) console.log(` ${BOLD$3}文件:${RESET$5} ${TEXT$4}${doc.fileName || doc.file_name}${RESET$5}`);
6518
6421
  const fileSize = doc.fileSize || doc.file_size;
6519
- if (fileSize) console.log(` ${BOLD$5}大小:${RESET$7} ${TEXT$6}${formatFileSize(Number(fileSize))}${RESET$7}`);
6422
+ if (fileSize) console.log(` ${BOLD$3}大小:${RESET$5} ${TEXT$4}${formatFileSize(Number(fileSize))}${RESET$5}`);
6520
6423
  const user = doc.userDisplayName || doc.userId;
6521
- if (user) console.log(` ${BOLD$5}上传者:${RESET$7} ${TEXT$6}${user}${RESET$7}`);
6522
- if (doc.clientIp) console.log(` ${BOLD$5}IP:${RESET$7} ${TEXT$6}${doc.clientIp}${RESET$7}`);
6424
+ if (user) console.log(` ${BOLD$3}上传者:${RESET$5} ${TEXT$4}${user}${RESET$5}`);
6425
+ if (doc.clientIp) console.log(` ${BOLD$3}IP:${RESET$5} ${TEXT$4}${doc.clientIp}${RESET$5}`);
6523
6426
  if (doc.status) {
6524
- const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$6;
6525
- console.log(` ${BOLD$5}状态:${RESET$7} ${statusColor}${doc.status}${RESET$7}`);
6427
+ const statusColor = doc.status === "completed" || doc.status === "COMPLETED" ? "\x1B[32m" : doc.status === "failed" || doc.status === "FAILED" ? "\x1B[31m" : TEXT$4;
6428
+ console.log(` ${BOLD$3}状态:${RESET$5} ${statusColor}${doc.status}${RESET$5}`);
6526
6429
  }
6527
6430
  if (doc.createdAt || doc.created_at) {
6528
6431
  const date = new Date(doc.createdAt || doc.created_at).toISOString().replace("T", " ").slice(0, 19);
6529
- console.log(` ${BOLD$5}创建时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6432
+ console.log(` ${BOLD$3}创建时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6530
6433
  }
6531
6434
  if (doc.updatedAt || doc.updated_at) {
6532
6435
  const date = new Date(doc.updatedAt || doc.updated_at).toISOString().replace("T", " ").slice(0, 19);
6533
- console.log(` ${BOLD$5}更新时间:${RESET$7} ${TEXT$6}${date}${RESET$7}`);
6436
+ console.log(` ${BOLD$3}更新时间:${RESET$5} ${TEXT$4}${date}${RESET$5}`);
6534
6437
  }
6535
6438
  if (doc.error || doc.errorMessage) {
6536
6439
  console.log();
6537
- console.log(` \x1b[31m${BOLD$5}错误:${RESET$7}`);
6538
- console.log(` \x1b[31m${doc.error || doc.errorMessage}${RESET$7}`);
6440
+ console.log(` \x1b[31m${BOLD$3}错误:${RESET$5}`);
6441
+ console.log(` \x1b[31m${doc.error || doc.errorMessage}${RESET$5}`);
6539
6442
  }
6540
6443
  if (hasContent) {
6541
6444
  console.log();
6542
- console.log(` ${BOLD$5}内容:${RESET$7}`);
6543
- console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6544
- for (const line of content.split("\n")) console.log(` ${TEXT$6}${line}${RESET$7}`);
6545
- console.log(`${DIM$7}${"─".repeat(48)}${RESET$7}`);
6445
+ console.log(` ${BOLD$3}内容:${RESET$5}`);
6446
+ console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6447
+ for (const line of content.split("\n")) console.log(` ${TEXT$4}${line}${RESET$5}`);
6448
+ console.log(`${DIM$5}${"─".repeat(48)}${RESET$5}`);
6546
6449
  } else if (doc.content === null || doc.content === void 0) {
6547
6450
  console.log();
6548
- console.log(` ${DIM$7}该文件类型不支持内容预览,可用 bfi docs download ${doc.id} 获取原始文件${RESET$7}`);
6451
+ console.log(` ${DIM$5}该文件类型不支持内容预览,可用 bfi docs download ${doc.id} 获取原始文件${RESET$5}`);
6549
6452
  }
6550
6453
  console.log();
6551
6454
  } catch (error) {
@@ -6572,20 +6475,20 @@ async function handleDownload(args, globalOpts) {
6572
6475
  const safeName = path$1.basename(fileName);
6573
6476
  const targetPath = path$1.resolve(safeName);
6574
6477
  fs.writeFileSync(targetPath, buffer);
6575
- console.log(`${TEXT$6}✓ 已保存 ${safeName} (${formatFileSize(buffer.length)})${RESET$7}`);
6478
+ console.log(`${TEXT$4}✓ 已保存 ${safeName} (${formatFileSize(buffer.length)})${RESET$5}`);
6576
6479
  } catch (error) {
6577
6480
  if (error.status === 404) console.error(`未找到文档:${id}`);
6578
6481
  else console.error(`下载失败:${error.message}`);
6579
6482
  process.exit(1);
6580
6483
  }
6581
6484
  }
6582
- const RESET$6 = "\x1B[0m";
6583
- const BOLD$4 = "\x1B[1m";
6584
- const DIM$6 = "\x1B[38;5;102m";
6585
- const TEXT$5 = "\x1B[38;5;145m";
6586
- const GREEN$5 = "\x1B[32m";
6485
+ const RESET$4 = "\x1B[0m";
6486
+ const BOLD$2 = "\x1B[1m";
6487
+ const DIM$4 = "\x1B[38;5;102m";
6488
+ const TEXT$3 = "\x1B[38;5;145m";
6489
+ const GREEN$3 = "\x1B[32m";
6587
6490
  const YELLOW$2 = "\x1B[33m";
6588
- const RED$4 = "\x1B[31m";
6491
+ const RED$2 = "\x1B[31m";
6589
6492
  async function runPublish(args, globalOpts) {
6590
6493
  const fromIdx = args.indexOf("--from");
6591
6494
  const mode = fromIdx !== -1 ? args[fromIdx + 1] : "dir";
@@ -6644,25 +6547,26 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
6644
6547
  console.log("需要包含 frontmatter(name, description)的 SKILL.md 文件。");
6645
6548
  process.exit(1);
6646
6549
  }
6647
- const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6550
+ const skillMdContent = fs.readFileSync(skillMdPath, "utf-8");
6551
+ const { data: frontmatter } = parseFrontmatter(skillMdContent);
6648
6552
  const skillName = frontmatter.name || path$1.basename(resolvedDir);
6649
- console.log(`${DIM$6}正在从目录发布技能...${RESET$6}`);
6650
- console.log(` ${BOLD$4}名称:${RESET$6} ${TEXT$5}${skillName}${RESET$6}`);
6651
- console.log(` ${BOLD$4}命名空间:${RESET$6} ${TEXT$5}${namespace}${RESET$6}`);
6652
- console.log(` ${BOLD$4}可见性:${RESET$6} ${TEXT$5}${visibility}${RESET$6}`);
6653
- console.log(` ${BOLD$4}目录:${RESET$6} ${TEXT$5}${resolvedDir}${RESET$6}`);
6553
+ console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
6554
+ console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6555
+ console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6556
+ console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
6557
+ console.log(` ${BOLD$2}目录:${RESET$4} ${TEXT$3}${resolvedDir}${RESET$4}`);
6654
6558
  console.log();
6655
- console.log(`${DIM$6}正在创建 zip...${RESET$6}`);
6559
+ console.log(`${DIM$4}正在创建 zip...${RESET$4}`);
6656
6560
  const zipBuffer = createZipFromDir(resolvedDir);
6657
- console.log(` ${GREEN$5}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$6}`);
6658
- console.log(`${DIM$6}正在上传到 SkillHub...${RESET$6}`);
6561
+ console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6562
+ console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
6659
6563
  try {
6660
6564
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6661
- console.log(` ${GREEN$5}发布成功!${RESET$6}`);
6662
- if (res.slug) console.log(` ${BOLD$4}Slug:${RESET$6} ${TEXT$5}${res.slug}${RESET$6}`);
6663
- if (res.url) console.log(` ${BOLD$4}URL:${RESET$6} ${TEXT$5}${res.url}${RESET$6}`);
6565
+ console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6566
+ if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6567
+ if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
6664
6568
  } catch (error) {
6665
- console.error(` ${RED$4}发布失败:${error.message}${RESET$6}`);
6569
+ console.error(` ${RED$2}发布失败:${error.message}${RESET$4}`);
6666
6570
  process.exit(1);
6667
6571
  }
6668
6572
  console.log();
@@ -6679,34 +6583,35 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
6679
6583
  console.error(`文件未找到:${resolvedZip}`);
6680
6584
  process.exit(1);
6681
6585
  }
6682
- console.log(`${DIM$6}正在解压 zip...${RESET$6}`);
6586
+ console.log(`${DIM$4}正在解压 zip...${RESET$4}`);
6683
6587
  const tmpDir = path$1.join(os$1.tmpdir(), `.bfi-publish-${Date.now()}`);
6684
6588
  fs.mkdirSync(tmpDir, { recursive: true });
6685
6589
  try {
6686
6590
  await extractZip(resolvedZip, tmpDir);
6687
6591
  const skillMdPath = findSkillMd(tmpDir);
6688
6592
  if (!skillMdPath) {
6689
- console.error(` ${RED$4}zip 文件中未找到 SKILL.md${RESET$6}`);
6593
+ console.error(` ${RED$2}zip 文件中未找到 SKILL.md${RESET$4}`);
6690
6594
  process.exit(1);
6691
6595
  }
6692
6596
  const skillDir = path$1.dirname(skillMdPath);
6693
- console.log(` ${GREEN$5}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$6}`);
6694
- const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6597
+ console.log(` ${GREEN$3}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$4}`);
6598
+ const skillMdContent = fs.readFileSync(skillMdPath, "utf-8");
6599
+ const { data: frontmatter } = parseFrontmatter(skillMdContent);
6695
6600
  const skillName = frontmatter.name || path$1.basename(skillDir);
6696
- console.log(` ${BOLD$4}名称:${RESET$6} ${TEXT$5}${skillName}${RESET$6}`);
6697
- console.log(` ${BOLD$4}命名空间:${RESET$6} ${TEXT$5}${namespace}${RESET$6}`);
6698
- console.log(` ${BOLD$4}可见性:${RESET$6} ${TEXT$5}${visibility}${RESET$6}`);
6601
+ console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6602
+ console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
6603
+ console.log(` ${BOLD$2}可见性:${RESET$4} ${TEXT$3}${visibility}${RESET$4}`);
6699
6604
  console.log();
6700
- console.log(`${DIM$6}正在重新打包...${RESET$6}`);
6605
+ console.log(`${DIM$4}正在重新打包...${RESET$4}`);
6701
6606
  const zipBuffer = createZipFromDir(skillDir);
6702
- console.log(` ${GREEN$5}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$6}`);
6703
- console.log(`${DIM$6}正在上传到 SkillHub...${RESET$6}`);
6607
+ console.log(` ${GREEN$3}Zip 已创建 (${formatSize(zipBuffer.length)})${RESET$4}`);
6608
+ console.log(`${DIM$4}正在上传到 SkillHub...${RESET$4}`);
6704
6609
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6705
- console.log(` ${GREEN$5}发布成功!${RESET$6}`);
6706
- if (res.slug) console.log(` ${BOLD$4}Slug:${RESET$6} ${TEXT$5}${res.slug}${RESET$6}`);
6707
- if (res.url) console.log(` ${BOLD$4}URL:${RESET$6} ${TEXT$5}${res.url}${RESET$6}`);
6610
+ console.log(` ${GREEN$3}发布成功!${RESET$4}`);
6611
+ if (res.slug) console.log(` ${BOLD$2}Slug:${RESET$4} ${TEXT$3}${res.slug}${RESET$4}`);
6612
+ if (res.url) console.log(` ${BOLD$2}URL:${RESET$4} ${TEXT$3}${res.url}${RESET$4}`);
6708
6613
  } catch (error) {
6709
- if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$4}错误:${error.message}${RESET$6}`);
6614
+ if (error.message && !error.message.includes("Publish failed")) console.error(` ${RED$2}错误:${error.message}${RESET$4}`);
6710
6615
  process.exit(1);
6711
6616
  } finally {
6712
6617
  try {
@@ -6735,18 +6640,18 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6735
6640
  }
6736
6641
  const effectiveBranch = branch || parsedRef || "main";
6737
6642
  const effectiveSubpath = directory || null;
6738
- console.log(`${DIM$6}正在从 Git 仓库发现技能...${RESET$6}`);
6739
- console.log(` ${BOLD$4}仓库:${RESET$6} ${TEXT$5}${repoUrl}${RESET$6}`);
6740
- console.log(` ${BOLD$4}分支:${RESET$6} ${TEXT$5}${effectiveBranch}${RESET$6}`);
6643
+ console.log(`${DIM$4}正在从 Git 仓库发现技能...${RESET$4}`);
6644
+ console.log(` ${BOLD$2}仓库:${RESET$4} ${TEXT$3}${repoUrl}${RESET$4}`);
6645
+ console.log(` ${BOLD$2}分支:${RESET$4} ${TEXT$3}${effectiveBranch}${RESET$4}`);
6741
6646
  console.log();
6742
6647
  let tmpDir = null;
6743
6648
  let skills = [];
6744
6649
  try {
6745
- console.log(`${DIM$6}正在克隆仓库...${RESET$6}`);
6650
+ console.log(`${DIM$4}正在克隆仓库...${RESET$4}`);
6746
6651
  const { cloneRepo } = await Promise.resolve().then(() => git_exports);
6747
6652
  tmpDir = await cloneRepo(repoUrl, effectiveBranch);
6748
- console.log(` ${GREEN$5}仓库克隆完成${RESET$6}`);
6749
- console.log(`${DIM$6}正在发现技能...${RESET$6}`);
6653
+ console.log(` ${GREEN$3}仓库克隆完成${RESET$4}`);
6654
+ console.log(`${DIM$4}正在发现技能...${RESET$4}`);
6750
6655
  const { discoverSkills } = await import("./_chunks/skills.mjs").then((n) => n.skills_exports);
6751
6656
  skills = (await discoverSkills(tmpDir, effectiveSubpath || void 0)).map((s) => ({
6752
6657
  path: s.path,
@@ -6754,7 +6659,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6754
6659
  description: s.description || ""
6755
6660
  }));
6756
6661
  } catch (error) {
6757
- console.error(` ${RED$4}克隆或发现失败:${error.message}${RESET$6}`);
6662
+ console.error(` ${RED$2}克隆或发现失败:${error.message}${RESET$4}`);
6758
6663
  if (tmpDir) try {
6759
6664
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6760
6665
  await cleanupTempDir(tmpDir);
@@ -6762,7 +6667,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6762
6667
  process.exit(1);
6763
6668
  }
6764
6669
  if (skills.length === 0) {
6765
- console.log(`${YELLOW$2}仓库中未发现技能。${RESET$6}`);
6670
+ console.log(`${YELLOW$2}仓库中未发现技能。${RESET$4}`);
6766
6671
  if (tmpDir) try {
6767
6672
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6768
6673
  await cleanupTempDir(tmpDir);
@@ -6774,7 +6679,7 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6774
6679
  const filters = skillFilter.split(",").map((s) => s.trim().toLowerCase());
6775
6680
  selectedSkills = skills.filter((s) => filters.some((f) => s.name.toLowerCase().includes(f)));
6776
6681
  if (selectedSkills.length === 0) {
6777
- console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$6}`);
6682
+ console.log(`${YELLOW$2}未找到匹配 "${skillFilter}" 的技能${RESET$4}`);
6778
6683
  console.log(`可用:${skills.map((s) => s.name).join(", ")}`);
6779
6684
  try {
6780
6685
  fs.rmSync(tmpDir, {
@@ -6785,12 +6690,12 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6785
6690
  process.exit(1);
6786
6691
  }
6787
6692
  }
6788
- console.log(`\n${BOLD$4}发现 ${skills.length} 个技能,将发布 ${selectedSkills.length} 个:${RESET$6}\n`);
6693
+ console.log(`\n${BOLD$2}发现 ${skills.length} 个技能,将发布 ${selectedSkills.length} 个:${RESET$4}\n`);
6789
6694
  for (const skill of selectedSkills) {
6790
6695
  const relPath = path$1.relative(tmpDir, skill.path) || ".";
6791
- console.log(` ${BOLD$4}${skill.name}${RESET$6}`);
6792
- console.log(` ${DIM$6}📁 ${relPath.split("/").join(" ▸ ")}${RESET$6}`);
6793
- if (skill.description) console.log(` ${DIM$6}${truncate(skill.description, 80)}${RESET$6}`);
6696
+ console.log(` ${BOLD$2}${skill.name}${RESET$4}`);
6697
+ console.log(` ${DIM$4}📁 ${relPath.split("/").join(" ▸ ")}${RESET$4}`);
6698
+ if (skill.description) console.log(` ${DIM$4}${truncate(skill.description, 80)}${RESET$4}`);
6794
6699
  console.log();
6795
6700
  }
6796
6701
  if (!yes) {
@@ -6809,17 +6714,17 @@ async function publishFromGit(positionalArgs, api, namespace, visibility, yes, b
6809
6714
  const { createZipFromDir } = await Promise.resolve().then(() => zip_exports);
6810
6715
  let successCount = 0;
6811
6716
  for (const skill of selectedSkills) {
6812
- console.log(`${DIM$6}正在发布 ${skill.name}...${RESET$6}`);
6717
+ console.log(`${DIM$4}正在发布 ${skill.name}...${RESET$4}`);
6813
6718
  try {
6814
6719
  const zipBuffer = createZipFromDir(skill.path);
6815
6720
  const res = await api.publishSkill(namespace, zipBuffer, visibility, true);
6816
- console.log(` ${GREEN$5}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$6}`);
6721
+ console.log(` ${GREEN$3}✓ 已发布:${namespace}--${res.slug || skill.name}${RESET$4}`);
6817
6722
  successCount++;
6818
6723
  } catch (error) {
6819
- console.error(` ${RED$4}✗ ${skill.name}:${error.message}${RESET$6}`);
6724
+ console.error(` ${RED$2}✗ ${skill.name}:${error.message}${RESET$4}`);
6820
6725
  }
6821
6726
  }
6822
- console.log(`\n${GREEN$5}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$6}`);
6727
+ console.log(`\n${GREEN$3}发布完成:${successCount}/${selectedSkills.length} 个技能${RESET$4}`);
6823
6728
  if (tmpDir) try {
6824
6729
  const { cleanupTempDir } = await Promise.resolve().then(() => git_exports);
6825
6730
  await cleanupTempDir(tmpDir);
@@ -6861,21 +6766,218 @@ function findSkillMd(dir) {
6861
6766
  }
6862
6767
  function formatSize(bytes) {
6863
6768
  if (bytes < 1024) return `${bytes} B`;
6864
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
6865
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6769
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
6770
+ return `${(bytes / 1048576).toFixed(1)} MB`;
6866
6771
  }
6867
6772
  function truncate(text, maxLen) {
6868
6773
  if (text.length <= maxLen) return text;
6869
6774
  return text.slice(0, maxLen) + "...";
6870
6775
  }
6776
+ var analytics_exports = /* @__PURE__ */ __exportAll({
6777
+ buildPayload: () => buildPayload,
6778
+ getInstallId: () => getInstallId,
6779
+ isCi: () => isCi,
6780
+ maybePrintAnalyticsNotice: () => maybePrintAnalyticsNotice,
6781
+ reportInstall: () => reportInstall,
6782
+ reportInstallEventForSkill: () => reportInstallEventForSkill,
6783
+ shouldReport: () => shouldReport
6784
+ });
6785
+ const INSTALL_ID_FILE = path$1.join(os$1.homedir(), ".bfi", "install-id");
6786
+ const ANALYTICS_NOTICE_FILE = path$1.join(os$1.homedir(), ".bfi", "analytics-notice-shown");
6787
+ function buildPayload(input, installId) {
6788
+ return {
6789
+ installId: installId ?? "anonymous",
6790
+ skillId: input.skillId,
6791
+ versionId: input.versionId,
6792
+ agentTarget: input.agentTarget,
6793
+ ci: input.ci ?? isCi(),
6794
+ action: input.action ?? "INSTALL"
6795
+ };
6796
+ }
6797
+ function isCi(env = process.env) {
6798
+ return Boolean(env.CI || env.CONTINUOUS_INTEGRATION || env.BUILD_NUMBER);
6799
+ }
6800
+ function shouldReport(config, env = process.env) {
6801
+ if (env.BFI_ANALYTICS === "off" || env.BFI_ANALYTICS === "false") return false;
6802
+ if (env.BFI_ANALYTICS === "on" || env.BFI_ANALYTICS === "true") return true;
6803
+ return config.analytics !== false;
6804
+ }
6805
+ function getInstallId(store) {
6806
+ const cached = store.read();
6807
+ if (cached && cached.trim().length > 0) return cached.trim();
6808
+ const id = randomUUID();
6809
+ store.write(id);
6810
+ return id;
6811
+ }
6812
+ function defaultInstallIdStore() {
6813
+ return {
6814
+ read: () => {
6815
+ try {
6816
+ if (fs.existsSync(INSTALL_ID_FILE)) return fs.readFileSync(INSTALL_ID_FILE, "utf8");
6817
+ } catch {}
6818
+ return null;
6819
+ },
6820
+ write: (value) => {
6821
+ try {
6822
+ fs.mkdirSync(path$1.dirname(INSTALL_ID_FILE), {
6823
+ recursive: true,
6824
+ mode: 448
6825
+ });
6826
+ fs.writeFileSync(INSTALL_ID_FILE, value, { mode: 384 });
6827
+ } catch {}
6828
+ }
6829
+ };
6830
+ }
6831
+ async function reportInstall(api, payload) {
6832
+ try {
6833
+ await api.reportInstallEvent(payload);
6834
+ } catch {}
6835
+ }
6836
+ async function reportInstallEventForSkill(api, input) {
6837
+ if (!api || typeof input.skillId !== "number") return;
6838
+ if (!shouldReport(loadGlobalConfig() || {})) return;
6839
+ const installId = getInstallId(defaultInstallIdStore());
6840
+ await reportInstall(api, buildPayload({
6841
+ skillId: input.skillId,
6842
+ agentTarget: input.agentTarget
6843
+ }, installId));
6844
+ }
6845
+ function maybePrintAnalyticsNotice(env = process.env) {
6846
+ if (env.BFI_ANALYTICS === "off" || env.BFI_ANALYTICS === "false") return;
6847
+ try {
6848
+ if (fs.existsSync(ANALYTICS_NOTICE_FILE)) return;
6849
+ fs.mkdirSync(path$1.dirname(ANALYTICS_NOTICE_FILE), {
6850
+ recursive: true,
6851
+ mode: 448
6852
+ });
6853
+ fs.writeFileSync(ANALYTICS_NOTICE_FILE, (/* @__PURE__ */ new Date()).toISOString(), { mode: 384 });
6854
+ console.log("bfi 会匿名上报技能安装事件(仅安装 id 与技能 id,不含用户与 IP),用于市场统计。");
6855
+ console.log("关闭:bfi config analytics off");
6856
+ console.log();
6857
+ } catch {}
6858
+ }
6859
+ const pluginTargets = [
6860
+ "claude-code",
6861
+ "codex",
6862
+ "zcode",
6863
+ "codebuddy",
6864
+ "qwen-code"
6865
+ ];
6866
+ const isPluginArchive = (value) => /\.(zip|tgz|tar\.gz)$/iu.test(value);
6867
+ const isPluginVersion = (value) => /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.test(value);
6868
+ function parsePackageIntent(args) {
6869
+ const output = [...args];
6870
+ let mode = "skills";
6871
+ const occurrences = args.filter((value) => value === "--as" || value.startsWith("--as="));
6872
+ if (occurrences.length) {
6873
+ const index = output.indexOf("--as");
6874
+ const requested = output[index + 1];
6875
+ if (occurrences.length !== 1 || index < 0 || !["skills", "plugin"].includes(requested ?? "")) throw new Error("Use --as skills or --as plugin exactly once; upgrade bfi if this option is unavailable");
6876
+ mode = requested;
6877
+ output.splice(index, 2);
6878
+ }
6879
+ if (mode === "skills" && (output.some((value) => [
6880
+ "--plan",
6881
+ "--export",
6882
+ "--scope",
6883
+ "--root",
6884
+ "--operation"
6885
+ ].includes(value) || /^(--plan|--export|--scope|--root|--operation)=/u.test(value)) || isPluginArchive(output[1] ?? ""))) throw new Error("Plugin archives and plugin options require explicit --as plugin; no skills were installed");
6886
+ return {
6887
+ mode,
6888
+ args: output
6889
+ };
6890
+ }
6891
+ function parsePluginArguments(args) {
6892
+ const command = {
6893
+ install: "install",
6894
+ i: "install",
6895
+ update: "update",
6896
+ up: "update",
6897
+ uninstall: "uninstall",
6898
+ rm: "uninstall",
6899
+ list: "list",
6900
+ ls: "list"
6901
+ }[args[0] ?? ""];
6902
+ if (!command) throw new Error("Plugin intent supports install, update, uninstall and list");
6903
+ const result = {
6904
+ command,
6905
+ scope: "project",
6906
+ planOnly: false,
6907
+ json: false
6908
+ };
6909
+ const seen = /* @__PURE__ */ new Set();
6910
+ const values = /* @__PURE__ */ new Set([
6911
+ "--agent",
6912
+ "--version",
6913
+ "--scope",
6914
+ "--root",
6915
+ "--export",
6916
+ "--operation",
6917
+ "--registry",
6918
+ "--token",
6919
+ "--namespace"
6920
+ ]);
6921
+ for (let index = 1; index < args.length; index++) {
6922
+ const option = args[index];
6923
+ if (!option.startsWith("-")) {
6924
+ if (result.source) throw new Error("Specify exactly one plugin source");
6925
+ result.source = option;
6926
+ continue;
6927
+ }
6928
+ const flag = option === "-g" ? "--global" : option === "-y" ? "--yes" : option;
6929
+ if (seen.has(flag)) throw new Error(`Duplicate plugin option: ${flag}`);
6930
+ seen.add(flag);
6931
+ if (values.has(flag)) {
6932
+ const value = args[++index];
6933
+ if (value === void 0 || value.startsWith("-") || /[\u0000-\u001f\u007f]/u.test(value)) throw new Error(`Missing or invalid value for ${flag}`);
6934
+ if (flag === "--agent") {
6935
+ if (!pluginTargets.includes(value)) throw new Error("Unknown native plugin target");
6936
+ result.agent = value;
6937
+ } else if (flag === "--version") {
6938
+ if (!isPluginVersion(value)) throw new Error("Plugin version must be exact SemVer, not latest or a range");
6939
+ result.version = value;
6940
+ } else if (flag === "--scope") {
6941
+ if (!["project", "user"].includes(value)) throw new Error("Plugin scope must be project or user");
6942
+ result.scope = value;
6943
+ } else if (flag === "--root") result.root = value;
6944
+ else if (flag === "--export") result.exportPath = value;
6945
+ else if (flag === "--operation") result.operationId = value;
6946
+ } else if (flag === "--global") result.scope = "user";
6947
+ else if (flag === "--plan") result.planOnly = true;
6948
+ else if (flag === "--json") result.json = true;
6949
+ else if (flag !== "--yes") throw new Error(`Unknown plugin option: ${flag}; upgrade bfi if needed`);
6950
+ }
6951
+ if (seen.has("--scope") && seen.has("--global")) throw new Error("Use --scope or --global, not both");
6952
+ if (command !== "list" && !result.agent) throw new Error("Full plugin operations require an explicit --agent");
6953
+ if (command !== "list" && !result.source && !(command === "uninstall" && result.operationId)) throw new Error("Specify @namespace/package or a local zip/tgz path");
6954
+ if (result.source && !/^@[^/\s]+\/[^/\s]+$/u.test(result.source) && !isPluginArchive(result.source)) throw new Error("Use a namespace-qualified @namespace/package reference or local archive");
6955
+ if (result.planOnly && result.exportPath) throw new Error("Plan and export are separate operations");
6956
+ if (result.root !== void 0 && !isPluginArchive(result.source ?? "") || result.operationId && command !== "uninstall" || (result.exportPath || result.root !== void 0) && command !== "install") throw new Error("Plugin option is invalid for this operation");
6957
+ if (command === "list" && (result.source || result.version || result.planOnly || result.exportPath || result.operationId)) throw new Error("Invalid plugin list options");
6958
+ return result;
6959
+ }
6871
6960
  var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
6872
- const RESET$5 = "\x1B[0m";
6873
- const BOLD$3 = "\x1B[1m";
6874
- const DIM$5 = "\x1B[38;5;102m";
6875
- const GREEN$4 = "\x1B[32m";
6876
- const RED$3 = "\x1B[31m";
6961
+ const RESET$3 = "\x1B[0m";
6962
+ const BOLD$1 = "\x1B[1m";
6963
+ const DIM$3 = "\x1B[38;5;102m";
6964
+ const GREEN$2 = "\x1B[32m";
6965
+ const RED$1 = "\x1B[31m";
6877
6966
  const YELLOW$1 = "\x1B[33m";
6878
6967
  async function runPackage(args, globalOpts) {
6968
+ const intent = parsePackageIntent(args);
6969
+ const previousDirectory = process.cwd();
6970
+ try {
6971
+ if (globalOpts.workdir) process.chdir(globalOpts.workdir);
6972
+ if (intent.mode === "plugin") {
6973
+ const { runPluginPackage } = await import("./_chunks/package-plugin.mjs");
6974
+ await runPluginPackage(intent.args, globalOpts);
6975
+ } else await dispatchPackage(intent.args, globalOpts);
6976
+ } finally {
6977
+ process.chdir(previousDirectory);
6978
+ }
6979
+ }
6980
+ async function dispatchPackage(args, globalOpts) {
6879
6981
  const subcommand = args[0];
6880
6982
  const { registry, token } = resolveConfig(globalOpts);
6881
6983
  const api = new SkillHubAPI(registry, token);
@@ -6919,28 +7021,39 @@ function getWorkdir(globalOpts, args) {
6919
7021
  return globalOpts.workdir || process.cwd();
6920
7022
  }
6921
7023
  function printPackageHelp() {
6922
- console.log(`${BOLD$3}包命令:${RESET$5}`);
7024
+ console.log(`${BOLD$1}包命令:${RESET$3}`);
6923
7025
  console.log();
6924
- console.log(`${BOLD$3}本地操作:${RESET$5}`);
6925
- console.log(` ${DIM$5}bfi skills package list${RESET$5} 列出已安装的包`);
6926
- console.log(` ${DIM$5}bfi skills package install <ref>${RESET$5} 安装包(含全部技能)`);
6927
- console.log(` ${DIM$5}bfi skills package uninstall <ref>${RESET$5} 卸载包(含全部技能)`);
6928
- console.log(` ${DIM$5}bfi skills package update [ref]${RESET$5} 更新包中技能`);
6929
- console.log(` ${DIM$5}bfi skills package search <query>${RESET$5} 搜索包`);
7026
+ console.log(`${BOLD$1}本地操作:${RESET$3}`);
7027
+ console.log(` ${DIM$3}bfi skills package list${RESET$3} 列出已安装的包`);
7028
+ console.log(` ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包中的技能组合`);
7029
+ console.log(` ${DIM$3}bfi skills package uninstall <ref>${RESET$3} 卸载包(含全部技能)`);
7030
+ console.log(` ${DIM$3}bfi skills package update [ref]${RESET$3} 更新包中技能`);
7031
+ console.log(` ${DIM$3}bfi skills package search <query>${RESET$3} 搜索包`);
6930
7032
  console.log();
6931
- console.log(`${BOLD$3}服务端管理:${RESET$5}`);
6932
- console.log(` ${DIM$5}bfi skills package create <slug>${RESET$5} 创建包`);
6933
- console.log(` ${DIM$5}bfi skills package add-skills <ref> [skills...]${RESET$5} 添加技能到包`);
6934
- console.log(` ${DIM$5}bfi skills package remove-skills <ref> [skills...]${RESET$5} 从包移除技能`);
7033
+ console.log(`${BOLD$1}服务端管理:${RESET$3}`);
7034
+ console.log(` ${DIM$3}bfi skills package create <slug>${RESET$3} 创建包`);
7035
+ console.log(` ${DIM$3}bfi skills package add-skills <ref> [skills...]${RESET$3} 添加技能到包`);
7036
+ console.log(` ${DIM$3}bfi skills package remove-skills <ref> [skills...]${RESET$3} 从包移除技能`);
6935
7037
  console.log();
6936
- console.log(`${BOLD$3}选项:${RESET$5}`);
7038
+ console.log(`${BOLD$1}选项:${RESET$3}`);
6937
7039
  console.log(` --namespace <ns> 目标命名空间`);
7040
+ console.log(` --agent <a> 目标 agent(如 claude-code、codex)`);
7041
+ console.log(` --as skills|plugin 默认 skills;完整插件必须显式 --as plugin --agent <a>`);
7042
+ console.log(` --version <v> 插件固定版本;省略只解析显式 stable,不回退 latest`);
7043
+ console.log(` --plan 插件模式只读计划,不写配置或安装记录`);
7044
+ console.log(` --export <archive> 插件模式校验后导出原始制品,不安装、不覆盖文件`);
7045
+ console.log(` --scope user|project 插件安装范围,默认 project`);
7046
+ console.log(` --root <path> 本地 zip/tgz 多插件根必须明确选择`);
7047
+ console.log(` --operation <id> 按本机精确安装记录卸载插件,不删除额外用户文件`);
7048
+ console.log(` -g, --global 安装到主目录而非当前项目`);
6938
7049
  console.log(` --name <name> 显示名称(create 时)`);
6939
7050
  console.log(` --description <t> 描述(create 时)`);
6940
7051
  console.log(` --json JSON 输出`);
7052
+ console.log();
6941
7053
  }
6942
7054
  async function handleLocalList(args, globalOpts) {
6943
- const lock = loadLockfile(getWorkdir(globalOpts, args));
7055
+ const cwd = getWorkdir(globalOpts, args);
7056
+ const lock = loadLockfile(cwd);
6944
7057
  args.includes("-g") || args.includes("--global");
6945
7058
  const pkgs = lock.packages || {};
6946
7059
  const entries = Object.entries(pkgs);
@@ -6950,18 +7063,18 @@ async function handleLocalList(args, globalOpts) {
6950
7063
  }
6951
7064
  if (entries.length === 0) {
6952
7065
  console.log("没有已安装的包。");
6953
- console.log(`使用 ${DIM$5}bfi skills package install <ref>${RESET$5} 安装包。`);
7066
+ console.log(`使用 ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包。`);
6954
7067
  return;
6955
7068
  }
6956
7069
  console.log();
6957
- console.log(`${BOLD$3}已安装的包(${entries.length} 个):${RESET$5}`);
7070
+ console.log(`${BOLD$1}已安装的包(${entries.length} 个):${RESET$3}`);
6958
7071
  console.log();
6959
7072
  for (const [ref, info] of entries) {
6960
7073
  const pkg = info;
6961
7074
  const skills = lock.skills || {};
6962
7075
  const pkgSkills = Object.entries(skills).filter(([, s]) => s.package?.slug === pkg.slug);
6963
- console.log(` ${BOLD$3}${pkg.name || pkg.slug}${RESET$5}`);
6964
- console.log(` ${DIM$5}命名空间:@${pkg.namespace} | 版本:${pkg.version || "latest"} | 技能数:${pkgSkills.length}${RESET$5}`);
7076
+ console.log(` ${BOLD$1}${pkg.name || pkg.slug}${RESET$3}`);
7077
+ console.log(` ${DIM$3}命名空间:@${pkg.namespace} | 版本:${pkg.version || "latest"} | 技能数:${pkgSkills.length}${RESET$3}`);
6965
7078
  console.log();
6966
7079
  }
6967
7080
  }
@@ -7018,41 +7131,71 @@ async function handleInstall(args, api, globalOpts) {
7018
7131
  process.exit(1);
7019
7132
  }
7020
7133
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7134
+ try {
7135
+ const blocklist = await api.getBlocklist();
7136
+ const ref = `@${namespace}/${slug}`;
7137
+ const critical = (blocklist?.critical ?? []).find((entry) => entry.ref === ref);
7138
+ if (critical) {
7139
+ console.error(`${RED$1}该技能包已被紧急下架:${critical.reason}${RESET$3}`);
7140
+ process.exit(1);
7141
+ }
7142
+ const removed = (blocklist?.removed ?? []).find((entry) => entry.ref === ref);
7143
+ if (removed) {
7144
+ console.error(`${RED$1}该技能包已被移除:${removed.reason}${RESET$3}`);
7145
+ if (removed.replacedBy) console.error(`${DIM$3}建议改用:${removed.replacedBy}${RESET$3}`);
7146
+ process.exit(1);
7147
+ }
7148
+ } catch {}
7021
7149
  const isYes = args.includes("-y") || args.includes("--yes") || globalOpts.yes;
7022
7150
  const isGlobal = args.includes("-g") || args.includes("--global");
7023
- console.log(`${DIM$5}正在获取包信息...${RESET$5}`);
7151
+ const agentOption = getOptionValue(args, "--agent");
7152
+ const requestedAgents = agentOption ? agentOption.split(",").map((value) => value.trim()).filter(Boolean) : void 0;
7153
+ console.log(`${DIM$3}正在获取包信息...${RESET$3}`);
7024
7154
  let pkgInfo;
7025
7155
  try {
7026
7156
  pkgInfo = await api.getPackage(namespace, slug);
7027
7157
  pkgInfo = pkgInfo.data || pkgInfo;
7028
7158
  } catch (error) {
7029
- console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7159
+ console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7030
7160
  process.exit(1);
7031
7161
  }
7032
7162
  const skills = pkgInfo.skills || [];
7033
7163
  if (skills.length === 0) {
7034
- console.log(`${YELLOW$1}包中没有技能。${RESET$5}`);
7164
+ console.log(`${YELLOW$1}包中没有可独立安装的技能。${RESET$3}`);
7035
7165
  return;
7036
7166
  }
7037
- console.log(`${BOLD$3}${pkgInfo.name || slug}${RESET$5}(${skills.length} 个技能):`);
7167
+ console.log(`${BOLD$1}${pkgInfo.name || slug}${RESET$3}(${skills.length} 个技能):`);
7038
7168
  console.log();
7039
7169
  for (const skill of skills) {
7040
7170
  const ref = `@${skill.namespace || namespace}/${skill.slug}`;
7041
- console.log(` ${DIM$5}• ${skill.displayName || skill.slug}${RESET$5} ${DIM$5}${ref}${RESET$5}`);
7171
+ console.log(` ${DIM$3}• ${skill.displayName || skill.slug}${RESET$3} ${DIM$3}${ref}${RESET$3}`);
7042
7172
  }
7043
7173
  console.log();
7044
7174
  let targetAgents;
7045
7175
  let installGlobally;
7046
7176
  let installMode;
7047
7177
  let eveSubagentTargets = [void 0];
7048
- if (isYes) {
7178
+ if (requestedAgents) {
7179
+ const validAgents = Object.keys(agents);
7180
+ const invalid = requestedAgents.filter((value) => !validAgents.includes(value));
7181
+ if (invalid.length > 0) {
7182
+ console.error(`${RED$1}未知 agent:${invalid.join(", ")}${RESET$3}`);
7183
+ process.exit(1);
7184
+ }
7185
+ targetAgents = requestedAgents;
7186
+ installGlobally = isGlobal;
7187
+ installMode = "copy";
7188
+ console.log(`${DIM$3}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$3}`);
7189
+ console.log(`${DIM$3}范围:${installGlobally ? "全局" : "项目"}${RESET$3}`);
7190
+ console.log();
7191
+ } else if (isYes) {
7049
7192
  const installed = await detectInstalledAgents();
7050
7193
  const validAgents = Object.keys(agents);
7051
7194
  targetAgents = ensureUniversalAgents(installed.length > 0 ? installed : validAgents);
7052
7195
  installGlobally = isGlobal;
7053
7196
  installMode = "symlink";
7054
- console.log(`${DIM$5}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$5}`);
7055
- console.log(`${DIM$5}范围:${installGlobally ? "全局" : "项目"} | 方式:${installMode === "symlink" ? "符号链接" : "复制"}${RESET$5}`);
7197
+ console.log(`${DIM$3}安装到:${targetAgents.map((a) => agents[a].displayName).join(", ")}${RESET$3}`);
7198
+ console.log(`${DIM$3}范围:${installGlobally ? "全局" : "项目"} | 方式:${installMode === "symlink" ? "符号链接" : "复制"}${RESET$3}`);
7056
7199
  console.log();
7057
7200
  } else {
7058
7201
  const spinner$1 = spinner();
@@ -7073,7 +7216,7 @@ async function handleInstall(args, api, globalOpts) {
7073
7216
  }
7074
7217
  if (useEve) {
7075
7218
  targetAgents = ["eve"];
7076
- console.log(`${DIM$5}安装到:eve agent${RESET$5}`);
7219
+ console.log(`${DIM$3}安装到:eve agent${RESET$3}`);
7077
7220
  } else {
7078
7221
  const selected = await selectAgentsInteractive({ global: false });
7079
7222
  if (isCancel(selected)) {
@@ -7095,7 +7238,7 @@ async function handleInstall(args, api, globalOpts) {
7095
7238
  } else if (installedAgents.length === 1) {
7096
7239
  targetAgents = ensureUniversalAgents(installedAgents);
7097
7240
  const firstAgent = installedAgents[0];
7098
- console.log(`${DIM$5}安装到:${agents[firstAgent].displayName}${RESET$5}`);
7241
+ console.log(`${DIM$3}安装到:${agents[firstAgent].displayName}${RESET$3}`);
7099
7242
  } else {
7100
7243
  const selected = await selectAgentsInteractive({ global: false });
7101
7244
  if (isCancel(selected)) {
@@ -7107,17 +7250,18 @@ async function handleInstall(args, api, globalOpts) {
7107
7250
  if (targetAgents.includes("eve")) {
7108
7251
  const availableSubagents = getEveSubagents(process.cwd());
7109
7252
  if (availableSubagents.length > 0) {
7253
+ const subagentChoices = [{
7254
+ value: "",
7255
+ label: "根 Agent",
7256
+ hint: "agent/skills"
7257
+ }, ...availableSubagents.map((name) => ({
7258
+ value: name,
7259
+ label: name,
7260
+ hint: `agent/subagents/${name}/skills`
7261
+ }))];
7110
7262
  const selectedSubagents = await multiselect$1({
7111
7263
  message: "Eve 技能安装位置?",
7112
- options: [{
7113
- value: "",
7114
- label: "根 Agent",
7115
- hint: "agent/skills"
7116
- }, ...availableSubagents.map((name) => ({
7117
- value: name,
7118
- label: name,
7119
- hint: `agent/subagents/${name}/skills`
7120
- }))],
7264
+ options: subagentChoices,
7121
7265
  initialValues: [""],
7122
7266
  required: true
7123
7267
  });
@@ -7173,7 +7317,7 @@ async function handleInstall(args, api, globalOpts) {
7173
7317
  const overwriteChecks = await Promise.all(skills.flatMap((skill) => installTargets.map(async (target) => ({
7174
7318
  skillName: skill.slug,
7175
7319
  target,
7176
- installed: await isSkillInstalled(skill.slug, target.agent, {
7320
+ installed: await isSkillInstalled(packageSkillName(skill.namespace || namespace, skill.slug), target.agent, {
7177
7321
  global: installGlobally,
7178
7322
  eveSubagent: target.subagent
7179
7323
  })
@@ -7204,6 +7348,9 @@ async function handleInstall(args, api, globalOpts) {
7204
7348
  const installedSkills = [];
7205
7349
  const nonEveAgents = targetAgents.filter((a) => a !== "eve");
7206
7350
  const runAddBaseOpts = {
7351
+ registry: globalOpts.registry,
7352
+ token: globalOpts.token,
7353
+ packageSkill: true,
7207
7354
  global: installGlobally,
7208
7355
  copy: installMode === "copy",
7209
7356
  yes: true
@@ -7212,16 +7359,32 @@ async function handleInstall(args, api, globalOpts) {
7212
7359
  if (targetAgents.includes("eve")) runAddBaseOpts.subagent = eveSubagentTargets.map((s) => s ?? "root");
7213
7360
  for (const skill of skills) {
7214
7361
  const skillRef = `@${skill.namespace || namespace}/${skill.slug}`;
7215
- console.log(` ${DIM$5}正在安装 ${skillRef}...${RESET$5}`);
7362
+ console.log(` ${DIM$3}正在安装 ${skillRef}...${RESET$3}`);
7216
7363
  try {
7217
7364
  await runAdd([skillRef], runAddBaseOpts);
7218
- console.log(` ${GREEN$4}✓ ${skill.slug}${RESET$5}`);
7219
- installedSkills.push(skill.slug);
7365
+ const targets = targetAgents.flatMap((agent) => agent === "eve" ? eveSubagentTargets.map((subagent) => ({
7366
+ agent,
7367
+ subagent
7368
+ })) : [{
7369
+ agent,
7370
+ subagent: void 0
7371
+ }]);
7372
+ const verified = await Promise.all(targets.map((target) => isSkillInstalled(packageSkillName(skill.namespace || namespace, skill.slug), target.agent, {
7373
+ global: installGlobally,
7374
+ eveSubagent: target.subagent
7375
+ })));
7376
+ if (verified.length === 0 || verified.some((result) => !result)) throw new Error("Skill installation could not be verified");
7377
+ console.log(` ${GREEN$2}✓ ${skill.slug}${RESET$3}`);
7378
+ installedSkills.push(skillRef);
7220
7379
  } catch (error) {
7221
- console.log(` ${RED$3}✗ ${skill.slug}:${error.message}${RESET$5}`);
7380
+ console.log(` ${RED$1}✗ ${skill.slug}:${error.message}${RESET$3}`);
7222
7381
  }
7223
7382
  }
7224
- const cwd = getWorkdir(globalOpts, args);
7383
+ if (installedSkills.length === 0) {
7384
+ console.log(`${YELLOW$1}没有确认安装成功的技能,未创建包安装记录${RESET$3}`);
7385
+ return;
7386
+ }
7387
+ const cwd = installGlobally ? os$1.homedir() : getWorkdir(globalOpts, args);
7225
7388
  const lock = loadLockfile(cwd);
7226
7389
  const pkgKey = `@${namespace}/${slug}`;
7227
7390
  if (!lock.packages) lock.packages = {};
@@ -7232,20 +7395,28 @@ async function handleInstall(args, api, globalOpts) {
7232
7395
  version: pkgInfo.version || "latest",
7233
7396
  skillCount: installedSkills.length
7234
7397
  };
7235
- for (const skillSlug of installedSkills) {
7236
- if (!lock.skills[skillSlug]) lock.skills[skillSlug] = {
7237
- namespace,
7238
- slug,
7239
- version: "latest"
7240
- };
7241
- lock.skills[skillSlug].package = {
7242
- namespace,
7243
- slug
7398
+ for (const skillRef of installedSkills) {
7399
+ const identity = parseSkillRef(skillRef);
7400
+ const existing = lock.skills[skillRef];
7401
+ lock.skills[skillRef] = {
7402
+ ...existing,
7403
+ namespace: identity.namespace,
7404
+ slug: identity.slug,
7405
+ installedName: packageSkillName(identity.namespace, identity.slug),
7406
+ version: existing?.version || "latest",
7407
+ package: {
7408
+ namespace,
7409
+ slug
7410
+ }
7244
7411
  };
7245
7412
  }
7246
7413
  saveLockfile(cwd, lock);
7414
+ for (const skillRef of installedSkills) await reportInstallEventForSkill(api, {
7415
+ skillId: skills.find((entry) => `@${entry.namespace || namespace}/${entry.slug}` === skillRef)?.skillId,
7416
+ agentTarget: targetAgents[0]
7417
+ });
7247
7418
  console.log();
7248
- console.log(`${GREEN$4}✓ 包安装完成${RESET$5}`);
7419
+ console.log(installedSkills.length === skills.length ? `${GREEN$2}✓ 包安装完成${RESET$3}` : `${YELLOW$1}包仅部分安装:${installedSkills.length}/${skills.length},仅记录已确认成功的技能${RESET$3}`);
7249
7420
  }
7250
7421
  async function handleUninstall(args, globalOpts) {
7251
7422
  const pkgRef = args[0];
@@ -7255,10 +7426,10 @@ async function handleUninstall(args, globalOpts) {
7255
7426
  }
7256
7427
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7257
7428
  const pkgKey = `@${namespace}/${slug}`;
7258
- const cwd = getWorkdir(globalOpts, args);
7429
+ const cwd = args.includes("-g") || args.includes("--global") ? os$1.homedir() : getWorkdir(globalOpts, args);
7259
7430
  const lock = loadLockfile(cwd);
7260
7431
  if (!lock.packages || !lock.packages[pkgKey]) {
7261
- console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$5}`);
7432
+ console.log(`${YELLOW$1}包未安装:${pkgKey}${RESET$3}`);
7262
7433
  return;
7263
7434
  }
7264
7435
  const skills = lock.skills || {};
@@ -7268,28 +7439,31 @@ async function handleUninstall(args, globalOpts) {
7268
7439
  if (skillInfo.package?.slug === slug && skillInfo.package?.namespace === namespace) {
7269
7440
  const { removeCommand } = await Promise.resolve().then(() => remove_exports);
7270
7441
  try {
7271
- await removeCommand([skillName], {
7272
- global: false,
7442
+ const installedName = skillInfo.installedName || (skillName.startsWith("@") ? packageSkillName(skillInfo.namespace, skillInfo.slug) : skillName);
7443
+ if (!(await removeCommand([installedName], {
7444
+ global: args.includes("-g") || args.includes("--global"),
7273
7445
  yes: true
7274
- });
7446
+ })).removed.includes(installedName)) throw new Error("Removal could not be verified");
7447
+ delete lock.skills[skillName];
7275
7448
  removed++;
7276
7449
  } catch {}
7277
7450
  }
7278
7451
  }
7279
- delete lock.packages[pkgKey];
7280
- const { saveLockfile } = await Promise.resolve().then(() => config_exports);
7452
+ if (!Object.values(lock.skills).some((info) => info.package?.slug === slug && info.package?.namespace === namespace)) delete lock.packages[pkgKey];
7453
+ const { saveLockfile } = await import("./_chunks/config.mjs").then((n) => n.config_exports);
7281
7454
  saveLockfile(cwd, lock);
7282
- console.log(`${GREEN$4}✓ 已卸载包,移除 ${removed} 个技能${RESET$5}`);
7455
+ console.log(lock.packages[pkgKey] ? `${YELLOW$1}包未完全卸载:移除 ${removed} 个技能,未确认移除的记录已保留${RESET$3}` : `${GREEN$2}✓ 已卸载包,移除 ${removed} 个技能${RESET$3}`);
7283
7456
  }
7284
7457
  async function handleUpdate(args, api, globalOpts) {
7285
7458
  const pkgRef = args[0];
7286
- const lock = loadLockfile(getWorkdir(globalOpts, args));
7459
+ const cwd = getWorkdir(globalOpts, args);
7460
+ const lock = loadLockfile(cwd);
7287
7461
  let packagesToUpdate = [];
7288
7462
  const pkgs = lock.packages || {};
7289
7463
  if (pkgRef) {
7290
7464
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7291
7465
  if (!pkgs[`@${namespace}/${slug}`]) {
7292
- console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$5}`);
7466
+ console.log(`${YELLOW$1}包未安装:@${namespace}/${slug}${RESET$3}`);
7293
7467
  return;
7294
7468
  }
7295
7469
  packagesToUpdate.push({
@@ -7304,25 +7478,27 @@ async function handleUpdate(args, api, globalOpts) {
7304
7478
  console.log("没有已安装的包需要更新。");
7305
7479
  return;
7306
7480
  }
7307
- console.log(`${DIM$5}正在更新 ${packagesToUpdate.length} 个包...${RESET$5}`);
7481
+ console.log(`${DIM$3}正在更新 ${packagesToUpdate.length} 个包...${RESET$3}`);
7308
7482
  for (const pkg of packagesToUpdate) try {
7309
7483
  const pkgInfo = await api.getPackage(pkg.namespace, pkg.slug);
7310
7484
  const skills = (pkgInfo.data || pkgInfo).skills || [];
7311
- console.log(` ${DIM$5}更新 @${pkg.namespace}/${pkg.slug}(${skills.length} 个技能)...${RESET$5}`);
7485
+ console.log(` ${DIM$3}更新 @${pkg.namespace}/${pkg.slug}(${skills.length} 个技能)...${RESET$3}`);
7312
7486
  for (const skill of skills) {
7313
7487
  const skillRef = skill.namespace ? `@${skill.namespace}/${skill.slug}` : skill.slug;
7314
7488
  const { runAdd } = await Promise.resolve().then(() => add_exports);
7315
7489
  try {
7316
7490
  await runAdd([skillRef], {
7317
7491
  ...globalOpts,
7318
- yes: true
7492
+ yes: true,
7493
+ packageSkill: true,
7494
+ global: args.includes("-g") || args.includes("--global")
7319
7495
  });
7320
7496
  } catch {}
7321
7497
  }
7322
7498
  } catch (error) {
7323
- console.log(` ${RED$3}✗ @${pkg.namespace}/${pkg.slug}:${error.message}${RESET$5}`);
7499
+ console.log(` ${RED$1}✗ @${pkg.namespace}/${pkg.slug}:${error.message}${RESET$3}`);
7324
7500
  }
7325
- console.log(`${GREEN$4}✓ 包更新完成${RESET$5}`);
7501
+ console.log(`${GREEN$2}✓ 包更新完成${RESET$3}`);
7326
7502
  }
7327
7503
  async function handleSearch(args, api, globalOpts) {
7328
7504
  const query = args.filter((a) => !a.startsWith("--")).join(" ") || void 0;
@@ -7342,11 +7518,11 @@ async function handleSearch(args, api, globalOpts) {
7342
7518
  }, null, 2));
7343
7519
  return;
7344
7520
  }
7345
- console.log(`\n${BOLD$3}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$5}\n`);
7521
+ console.log(`\n${BOLD$1}找到 ${skills.length} 个相关技能(按命名空间分组):${RESET$3}\n`);
7346
7522
  for (const [ns, sk] of namespaces) {
7347
- console.log(` ${BOLD$3}@${ns}${RESET$5}(${sk.length} 个技能)`);
7348
- for (const s of sk.slice(0, 5)) console.log(` ${DIM$5}- ${s.displayName || s.name} (${s.slug})${RESET$5}`);
7349
- if (sk.length > 5) console.log(` ${DIM$5}... 还有 ${sk.length - 5} 个${RESET$5}`);
7523
+ console.log(` ${BOLD$1}@${ns}${RESET$3}(${sk.length} 个技能)`);
7524
+ for (const s of sk.slice(0, 5)) console.log(` ${DIM$3}- ${s.displayName || s.name} (${s.slug})${RESET$3}`);
7525
+ if (sk.length > 5) console.log(` ${DIM$3}... 还有 ${sk.length - 5} 个${RESET$3}`);
7350
7526
  console.log();
7351
7527
  }
7352
7528
  } else {
@@ -7385,11 +7561,11 @@ async function handleSearch(args, api, globalOpts) {
7385
7561
  };
7386
7562
  const maxName = Math.max(...allPackages.map((p) => dw(p.displayName || p.name || p.slug || "")), 4);
7387
7563
  const maxSlug = Math.max(...allPackages.map((p) => dw(`@${p._namespace}/${p.slug}`)), 4);
7388
- console.log(`\n${BOLD$3}所有技能包(${allPackages.length} 个):${RESET$5}\n`);
7564
+ console.log(`\n${BOLD$1}所有技能包(${allPackages.length} 个):${RESET$3}\n`);
7389
7565
  for (const pkg of allPackages) {
7390
7566
  const name = pad(pkg.displayName || pkg.name || pkg.slug || "", maxName);
7391
7567
  const ref = pad(`@${pkg._namespace}/${pkg.slug}`, maxSlug);
7392
- console.log(` ${BOLD$3}${name}${RESET$5} ${DIM$5}${ref} ${pkg.visibility === "PUBLIC" ? "公开" : "私有"}${RESET$5}`);
7568
+ console.log(` ${BOLD$1}${name}${RESET$3} ${DIM$3}${ref} ${pkg.visibility === "PUBLIC" ? "公开" : "私有"}${RESET$3}`);
7393
7569
  }
7394
7570
  }
7395
7571
  }
@@ -7410,11 +7586,11 @@ async function handleCreate(args, api, globalOpts) {
7410
7586
  description: description || "",
7411
7587
  visibility: visibility.toUpperCase()
7412
7588
  });
7413
- console.log(`${GREEN$4}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$5}`);
7589
+ console.log(`${GREEN$2}✓ 已创建包 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7414
7590
  const pkg = result.package || result.data || result;
7415
- if (pkg) console.log(` ${DIM$5}名称:${pkg.name || slug} | 可见性:${pkg.visibility || visibility}${RESET$5}`);
7591
+ if (pkg) console.log(` ${DIM$3}名称:${pkg.name || slug} | 可见性:${pkg.visibility || visibility}${RESET$3}`);
7416
7592
  } catch (error) {
7417
- console.error(`${RED$3}创建包失败:${error.message}${RESET$5}`);
7593
+ console.error(`${RED$1}创建包失败:${error.message}${RESET$3}`);
7418
7594
  process.exit(1);
7419
7595
  }
7420
7596
  }
@@ -7440,11 +7616,11 @@ async function handleAddSkills(args, api, globalOpts) {
7440
7616
  };
7441
7617
  });
7442
7618
  if (skills.length === 0) {
7443
- console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$5}`);
7619
+ console.log(`${YELLOW$1}命名空间 "${namespace}" 中没有技能。${RESET$3}`);
7444
7620
  return;
7445
7621
  }
7446
7622
  } catch (error) {
7447
- console.error(`${RED$3}获取技能列表失败:${error.message}${RESET$5}`);
7623
+ console.error(`${RED$1}获取技能列表失败:${error.message}${RESET$3}`);
7448
7624
  process.exit(1);
7449
7625
  }
7450
7626
  else skills = skillRefs.map((ref) => {
@@ -7456,9 +7632,9 @@ async function handleAddSkills(args, api, globalOpts) {
7456
7632
  });
7457
7633
  try {
7458
7634
  await api.addSkillsToPackage(namespace, slug, skills);
7459
- console.log(`${GREEN$4}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$5}`);
7635
+ console.log(`${GREEN$2}✓ 已添加 ${skills.length} 个技能到 ${toSkillRefString(namespace, slug)}${RESET$3}`);
7460
7636
  } catch (error) {
7461
- console.error(`${RED$3}添加失败:${error.message}${RESET$5}`);
7637
+ console.error(`${RED$1}添加失败:${error.message}${RESET$3}`);
7462
7638
  process.exit(1);
7463
7639
  }
7464
7640
  }
@@ -7483,7 +7659,7 @@ async function handleRemoveSkills(args, api, globalOpts) {
7483
7659
  return;
7484
7660
  }
7485
7661
  } catch (error) {
7486
- console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7662
+ console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7487
7663
  process.exit(1);
7488
7664
  }
7489
7665
  else skills = skillRefs.map((ref) => {
@@ -7495,9 +7671,9 @@ async function handleRemoveSkills(args, api, globalOpts) {
7495
7671
  });
7496
7672
  try {
7497
7673
  await api.removeSkillsFromPackage(namespace, slug, skills);
7498
- console.log(`${GREEN$4}✓ 已从包移除 ${skills.length} 个技能${RESET$5}`);
7674
+ console.log(`${GREEN$2}✓ 已从包移除 ${skills.length} 个技能${RESET$3}`);
7499
7675
  } catch (error) {
7500
- console.error(`${RED$3}移除失败:${error.message}${RESET$5}`);
7676
+ console.error(`${RED$1}移除失败:${error.message}${RESET$3}`);
7501
7677
  process.exit(1);
7502
7678
  }
7503
7679
  }
@@ -7516,19 +7692,19 @@ async function handleServerInfo(args, api, globalOpts) {
7516
7692
  console.log(JSON.stringify(pkg, null, 2));
7517
7693
  return;
7518
7694
  }
7519
- console.log(`\n${BOLD$3}${pkg.displayName || pkg.name || slug}${RESET$5}`);
7520
- console.log(`${DIM$5}${"=".repeat(48)}${RESET$5}`);
7521
- console.log(` ${BOLD$3}Slug:${RESET$5} ${toCanonicalSlug(namespace, slug)}`);
7522
- console.log(` ${BOLD$3}命名空间:${RESET$5} @${namespace}`);
7523
- console.log(` ${BOLD$3}可见性:${RESET$5} ${pkg.visibility || "PRIVATE"}`);
7695
+ console.log(`\n${BOLD$1}${pkg.displayName || pkg.name || slug}${RESET$3}`);
7696
+ console.log(`${DIM$3}${"=".repeat(48)}${RESET$3}`);
7697
+ console.log(` ${BOLD$1}Slug:${RESET$3} ${toCanonicalSlug(namespace, slug)}`);
7698
+ console.log(` ${BOLD$1}命名空间:${RESET$3} @${namespace}`);
7699
+ console.log(` ${BOLD$1}可见性:${RESET$3} ${pkg.visibility || "PRIVATE"}`);
7524
7700
  const skills = pkg.skills || [];
7525
7701
  if (skills.length > 0) {
7526
- console.log(`\n ${BOLD$3}技能(${skills.length} 个):${RESET$5}`);
7527
- for (const s of skills) console.log(` ${DIM$5}- ${s.displayName || s.slug} (${s.namespace || namespace}--${s.slug})${RESET$5}`);
7702
+ console.log(`\n ${BOLD$1}技能(${skills.length} 个):${RESET$3}`);
7703
+ for (const s of skills) console.log(` ${DIM$3}- ${s.displayName || s.slug} (${s.namespace || namespace}--${s.slug})${RESET$3}`);
7528
7704
  }
7529
7705
  console.log();
7530
7706
  } catch (error) {
7531
- console.error(`${RED$3}获取包信息失败:${error.message}${RESET$5}`);
7707
+ console.error(`${RED$1}获取包信息失败:${error.message}${RESET$3}`);
7532
7708
  process.exit(1);
7533
7709
  }
7534
7710
  }
@@ -7536,418 +7712,6 @@ function getOptionValue(args, flag) {
7536
7712
  const idx = args.indexOf(flag);
7537
7713
  return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
7538
7714
  }
7539
- const RESET$4 = "\x1B[0m";
7540
- const BOLD$2 = "\x1B[1m";
7541
- const DIM$4 = "\x1B[38;5;102m";
7542
- const TEXT$4 = "\x1B[38;5;145m";
7543
- const GREEN$3 = "\x1B[32m";
7544
- const RED$2 = "\x1B[31m";
7545
- async function runPlugin(args, globalOpts) {
7546
- const sub = args[0];
7547
- const subArgs = args.slice(1);
7548
- switch (sub) {
7549
- case "create":
7550
- case "new":
7551
- await createScaffold(subArgs);
7552
- break;
7553
- case "validate":
7554
- await validate(subArgs);
7555
- break;
7556
- case "publish":
7557
- await publish(subArgs, globalOpts);
7558
- break;
7559
- case "list":
7560
- case "ls":
7561
- await list$1(subArgs, globalOpts);
7562
- break;
7563
- case "info":
7564
- await info$1(subArgs, globalOpts);
7565
- break;
7566
- case "install":
7567
- await install(subArgs, globalOpts);
7568
- break;
7569
- case "--help":
7570
- case "-h":
7571
- case void 0:
7572
- showHelp$2();
7573
- break;
7574
- default:
7575
- console.log(`未知 plugin 命令:${sub}`);
7576
- showHelp$2();
7577
- }
7578
- }
7579
- function showHelp$2() {
7580
- console.log();
7581
- console.log(`${BOLD$2}bfi plugin <command>${RESET$4} — Claude Code plugin 管理`);
7582
- console.log();
7583
- console.log(`${BOLD$2}Commands:${RESET$4}`);
7584
- console.log(` create <name> Scaffold a plugin directory (skills/, agents/, hooks/, mcp/)`);
7585
- console.log(` validate [path] Validate plugin.json and directory layout`);
7586
- console.log(` publish <path> Publish a plugin to SkillHub`);
7587
- console.log(` list, ls List plugins on SkillHub`);
7588
- console.log(` info <id> Show plugin details`);
7589
- console.log(` install <ref> Install a plugin (slug, plugin id, or local .zip)`);
7590
- console.log();
7591
- }
7592
- async function createScaffold(args) {
7593
- const name = args.find((a, i) => i === 0 || args[i - 1] !== "--with" && !a.startsWith("-"));
7594
- if (!name || name.startsWith("-")) {
7595
- console.error("用法:bfi plugin create <name> [--with skills agents hooks mcp]");
7596
- process.exit(1);
7597
- }
7598
- const withIdx = args.indexOf("--with");
7599
- const components = withIdx !== -1 ? args.slice(withIdx + 1) : [];
7600
- const target = path$1.resolve(name);
7601
- if (fs.existsSync(path$1.join(target, ".claude-plugin", "plugin.json"))) {
7602
- console.error(`plugin 已存在:${target}`);
7603
- process.exit(1);
7604
- }
7605
- fs.mkdirSync(path$1.join(target, ".claude-plugin"), { recursive: true });
7606
- const manifest = {
7607
- $schema: "https://anthropic.com/claude-code/plugin.schema.json",
7608
- name: path$1.basename(target),
7609
- version: "0.1.0",
7610
- description: "",
7611
- author: { name: "" },
7612
- ...components.includes("skills") ? { skills: ["./skills"] } : {}
7613
- };
7614
- fs.writeFileSync(path$1.join(target, ".claude-plugin", "plugin.json"), JSON.stringify(manifest, null, 2) + "\n");
7615
- if (components.includes("skills")) fs.mkdirSync(path$1.join(target, "skills"), { recursive: true });
7616
- if (components.includes("agents")) fs.mkdirSync(path$1.join(target, "agents"), { recursive: true });
7617
- if (components.includes("hooks")) {
7618
- fs.mkdirSync(path$1.join(target, "hooks"), { recursive: true });
7619
- fs.writeFileSync(path$1.join(target, "hooks", "hooks.json"), JSON.stringify({ hooks: {} }, null, 2) + "\n");
7620
- }
7621
- if (components.includes("mcp")) fs.writeFileSync(path$1.join(target, ".mcp.json"), JSON.stringify({ mcpServers: {} }, null, 2) + "\n");
7622
- console.log(`${GREEN$3}✓${RESET$4} Created plugin ${TEXT$4}${path$1.basename(target)}${RESET$4}`);
7623
- console.log(` ${DIM$4}${target}${RESET$4}`);
7624
- }
7625
- async function validate(args) {
7626
- const target = path$1.resolve(args[0] ?? ".");
7627
- const standardManifest = path$1.join(target, ".claude-plugin", "plugin.json");
7628
- const bfiManifest = path$1.join(target, "plugin.json");
7629
- const manifestPath = fs.existsSync(standardManifest) ? standardManifest : fs.existsSync(bfiManifest) ? bfiManifest : standardManifest;
7630
- const isBfiLayout = manifestPath === bfiManifest;
7631
- const errors = [];
7632
- const warnings = [];
7633
- if (!fs.existsSync(manifestPath)) errors.push(`未找到 ${manifestPath}`);
7634
- else try {
7635
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
7636
- if (!manifest.name) errors.push("plugin.json 缺少 name 字段");
7637
- if (!manifest.version) warnings.push("plugin.json 缺少 version 字段");
7638
- if (!manifest.description) warnings.push("plugin.json 缺少 description 字段");
7639
- const skillPaths = manifest.skills ?? manifest.provides?.skills ?? [];
7640
- for (const skillPath of skillPaths) {
7641
- const normalized = skillPath.startsWith("./") ? skillPath.slice(2) : skillPath;
7642
- if (!isBfiLayout && !skillPath.startsWith("./")) errors.push(`skills 路径必须以 ./ 开头:${skillPath}`);
7643
- else if (!fs.existsSync(path$1.join(target, normalized))) errors.push(`skills 路径不存在:${skillPath}`);
7644
- }
7645
- } catch (e) {
7646
- errors.push(`plugin.json 解析失败:${e.message}`);
7647
- }
7648
- if (fs.existsSync(path$1.join(target, ".mcp.json"))) try {
7649
- JSON.parse(fs.readFileSync(path$1.join(target, ".mcp.json"), "utf-8"));
7650
- } catch (e) {
7651
- errors.push(`.mcp.json 解析失败:${e.message}`);
7652
- }
7653
- if (fs.existsSync(path$1.join(target, "hooks", "hooks.json"))) try {
7654
- JSON.parse(fs.readFileSync(path$1.join(target, "hooks", "hooks.json"), "utf-8"));
7655
- } catch (e) {
7656
- errors.push(`hooks/hooks.json 解析失败:${e.message}`);
7657
- }
7658
- for (const error of errors) console.log(`${RED$2}✗${RESET$4} ${error}`);
7659
- for (const warning of warnings) console.log(`${DIM$4}⚠${RESET$4} ${warning}`);
7660
- if (errors.length === 0) console.log(`${GREEN$3}✓${RESET$4} Validation passed${warnings.length > 0 ? ` with ${warnings.length} warning(s)` : ""}`);
7661
- else process.exitCode = 1;
7662
- }
7663
- async function publish(args, globalOpts) {
7664
- const target = args[0];
7665
- if (!target) {
7666
- console.error("用法:bfi plugin publish <directory|file.zip|file.tgz>");
7667
- process.exit(1);
7668
- }
7669
- const resolved = path$1.resolve(target);
7670
- const namespace = getOption$1(args, "--namespace") || globalOpts.namespace || "global";
7671
- const visibility = getOption$1(args, "--visibility") || "public";
7672
- const { registry, token } = resolveConfig(globalOpts);
7673
- if (!token) {
7674
- console.error("未登录。请先运行:bfi auth login --token <token>");
7675
- process.exit(1);
7676
- }
7677
- const api = new SkillHubAPI(registry, token);
7678
- if (/\.(tgz|tar\.gz|zip)$/i.test(resolved)) {
7679
- if (!fs.existsSync(resolved)) {
7680
- console.error(`文件未找到:${resolved}`);
7681
- process.exit(1);
7682
- }
7683
- console.log(`上传 ${TEXT$4}${path$1.basename(resolved)}${RESET$4} → ${DIM$4}${registry}${RESET$4}`);
7684
- try {
7685
- const created = await api.uploadPlugin(fs.readFileSync(resolved), path$1.basename(resolved), namespace, { visibility: visibility.toUpperCase() });
7686
- const plugin = created?.data ?? created;
7687
- console.log(`${GREEN$3}✓${RESET$4} Published ${TEXT$4}${plugin.slug}${RESET$4} (id=${plugin.id})`);
7688
- } catch (e) {
7689
- console.error(`发布失败:${e.message}`);
7690
- process.exit(1);
7691
- }
7692
- return;
7693
- }
7694
- const standardManifest = path$1.join(resolved, ".claude-plugin", "plugin.json");
7695
- const bfiManifest = path$1.join(resolved, "plugin.json");
7696
- const manifestPath = fs.existsSync(standardManifest) ? standardManifest : fs.existsSync(bfiManifest) ? bfiManifest : null;
7697
- if (!manifestPath) {
7698
- console.error(`不是有效 plugin 目录(缺少 .claude-plugin/plugin.json 或 plugin.json):${resolved}`);
7699
- process.exit(1);
7700
- }
7701
- const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
7702
- const namespaces = await api.myNamespaces();
7703
- const ns = (Array.isArray(namespaces) ? namespaces : namespaces?.data ?? []).find((n) => n.slug === namespace);
7704
- if (!ns) {
7705
- console.error(`命名空间不存在:${namespace}`);
7706
- process.exit(1);
7707
- }
7708
- const zipBuffer = createZipFromDir(resolved);
7709
- const versionMatch = manifest.version ?? "0.1.0";
7710
- console.log(`发布 ${TEXT$4}${manifest.name}@${versionMatch}${RESET$4} → ${DIM$4}${registry}${RESET$4}`);
7711
- const created = await api.createPlugin({
7712
- namespaceId: ns.id,
7713
- slug: manifest.name,
7714
- displayName: manifest.name,
7715
- summary: manifest.description ?? "",
7716
- description: manifest.description ?? "",
7717
- visibility: visibility.toUpperCase()
7718
- });
7719
- const plugin = created?.data ?? created;
7720
- const version = await api.createPluginVersion(plugin.id, {
7721
- version: versionMatch,
7722
- changelog: "Published via bfi plugin publish"
7723
- });
7724
- const versionBody = version?.data ?? version;
7725
- const tmpZip = path$1.join(os$1.tmpdir(), `${manifest.name}-${versionMatch}.zip`);
7726
- fs.writeFileSync(tmpZip, zipBuffer);
7727
- console.log(`${GREEN$3}✓${RESET$4} Plugin created (id=${plugin.id}, version=${versionBody.version})`);
7728
- console.log(` ${DIM$4}zip: ${tmpZip}${RESET$4}`);
7729
- }
7730
- async function list$1(_args, globalOpts) {
7731
- const { registry, token } = resolveConfig(globalOpts);
7732
- const result = await new SkillHubAPI(registry, token).listPlugins();
7733
- const plugins = Array.isArray(result) ? result : result?.content ?? result?.data ?? [];
7734
- if (plugins.length === 0) {
7735
- console.log("暂无 plugin。");
7736
- return;
7737
- }
7738
- console.log();
7739
- for (const p of plugins) {
7740
- console.log(` ${TEXT$4}${p.slug}${RESET$4} ${DIM$4}${p.latestVersionId ? "v" + p.latestVersionId : ""}${RESET$4}`);
7741
- console.log(` ${p.summary ?? ""}`);
7742
- console.log(` ${DIM$4}下载 ${p.downloadCount ?? 0} · star ${p.starCount ?? 0}${RESET$4}`);
7743
- }
7744
- console.log();
7745
- }
7746
- async function info$1(args, globalOpts) {
7747
- const idArg = args[0];
7748
- if (!idArg) {
7749
- console.error("用法:bfi plugin info <pluginId>");
7750
- process.exit(1);
7751
- }
7752
- const { registry, token } = resolveConfig(globalOpts);
7753
- const plugin = await new SkillHubAPI(registry, token).getPlugin(Number(idArg));
7754
- console.log();
7755
- console.log(`${BOLD$2}${plugin.displayName ?? plugin.slug}${RESET$4} (id=${plugin.id})`);
7756
- console.log(` ${plugin.summary ?? ""}`);
7757
- console.log(` ${DIM$4}visibility=${plugin.visibility} status=${plugin.status}${RESET$4}`);
7758
- console.log(` ${DIM$4}下载 ${plugin.downloadCount ?? 0} · star ${plugin.starCount ?? 0}${RESET$4}`);
7759
- console.log();
7760
- }
7761
- async function install(args, globalOpts) {
7762
- const ref = args[0];
7763
- if (!ref) {
7764
- console.error("用法:bfi plugin install <slug|插件ID|./plugin.zip>");
7765
- process.exit(1);
7766
- }
7767
- const homeSkills = path$1.join(os$1.homedir(), ".claude", "skills");
7768
- if (ref.endsWith(".zip") || fs.existsSync(ref)) {
7769
- const resolved = path$1.resolve(ref);
7770
- extractZip(resolved, homeSkills);
7771
- console.log(`${GREEN$3}✓${RESET$4} Installed from ${resolved}`);
7772
- console.log(` ${DIM$4}${homeSkills}${RESET$4}`);
7773
- console.log(` ${DIM$4}重启 Claude Code 会话后生效${RESET$4}`);
7774
- return;
7775
- }
7776
- const { registry, token } = resolveConfig(globalOpts);
7777
- const api = new SkillHubAPI(registry, token);
7778
- let plugin;
7779
- if (/^\d+$/.test(ref)) plugin = await api.getPlugin(Number(ref));
7780
- else {
7781
- const list = await api.listPlugins();
7782
- const match = (Array.isArray(list) ? list : list?.content ?? list?.data ?? []).find((p) => p.slug === ref || p.displayName === ref);
7783
- if (!match) {
7784
- console.error(`未找到插件:${ref}(支持传 slug 或插件 ID)`);
7785
- process.exit(1);
7786
- }
7787
- plugin = await api.getPlugin(match.id);
7788
- }
7789
- const slug = plugin.slug ?? `plugin-${plugin.id}`;
7790
- if (!plugin.latestVersionId) {
7791
- console.error(`插件 ${slug} 尚无已发布版本,无法安装`);
7792
- process.exit(1);
7793
- }
7794
- const tmpZip = path$1.join(os$1.tmpdir(), `${slug}-install.zip`);
7795
- console.log(`下载 ${TEXT$4}${slug}${RESET$4} ← ${DIM$4}${registry}${RESET$4}`);
7796
- await api.downloadPluginBundle(plugin.id, plugin.latestVersionId, tmpZip);
7797
- extractZip(tmpZip, homeSkills);
7798
- fs.unlinkSync(tmpZip);
7799
- console.log(`${GREEN$3}✓${RESET$4} Installed ${TEXT$4}${slug}${RESET$4}`);
7800
- console.log(` ${DIM$4}${homeSkills}${RESET$4}`);
7801
- console.log(` ${DIM$4}重启 Claude Code 会话后生效${RESET$4}`);
7802
- }
7803
- function getOption$1(args, flag) {
7804
- const idx = args.indexOf(flag);
7805
- return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
7806
- }
7807
- const RESET$3 = "\x1B[0m";
7808
- const BOLD$1 = "\x1B[1m";
7809
- const DIM$3 = "\x1B[38;5;102m";
7810
- const TEXT$3 = "\x1B[38;5;145m";
7811
- const GREEN$2 = "\x1B[32m";
7812
- const RED$1 = "\x1B[31m";
7813
- async function runMcp(args, globalOpts) {
7814
- const sub = args[0];
7815
- const subArgs = args.slice(1);
7816
- switch (sub) {
7817
- case "list":
7818
- case "ls":
7819
- await list(subArgs, globalOpts);
7820
- break;
7821
- case "info":
7822
- await info(subArgs, globalOpts);
7823
- break;
7824
- case "config":
7825
- await config(subArgs, globalOpts);
7826
- break;
7827
- case "add":
7828
- await add(subArgs, globalOpts);
7829
- break;
7830
- case "remove":
7831
- case "rm":
7832
- await remove(subArgs);
7833
- break;
7834
- case "--help":
7835
- case "-h":
7836
- case void 0:
7837
- showHelp$1();
7838
- break;
7839
- default:
7840
- console.log(`未知 mcp 命令:${sub}`);
7841
- showHelp$1();
7842
- }
7843
- }
7844
- function showHelp$1() {
7845
- console.log();
7846
- console.log(`${BOLD$1}bfi mcp <command>${RESET$3} — MCP 服务器管理`);
7847
- console.log();
7848
- console.log(`${BOLD$1}Commands:${RESET$3}`);
7849
- console.log(` list, ls List MCP servers on SkillHub`);
7850
- console.log(` info <id> Show MCP server details`);
7851
- console.log(` config <id> Print .mcp.json config fragment`);
7852
- console.log(` add <id> Write server into local .mcp.json (user scope)`);
7853
- console.log(` remove <name> Remove a server from local .mcp.json`);
7854
- console.log();
7855
- }
7856
- async function list(_args, globalOpts) {
7857
- const { registry, token } = resolveConfig(globalOpts);
7858
- const result = await new SkillHubAPI(registry, token).listMcpServers();
7859
- const servers = Array.isArray(result) ? result : result?.content ?? result?.data ?? [];
7860
- if (servers.length === 0) {
7861
- console.log("暂无 MCP 服务器。");
7862
- return;
7863
- }
7864
- console.log();
7865
- for (const s of servers) {
7866
- console.log(` ${TEXT$3}${s.slug}${RESET$3} ${DIM$3}[${s.transportType}]${RESET$3}`);
7867
- console.log(` ${s.summary ?? ""}`);
7868
- console.log(` ${DIM$3}下载 ${s.downloadCount ?? 0} · star ${s.starCount ?? 0}${RESET$3}`);
7869
- }
7870
- console.log();
7871
- }
7872
- async function info(args, globalOpts) {
7873
- const idArg = args[0];
7874
- if (!idArg) {
7875
- console.error("用法:bfi mcp info <mcpId>");
7876
- process.exit(1);
7877
- }
7878
- const { registry, token } = resolveConfig(globalOpts);
7879
- const server = await new SkillHubAPI(registry, token).getMcpServer(Number(idArg));
7880
- console.log();
7881
- console.log(`${BOLD$1}${server.displayName ?? server.slug}${RESET$3} (id=${server.id})`);
7882
- console.log(` transport: ${server.transportType}`);
7883
- if (server.serverUrl) console.log(` url: ${server.serverUrl}`);
7884
- if (server.command) console.log(` command: ${server.command}`);
7885
- console.log(` ${DIM$3}visibility=${server.visibility} status=${server.status}${RESET$3}`);
7886
- console.log();
7887
- }
7888
- async function config(args, globalOpts) {
7889
- const idArg = args[0];
7890
- if (!idArg) {
7891
- console.error("用法:bfi mcp config <mcpId>");
7892
- process.exit(1);
7893
- }
7894
- const { registry, token } = resolveConfig(globalOpts);
7895
- const configJson = await new SkillHubAPI(registry, token).getMcpConfig(Number(idArg));
7896
- console.log(configJson);
7897
- }
7898
- async function add(args, globalOpts) {
7899
- const idArg = args[0];
7900
- if (!idArg) {
7901
- console.error("用法:bfi mcp add <mcpId>");
7902
- process.exit(1);
7903
- }
7904
- const { registry, token } = resolveConfig(globalOpts);
7905
- const api = new SkillHubAPI(registry, token);
7906
- const server = await api.getMcpServer(Number(idArg));
7907
- const configJson = JSON.parse(await api.getMcpConfig(Number(idArg)));
7908
- const mcpPath = resolveMcpPath(getOption(args, "--scope") ?? "user");
7909
- let existing = { mcpServers: {} };
7910
- if (fs.existsSync(mcpPath)) {
7911
- existing = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
7912
- if (!existing.mcpServers) existing.mcpServers = {};
7913
- }
7914
- const serverName = server.slug ?? `mcp-${server.id}`;
7915
- existing.mcpServers[serverName] = configJson.mcpServers[Object.keys(configJson.mcpServers)[0]];
7916
- fs.mkdirSync(path$1.dirname(mcpPath), { recursive: true });
7917
- fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + "\n");
7918
- console.log(`${GREEN$2}✓${RESET$3} Added ${TEXT$3}${serverName}${RESET$3} → ${DIM$3}${mcpPath}${RESET$3}`);
7919
- }
7920
- async function remove(args) {
7921
- const name = args[0];
7922
- if (!name) {
7923
- console.error("用法:bfi mcp remove <name> [--scope user|project|local]");
7924
- process.exit(1);
7925
- }
7926
- const mcpPath = resolveMcpPath(getOption(args, "--scope") ?? "user");
7927
- if (!fs.existsSync(mcpPath)) {
7928
- console.error(`配置文件不存在:${mcpPath}`);
7929
- process.exit(1);
7930
- }
7931
- const existing = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
7932
- if (!existing.mcpServers?.[name]) {
7933
- console.error(`${RED$1}未找到服务器:${name}${RESET$3}`);
7934
- process.exit(1);
7935
- }
7936
- delete existing.mcpServers[name];
7937
- fs.writeFileSync(mcpPath, JSON.stringify(existing, null, 2) + "\n");
7938
- console.log(`${GREEN$2}✓${RESET$3} Removed ${TEXT$3}${name}${RESET$3}`);
7939
- }
7940
- function resolveMcpPath(scope) {
7941
- switch (scope) {
7942
- case "project": return path$1.join(process.cwd(), ".mcp.json");
7943
- case "local": return path$1.join(process.cwd(), ".claude", ".mcp.json.local");
7944
- default: return path$1.join(os$1.homedir(), ".claude", ".mcp.json");
7945
- }
7946
- }
7947
- function getOption(args, flag) {
7948
- const idx = args.indexOf(flag);
7949
- return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : void 0;
7950
- }
7951
7715
  const RESET$2 = "\x1B[0m";
7952
7716
  const DIM$2 = "\x1B[38;5;102m";
7953
7717
  const TEXT$2 = "\x1B[38;5;145m";
@@ -8061,7 +7825,7 @@ async function runInstall(args, globalOpts) {
8061
7825
  if (failedCount > 0) console.log(`${YELLOW}⚠ ${failedCount} 项恢复失败${RESET$1}`);
8062
7826
  console.log();
8063
7827
  }
8064
- const YMC_DEFAULT_BASE = process.env.BFI_YMC_BASE || "http://172.20.35.178:8901/bficli/api/v2";
7828
+ const YMC_DEFAULT_BASE = process.env.BFI_YMC_BASE || "https://bfi.yyuap.com/bfi-api/bficli/api/v2";
8065
7829
  var YmcApi = class {
8066
7830
  baseUrl;
8067
7831
  token;
@@ -8867,7 +8631,7 @@ async function runYmc(args, globalOpts) {
8867
8631
  if (!route) {
8868
8632
  console.error("用法:bfi ymc call <route> -e <env> [--data '{\"k\":\"v\"}'] [--timeout 秒] [-t time | --start-time <s> --end-time <e>]");
8869
8633
  console.error("route 例:warningCall/warningSql/exceptionHistory/bpr/list/alert/detail/uba/query/tool/list/environment ...");
8870
- console.error("完整清单见 http://172.20.35.178:8901/docs");
8634
+ console.error("完整清单见 https://bfi.yyuap.com/bfi-api/docs");
8871
8635
  process.exit(1);
8872
8636
  }
8873
8637
  let extra;
@@ -9008,7 +8772,7 @@ const HELP = {
9008
8772
  输出默认取文件名部分(monitor/xx.html → xx.html)。`,
9009
8773
  call: `bfi ymc call <route> -e <env> [--data '<json>'] [-t <time> | --start-time <s> --end-time <e>] [--timeout <秒>] [--json]
9010
8774
  通用透传:覆盖全部注册表端点(warningCall/warningSql/exceptionHistory/bpr/list/alert/detail/tool/list/app/history/environment/uba/query ...)。
9011
- 完整清单与参数声明:curl http://172.20.35.178:8901/openapi.json 或 /docs(Swagger UI)。
8775
+ 完整清单与参数声明:curl https://bfi.yyuap.com/bfi-api/openapi.json 或 /docs(Swagger UI)。
9012
8776
  时间参数(-t/--start-time/--end-time)由服务端按端点 time_fields 展开为 beginTs/endTs 等——
9013
8777
  禁止在 --data JSON 里手传 start/end/start_time(数字 422、字符串被忽略返回空)。
9014
8778
  ⚠️ app/history、jvm/history 等资源端点的 appId 必须带环境前缀(如 stage-dc-core1-<appCode>,
@@ -9291,22 +9055,37 @@ async function runEvent(args, globalOpts) {
9291
9055
  process.exit(1);
9292
9056
  }
9293
9057
  function printHelp$1() {
9294
- console.log(`bfi ms — 微服务→仓库映射(诊断中把微服务编码可靠地转换为仓库列表)
9058
+ console.log(`bfi ms — 微服务/二方包 查询(编码 → 仓库列表 + 归属画像)
9295
9059
 
9296
9060
  用法:
9297
- bfi ms <微服务编码> # 精确/模糊查询(精确匹配行排前)
9298
- bfi ms --keyword <名称关键词> # 按微服务中文名模糊查询
9061
+ bfi ms <关键词> # 编码或名称片段,双列 OR 命中(微服务 + 二方包一并返回)
9299
9062
  全局: --json / --dry-run / --token <tok>
9063
+ 可选: --limit <n>(默认 50)
9300
9064
 
9301
- 输出: 每个微服务的 code/名称/类型/部门/负责人/Jira 项目 + repos 列表
9302
- (repo 为 BCS 图谱仓库名(git 地址末段),可直接作 bfi-code-search context 的 repo 参数)
9065
+ 输出: 分类(微服务/二方包)/编码/名称/类型/领域云/领域/部门/数据库/rpcDomain/简介/
9066
+ 流水线名称+编码/脚本流水线+路径/仓库列表/人员信息/关联前端/关联后端
9303
9067
 
9304
9068
  示例:
9305
- bfi ms yonbip-scm-stock
9306
- bfi ms --keyword 库存
9069
+ bfi ms yonbip-am-aum
9070
+ bfi ms 库存
9307
9071
 
9308
9072
  提示: 事件监听的 microServiceCode 字段 / 异常栈的包名线索都可用本命令反查仓库。`);
9309
9073
  }
9074
+ const KIND_LABEL = {
9075
+ MS: "微服务",
9076
+ SPL: "二方包"
9077
+ };
9078
+ const STATUS_LABEL = {
9079
+ 0: "已废弃",
9080
+ 1: "在用",
9081
+ 2: "已停用"
9082
+ };
9083
+ function peopleLine(maintainers) {
9084
+ return maintainers.map((m) => `${m.name || "-"}(${m.role || "-"})`).join(", ");
9085
+ }
9086
+ function relateLine(items) {
9087
+ return items.map((x) => `${x.name || "-"}(${x.code || "-"})`).join(", ");
9088
+ }
9310
9089
  async function runMs(args, globalOpts) {
9311
9090
  const rest = args;
9312
9091
  if (!args[0] || flag(rest, "--help") || flag(rest, "-h")) {
@@ -9320,32 +9099,41 @@ async function runMs(args, globalOpts) {
9320
9099
  console.error("未认证。先运行:bfi auth login --token <sk-token>(或传 --token)");
9321
9100
  process.exit(1);
9322
9101
  }
9323
- const keyword = opt(rest, "--keyword");
9324
- const code = keyword ? "" : positionals(rest)[0] ?? "";
9325
- if (!code && !keyword) {
9326
- console.error("缺少微服务编码或 --keyword。运行 bfi ms --help 查看用法。");
9102
+ const keyword = positionals(rest)[0] ?? "";
9103
+ if (!keyword.trim()) {
9104
+ console.error("缺少检索词。运行 bfi ms --help 查看用法。");
9327
9105
  process.exit(1);
9328
9106
  }
9329
9107
  const body = {
9330
- code,
9331
- name: keyword ?? "",
9332
- use_status: opt(rest, "--use-status") ?? "1",
9333
- page: Number(opt(rest, "--page") ?? 1),
9334
- size: Number(opt(rest, "--size") ?? 20)
9108
+ keyword,
9109
+ limit: Number(opt(rest, "--limit") ?? 50)
9335
9110
  };
9336
9111
  emit(await api.call("code/microservice", body), jsonMode, (data) => {
9337
9112
  const d = data;
9338
9113
  const rows = d.rows ?? [];
9339
- if (!rows.length) return `无匹配微服务(total=${d.total ?? 0})`;
9340
- return rows.map((r) => {
9114
+ if (!rows.length) return `无匹配(total=${d.total ?? 0})`;
9115
+ return (d.truncated ? `⚠ 命中 ${d.total} 行,仅展示 ${rows.length} 行,请收窄关键词\n\n` : "") + rows.map((r) => {
9341
9116
  const repos = r.repos ?? [];
9342
- const repoLines = repos.map((x) => ` - ${x.repo} (${x.git_url}${x.branch ? ` @${x.branch}` : ""})`).join("\n");
9343
- return [
9344
- `${r.code} ${r.name} [${r.type || "-"}]`,
9345
- ` 部门: ${r.department || "-"} | 开发: ${r.developer_name || "-"} | 架构: ${r.architect_name || "-"} | Jira: ${r.jira_project_name || "-"}`,
9346
- ` 仓库(${repos.length}):`,
9347
- repoLines || " (无 git 地址)"
9348
- ].join("\n");
9117
+ const kind = KIND_LABEL[String(r.kind)] ?? String(r.kind ?? "");
9118
+ const status = STATUS_LABEL[String(r.use_status)] ?? String(r.use_status ?? "-");
9119
+ const lines = [
9120
+ `[${kind}] ${r.code} ${r.name} (${r.type || "-"}, ${status})`,
9121
+ ` 领域云: ${r.domain_cloud || "-"} | 领域: ${r.bfi_domain || "-"} | 部门: ${r.department || "-"}`,
9122
+ ` 数据库: ${r.schema || "-"}${r.rpc_domain ? ` | rpcDomain: ${r.rpc_domain}` : ""}`
9123
+ ];
9124
+ if (r.description) lines.push(` 简介: ${r.description}`);
9125
+ if (r.pipeline_name || r.pipeline_code || r.bfi_pipeline_code) lines.push(` 流水线: ${r.pipeline_name || "-"} (${r.pipeline_code || "-"}) | 脚本: ${r.bfi_pipeline_code || "-"} @ ${r.bfi_script_path || "-"}`);
9126
+ lines.push(` 仓库(${repos.length}):`);
9127
+ lines.push(repos.length ? repos.map((x) => ` - ${x.repo} (${x.url}${x.branch ? ` @${x.branch}` : ""})`).join("\n") : " (无 git 地址)");
9128
+ const people = r.maintainers ?? [];
9129
+ if (people.length) lines.push(` 人员: ${peopleLine(people)}`);
9130
+ const rf = r.related_front ?? [];
9131
+ const rb = r.related_backend ?? [];
9132
+ const rfLabel = r.type === "isFe" ? "关联前端二方包" : "关联前端";
9133
+ if (rf.length) lines.push(` ${rfLabel}: ${relateLine(rf)}`);
9134
+ if (rb.length) lines.push(` 关联后端: ${relateLine(rb)}`);
9135
+ if (r.product_name || r.msc_code) lines.push(` 所属应用: ${r.product_name || "-"} | 提供方微服务: ${r.msc_code || "-"}`);
9136
+ return lines.join("\n");
9349
9137
  }).join("\n\n");
9350
9138
  });
9351
9139
  }
@@ -9769,21 +9557,11 @@ ${BOLD}━━━ 技能包管理 ━━━${RESET}
9769
9557
  skills package create <slug> [--name] [--description] 创建包
9770
9558
  skills package add <pkg> <skill...> 添加技能到包
9771
9559
  skills package remove <pkg> <skill...> 从包移除技能
9772
-
9773
- ${BOLD}━━━ 插件管理 ━━━${RESET}
9774
- plugin create <name> [--with ...] 脚手架一个插件目录
9775
- plugin validate [path] 校验插件结构
9776
- plugin publish <dir|zip|tgz> 发布插件到 SkillHub
9777
- plugin list 列出插件
9778
- plugin info <id> 查看插件详情
9779
- plugin install <slug|id|file.zip> 安装插件(名称 / ID / 本地压缩包)
9780
-
9781
- ${BOLD}━━━ MCP 服务器 ━━━${RESET}
9782
- mcp list 列出 MCP 服务器
9783
- mcp info <id> 查看详情
9784
- mcp config <id> 打印 .mcp.json 配置
9785
- mcp add <id> 写入本地 .mcp.json
9786
- mcp remove <name> 从本地 .mcp.json 移除
9560
+ skills package install <ref> [--agent <a>] 安装技能组合(默认,不安装插件组件)
9561
+ --as plugin 显式完整插件模式;支持本地 zip/tgz,不兼容时不会降级安装
9562
+ --plan 只读校验安装计划;--export <archive> 仅导出,不安装
9563
+ --agent <a> 目标 agent(如 claude-code、codex、zcode)
9564
+ --global 安装到主目录(跨项目可用)
9787
9565
 
9788
9566
  ${BOLD}━━━ 文档 ━━━${RESET}
9789
9567
  docs upload <file> 上传文档
@@ -9876,7 +9654,7 @@ function runInit(args) {
9876
9654
  return;
9877
9655
  }
9878
9656
  if (hasName) mkdirSync(skillDir, { recursive: true });
9879
- writeFileSync(skillFile, `---
9657
+ const skillContent = `---
9880
9658
  name: ${skillName}
9881
9659
  description: A brief description of what this skill does
9882
9660
  ---
@@ -9894,7 +9672,8 @@ Describe when this skill should be used.
9894
9672
  1. First step
9895
9673
  2. Second step
9896
9674
  3. Additional steps as needed
9897
- `);
9675
+ `;
9676
+ writeFileSync(skillFile, skillContent);
9898
9677
  console.log(`${TEXT}已初始化技能:${DIM}${skillName}${RESET}`);
9899
9678
  console.log();
9900
9679
  console.log(`${DIM}已创建:${RESET}`);
@@ -10052,6 +9831,10 @@ async function main() {
10052
9831
  }
10053
9832
  const command = args[0];
10054
9833
  const restArgs = args.slice(1);
9834
+ try {
9835
+ const { maybePrintAnalyticsNotice } = await Promise.resolve().then(() => analytics_exports);
9836
+ maybePrintAnalyticsNotice();
9837
+ } catch {}
10055
9838
  const globalOpts = {};
10056
9839
  const nsIdx = args.indexOf("--namespace");
10057
9840
  if (nsIdx !== -1 && nsIdx + 1 < args.length) globalOpts.namespace = args[nsIdx + 1];
@@ -10060,8 +9843,9 @@ async function main() {
10060
9843
  const tokIdx = args.indexOf("--token");
10061
9844
  if (tokIdx !== -1 && tokIdx + 1 < args.length) globalOpts.token = args[tokIdx + 1];
10062
9845
  globalOpts.workdir = process.cwd();
9846
+ globalOpts.version = VERSION;
10063
9847
  try {
10064
- const { resolveConfig } = await Promise.resolve().then(() => config_exports);
9848
+ const { resolveConfig } = await import("./_chunks/config.mjs").then((n) => n.config_exports);
10065
9849
  const { resolveAgents } = await import("./_chunks/agents2.mjs");
10066
9850
  const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
10067
9851
  const { setAgents } = await import("./_chunks/agents.mjs").then((n) => n.agents_exports);
@@ -10116,12 +9900,6 @@ async function main() {
10116
9900
  case "pkg":
10117
9901
  await runPackage(restArgs, globalOpts);
10118
9902
  break;
10119
- case "plugin":
10120
- await runPlugin(restArgs, globalOpts);
10121
- break;
10122
- case "mcp":
10123
- await runMcp(restArgs, globalOpts);
10124
- break;
10125
9903
  case "log":
10126
9904
  await runLog(restArgs, globalOpts);
10127
9905
  break;
@@ -10204,4 +9982,4 @@ main().catch((e) => {
10204
9982
  console.error(`✗ ${e?.message || e}`);
10205
9983
  process.exit(1);
10206
9984
  });
10207
- export { loadGlobalConfig };
9985
+ export { isPluginArchive, isPluginVersion, parsePluginArguments };