bfi-cli 0.1.99 → 0.1.101

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,7 +4,7 @@ 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";
7
+ import { PluginRegistryClient, parsePackageIntent } from "./_chunks/intent.mjs";
8
8
  import { loadGlobalConfig, loadLockfile, loadProjectConfig, resolveConfig, saveGlobalConfig, saveLockfile, setConfigValue } from "./_chunks/config.mjs";
9
9
  import { esm_default } from "./_chunks/libs/simple-git.mjs";
10
10
  import { EVE_SUBAGENTS_DIR, agents, detectInstalledAgents, getEveSubagents, getNonUniversalAgents, getUniversalAgents, getVisibleUniversalAgents, isUniversalAgent } from "./_chunks/agents.mjs";
@@ -451,8 +451,10 @@ async function searchMultiselect(options) {
451
451
  }
452
452
  if (key.name === "space") {
453
453
  const item = filtered[cursor];
454
- if (item) if (selected.has(item.value)) selected.delete(item.value);
455
- 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
+ }
456
458
  render();
457
459
  return;
458
460
  }
@@ -473,6 +475,46 @@ async function searchMultiselect(options) {
473
475
  render();
474
476
  });
475
477
  }
478
+ function getCapabilities(version) {
479
+ return {
480
+ schemaVersion: 1,
481
+ version,
482
+ capabilities: [
483
+ "skill-install-v1",
484
+ "content-plan-v1",
485
+ "collection-bundle-v1",
486
+ "collection-mcp-v1",
487
+ "scope-selection-v1",
488
+ "plugin-plan-v1",
489
+ "plugin-export-v1",
490
+ "plugin-handoff-v1"
491
+ ]
492
+ };
493
+ }
494
+ function installationArgumentError(args) {
495
+ const command = ["skills", "skill"].includes(args[0] ?? "") ? args.slice(1) : args;
496
+ const isPackageInstall = ["package", "pkg"].includes(command[0] ?? "") && ["install", "i"].includes(command[1] ?? "");
497
+ if (!isPackageInstall && ![
498
+ "add",
499
+ "a",
500
+ "i",
501
+ "install"
502
+ ].includes(command[0] ?? "")) return;
503
+ if (isPackageInstall) try {
504
+ if (parsePackageIntent(command.slice(1)).mode === "plugin") return;
505
+ } catch {
506
+ return "安装参数或模式无效;插件参数必须使用明确的 --as plugin,尚未支持的技能参数不会执行。";
507
+ }
508
+ const reserved = [
509
+ "--content-plan",
510
+ "--scope",
511
+ "--from-archive",
512
+ "--input-env",
513
+ "--skills-only"
514
+ ];
515
+ const found = command.find((argument) => reserved.includes(argument.split("=")[0]));
516
+ if (found) return `当前命令不支持 ${found.split("=")[0]};${found.split("=")[0]} 仅用于技能组合完整安装(bfi skills package install)。现有安装不会静默忽略此参数。`;
517
+ }
476
518
  var api_exports = /* @__PURE__ */ __exportAll({ SkillHubAPI: () => SkillHubAPI });
