bfi-cli 0.1.25 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +169 -43
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -136,7 +136,30 @@ function parseSource(input) {
136
136
  const alias = SOURCE_ALIASES[input];
137
137
  if (alias) input = alias;
138
138
  const githubPrefixMatch = input.match(/^github:(.+)$/);
139
- if (githubPrefixMatch) return parseSource(appendFragmentRef(githubPrefixMatch[1], fragmentRef, fragmentSkillFilter));
139
+ if (githubPrefixMatch) {
140
+ const rest = githubPrefixMatch[1];
141
+ const atSkill = rest.match(/^([^/]+)\/([^/@]+)@(.+)$/);
142
+ if (atSkill && !rest.includes(":")) {
143
+ const [, owner, repo, skillFilter] = atSkill;
144
+ return {
145
+ type: "github",
146
+ url: `https://github.com/${owner}/${repo}.git`,
147
+ ...fragmentRef ? { ref: fragmentRef } : {},
148
+ skillFilter: fragmentSkillFilter || skillFilter
149
+ };
150
+ }
151
+ const shorthand = rest.match(/^([^/]+)\/([^/]+)(?:\/(.+?))?\/?$/);
152
+ if (shorthand && !rest.includes(":") && !rest.startsWith(".")) {
153
+ const [, owner, repo, subpath] = shorthand;
154
+ return {
155
+ type: "github",
156
+ url: `https://github.com/${owner}/${repo}.git`,
157
+ ...fragmentRef ? { ref: fragmentRef } : {},
158
+ subpath: subpath ? sanitizeSubpath(subpath) : subpath,
159
+ ...fragmentSkillFilter ? { skillFilter: fragmentSkillFilter } : {}
160
+ };
161
+ }
162
+ }
140
163
  const gitlabPrefixMatch = input.match(/^gitlab:(.+)$/);
141
164
  if (gitlabPrefixMatch) return parseSource(appendFragmentRef(`https://gitlab.com/${gitlabPrefixMatch[1]}`, fragmentRef, fragmentSkillFilter));
142
165
  const githubTreeWithPathMatch = input.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)/);
@@ -4448,6 +4471,7 @@ async function cloneWithGitHubFallback(url, ref, spinner) {
4448
4471
  }
4449
4472
  }
4450
4473
  async function installFromSkillHub(parsed, options, spinner) {
4474
+ let tempDir = null;
4451
4475
  const config = resolveConfig();
4452
4476
  const api = new SkillHubAPI(config.registry, config.token);
4453
4477
  const rawRef = parsed.url.startsWith("skillhub:") ? parsed.url.slice(9) : parsed.url;
@@ -4469,6 +4493,15 @@ async function installFromSkillHub(parsed, options, spinner) {
4469
4493
  return (b.score || 0) - (a.score || 0);
4470
4494
  }).slice(0, 20);
