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 +81 -13
- package/package.json +1 -1
- package/skills/skillhub-skills/SKILL.md +48 -114
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
|
-
|
|
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
|
|
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"
|
|
7024
|
-
else if (
|
|
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}
|
|
7089
|
+
console.log(` ${YELLOW}跳过 ${skillName}:未知源类型 (${sourceType})${RESET$1}`);
|
|
7027
7090
|
continue;
|
|
7028
7091
|
}
|
|
7029
|
-
console.log(` ${TEXT$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}
|
|
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
|
|
7042
|
-
|
|
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
|
-
|
|
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}
|
|
7117
|
+
console.error(` ${YELLOW}✗ ${error.message}${RESET$1}`);
|
|
7050
7118
|
}
|
|
7051
7119
|
}
|
|
7052
7120
|
console.log();
|
package/package.json
CHANGED
|
@@ -7,24 +7,18 @@ description: 使用 bfi CLI 在 SkillHub 上搜索、安装、发布和管理技
|
|
|
7
7
|
|
|
8
8
|
bfi 是 SkillHub 生态的统一命令行工具。融合了开源 agent skills 生态能力和 SkillHub 专有功能。
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 第零步:检查 bfi CLI 是否安装
|
|
11
11
|
|
|
12
|
-
|
|
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
|
-
|
|
33
|
+
## ⚠️ 关键区分:使用 vs 管理
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
- **使用**:只读取 SkillHub 数据或操作本地文件。包括:搜索、查看、安装、卸载、更新、列表、日志。
|
|
36
|
+
- **管理**:会修改 SkillHub 服务端数据,需要写权限。包括:发布技能、创建包、添加/移除包内技能。
|
|
45
37
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
### 场景 1:使用技能(搜索、安装、使用、查看)
|
|
38
|
+
---
|
|
49
39
|
|
|
50
|
-
|
|
40
|
+
## 场景 1:使用技能
|
|
51
41
|
|
|
52
|
-
|
|
42
|
+
### 1.1 搜索
|
|
53
43
|
```bash
|
|
54
|
-
bfi skills search <关键词>
|
|
55
|
-
bfi skills search <关键词> --marketplace #
|
|
44
|
+
bfi skills search <关键词>
|
|
45
|
+
bfi skills search <关键词> --marketplace # skills.sh 公开市场
|
|
56
46
|
```
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
### 1.2 查看详情
|
|
59
49
|
```bash
|
|
60
50
|
bfi skills info <@namespace/slug 或 namespace--slug>
|
|
61
51
|
```
|
|
62
52
|
|
|
63
|
-
|
|
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
|
-
|
|
61
|
+
### 1.4 安装技能包
|
|
83
62
|
```bash
|
|
84
|
-
bfi skills package install @namespace/
|
|
63
|
+
bfi skills package install @namespace/pkg
|
|
85
64
|
```
|
|
86
65
|
|
|
87
|
-
|
|
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
|
-
|
|
72
|
+
### 1.6 卸载
|
|
94
73
|
```bash
|
|
95
|
-
bfi skills
|
|
74
|
+
bfi skills remove <技能名> -y
|
|
96
75
|
```
|
|
97
76
|
|
|
98
|
-
###
|
|
99
|
-
|
|
100
|
-
用户想发布技能、管理包、更新/卸载技能。
|
|
101
|
-
|
|
102
|
-
**2.1 发布技能**
|
|
77
|
+
### 1.7 更新
|
|
103
78
|
```bash
|
|
104
|
-
|
|
105
|
-
bfi skills
|
|
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
|
-
|
|
83
|
+
### 1.8 记录调用
|
|
121
84
|
```bash
|
|
122
|
-
bfi skills
|
|
85
|
+
bfi skills log <技能名> "简要描述"
|
|
123
86
|
```
|
|
124
87
|
|
|
125
|
-
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 场景 2:管理技能
|
|
91
|
+
|
|
92
|
+
### 2.1 发布
|
|
126
93
|
```bash
|
|
127
|
-
bfi skills
|
|
128
|
-
bfi skills
|
|
129
|
-
#
|
|
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
|
-
|
|
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` |
|
|
166
|
-
| `ns--slug` |
|
|
167
|
-
| `owner/repo` |
|
|
168
|
-
| `github:owner/repo` |
|
|
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
|
|
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 字段。
|