477
519
  var SkillHubAPI = class {
478
520
  registry;
@@ -512,12 +554,14 @@ var SkillHubAPI = class {
512
554
  if (url.protocol === "https:") requestOptions.rejectUnauthorized = this.rejectUnauthorized;
513
555
  let bodyStr;
514
556
  let bodyBuf;
515
- if (options.body !== void 0) if (options.body instanceof Buffer) bodyBuf = options.body;
516
- else if (typeof options.body === "string") bodyStr = options.body;
517
- else if (typeof FormData !== "undefined" && options.body instanceof FormData) return this.fetchRequest(url, requestOptions, options.body);
518
- else {
519
- requestOptions.headers["Content-Type"] = "application/json";
520
- bodyStr = JSON.stringify(options.body);
557
+ if (options.body !== void 0) {
558
+ if (options.body instanceof Buffer) bodyBuf = options.body;
559
+ else if (typeof options.body === "string") bodyStr = options.body;
560
+ else if (typeof FormData !== "undefined" && options.body instanceof FormData) return this.fetchRequest(url, requestOptions, options.body);
561
+ else {
562
+ requestOptions.headers["Content-Type"] = "application/json";
563
+ bodyStr = JSON.stringify(options.body);
564
+ }
521
565
  }
522
566
  return new Promise((resolve, reject) => {
523
567
  const req = (url.protocol === "https:" ? https : http).request(url, requestOptions, (res) => {
@@ -674,7 +718,7 @@ var SkillHubAPI = class {
674
718
  return body.data || body;
675
719
  }
676
720
  async getPackage(namespace, slug) {
677
- const body = (await this.request("GET", `/namespaces/${namespace}/packages/${slug}`)).body;
721
+ const body = (await this.request("GET", `/namespaces/${namespace}/packages/${slug}`, { headers: { "X-BFI-Capabilities": getCapabilities("").capabilities.join(",") } })).body;
678
722
  return body.data || body;
679
723
  }
680
724
  async listComponentFiles(namespace, slug, componentId) {
@@ -1301,10 +1345,12 @@ async function isDirEntryOrSymlinkToDir(entry, entryPath) {
1301
1345
  }
1302
1346
  }
1303
1347
  function getCanonicalSkillsDir(global, cwd) {
1304
- return join(global ? homedir() : cwd || process.cwd(), AGENTS_DIR, SKILLS_SUBDIR);
1348
+ const baseDir = global ? homedir() : cwd || process.cwd();
1349
+ return join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);
1305
1350
  }
1306
1351
  function getEveSubagentSkillsDir(subagent, cwd) {
1307
- return join(cwd || process.cwd(), EVE_SUBAGENTS_DIR, sanitizeName(subagent), "skills");
1352
+ const baseDir = cwd || process.cwd();
1353
+ return join(baseDir, EVE_SUBAGENTS_DIR, sanitizeName(subagent), "skills");
1308
1354
  }
1309
1355
  function getAgentBaseDir(agentType, global, cwd, eveSubagent) {
1310
1356
  if (isUniversalAgent(agentType)) return getCanonicalSkillsDir(global, cwd);
@@ -1382,7 +1428,8 @@ async function resolveParentSymlinks(path) {
1382
1428
  const dir = dirname(resolved);
1383
1429
  const base = basename(resolved);
1384
1430
  try {
1385
- return join(await realpath(dir), base);
1431
+ const realDir = await realpath(dir);
1432
+ return join(realDir, base);
1386
1433
  } catch {
1387
1434
  return resolved;
1388
1435
  }
@@ -1406,7 +1453,8 @@ async function createSymlink(target, linkPath) {
1406
1453
  }
1407
1454
  const linkDir = dirname(linkPath);
1408
1455
  await mkdir(linkDir, { recursive: true });
1409
- const relativePath = relative(await resolveParentSymlinks(linkDir), target);
1456
+ const realLinkDir = await resolveParentSymlinks(linkDir);
1457
+ const relativePath = relative(realLinkDir, target);
1410
1458
  const symlinkType = platform() === "win32" ? "junction" : void 0;
1411
1459
  await symlink(symlinkType === "junction" ? resolvedTarget : relativePath, linkPath, symlinkType);
1412
1460
  return true;
@@ -1431,6 +1479,8 @@ async function installSkillForAgent(skill, agentType, options = {}) {
1431
1479
  const canonicalDir = join(canonicalBase, skillName);
1432
1480
  const agentBase = getAgentBaseDir(agentType, isGlobal, cwd, eveSubagent);
1433
1481
  const agentDir = join(agentBase, skillName);
1482
+ const { assertLegacyUnmanaged } = await import("./_chunks/ownership.mjs");
1483
+ await assertLegacyUnmanaged([canonicalDir, agentDir]);
1434
1484
  if (!isPathSafe$1(canonicalBase, canonicalDir)) return {
1435
1485
  success: false,
1436
1486
  path: agentDir,
@@ -1475,7 +1525,8 @@ async function installSkillForAgent(skill, agentType, options = {}) {
1475
1525
  mode: "symlink"
1476
1526
  };
1477
1527
  if (!isGlobal && !isUniversalAgent(agentType)) {
1478
- if (!existsSync(join(cwd, agents[agentType].skillsDir.split("/")[0])) && agentType !== "claude-code") return {
1528
+ const agentRootDir = join(cwd, agents[agentType].skillsDir.split("/")[0]);
1529
+ if (!existsSync(agentRootDir) && agentType !== "claude-code") return {
1479
1530
  success: true,
1480
1531
  path: canonicalDir,
1481
1532
  canonicalPath: canonicalDir,
@@ -1549,7 +1600,8 @@ async function copyDirectory(src, dest, agentType) {
1549
1600
  dereference: true,
1550
1601
  recursive: true
1551
1602
  });
1552
- await chmod(destPath, (await stat(srcPath)).mode & 511);
1603
+ const sourceStats = await stat(srcPath);
1604
+ await chmod(destPath, sourceStats.mode & 511);
1553
1605
  } catch (err) {
1554
1606
  if (err instanceof Error && "code" in err && err.code === "ENOENT" && entry.isSymbolicLink()) console.warn(`Skipping broken symlink: ${srcPath}`);
1555
1607
  else throw err;
@@ -1766,7 +1818,8 @@ async function installBlobSkillForAgent(skill, agentType, options = {}) {
1766
1818
  mode: "symlink"
1767
1819
  };
1768
1820
  if (!isGlobal && !isUniversalAgent(agentType)) {
1769
- if (!existsSync(join(cwd, agents[agentType].skillsDir.split("/")[0]))) return {
1821
+ const agentRootDir = join(cwd, agents[agentType].skillsDir.split("/")[0]);
1822
+ if (!existsSync(agentRootDir)) return {
1770
1823
  success: true,
1771
1824
  path: canonicalDir,
1772
1825
  canonicalPath: canonicalDir,
@@ -1994,7 +2047,7 @@ var ProviderRegistryImpl = class {
1994
2047
  };
1995
2048
  new ProviderRegistryImpl();
1996
2049
  const DISCOVERY_SCHEMA_V2 = "https://schemas.agentskills.io/discovery/0.2.0/schema.json";
1997
- const MAX_ARCHIVE_UNPACKED_BYTES = 50 * 1024 * 1024;
2050
+ const MAX_ARCHIVE_UNPACKED_BYTES = 52428800;
1998
2051
  const MAX_ARCHIVE_FILES = 1e3;
1999
2052
  var WellKnownProvider = class {
2000
2053
  id = "well-known";
@@ -3147,22 +3200,23 @@ async function handleWellKnownSkills(source, url, options, spinner) {
3147
3200
  const installedAgents = await detectInstalledAgents();
3148
3201
  const totalAgents = Object.keys(agents).length;
3149
3202
  spinner.stop(`${totalAgents} agents`);
3150
- if (installedAgents.length === 0) if (options.yes) {
3151
- targetAgents = validAgents;
3152
- log.info("正在安装到全部 Agent");
3153
- } else {
3154
- log.info("请选择要安装技能的 Agent");
3155
- const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).map(([key, config]) => ({
3156
- value: key,
3157
- label: config.displayName
3158
- })));
3159
- if (isCancel(selected)) {
3160
- cancel("安装已取消");
3161
- process.exit(0);
3203
+ if (installedAgents.length === 0) {
3204
+ if (options.yes) {
3205
+ targetAgents = validAgents;
3206
+ log.info("正在安装到全部 Agent");
3207
+ } else {
3208
+ log.info("请选择要安装技能的 Agent");
3209
+ const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).map(([key, config]) => ({
3210
+ value: key,
3211
+ label: config.displayName
3212
+ })));
3213
+ if (isCancel(selected)) {
3214
+ cancel("安装已取消");
3215
+ process.exit(0);
3216
+ }
3217
+ targetAgents = selected;
3162
3218
  }
3163
- targetAgents = selected;
3164
- }
3165
- else if (installedAgents.length === 1 || options.yes) {
3219
+ } else if (installedAgents.length === 1 || options.yes) {
3166
3220
  targetAgents = ensureUniversalAgents(installedAgents);
3167
3221
  if (installedAgents.length === 1) {
3168
3222
  const firstAgent = installedAgents[0];
@@ -3397,13 +3451,14 @@ async function installFromSkillHub(parsed, options, spinner) {
3397
3451
  slug = hit.slug;
3398
3452
  log.info(`自动选择:${import_picocolors.default.cyan(`@${namespace}/${slug}`)} — ${hit.description || hit.name}`);
3399
3453
  } else {
3454
+ const choices = hits.map((h, idx) => ({
3455
+ value: idx,
3456
+ label: `@${h.namespace}/${h.slug}`,
3457
+ hint: h.description || h.name
3458
+ }));
3400
3459
  const idx = await select({
3401
3460
  message: "匹配到多个技能 — 请选择一个",
3402
- options: hits.map((h, idx) => ({
3403
- value: idx,
3404
- label: `@${h.namespace}/${h.slug}`,
3405
- hint: h.description || h.name
3406
- }))
3461
+ options: choices
3407
3462
  });
3408
3463
  if (isCancel(idx)) {
3409
3464
  cancel("安装已取消");
@@ -3430,7 +3485,8 @@ async function installFromSkillHub(parsed, options, spinner) {
3430
3485
  }
3431
3486
  const meta = metadata;
3432
3487
  spinner.stop(`Skill: ${import_picocolors.default.cyan(`@${namespace}/${slug}`)}${meta.description ? ` — ${import_picocolors.default.dim(meta.description)}` : ""}`);
3433
- tempDir = join(tmpdir(), `.skillhub-skillshub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
3488
+ const tmpRoot = tmpdir();
3489
+ tempDir = join(tmpRoot, `.skillhub-skillshub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
3434
3490
  mkdirSync(tempDir, { recursive: true });
3435
3491
  const zipPath = join(tempDir, "skill.zip");
3436
3492
  spinner.start("正在下载技能...");
@@ -3766,23 +3822,24 @@ async function runAdd(args, options = {}) {
3766
3822
  }
3767
3823
  targetAgents = selected;
3768
3824
  }
3769
- } else if (installedAgents.length === 0) if (options.yes) {
3770
- targetAgents = validAgents;
3771
- log.info("正在安装到全部 Agent");
3772
- } else {
3773
- log.info("请选择要安装技能的 Agent");
3774
- const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
3775
- value: key,
3776
- label: config.displayName
3777
- })));
3778
- if (isCancel(selected)) {
3779
- cancel("安装已取消");
3780
- await cleanup(tempDir);
3781
- process.exit(0);
3825
+ } else if (installedAgents.length === 0) {
3826
+ if (options.yes) {
3827
+ targetAgents = validAgents;
3828
+ log.info("正在安装到全部 Agent");
3829
+ } else {
3830
+ log.info("请选择要安装技能的 Agent");
3831
+ const selected = await promptForAgents("请选择要安装到的 Agent:", Object.entries(agents).filter(([key]) => key !== "eve").map(([key, config]) => ({
3832
+ value: key,
3833
+ label: config.displayName
3834
+ })));
3835
+ if (isCancel(selected)) {
3836
+ cancel("安装已取消");
3837
+ await cleanup(tempDir);
3838
+ process.exit(0);
3839
+ }
3840
+ targetAgents = selected;
3782
3841
  }
3783
- targetAgents = selected;
3784
- }
3785
- else if (installedAgents.length === 1 || options.yes) {
3842
+ } else if (installedAgents.length === 1 || options.yes) {
3786
3843
  targetAgents = ensureUniversalAgents(installedAgents);
3787
3844
  if (installedAgents.length === 1) {
3788
3845
  const firstAgent = installedAgents[0];
@@ -3804,17 +3861,18 @@ async function runAdd(args, options = {}) {
3804
3861
  const availableSubagents = getEveSubagents(process.cwd());
3805
3862
  if (options.subagent && options.subagent.length > 0) eveSubagentTargets = options.subagent.map((s) => s === "root" || s === "." ? void 0 : s);
3806
3863
  else if (availableSubagents.length > 0 && !options.yes) {
3864
+ const subagentChoices = [{
3865
+ value: "",
3866
+ label: "根 Agent",
3867
+ hint: "agent/skills"
3868
+ }, ...availableSubagents.map((name) => ({
3869
+ value: name,
3870
+ label: name,
3871
+ hint: `agent/subagents/${name}/skills`
3872
+ }))];
3807
3873
  const selectedSubagents = await multiselect$1({
3808
3874
  message: "Eve 技能安装位置?",
3809
- options: [{
3810
- value: "",
3811
- label: "根 Agent",
3812
- hint: "agent/skills"
3813
- }, ...availableSubagents.map((name) => ({
3814
- value: name,
3815
- label: name,
3816
- hint: `agent/subagents/${name}/skills`
3817
- }))],
3875
+ options: subagentChoices,
3818
3876
  initialValues: [""],
3819
3877
  required: true
3820
3878
  });
@@ -3992,9 +4050,11 @@ async function runAdd(args, options = {}) {
3992
4050
  const normalizedSource = getOwnerRepo(parsed);
3993
4051
  const lockSource = getLockSource(parsed.url, normalizedSource);
3994
4052
  const projectLockSourceUrl = getProjectLockSourceUrl(parsed.type, parsed.url);
3995
- if (normalizedSource) if (parseOwnerRepo(normalizedSource)) {
3996
- if (await repoPrivacyPromise === false) selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
3997
- } else selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4053
+ if (normalizedSource) {
4054
+ if (parseOwnerRepo(normalizedSource)) {
4055
+ if (await repoPrivacyPromise === false) selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4056
+ } else selectedSkills.map((s) => s.name).join(","), targetAgents.join(","), { ...installGlobally && { global: "1" } }, JSON.stringify(skillFiles), options.metadata;
4057
+ }
3998
4058
  if (successful.length > 0 && installGlobally && (normalizedSource || parsed.type === "skillhub")) {
3999
4059
  const successfulSkillNames = new Set(successful.map((r) => r.skill));
4000
4060
  let cachedTree;
@@ -4011,7 +4071,8 @@ async function runAdd(args, options = {}) {
4011
4071
  const hash = getSkillFolderHashFromTree(cachedTree, skillPathValue);
4012
4072
  if (hash) skillFolderHash = hash;
4013
4073
  } else if (skillPathValue && tempDir) {
4014
- const hash = await computeSkillFolderHash(join(tempDir, dirname(skillPathValue)));
4074
+ const skillDir = join(tempDir, dirname(skillPathValue));
4075
+ const hash = await computeSkillFolderHash(skillDir);
4015
4076
  if (hash) skillFolderHash = hash;
4016
4077
  }
4017
4078
  await addSkillToLock(skill.name, {
@@ -4055,11 +4116,13 @@ async function runAdd(args, options = {}) {
4055
4116
  const skillResults = bySkill.get(r.skill) || [];
4056
4117
  skillResults.push(r);
4057
4118
  bySkill.set(r.skill, skillResults);
4058
- if (skillResults.length === 1) if (r.pluginName) {
4059
- const group = r.pluginName;
4060
- if (!groupedResults[group]) groupedResults[group] = [];
4061
- groupedResults[group].push(r);
4062
- } else ungroupedResults.push(r);
4119
+ if (skillResults.length === 1) {
4120
+ if (r.pluginName) {
4121
+ const group = r.pluginName;
4122
+ if (!groupedResults[group]) groupedResults[group] = [];
4123
+ groupedResults[group].push(r);
4124
+ } else ungroupedResults.push(r);
4125
+ }
4063
4126
  }
4064
4127
  const skillCount = bySkill.size;
4065
4128
  const symlinkFailures = successful.filter((r) => r.mode === "symlink" && r.symlinkFailed);
@@ -4709,6 +4772,14 @@ async function removeCommand(skillNames, options) {
4709
4772
  targetAgents = Object.keys(agents);
4710
4773
  spinner$2.stop(`Targeting ${targetAgents.length} potential agent(s)`);
4711
4774
  }
4775
+ const { assertLegacyUnmanaged } = await import("./_chunks/ownership.mjs");
4776
+ await assertLegacyUnmanaged(selectedSkills.flatMap((skill) => [getCanonicalPath(skill, {
4777
+ global: isGlobal,
4778
+ cwd
4779
+ }), ...targetAgents.map((agent) => getInstallPath(skill, agent, {
4780
+ global: isGlobal,
4781
+ cwd
4782
+ }))]));
4712
4783
  if (!options.yes) {
4713
4784
  console.log();
4714
4785
  log.info("要卸载的技能:");
@@ -4755,12 +4826,15 @@ async function removeCommand(skillNames, options) {
4755
4826
  }
4756
4827
  const remainingAgents = (await detectInstalledAgents()).filter((a) => !targetAgents.includes(a));
4757
4828
  let isStillUsed = false;
4758
- for (const agentKey of remainingAgents) if (await lstat(getInstallPath(skillName, agentKey, {
4759
- global: isGlobal,
4760
- cwd
4761
- })).catch(() => null)) {
4762
- isStillUsed = true;
4763
- break;
4829
+ for (const agentKey of remainingAgents) {
4830
+ const path = getInstallPath(skillName, agentKey, {
4831
+ global: isGlobal,
4832
+ cwd
4833
+ });
4834
+ if (await lstat(path).catch(() => null)) {
4835
+ isStillUsed = true;
4836
+ break;
4837
+ }
4764
4838
  }
4765
4839
  if (!isStillUsed) await rm(canonicalPath, {
4766
4840
  recursive: true,
@@ -4900,12 +4974,14 @@ function parseUpdateOptions(args) {
4900
4974
  }
4901
4975
  function hasProjectSkills(cwd) {
4902
4976
  const dir = cwd || process.cwd();
4903
- if (existsSync(join(dir, "skills-lock.json"))) return true;
4977
+ const lockPath = join(dir, "skills-lock.json");
4978
+ if (existsSync(lockPath)) return true;
4904
4979
  const skillsDir = join(dir, ".agents", "skills");
4905
4980
  try {
4906
4981
  const entries = readdirSync(skillsDir, { withFileTypes: true });
4907
4982
  for (const entry of entries) if (entry.isDirectory()) {
4908
- if (existsSync(join(skillsDir, entry.name, "SKILL.md"))) return true;
4983
+ const skillMd = join(skillsDir, entry.name, "SKILL.md");
4984
+ if (existsSync(skillMd)) return true;
4909
4985
  }
4910
4986
  } catch {}
4911
4987
  return false;
@@ -5329,7 +5405,8 @@ async function updateProjectSkills(options = {}) {
5329
5405
  try {
5330
5406
  tempDir = await cloneRepo(sourceUrl, ref);
5331
5407
  const discoveredPaths = (await discoverSkills(tempDir)).map((s) => {
5332
- return join(relative(tempDir, s.path), "SKILL.md").split(sep).join("/");
5408
+ const relPath = relative(tempDir, s.path);
5409
+ return join(relPath, "SKILL.md").split(sep).join("/");
5333
5410
  });
5334
5411
  deletedSkills = await checkAndPromptForDeletions(source, allLockedForSource, localLock.skills, false, options, discoveredPaths);
5335
5412
  } catch (error) {
@@ -6300,8 +6377,8 @@ const DIM$5 = "\x1B[38;5;102m";
6300
6377
  const TEXT$4 = "\x1B[38;5;145m";
6301
6378
  function formatFileSize(bytes) {
6302
6379
  if (bytes < 1024) return `${bytes} B`;
6303
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
6304
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6380
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
6381
+ return `${(bytes / 1048576).toFixed(1)} MB`;
6305
6382
  }
6306
6383
  async function runDocs(args, globalOpts) {
6307
6384
  switch (args[0]) {
@@ -6565,7 +6642,8 @@ async function publishFromDir(positionalArgs, api, namespace, visibility) {
6565
6642
  console.log("需要包含 frontmatter(name, description)的 SKILL.md 文件。");
6566
6643
  process.exit(1);
6567
6644
  }
6568
- const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6645
+ const skillMdContent = fs.readFileSync(skillMdPath, "utf-8");
6646
+ const { data: frontmatter } = parseFrontmatter(skillMdContent);
6569
6647
  const skillName = frontmatter.name || path$1.basename(resolvedDir);
6570
6648
  console.log(`${DIM$4}正在从目录发布技能...${RESET$4}`);
6571
6649
  console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
@@ -6612,7 +6690,8 @@ async function publishFromZip(positionalArgs, api, namespace, visibility) {
6612
6690
  }
6613
6691
  const skillDir = path$1.dirname(skillMdPath);
6614
6692
  console.log(` ${GREEN$3}在 ${path$1.relative(tmpDir, skillDir) || "."} 中找到 SKILL.md${RESET$4}`);
6615
- const { data: frontmatter } = parseFrontmatter(fs.readFileSync(skillMdPath, "utf-8"));
6693
+ const skillMdContent = fs.readFileSync(skillMdPath, "utf-8");
6694
+ const { data: frontmatter } = parseFrontmatter(skillMdContent);
6616
6695
  const skillName = frontmatter.name || path$1.basename(skillDir);
6617
6696
  console.log(` ${BOLD$2}名称:${RESET$4} ${TEXT$3}${skillName}${RESET$4}`);
6618
6697
  console.log(` ${BOLD$2}命名空间:${RESET$4} ${TEXT$3}${namespace}${RESET$4}`);
@@ -6793,8 +6872,8 @@ function findSkillMd(dir) {
6793
6872
  }
6794
6873
  function formatSize(bytes) {
6795
6874
  if (bytes < 1024) return `${bytes} B`;
6796
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
6797
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
6875
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} KB`;
6876
+ return `${(bytes / 1048576).toFixed(1)} MB`;
6798
6877
  }
6799
6878
  function truncate(text, maxLen) {
6800
6879
  if (text.length <= maxLen) return text;
@@ -6883,107 +6962,6 @@ function maybePrintAnalyticsNotice(env = process.env) {
6883
6962
  console.log();
6884
6963
  } catch {}
6885
6964
  }
6886
- const pluginTargets = [
6887
- "claude-code",
6888
- "codex",
6889
- "zcode",
6890
- "codebuddy",
6891
- "qwen-code"
6892
- ];
6893
- const isPluginArchive = (value) => /\.(zip|tgz|tar\.gz)$/iu.test(value);
6894
- 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);
6895
- function parsePackageIntent(args) {
6896
- const output = [...args];
6897
- let mode = "skills";
6898
- const occurrences = args.filter((value) => value === "--as" || value.startsWith("--as="));
6899
- if (occurrences.length) {
6900
- const index = output.indexOf("--as");
6901
- const requested = output[index + 1];
6902
- 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");
6903
- mode = requested;
6904
- output.splice(index, 2);
6905
- }
6906
- if (mode === "skills" && (output.some((value) => [
6907
- "--plan",
6908
- "--export",
6909
- "--scope",
6910
- "--root",
6911
- "--operation"
6912
- ].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");
6913
- return {
6914
- mode,
6915
- args: output
6916
- };
6917
- }
6918
- function parsePluginArguments(args) {
6919
- const command = {
6920
- install: "install",
6921
- i: "install",
6922
- update: "update",
6923
- up: "update",
6924
- uninstall: "uninstall",
6925
- rm: "uninstall",
6926
- list: "list",
6927
- ls: "list"
6928
- }[args[0] ?? ""];
6929
- if (!command) throw new Error("Plugin intent supports install, update, uninstall and list");
6930
- const result = {
6931
- command,
6932
- scope: "project",
6933
- planOnly: false,
6934
- json: false
6935
- };
6936
- const seen = /* @__PURE__ */ new Set();
6937
- const values = /* @__PURE__ */ new Set([
6938
- "--agent",
6939
- "--version",
6940
- "--scope",
6941
- "--root",
6942
- "--export",
6943
- "--operation",
6944
- "--registry",
6945
- "--token",
6946
- "--namespace"
6947
- ]);
6948
- for (let index = 1; index < args.length; index++) {
6949
- const option = args[index];
6950
- if (!option.startsWith("-")) {
6951
- if (result.source) throw new Error("Specify exactly one plugin source");
6952
- result.source = option;
6953
- continue;
6954
- }
6955
- const flag = option === "-g" ? "--global" : option === "-y" ? "--yes" : option;
6956
- if (seen.has(flag)) throw new Error(`Duplicate plugin option: ${flag}`);
6957
- seen.add(flag);
6958
- if (values.has(flag)) {
6959
- const value = args[++index];
6960
- if (value === void 0 || value.startsWith("-") || /[\u0000-\u001f\u007f]/u.test(value)) throw new Error(`Missing or invalid value for ${flag}`);
6961
- if (flag === "--agent") {
6962
- if (!pluginTargets.includes(value)) throw new Error("Unknown native plugin target");
6963
- result.agent = value;
6964
- } else if (flag === "--version") {
6965
- if (!isPluginVersion(value)) throw new Error("Plugin version must be exact SemVer, not latest or a range");
6966
- result.version = value;
6967
- } else if (flag === "--scope") {
6968
- if (!["project", "user"].includes(value)) throw new Error("Plugin scope must be project or user");
6969
- result.scope = value;
6970
- } else if (flag === "--root") result.root = value;
6971
- else if (flag === "--export") result.exportPath = value;
6972
- else if (flag === "--operation") result.operationId = value;
6973
- } else if (flag === "--global") result.scope = "user";
6974
- else if (flag === "--plan") result.planOnly = true;
6975
- else if (flag === "--json") result.json = true;
6976
- else if (flag !== "--yes") throw new Error(`Unknown plugin option: ${flag}; upgrade bfi if needed`);
6977
- }
6978
- if (seen.has("--scope") && seen.has("--global")) throw new Error("Use --scope or --global, not both");
6979
- if (command !== "list" && !result.agent) throw new Error("Full plugin operations require an explicit --agent");
6980
- if (command !== "list" && !result.source && !(command === "uninstall" && result.operationId)) throw new Error("Specify @namespace/package or a local zip/tgz path");
6981
- 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");
6982
- if (result.planOnly && result.exportPath) throw new Error("Plan and export are separate operations");
6983
- 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");
6984
- if (command === "list" && (result.source || result.version || result.planOnly || result.exportPath || result.operationId)) throw new Error("Invalid plugin list options");
6985
- return result;
6986
- }
6987
6965
  var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
6988
6966
  const RESET$3 = "\x1B[0m";
6989
6967
  const BOLD$1 = "\x1B[1m";
@@ -7065,7 +7043,7 @@ function printPackageHelp() {
7065
7043
  console.log(`${BOLD$1}选项:${RESET$3}`);
7066
7044
  console.log(` --namespace <ns> 目标命名空间`);
7067
7045
  console.log(` --agent <a> 目标 agent(如 claude-code、codex)`);
7068
- console.log(` --as skills|plugin 默认 skills;完整插件必须显式 --as plugin --agent <a>`);
7046
+ console.log(` --as skills|plugin 默认 skills;完整插件必须显式 --as plugin,未指定 Agent/范围时交互选择`);
7069
7047
  console.log(` --version <v> 插件固定版本;省略只解析显式 stable,不回退 latest`);
7070
7048
  console.log(` --plan 插件模式只读计划,不写配置或安装记录`);
7071
7049
  console.log(` --export <archive> 插件模式校验后导出原始制品,不安装、不覆盖文件`);
@@ -7079,15 +7057,28 @@ function printPackageHelp() {
7079
7057
  console.log();
7080
7058
  }
7081
7059
  async function handleLocalList(args, globalOpts) {
7082
- const lock = loadLockfile(getWorkdir(globalOpts, args));
7060
+ const cwd = getWorkdir(globalOpts, args);
7061
+ const lock = loadLockfile(cwd);
7083
7062
  args.includes("-g") || args.includes("--global");
7084
7063
  const pkgs = lock.packages || {};
7085
7064
  const entries = Object.entries(pkgs);
7086
- if (args.includes("--json")) {
7087
- console.log(JSON.stringify(Object.values(pkgs), null, 2));
7065
+ const json = args.includes("--json");
7066
+ const { receipts } = await import("./_chunks/receipt.mjs");
7067
+ const installed = (await receipts()).filter((record) => record.plan.kind === "COLLECTION");
7068
+ if (json) {
7069
+ console.log(JSON.stringify([...Object.values(pkgs), ...installed.map((record) => ({
7070
+ ref: record.plan.ref,
7071
+ registry: record.plan.registry,
7072
+ state: record.state,
7073
+ operation: record.id,
7074
+ destination: record.destination,
7075
+ skills: record.plan.skills.length,
7076
+ mcps: record.plan.mcps.length
7077
+ }))], null, 2));
7088
7078
  return;
7089
7079
  }
7090
- if (entries.length === 0) {
7080
+ for (const record of installed) console.log(`${record.plan.ref} · ${record.state} · ${record.destination.agents.join(", ")} · ${record.destination.scope} · ${record.plan.skills.length} 技能 + ${record.plan.mcps.length} MCP · ${record.id}`);
7081
+ if (entries.length === 0 && installed.length === 0) {
7091
7082
  console.log("没有已安装的包。");
7092
7083
  console.log(`使用 ${DIM$3}bfi skills package install <ref>${RESET$3} 安装包。`);
7093
7084
  return;
@@ -7276,17 +7267,18 @@ async function handleInstall(args, api, globalOpts) {
7276
7267
  if (targetAgents.includes("eve")) {
7277
7268
  const availableSubagents = getEveSubagents(process.cwd());
7278
7269
  if (availableSubagents.length > 0) {
7270
+ const subagentChoices = [{
7271
+ value: "",
7272
+ label: "根 Agent",
7273
+ hint: "agent/skills"
7274
+ }, ...availableSubagents.map((name) => ({
7275
+ value: name,
7276
+ label: name,
7277
+ hint: `agent/subagents/${name}/skills`
7278
+ }))];
7279
7279
  const selectedSubagents = await multiselect$1({
7280
7280
  message: "Eve 技能安装位置?",
7281
- options: [{
7282
- value: "",
7283
- label: "根 Agent",
7284
- hint: "agent/skills"
7285
- }, ...availableSubagents.map((name) => ({
7286
- value: name,
7287
- label: name,
7288
- hint: `agent/subagents/${name}/skills`
7289
- }))],
7281
+ options: subagentChoices,
7290
7282
  initialValues: [""],
7291
7283
  required: true
7292
7284
  });
@@ -7481,7 +7473,8 @@ async function handleUninstall(args, globalOpts) {
7481
7473
  }
7482
7474
  async function handleUpdate(args, api, globalOpts) {
7483
7475
  const pkgRef = args[0];
7484
- const lock = loadLockfile(getWorkdir(globalOpts, args));
7476
+ const cwd = getWorkdir(globalOpts, args);
7477
+ const lock = loadLockfile(cwd);
7485
7478
  let packagesToUpdate = [];
7486
7479
  const pkgs = lock.packages || {};
7487
7480
  if (pkgRef) {
@@ -8814,7 +8807,6 @@ async function runYmc(args, globalOpts) {
8814
8807
  break;
8815
8808
  }
8816
8809
  default: {
8817
- if (sub === "cases" || sub.startsWith("cases")) console.error("案例库已迁移 WeKnora:检索/归档改用 weknora-bfi MCP 工具(kb_search / kb_archive_case)。");
8818
8810
  console.error(`未知子命令:${sub}`);
8819
8811
  const hint = SUBCOMMAND_HINTS[sub];
8820
8812
  if (hint) console.error(`提示:${hint}`);
@@ -8850,7 +8842,7 @@ const HELP = {
8850
8842
  禁止 * | SELECT * WHERE 字段=... (WHERE 全扫描必超时)
8851
8843
  -t <time> 时间简写 10m/2h/3d/4w(默认无时间=服务端超大窗兜底,会命中数天前记录,务必显式指定)
8852
8844
  --start-time/--end-time 精确窗口 yyyy-MM-dd HH:mm:ss 北京时间(优先于 -t)
8853
- --days N 按天数回溯(旧参数,等价 -t Nd)
8845
+ --days N 按天数回溯(等价 -t Nd)
8854
8846
  --line N 返回行数上限
8855
8847
  示例:
8856
8848
  bfi ymc sls-raw 'traceid: abc | SELECT * LIMIT 200' -e daily -t 1d
@@ -8884,8 +8876,8 @@ const HELP = {
8884
8876
  --app 服务维度过滤(裸 appCode)
8885
8877
  --method 按调用方法过滤
8886
8878
  --min-cost <ms> 最小耗时过滤(body.costTime=[ms, 999999])
8887
- (无 --profiler) 历史参数已移除映射——上游 enableProfiler 是"仅返回有 CPU 采样
8888
- 记录"的过滤器,实测任何组合均空集。CPU 热点走 dump-list。
8879
+ --profiler 透传上游 enableProfiler(仅返回有 CPU 采样记录的调用);
8880
+ 该过滤器常返回空集,常规取证勿带,CPU 热点走 dump-list。
8889
8881
  示例:
8890
8882
  bfi ymc slowcall -t 1d --trace-id abc -e core3 # 链路分层分解(跨服务根因链必用)
8891
8883
  bfi ymc slowcall -t 4w --app yonbip-scm-pu -e pre # 服务慢调用趋势`,
@@ -8910,12 +8902,6 @@ const HELP = {
8910
8902
  --size N 返回条数(默认 100,最大 5000)`,
8911
8903
  "dump-list": `bfi ymc dump-list -t <time> -e <env> [--app <appCode>] [--type profiler|heap|...] [--json]
8912
8904
  诊断文件列表(火焰图/JVM dump;CPU 热点取数的正确入口)。`,
8913
- cases: `bfi ymc cases <search|show|upload|index> [参数]
8914
- KEDB 案例库(内部诊断先验第一源)。
8915
- search [--type <t>] [--finger "<指纹>"] [--service <svc>] [--kw "<关键词>"] [--limit N]
8916
- show <case_id>
8917
- upload --file <报告.html> [--type slow-req] [--finger "词1,词2"] [--env] [--service]
8918
- index 案例库索引重建`,
8919
8905
  wiki: `bfi ymc wiki <search|show> [参数]
8920
8906
  知识库统一检索(confluence + jira + 文库 ecfile 三源——诊断先验的外部源,勿只查其一)。
8921
8907
  search "<关键词>" [--source confluence|jira|ecfile] [--limit N] [--titles]
@@ -8982,7 +8968,7 @@ bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
8982
8968
  sls-grep "<关键词>" -e <env> SLS 全文检索聚合(异常历史分布取证)
8983
8969
  slowsql -t <time> [-e] [--sql-str] [--md5] [--trace-id] [--app] [--no-profiler]
8984
8970
  slowcall -t <time> [-e] [--trace-id] [--app] [--method] [--min-cost ms]
8985
- [--profiler] # ⚠️ 采样过滤器实测常为空集,常规取证勿带
8971
+ [--profiler] # ⚠️ 采样过滤器常为空集,常规取证勿带
8986
8972
  exceptions -t <time> [-e] [--app]
8987
8973
  alerts -t <time> [-e] [--level error|warn|info]
8988
8974
  url-stats </uri> -t <time> -e <env> [--app <service_name>]
@@ -8994,7 +8980,6 @@ bfi ymc — 观测查询(v2 API:YMC/Kibana/SLS/trace)
8994
8980
  callstat / sqlstat 慢调用/慢SQL 统计版聚合
8995
8981
  rca <...> 官方智能诊断 RCA(长耗时)
8996
8982
  bpr-download <pk> BPR 报告下载
8997
- cases <search|show|upload|index> 案例库(KEDB)
8998
8983
  wiki search "<kw>" [--source] [--titles] 知识库统一检索(wiki/jira/文库)
8999
8984
  wiki show <id> [--source] 知识条目全文
9000
8985
  call <route> -e <env> [--data '<json>'] 通用透传(全部注册表端点)
@@ -9802,11 +9787,12 @@ ${BOLD}━━━ 技能包管理 ━━━${RESET}
9802
9787
  skills package list [--namespace <ns>] 列出技能包
9803
9788
  skills package info <ref> 查看包详情
9804
9789
  skills package create <slug> [--name] [--description] 创建包
9805
- skills package add <pkg> <skill...> 添加技能到包
9806
- skills package remove <pkg> <skill...> 从包移除技能
9790
+ skills package add-skills <pkg> <skill...> 添加技能到包
9791
+ skills package remove-skills <pkg> <skill...> 从包移除技能
9807
9792
  skills package install <ref> [--agent <a>] 安装技能组合(默认,不安装插件组件)
9808
9793
  --as plugin 显式完整插件模式;支持本地 zip/tgz,不兼容时不会降级安装
9809
9794
  --plan 只读校验安装计划;--export <archive> 仅导出,不安装
9795
+ --prepare-native <dir> 准备完整原生目录和市场索引,审阅后交给宿主安装;不注册、不转技能
9810
9796
  --agent <a> 目标 agent(如 claude-code、codex、zcode)
9811
9797
  --global 安装到主目录(跨项目可用)
9812
9798
 
@@ -9815,6 +9801,12 @@ ${BOLD}━━━ 文档 ━━━${RESET}
9815
9801
  docs list 列出文档
9816
9802
  docs info <id> 查看文档详情
9817
9803
 
9804
+ ${BOLD}━━━ MCP ━━━${RESET}
9805
+ mcp search / info 查询独立 MCP 市场
9806
+ mcp install <name...> --agent <agent> 保留已有配置,安装选定 MCP
9807
+ mcp list / remove / test --agent <agent> 管理或验证 MCP
9808
+ mcp --help 参数、支持范围与安全说明
9809
+
9818
9810
  ${BOLD}━━━ 观测查询(ymc)━━━${RESET}
9819
9811
  ymc status 登录会话状态
9820
9812
  ymc trace <trace_id> -e <env> traceId 三源合一(SLS+链路+ingress)
@@ -9831,6 +9823,7 @@ ${BOLD}━━━ DB 取证辅助(db)━━━${RESET}
9831
9823
  ytenant_id 条件且分库未知时,先定位再连)
9832
9824
 
9833
9825
  ${BOLD}━━━ 配置 ━━━${RESET}
9826
+ capabilities --json 只读查询此构建已实现的安装能力(不联网、不修改配置)
9834
9827
  config get [key] 查看配置
9835
9828
  config set <key> <value> [--global] 设置配置
9836
9829
 
@@ -9901,7 +9894,7 @@ function runInit(args) {
9901
9894
  return;
9902
9895
  }
9903
9896
  if (hasName) mkdirSync(skillDir, { recursive: true });
9904
- writeFileSync(skillFile, `---
9897
+ const skillContent = `---
9905
9898
  name: ${skillName}
9906
9899
  description: A brief description of what this skill does
9907
9900
  ---
@@ -9919,7 +9912,8 @@ Describe when this skill should be used.
9919
9912
  1. First step
9920
9913
  2. Second step
9921
9914
  3. Additional steps as needed
9922
- `);
9915
+ `;
9916
+ writeFileSync(skillFile, skillContent);
9923
9917
  console.log(`${TEXT}已初始化技能:${DIM}${skillName}${RESET}`);
9924
9918
  console.log();
9925
9919
  console.log(`${DIM}已创建:${RESET}`);
@@ -10077,6 +10071,45 @@ async function main() {
10077
10071
  }
10078
10072
  const command = args[0];
10079
10073
  const restArgs = args.slice(1);
10074
+ if (command === "capabilities") {
10075
+ if (restArgs.some((argument) => argument !== "--json")) {
10076
+ console.error("用法:bfi capabilities [--json]");
10077
+ process.exitCode = 1;
10078
+ return;
10079
+ }
10080
+ console.log(JSON.stringify(getCapabilities(VERSION), null, 2));
10081
+ return;
10082
+ }
10083
+ const { dispatchInstallation } = await import("./_chunks/command.mjs");
10084
+ if (await dispatchInstallation(args)) return;
10085
+ const installationError = installationArgumentError(args);
10086
+ if (installationError) {
10087
+ console.error(installationError);
10088
+ process.exitCode = 1;
10089
+ return;
10090
+ }
10091
+ if (command === "mcp") {
10092
+ const { runMcp } = await import("./_chunks/mcp.mjs");
10093
+ await runMcp(restArgs);
10094
+ return;
10095
+ }
10096
+ const packageRoute = ["skills", "skill"].includes(command) ? restArgs : args;
10097
+ if (["package", "pkg"].includes(packageRoute[0] ?? "") && packageRoute.some((argument) => argument === "--as" || argument.startsWith("--as="))) {
10098
+ const intent = parsePackageIntent(packageRoute.slice(1));
10099
+ if (intent.mode === "plugin") {
10100
+ const pluginOpts = {
10101
+ workdir: process.cwd(),
10102
+ version: VERSION
10103
+ };
10104
+ for (const name of ["registry", "token"]) {
10105
+ const index = args.indexOf(`--${name}`);
10106
+ if (index >= 0) pluginOpts[name] = args[index + 1];
10107
+ }
10108
+ const { runPluginPackage } = await import("./_chunks/package-plugin.mjs");
10109
+ await runPluginPackage(intent.args, pluginOpts);
10110
+ return;
10111
+ }
10112
+ }
10080
10113
  try {
10081
10114
  const { maybePrintAnalyticsNotice } = await Promise.resolve().then(() => analytics_exports);
10082
10115
  maybePrintAnalyticsNotice();
@@ -10228,4 +10261,4 @@ main().catch((e) => {
10228
10261
  console.error(`✗ ${e?.message || e}`);
10229
10262
  process.exit(1);
10230
10263
  });
10231
- export { isPluginArchive, isPluginVersion, parsePluginArguments };
10264
+ export { SkillHubAPI, getAgentBaseDir };