bfi-cli 0.1.36 → 0.1.38

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
@@ -905,6 +905,11 @@ function setConfigValue(key, value, isGlobal = false) {
905
905
  saveProjectConfig(workdir, config);
906
906
  }
907
907
  }
908
+ var skill_ref_exports = /* @__PURE__ */ __exportAll({
909
+ parseSkillRef: () => parseSkillRef,
910
+ toCanonicalSlug: () => toCanonicalSlug,
911
+ toSkillRefString: () => toSkillRefString
912
+ });
908
913
  function parseSkillRef(ref, defaultNamespace = "global") {
909
914
  if (!ref || typeof ref !== "string") throw new Error("Skill reference is required");
910
915
  const trimmed = ref.trim();
@@ -5039,7 +5044,29 @@ async function updateGlobalSkills(options = {}) {
5039
5044
  let tempDir = null;
5040
5045
  process.stdout.write(`\r${DIM$9}Checking skills from source: ${source}${RESET$9}\x1b[K\n`);
5041
5046
  if (firstEntry.sourceType === "skillhub") {
5042
- console.log(` ${DIM$9}SkillHub 技能请使用 bfi skills add 重新安装来更新${RESET$9}`);
5047
+ const skillhubRef = source.replace(/^skillhub:/, "");
5048
+ const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
5049
+ const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
5050
+ const { resolveConfig } = await Promise.resolve().then(() => config_exports);
5051
+ const cfg = resolveConfig({});
5052
+ new SkillHubAPI(cfg.registry, cfg.token);
5053
+ for (const item of itemsForSource) {
5054
+ const safeName = sanitizeMetadata(item.name);
5055
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5056
+ try {
5057
+ const parts = skillhubRef.split("/");
5058
+ const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
5059
+ const { runAdd } = await Promise.resolve().then(() => add_exports);
5060
+ await runAdd([ref], {
5061
+ global: options.global,
5062
+ yes: true
5063
+ });
5064
+ successCount++;
5065
+ } catch (error) {
5066
+ console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5067
+ failCount++;
5068
+ }
5069
+ }
5043
5070
  continue;
5044
5071
  }
5045
5072
  try {
@@ -5220,6 +5247,32 @@ async function updateProjectSkills(options = {}) {
5220
5247
  const firstEntry = skillsForSource[0].entry;
5221
5248
  const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
5222
5249
  const ref = firstEntry.ref;
5250
+ if (firstEntry.sourceType === "skillhub") {
5251
+ const skillhubRef = source.replace(/^skillhub:/, "");
5252
+ const { parseSkillRef, toCanonicalSlug } = await Promise.resolve().then(() => skill_ref_exports);
5253
+ const { SkillHubAPI } = await Promise.resolve().then(() => api_exports);
5254
+ const { resolveConfig } = await Promise.resolve().then(() => config_exports);
5255
+ const cfg = resolveConfig({});
5256
+ new SkillHubAPI(cfg.registry, cfg.token);
5257
+ for (const item of skillsForSource) {
5258
+ const safeName = sanitizeMetadata(item.name);
5259
+ console.log(`${TEXT$7}正在更新 ${safeName}...${RESET$9}`);
5260
+ try {
5261
+ const parts = skillhubRef.split("/");
5262
+ const ref = parts.length === 2 ? `@${parts[0]}/${parts[1]}` : skillhubRef;
5263
+ const { runAdd } = await Promise.resolve().then(() => add_exports);
5264
+ await runAdd([ref], {
5265
+ global: false,
5266
+ yes: true
5267
+ });
5268
+ successCount++;
5269
+ } catch (error) {
5270
+ console.log(` ${DIM$9}✗ ${safeName}: ${error.message}${RESET$9}`);
5271
+ failCount++;
5272
+ }
5273
+ }
5274
+ continue;
5275
+ }
5223
5276
  const allLockedForSource = Object.entries(localLock.skills).filter(([_, entry]) => (entry.sourceUrl || entry.source) === source).map(([name, _]) => name);
5224
5277
  let tempDir = null;
5225
5278
  let deletedSkills = [];
@@ -6578,6 +6631,7 @@ function truncate(text, maxLen) {
6578
6631
  if (text.length <= maxLen) return text;
6579
6632
  return text.slice(0, maxLen) + "...";
6580
6633
  }
6634
+ var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
6581
6635
  const RESET$3 = "\x1B[0m";
6582
6636
  const BOLD$1 = "\x1B[1m";
6583
6637
  const DIM$3 = "\x1B[38;5;102m";
@@ -6997,7 +7051,16 @@ const GREEN = "\x1B[32m";
6997
7051
  const YELLOW = "\x1B[33m";
6998
7052
  async function runInstall(args, globalOpts) {
6999
7053
  const yes = args.includes("--yes") || args.includes("-y");
7000
- const lock = loadLockfile(globalOpts.workdir || process.cwd());
7054
+ const workdir = globalOpts.workdir || process.cwd();
7055
+ const lock = loadLockfile(workdir);
7056
+ try {
7057
+ const skillsLock = await readLocalLock(workdir);
7058
+ for (const [name, entry] of Object.entries(skillsLock.skills)) if (!lock.skills[name]) lock.skills[name] = {
7059
+ ...entry,
7060
+ namespace: "global",
7061
+ slug: name
7062
+ };
7063
+ } catch {}
7001
7064
  const skillEntries = Object.entries(lock.skills);
7002
7065
  const packageEntries = Object.entries(lock.packages);
7003
7066
  if (skillEntries.length === 0 && packageEntries.length === 0) {
@@ -7014,39 +7077,44 @@ async function runInstall(args, globalOpts) {
7014
7077
  let failedCount = 0;
7015
7078
  for (const [skillName, entry] of skillEntries) {
7016
7079
  const skillEntry = entry;
7017
- const sourceType = String(skillEntry.sourceType || "");
7080
+ const sourceType = String(skillEntry.sourceType || skillEntry.source || "");
7018
7081
  const namespace = String(skillEntry.namespace || "global");
7019
7082
  const slug = String(skillEntry.slug || skillName);
7020
7083
  const source = String(skillEntry.source || "");
7021
- String(skillEntry.version || "latest");
7022
7084
  let installSource;
7023
- if (sourceType === "skillhub" || namespace !== "global") installSource = `@${namespace}/${slug}`;
7024
- else if (source) installSource = source;
7085
+ if (sourceType === "skillhub") installSource = `@${namespace}/${slug}`;
7086
+ else if (sourceType === "github" || sourceType === "gitlab") installSource = source;
7087
+ else if (source && (source.startsWith("http://") || source.startsWith("https://") || source.startsWith("git@"))) installSource = source;
7025
7088
  else {
7026
- console.log(` ${YELLOW}跳过 ${skillName}:未知源类型${RESET$1}`);
7089
+ console.log(` ${YELLOW}跳过 ${skillName}:未知源类型 (${sourceType})${RESET$1}`);
7027
7090
  continue;
7028
7091
  }
7029
- console.log(` ${TEXT$1}正在从 ${installSource} 安装 ${skillName}...${RESET$1}`);
7092
+ console.log(` ${TEXT$1}正在安装 ${installSource}...${RESET$1}`);
7030
7093
  try {
7031
7094
  await runAdd([installSource], { yes });
7032
7095
  installedCount++;
7033
7096
  console.log(` ${GREEN}✓ ${skillName}${RESET$1}`);
7034
7097
  } catch (error) {
7035
7098
  failedCount++;
7036
- console.error(` ${YELLOW}失败:${error.message}${RESET$1}`);
7099
+ console.error(` ${YELLOW}✗ ${error.message}${RESET$1}`);
7037
7100
  }
7038
7101
  }
7039
7102
  for (const [pkgRef, entry] of packageEntries) {
7040
7103
  const pkgEntry = entry;
7041
- const installSource = `@${String(pkgEntry.namespace || "global")}/${String(pkgEntry.slug || pkgRef)}`;
7042
- console.log(` ${TEXT$1}正在从 ${installSource} 安装包 ${pkgRef}...${RESET$1}`);
7104
+ const namespace = String(pkgEntry.namespace || "global");
7105
+ const slug = String(pkgEntry.slug || pkgRef);
7106
+ console.log(` ${TEXT$1}正在安装包 @${namespace}/${slug}...${RESET$1}`);
7043
7107
  try {
7044
- await runAdd([installSource], { yes });
7108
+ const { runPackage } = await Promise.resolve().then(() => package_exports);
7109
+ await runPackage(["install", `@${namespace}/${slug}`], {
7110
+ ...globalOpts,
7111
+ yes
7112
+ });
7045
7113
  installedCount++;
7046
7114
  console.log(` ${GREEN}✓ ${pkgRef}${RESET$1}`);
7047
7115
  } catch (error) {
7048
7116
  failedCount++;
7049
- console.error(` ${YELLOW}失败:${error.message}${RESET$1}`);
7117
+ console.error(` ${YELLOW}✗ ${error.message}${RESET$1}`);
7050
7118
  }
7051
7119
  }
7052
7120
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfi-cli",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "用友大业财BFI统一命令行工具,支持技能,技能包,元数据,UI元数据等",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,24 +7,18 @@ description: 使用 bfi CLI 在 SkillHub 上搜索、安装、发布和管理技
7
7
 
8
8
  bfi 是 SkillHub 生态的统一命令行工具。融合了开源 agent skills 生态能力和 SkillHub 专有功能。
9
9
 
10
- ## ⚠️ 第零步:检查 bfi CLI 是否安装(最早执行)
10
+ ## 第零步:检查 bfi CLI 是否安装
11
11
 
12
- **在执行任何 SkillHub 操作之前,必须先确认 bfi CLI 已安装。**
13
-
14
- 静默运行 `bfi --version`。如果返回错误或未找到命令:
12
+ 静默运行 `bfi --version`。如果未找到:
15
13
 
16
14
  ```
17
15
  需要安装 bfi CLI 工具。正在安装:
18
-
19
- ```bash
20
16
  npm install -g bfi-cli
21
17
  ```
22
18
 
23
- 安装完成后,继续执行后续步骤。
19
+ ## 第一步:检查登录状态
24
20
 
25
- **在做任何操作之前,必须先确认用户已登录。**
26
-
27
- 静默运行 `bfi whoami`。如果返回错误或未认证:
21
+ 静默运行 `bfi whoami`。如果未认证:
28
22
 
29
23
  ```
30
24
  你需要登录 SkillHub 才能继续。请提供你的 API Token。
@@ -34,154 +28,94 @@ npm install -g bfi-cli
34
28
  请直接回复你的 Token,我会自动完成登录。
35
29
  ```
36
30
 
37
- 用户提供 Token 后,立即静默执行:
38
- ```bash
39
- bfi auth login --token <用户提供的Token>
40
- ```
31
+ 用户提供 Token 后,立即执行 `bfi auth login --token <Token>`。登录成功后继续用户原请求。
41
32
 
42
- 登录成功后,继续执行用户原本请求的操作,无需用户再次输入。如果登录失败,告知用户 Token 无效,请重新提供。
33
+ ## ⚠️ 关键区分:使用 vs 管理
43
34
 
44
- ## 判断场景
35
+ - **使用**:只读取 SkillHub 数据或操作本地文件。包括:搜索、查看、安装、卸载、更新、列表、日志。
36
+ - **管理**:会修改 SkillHub 服务端数据,需要写权限。包括:发布技能、创建包、添加/移除包内技能。
45
37
 
46
- 根据用户意图选择对应场景:
47
-
48
- ### 场景 1:使用技能(搜索、安装、使用、查看)
38
+ ---
49
39
 
50
- 用户想找技能、安装技能、试用技能、查看已安装的技能。
40
+ ## 场景 1:使用技能
51
41
 
52
- **1.1 搜索技能**
42
+ ### 1.1 搜索
53
43
  ```bash
54
- bfi skills search <关键词> # 搜索 SkillHub(默认)
55
- bfi skills search <关键词> --marketplace # 搜索 skills.sh 公开市场
44
+ bfi skills search <关键词>
45
+ bfi skills search <关键词> --marketplace # skills.sh 公开市场
56
46
  ```
57
47
 
58
- **1.2 查看技能详情**
48
+ ### 1.2 查看详情
59
49
  ```bash
60
50
  bfi skills info <@namespace/slug 或 namespace--slug>
61
51
  ```
62
52
 
63
- **1.3 安装技能**
53
+ ### 1.3 安装
64
54
  ```bash
65
- # SkillHub
66
- bfi skills add @命名空间/技能名
67
- bfi skills add 命名空间--技能名
68
-
69
- # Git 仓库(默认 git.yyrd.com)
70
- bfi skills add owner/repo --skill <name> # 指定仓库中的某个技能
71
- bfi skills add owner/repo # 安装全部技能
72
- bfi skills add owner/repo --branch <分支> # 指定分支
73
-
74
- # GitHub
75
- bfi skills add github:owner/repo # 强制走 github.com
76
-
77
- # 安装选项
78
- bfi skills add <来源> -y # 跳过交互确认
79
- bfi skills add <来源> --list # 仅列出技能,不安装
55
+ bfi skills add @命名空间/技能名 # SkillHub
56
+ bfi skills add owner/repo --skill <name> # Git 仓库(默认 git.yyrd.com)
57
+ bfi skills add github:owner/repo # GitHub
58
+ bfi skills add <来源> -y # 跳过确认
80
59
  ```
81
60
 
82
- **1.4 安装技能包**
61
+ ### 1.4 安装技能包
83
62
  ```bash
84
- bfi skills package install @namespace/package-name
63
+ bfi skills package install @namespace/pkg
85
64
  ```
86
65
 
87
- **1.5 查看已安装**
66
+ ### 1.5 查看已安装
88
67
  ```bash
89
68
  bfi skills list
90
- bfi skills ls -g # 全局安装的技能
69
+ bfi skills ls -g # 全局
91
70
  ```
92
71
 
93
- **1.6 使用技能(不安装)**
72
+ ### 1.6 卸载
94
73
  ```bash
95
- bfi skills use <来源> # 生成 prompt 文本
74
+ bfi skills remove <技能名> -y
96
75
  ```
97
76
 
98
- ### 场景 2:管理技能(发布、更新、卸载、包管理)
99
-
100
- 用户想发布技能、管理包、更新/卸载技能。
101
-
102
- **2.1 发布技能**
77
+ ### 1.7 更新
103
78
  ```bash
104
- # 从 Git 发布(推荐,自动发现所有技能)
105
- bfi skills publish owner/repo --from git --namespace <ns>
106
-
107
- # 从本地目录发布
108
- bfi skills publish <路径> --namespace <ns>
109
-
110
- # 从 ZIP 发布
111
- bfi skills publish <路径> --from zip --namespace <ns>
112
-
113
- # 选项
114
- # --visibility public 公开发布(默认)
115
- # --branch <分支> 指定分支(默认 main)
116
- # --skill <name> 只发布指定技能
117
- # -y 跳过确认
79
+ bfi skills update
80
+ bfi skills update <技能名>
118
81
  ```
119
82
 
120
- **2.2 卸载技能**
83
+ ### 1.8 记录调用
121
84
  ```bash
122
- bfi skills remove <技能名> -y
85
+ bfi skills log <技能名> "简要描述"
123
86
  ```
124
87
 
125
- **2.3 更新技能**
88
+ ---
89
+
90
+ ## 场景 2:管理技能
91
+
92
+ ### 2.1 发布
126
93
  ```bash
127
- bfi skills update # 更新全部
128
- bfi skills update <技能名>
129
- # Git 来源的技能会检查远端更新
130
- # SkillHub 来源的技能请用 bfi skills add 重新安装
94
+ bfi skills publish owner/repo --from git --namespace <ns>
95
+ bfi skills publish <路径> --namespace <ns>
96
+ # 选项:--branch <分支>、--skill <name>、--visibility public(默认)、-y
131
97
  ```
132
98
 
133
- **2.4 技能包管理**
99
+ ### 2.2 技能包管理(服务端)
134
100
  ```bash
135
- # 创建包
136
101
  bfi skills package create <slug> --namespace <ns>
137
-
138
- # 添加技能到包
139
102
  bfi skills package add-skills @ns/pkg <skill...>
140
-
141
- # 从包移除技能
142
103
  bfi skills package remove-skills @ns/pkg <skill...>
143
-
144
- # 安装包
145
- bfi skills package install @ns/pkg
146
-
147
- # 卸载包
148
- bfi skills package uninstall @ns/pkg
149
-
150
- # 查看已安装的包
151
- bfi skills package list
152
- ```
153
-
154
- ### 场景 3:记录技能调用
155
-
156
- **每次使用技能时必须记录:**
157
- ```bash
158
- bfi skills log <技能名> "简要描述"
159
104
  ```
160
105
 
161
106
  ## 技能引用格式
162
107
 
163
- | 格式 | 示例 | 说明 |
164
- |------|------|------|
165
- | `@ns/slug` | `@retail/skill-pm` | SkillHub 技能 |
166
- | `ns--slug` | `retail--skill-pm` | 兼容格式 |
167
- | `owner/repo` | `bfi/bfi-skill` | Git 仓库(默认 git.yyrd.com) |
168
- | `github:owner/repo` | `github:vercel-labs/agent-skills` | 强制 GitHub |
108
+ | 格式 | 说明 |
109
+ |------|------|
110
+ | `@ns/slug` | SkillHub 技能 |
111
+ | `ns--slug` | 兼容格式 |
112
+ | `owner/repo` | Git 仓库(默认 git.yyrd.com) |
113
+ | `github:owner/repo` | 强制 GitHub |
169
114
 
170
115
  ## 配置
171
116
 
172
117
  ```bash
173
- bfi config get # 查看全部配置
174
- bfi config set registry <url> --global # 设置 API 地址
175
- bfi config set namespace <ns> # 设置默认命名空间
118
+ bfi config get
119
+ bfi config set registry <url> --global
120
+ bfi config set namespace <ns>
176
121
  ```
177
-
178
- ## 常见问题
179
-
180
- **Q: 公司 GitLab 仓库中的技能找不到?**
181
- A: 默认从 git.yyrd.com 克隆。如果是 GitHub 上的技能,使用 `github:` 前缀。
182
-
183
- **Q: 如何更新 SkillHub 上的技能?**
184
- A: 用 `bfi skills publish` 重新发布即可,服务端自动版本管理。
185
-
186
- **Q: 发布失败?**
187
- A: 确保 SKILL.md 文件在发布目录或仓库中,且包含 name 和 description 字段。