4471
4495
  if (hits.length === 0) {
4496
+ spinner.stop("SkillHub 未找到,尝试作为 Git 仓库...");
4497
+ const gitSource = parseSource(rawRef);
4498
+ if (gitSource.type === "git" || gitSource.type === "github" || gitSource.type === "gitlab") {
4499
+ tempDir = await cloneWithGitHubFallback(gitSource.url, gitSource.ref, spinner);
4500
+ return {
4501
+ skills: await discoverSkills(tempDir, gitSource.subpath, { includeInternal: true }),
4502
+ tempDir
4503
+ };
4504
+ }
4472
4505
  spinner.stop(import_picocolors.default.red("无结果"));
4473
4506
  outro(import_picocolors.default.red(`No skills found on SkillHub for "${rawRef}".`));
4474
4507
  process.exit(1);
@@ -4513,7 +4546,7 @@ async function installFromSkillHub(parsed, options, spinner) {
4513
4546
  }
4514
4547
  const meta = metadata;
4515
4548
  spinner.stop(`Skill: ${import_picocolors.default.cyan(`@${namespace}/${slug}`)}${meta.description ? ` — ${import_picocolors.default.dim(meta.description)}` : ""}`);
4516
- const tempDir = join(tmpdir(), `.bfi-skillhub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
4549
+ tempDir = join(tmpdir(), `.bfi-skillhub-${canonicalSlug.replace(/[/:@]/g, "-")}-${Date.now()}`);
4517
4550
  mkdirSync(tempDir, { recursive: true });
4518
4551
  const zipPath = join(tempDir, "skill.zip");
4519
4552
  spinner.start("正在下载技能...");
@@ -6219,7 +6252,7 @@ async function updateGlobalSkills(options = {}) {
6219
6252
  console.log(` ${DIM$9}✗ Cannot update ${safeName}: lock file is missing sourceUrl for this generic Git source${RESET$9}`);
6220
6253
  continue;
6221
6254
  }
6222
- const cliEntry = join(__dirname$1, "..", "bin", "cli.mjs");
6255
+ const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
6223
6256
  if (!existsSync(cliEntry)) {
6224
6257
  failCount++;
6225
6258
  console.log(` ${DIM$9}✗ Failed to update ${safeName}: CLI entrypoint not found at ${cliEntry}${RESET$9}`);
@@ -6303,7 +6336,7 @@ async function updateProjectSkills(options = {}) {
6303
6336
  bySource.set(source, existing);
6304
6337
  }
6305
6338
  const localLock = await readLocalLock();
6306
- const cliEntry = join(__dirname$1, "..", "bin", "cli.mjs");
6339
+ const cliEntry = join(__dirname$1, "..", "bin", "bfi.mjs");
6307
6340
  if (!existsSync(cliEntry)) {
6308
6341
  console.log(`${DIM$9}✗ CLI 入口未找到 ${cliEntry}${RESET$9}`);
6309
6342
  return {
@@ -6878,29 +6911,31 @@ const MARKETPLACE_API = process.env.SKILLS_API_URL || "https://skills.sh";
6878
6911
  async function runSearch(args, globalOpts) {
6879
6912
  const query = parseSearchQuery(args);
6880
6913
  const namespace = args.includes("--namespace") ? getOptionValue$2(args, "--namespace") : void 0;
6914
+ const json = args.includes("--json");
6881
6915
  if (!query) {
6882
- console.log("用法:bfi search <query> [--namespace <ns>] [--marketplace]");
6916
+ console.log("用法:bfi search <query> [--namespace <ns>] [--marketplace] [--json]");
6883
6917
  console.log();
6884
6918
  console.log("选项:");
6885
6919
  console.log(" --namespace <ns> 按 SkillHub 命名空间筛选");
6886
6920
  console.log(" --marketplace 仅搜索 skills.sh 市场");
6887
6921
  console.log(" --all 同时搜索 SkillHub 和市场");
6922
+ console.log(" --json 以 JSON 格式输出结果");
6888
6923
  return;
6889
6924
  }
6890
6925
  const useMarketplace = args.includes("--marketplace");
6891
6926
  const searchAll = args.includes("--all");
6892
6927
  if (useMarketplace) {
6893
- await searchMarketplace(query);
6928
+ await searchMarketplace(query, json);
6894
6929
  return;
6895
6930
  }
6896
6931
  if (searchAll) {
6897
6932
  console.log(`${BOLD$5}=== SkillHub 注册表 ===${RESET$8}\n`);
6898
- await searchSkillHub(query, namespace, globalOpts);
6933
+ await searchSkillHub(query, namespace, globalOpts, json);
6899
6934
  console.log(`\n${BOLD$5}=== skills.sh 市场 ===${RESET$8}\n`);
6900
- await searchMarketplace(query);
6935
+ await searchMarketplace(query, json);
6901
6936
  return;
6902
6937
  }
6903
- await searchSkillHub(query, namespace, globalOpts);
6938
+ await searchSkillHub(query, namespace, globalOpts, json);
6904
6939
  }
6905
6940
  function parseSearchQuery(args) {
6906
6941
  const parts = [];
@@ -6915,7 +6950,7 @@ function parseSearchQuery(args) {
6915
6950
  }
6916
6951
  return parts.join(" ");
6917
6952
  }
6918
- async function searchSkillHub(query, namespace, globalOpts) {
6953
+ async function searchSkillHub(query, namespace, globalOpts, json = false) {
6919
6954
  const { registry, token } = resolveConfig(globalOpts);
6920
6955
  const api = new SkillHubAPI(registry, token);
6921
6956
  try {
@@ -6926,7 +6961,30 @@ async function searchSkillHub(query, namespace, globalOpts) {
6926
6961
  });
6927
6962
  const skills = result.results || result.data || [];
6928
6963
  if (skills.length === 0) {
6929
- console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
6964
+ if (json) console.log(JSON.stringify({
6965
+ source: "skillhub",
6966
+ count: 0,
6967
+ results: []
6968
+ }, null, 2));
6969
+ else console.log(`${DIM$8}SkillHub 上未找到 "${query}" 的技能${RESET$8}`);
6970
+ return;
6971
+ }
6972
+ if (json) {
6973
+ const results = skills.map((skill) => {
6974
+ const canonicalSlug = skill.slug || "";
6975
+ const displaySlug = canonicalSlug.indexOf("--") > 0 ? canonicalSlug : `global--${canonicalSlug}`;
6976
+ return {
6977
+ name: skill.displayName || skill.name || skill.slug,
6978
+ slug: displaySlug,
6979
+ description: skill.summary || skill.description || "",
6980
+ version: skill.version || null
6981
+ };
6982
+ });
6983
+ console.log(JSON.stringify({
6984
+ source: "skillhub",
6985
+ count: results.length,
6986
+ results
6987
+ }, null, 2));
6930
6988
  return;
6931
6989
  }
6932
6990
  console.log(`SkillHub 上找到 ${skills.length} 个技能:\n`);
@@ -6946,7 +7004,7 @@ async function searchSkillHub(query, namespace, globalOpts) {
6946
7004
  console.error(`${DIM$8}SkillHub 搜索失败:${error.message}${RESET$8}`);
6947
7005
  }
6948
7006
  }
6949
- async function searchMarketplace(query) {
7007
+ async function searchMarketplace(query, json = false) {
6950
7008
  try {
6951
7009
  const params = new URLSearchParams({
6952
7010
  q: query,
@@ -6955,12 +7013,37 @@ async function searchMarketplace(query) {
6955
7013
  const url = `${MARKETPLACE_API}/api/search?${params.toString()}`;
6956
7014
  const res = await fetch(url);
6957
7015
  if (!res.ok) {
6958
- console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
7016
+ if (json) console.log(JSON.stringify({
7017
+ source: "marketplace",
7018
+ count: 0,
7019
+ results: []
7020
+ }, null, 2));
7021
+ else console.log(`${DIM$8}skills.sh 市场无结果${RESET$8}`);
6959
7022
  return;
6960
7023
  }
6961
7024
  const skills = (await res.json()).skills || [];
6962
7025
  if (skills.length === 0) {
6963
- console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
7026
+ if (json) console.log(JSON.stringify({
7027
+ source: "marketplace",
7028
+ count: 0,
7029
+ results: []
7030
+ }, null, 2));
7031
+ else console.log(`${DIM$8}skills.sh 上未找到 "${query}" 的技能${RESET$8}`);
7032
+ return;
7033
+ }
7034
+ if (json) {
7035
+ const results = skills.slice(0, 12).map((skill) => ({
7036
+ name: skill.name,
7037
+ source: skill.source || null,
7038
+ installs: skill.installs || 0,
7039
+ url: `https://skills.sh/${skill.id}`,
7040
+ installCommand: skill.source ? `bfi skills add github:${skill.source}` : null
7041
+ }));
7042
+ console.log(JSON.stringify({
7043
+ source: "marketplace",
7044
+ count: results.length,
7045
+ results
7046
+ }, null, 2));
6964
7047
  return;
