bfi-cli 0.1.35 → 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 +84 -17
- 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();
|
|
@@ -4115,19 +4120,18 @@ async function promptForBfiSkill(options, targetAgents) {
|
|
|
4115
4120
|
console.log();
|
|
4116
4121
|
log.step("正在安装 skillhub-skills 技能...");
|
|
4117
4122
|
try {
|
|
4118
|
-
await runAdd(["
|
|
4119
|
-
skill: ["skillhub-skills"],
|
|
4123
|
+
await runAdd(["@global/skillhub-skills"], {
|
|
4120
4124
|
global: true,
|
|
4121
4125
|
yes: true,
|
|
4122
4126
|
agent: bfiSkillAgents
|
|
4123
4127
|
});
|
|
4124
4128
|
} catch {
|
|
4125
4129
|
log.warn("安装 skillhub-skills 失败。你可以稍后重试:");
|
|
4126
|
-
log.message(import_picocolors.default.dim(" bfi skills add
|
|
4130
|
+
log.message(import_picocolors.default.dim(" bfi skills add @global/skillhub-skills -g -y"));
|
|
4127
4131
|
}
|
|
4128
4132
|
} else {
|
|
4129
4133
|
await dismissPrompt("bfiSkillPrompt");
|
|
4130
|
-
log.message(import_picocolors.default.dim("你可以稍后通过以下命令安装:bfi skills add
|
|
4134
|
+
log.message(import_picocolors.default.dim("你可以稍后通过以下命令安装:bfi skills add @global/skillhub-skills -g -y"));
|
|
4131
4135
|
}
|
|
4132
4136
|
} catch {}
|
|
4133
4137
|
}
|
|
@@ -5040,7 +5044,29 @@ async function updateGlobalSkills(options = {}) {
|
|
|
5040
5044
|
let tempDir = null;
|
|
5041
5045
|
process.stdout.write(`\r${DIM$9}Checking skills from source: ${source}${RESET$9}\x1b[K\n`);
|
|
5042
5046
|
if (firstEntry.sourceType === "skillhub") {
|
|
5043
|
-
|
|
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
|
+
}
|
|
5044
5070
|
continue;
|
|
5045
5071
|
}
|
|
5046
5072
|
try {
|
|
@@ -5221,6 +5247,32 @@ async function updateProjectSkills(options = {}) {
|
|
|
5221
5247
|
const firstEntry = skillsForSource[0].entry;
|
|
5222
5248
|
const sourceUrl = firstEntry.sourceUrl || firstEntry.source;
|
|
5223
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
|
+
}
|
|
5224
5276
|
const allLockedForSource = Object.entries(localLock.skills).filter(([_, entry]) => (entry.sourceUrl || entry.source) === source).map(([name, _]) => name);
|
|
5225
5277
|
let tempDir = null;
|
|
5226
5278
|
let deletedSkills = [];
|
|
@@ -6579,6 +6631,7 @@ function truncate(text, maxLen) {
|
|
|
6579
6631
|
if (text.length <= maxLen) return text;
|
|
6580
6632
|
return text.slice(0, maxLen) + "...";
|
|
6581
6633
|
}
|
|
6634
|
+
var package_exports = /* @__PURE__ */ __exportAll({ runPackage: () => runPackage });
|
|
6582
6635
|
const RESET$3 = "\x1B[0m";
|
|
6583
6636
|
const BOLD$1 = "\x1B[1m";
|
|
6584
6637
|
const DIM$3 = "\x1B[38;5;102m";
|
|
@@ -6998,7 +7051,16 @@ const GREEN = "\x1B[32m";
|
|
|
6998
7051
|
const YELLOW = "\x1B[33m";
|
|
6999
7052
|
async function runInstall(args, globalOpts) {
|
|
7000
7053
|
const yes = args.includes("--yes") || args.includes("-y");
|
|
7001
|
-
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 {}
|
|
7002
7064
|
const skillEntries = Object.entries(lock.skills);
|
|
7003
7065
|
const packageEntries = Object.entries(lock.packages);
|
|
7004
7066
|
if (skillEntries.length === 0 && packageEntries.length === 0) {
|
|
@@ -7015,39 +7077,44 @@ async function runInstall(args, globalOpts) {
|
|
|
7015
7077
|
let failedCount = 0;
|
|
7016
7078
|
for (const [skillName, entry] of skillEntries) {
|
|
7017
7079
|
const skillEntry = entry;
|
|
7018
|
-
const sourceType = String(skillEntry.sourceType || "");
|
|
7080
|
+
const sourceType = String(skillEntry.sourceType || skillEntry.source || "");
|
|
7019
7081
|
const namespace = String(skillEntry.namespace || "global");
|
|
7020
7082
|
const slug = String(skillEntry.slug || skillName);
|
|
7021
7083
|
const source = String(skillEntry.source || "");
|
|
7022
|
-
String(skillEntry.version || "latest");
|
|
7023
7084
|
let installSource;
|
|
7024
|
-
if (sourceType === "skillhub"
|
|
7025
|
-
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;
|
|
7026
7088
|
else {
|
|
7027
|
-
console.log(` ${YELLOW}跳过 ${skillName}
|
|
7089
|
+
console.log(` ${YELLOW}跳过 ${skillName}:未知源类型 (${sourceType})${RESET$1}`);
|
|
7028
7090
|
continue;
|
|
7029
7091
|
}
|
|
7030
|
-
console.log(` ${TEXT$1}
|
|
7092
|
+
console.log(` ${TEXT$1}正在安装 ${installSource}...${RESET$1}`);
|
|
7031
7093
|
try {
|
|
7032
7094
|
await runAdd([installSource], { yes });
|
|
7033
7095
|
installedCount++;
|
|
7034
7096
|
console.log(` ${GREEN}✓ ${skillName}${RESET$1}`);
|
|
7035
7097
|
} catch (error) {
|
|
7036
7098
|
failedCount++;
|
|
7037
|
-
console.error(` ${YELLOW}
|
|
7099
|
+
console.error(` ${YELLOW}✗ ${error.message}${RESET$1}`);
|
|
7038
7100
|
}
|
|
7039
7101
|
}
|
|
7040
7102
|
for (const [pkgRef, entry] of packageEntries) {
|
|
7041
7103
|
const pkgEntry = entry;
|
|
7042
|
-
const
|
|
7043
|
-
|
|
7104
|
+
const namespace = String(pkgEntry.namespace || "global");
|
|
7105
|
+
const slug = String(pkgEntry.slug || pkgRef);
|
|
7106
|
+
console.log(` ${TEXT$1}正在安装包 @${namespace}/${slug}...${RESET$1}`);
|
|
7044
7107
|
try {
|
|
7045
|
-
|
|
7108
|
+
const { runPackage } = await Promise.resolve().then(() => package_exports);
|
|
7109
|
+
await runPackage(["install", `@${namespace}/${slug}`], {
|
|
7110
|
+
...globalOpts,
|
|
7111
|
+
yes
|
|
7112
|
+
});
|
|
7046
7113
|
installedCount++;
|
|
7047
7114
|
console.log(` ${GREEN}✓ ${pkgRef}${RESET$1}`);
|
|
7048
7115
|
} catch (error) {
|
|
7049
7116
|
failedCount++;
|
|
7050
|
-
console.error(` ${YELLOW}
|
|
7117
|
+
console.error(` ${YELLOW}✗ ${error.message}${RESET$1}`);
|
|
7051
7118
|
}
|
|
7052
7119
|
}
|
|
7053
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 字段。
|