6965
7048
  }
6966
7049
  console.log(`skills.sh 上找到 ${skills.length} 个技能:\n`);
@@ -6999,19 +7082,21 @@ const YELLOW$2 = "\x1B[33m";
6999
7082
  const RED$2 = "\x1B[31m";
7000
7083
  const GREEN$4 = "\x1B[32m";
7001
7084
  async function runInfo(args, globalOpts) {
7002
- const slug = args[0];
7003
- if (!slug) {
7004
- console.log("用法:bfi info <skill-slug>");
7005
- console.log("示例:bfi info global/my-skill");
7085
+ const ref = args[0];
7086
+ if (!ref) {
7087
+ console.log("用法:bfi info <skill-ref>");
7088
+ console.log("示例:bfi info @global/my-skill");
7006
7089
  process.exit(1);
7007
7090
  }
7008
7091
  const { registry, token } = resolveConfig(globalOpts);
7009
7092
  const api = new SkillHubAPI(registry, token);
7093
+ const { namespace, slug } = parseSkillRef(ref, "global");
7094
+ const canonical = toCanonicalSlug(namespace, slug);
7010
7095
  try {
7011
- const result = await api.getSkill(slug);
7096
+ const result = await api.getSkill(canonical);
7012
7097
  const skill = result.data || result.skill || result;
7013
7098
  if (!skill || !skill.slug) {
7014
- console.log(`${DIM$7}未找到技能:${slug}${RESET$7}`);
7099
+ console.log(`${DIM$7}未找到技能:${ref}${RESET$7}`);
7015
7100
  process.exit(1);
7016
7101
  }
7017
7102
  console.log();
@@ -7072,7 +7157,7 @@ async function runInfo(args, globalOpts) {
7072
7157
  }
7073
7158
  console.log();
7074
7159
  } catch (error) {
7075
- if (error.status === 404) console.error(`未找到技能:${slug}`);
7160
+ if (error.status === 404) console.error(`未找到技能:${ref}`);
7076
7161
  else console.error(`获取技能信息失败:${error.message}`);
7077
7162
  process.exit(1);
7078
7163
  }
@@ -7683,11 +7768,11 @@ async function runPackage(args, globalOpts) {
7683
7768
  function printPackageHelp() {
7684
7769
  console.log();
7685
7770
  console.log(`${BOLD$1}包命令:${RESET$3}`);
7686
- console.log(` ${DIM$3}bfi package list${RESET$3} 列出包`);
7687
- console.log(` ${DIM$3}bfi package info <ref>${RESET$3} 查看包详情`);
7688
- console.log(` ${DIM$3}bfi package create <slug>${RESET$3} 创建新包`);
7689
- console.log(` ${DIM$3}bfi package add <pkg> <skills>${RESET$3} 添加技能到包`);
7690
- console.log(` ${DIM$3}bfi package remove <pkg> <skills>${RESET$3} 从包移除技能`);
7771
+ console.log(` ${DIM$3}bfi skills package list${RESET$3} 列出包`);
7772
+ console.log(` ${DIM$3}bfi skills package info <ref>${RESET$3} 查看包详情`);
7773
+ console.log(` ${DIM$3}bfi skills package create <slug>${RESET$3} 创建新包`);
7774
+ console.log(` ${DIM$3}bfi skills package add <pkg> [skills]${RESET$3} 添加技能到包(默认全部)`);
7775
+ console.log(` ${DIM$3}bfi skills package remove <pkg> [skills]${RESET$3} 从包移除技能(默认全部)`);
7691
7776
  console.log();
7692
7777
  console.log(`${BOLD$1}选项:${RESET$3}`);
7693
7778
  console.log(` --namespace <ns> 目标命名空间`);
@@ -7697,11 +7782,11 @@ function printPackageHelp() {
7697
7782
  console.log(` --json 以 JSON 输出`);
7698
7783
  console.log();
7699
7784
  console.log(`${BOLD$1}示例:${RESET$3}`);
7700
- console.log(` ${DIM$3}$ ${RESET$3}bfi package list --namespace myteam`);
7701
- console.log(` ${DIM$3}$ ${RESET$3}bfi package info @myteam/my-package`);
7702
- console.log(` ${DIM$3}$ ${RESET$3}bfi package create my-utils --namespace myteam`);
7703
- console.log(` ${DIM$3}$ ${RESET$3}bfi package add @myteam/my-package @myteam/skill-a @myteam/skill-b`);
7704
- console.log(` ${DIM$3}$ ${RESET$3}bfi package remove @myteam/my-package @myteam/skill-a`);
7785
+ console.log(` ${DIM$3}$ ${RESET$3}bfi skills package list --namespace myteam`);
7786
+ console.log(` ${DIM$3}$ ${RESET$3}bfi skills package info @myteam/my-package`);
7787
+ console.log(` ${DIM$3}$ ${RESET$3}bfi skills package create my-utils --namespace myteam`);
7788
+ console.log(` ${DIM$3}$ ${RESET$3}bfi skills package add @myteam/my-package @myteam/skill-a @myteam/skill-b`);
7789
+ console.log(` ${DIM$3}$ ${RESET$3}bfi skills package remove @myteam/my-package @myteam/skill-a`);
7705
7790
  console.log();
7706
7791
  }
7707
7792
  async function handleList(args, api, globalOpts) {
@@ -7711,11 +7796,15 @@ async function handleList(args, api, globalOpts) {
7711
7796
  const result = await api.listPackages(namespace);
7712
7797
  const packages = result.packages || result.data || [];
7713
7798
  if (json) {
7714
- console.log(JSON.stringify({ packages }, null, 2));
7799
+ console.log(JSON.stringify({
7800
+ namespace,
7801
+ packages
7802
+ }, null, 2));
7715
7803
  return;
7716
7804
  }
7717
7805
  if (packages.length === 0) {
7718
- console.log(`No packages found in namespace "${namespace}".`);
7806
+ console.log(`命名空间 "${namespace}" 中没有包。`);
7807
+ console.log(`使用 --namespace <ns> 查看其他命名空间,或 bfi whoami 查看你的命名空间列表。`);
7719
7808
  return;
7720
7809
  }
7721
7810
  console.log();
@@ -7739,11 +7828,11 @@ async function handleList(args, api, globalOpts) {
7739
7828
  async function handleInfo(args, api, globalOpts) {
7740
7829
  const pkgRef = args[0];
7741
7830
  if (!pkgRef) {
7742
- console.error("Usage: bfi package info <package-ref>");
7831
+ console.error("Usage: bfi skills package info <package-ref>");
7743
7832
  console.log();
7744
7833
  console.log("Examples:");
7745
- console.log(" bfi package info @myteam/my-package");
7746
- console.log(" bfi package info myteam--my-package");
7834
+ console.log(" bfi skills package info @myteam/my-package");
7835
+ console.log(" bfi skills package info myteam--my-package");
7747
7836
  process.exit(1);
7748
7837
  }
7749
7838
  const json = args.includes("--json");
@@ -7777,7 +7866,7 @@ async function handleInfo(args, api, globalOpts) {
7777
7866
  async function handleCreate(args, api, globalOpts) {
7778
7867
  const slug = args[0];
7779
7868
  if (!slug) {
7780
- console.error("用法:bfi package create <slug> [options]");
7869
+ console.error("用法:bfi skills package create <slug> [options]");
7781
7870
  process.exit(1);
7782
7871
  }
7783
7872
  const namespace = getOptionValue(args, "--namespace") || globalOpts.namespace || "global";
@@ -7805,12 +7894,33 @@ async function handleCreate(args, api, globalOpts) {
7805
7894
  async function handleAdd(args, api, globalOpts) {
7806
7895
  const pkgRef = args[0];
7807
7896
  const skillRefs = args.slice(1);
7808
- if (!pkgRef || skillRefs.length === 0) {
7809
- console.error("用法:bfi package add <package-ref> <skill-ref...>");
7897
+ if (!pkgRef) {
7898
+ console.error("用法:bfi skills package add <package-ref> [skill-ref...]");
7899
+ console.error(" 不指定技能时,添加当前命名空间的所有技能到包");
7810
7900
  process.exit(1);
7811
7901
  }
7812
7902
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7813
- const skills = skillRefs.map((ref) => {
7903
+ let skills;
7904
+ if (skillRefs.length === 0) try {
7905
+ skills = ((await api.searchSkills("", {
7906
+ namespace,
7907
+ limit: 1e3
7908
+ })).results || []).map((r) => {
7909
+ const { namespace: ns, slug: s } = parseSkillRef(r.slug, namespace);
7910
+ return {
7911
+ namespace: ns,
7912
+ slug: s
7913
+ };
7914
+ });
7915
+ if (skills.length === 0) {
7916
+ console.error(`命名空间 "${namespace}" 中没有技能。`);
7917
+ process.exit(1);
7918
+ }
7919
+ } catch (error) {
7920
+ console.error(`获取技能列表失败:${error.message}`);
7921
+ process.exit(1);
7922
+ }
7923
+ else skills = skillRefs.map((ref) => {
7814
7924
  const { namespace: skillNs, slug: skillSlug } = parseSkillRef(ref, namespace);
7815
7925
  return {
7816
7926
  namespace: skillNs,
@@ -7829,12 +7939,28 @@ async function handleAdd(args, api, globalOpts) {
7829
7939
  async function handleRemove(args, api, globalOpts) {
7830
7940
  const pkgRef = args[0];
7831
7941
  const skillRefs = args.slice(1);
7832
- if (!pkgRef || skillRefs.length === 0) {
7833
- console.error("用法:bfi package remove <package-ref> <skill-ref...>");
7942
+ if (!pkgRef) {
7943
+ console.error("用法:bfi skills package remove <package-ref> [skill-ref...]");
7944
+ console.error(" 不指定技能时,移除包中所有技能");
7834
7945
  process.exit(1);
7835
7946
  }
7836
7947
  const { namespace, slug } = parseSkillRef(pkgRef, globalOpts.namespace);
7837
- const skills = skillRefs.map((ref) => {
7948
+ let skills;
7949
+ if (skillRefs.length === 0) try {
7950
+ const existingSkills = (await api.getPackage(namespace, slug)).skills || [];
7951
+ if (existingSkills.length === 0) {
7952
+ console.log("包中没有技能。");
7953
+ return;
7954
+ }
7955
+ skills = existingSkills.map((s) => ({
7956
+ namespace: s.namespace || namespace,
7957
+ slug: s.slug
7958
+ }));
7959
+ } catch (error) {
7960
+ console.error(`获取包信息失败:${error.message}`);
7961
+ process.exit(1);
7962
+ }
7963
+ else skills = skillRefs.map((ref) => {
7838
7964
  const { namespace: skillNs, slug: skillSlug } = parseSkillRef(ref, namespace);
7839
7965
  return {
7840
7966
  namespace: skillNs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfi-cli",
3
- "version": "0.1.25",
3
+ "version": "0.1.29",
4
4
  "description": "用友大业财BFI统一命令行工具,支持技能,技能包,元数据,UI元数据等",
5
5
  "type": "module",
6
6
  "bin": {