bf-skills 1.0.1 → 1.1.0
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 +76 -57
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -41,6 +41,17 @@ function readFrontmatter(filePath) {
|
|
|
41
41
|
return {};
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
+
function shortTagline(raw) {
|
|
45
|
+
if (!raw) return "";
|
|
46
|
+
const flat = raw.replace(/\s+/g, " ").trim();
|
|
47
|
+
const periodIdx = flat.indexOf(". ");
|
|
48
|
+
const first = periodIdx > 0 ? flat.slice(0, periodIdx) : flat;
|
|
49
|
+
const text = first.replace(/^This\s+skill\s+should\s+be\s+used\s+when\s+the\s+user\s+(asks?\s+(to|about|for)\s+)?/i, "").replace(/^(Complete\s+(guide\s+for|reference\s+for|skill\s+for)?|Comprehensive\s+|Full-?(stack\s+|spectrum\s+|cycle\s+)?|Unified\s+|Expert\s+skill\s+(for|covering)\s+)/i, "").replace(/^(Use\s+(when|for|whenever)|Covers\s+|Trigger(s)?\s*(when|on)|Designed\s+to)\s+/i, "").replace(/\s+skill$/i, "").trim();
|
|
50
|
+
const result = text || first;
|
|
51
|
+
if (result.length <= 60) return result;
|
|
52
|
+
const cut = result.lastIndexOf(" ", 57);
|
|
53
|
+
return (cut > 15 ? result.slice(0, cut) : result.slice(0, 57)) + "\u2026";
|
|
54
|
+
}
|
|
44
55
|
function walkForSkills(dir, results) {
|
|
45
56
|
if (!fs.existsSync(dir)) return;
|
|
46
57
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -51,7 +62,7 @@ function walkForSkills(dir, results) {
|
|
|
51
62
|
if (fs.existsSync(skillMd)) {
|
|
52
63
|
const fm = readFrontmatter(skillMd);
|
|
53
64
|
const name = fm["name"] || entry.name;
|
|
54
|
-
const description = fm["description"] || "";
|
|
65
|
+
const description = shortTagline(fm["description"] || "");
|
|
55
66
|
results.push({ name, description, dir: skillDir });
|
|
56
67
|
}
|
|
57
68
|
}
|
|
@@ -211,7 +222,38 @@ async function runInstall(source, opts) {
|
|
|
211
222
|
p.log.error(err.message);
|
|
212
223
|
process.exit(1);
|
|
213
224
|
}
|
|
214
|
-
p.intro(
|
|
225
|
+
p.intro(pc.bold("bf-skills installer"));
|
|
226
|
+
let targetAgents;
|
|
227
|
+
if (opts.agent) {
|
|
228
|
+
if (opts.agent === "all") {
|
|
229
|
+
targetAgents = [...AGENTS];
|
|
230
|
+
} else {
|
|
231
|
+
const found = getAgentById(opts.agent);
|
|
232
|
+
if (!found) {
|
|
233
|
+
p.log.error(`Unknown agent "${opts.agent}". Use: general, claude-code, root, or all`);
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
targetAgents = [found];
|
|
237
|
+
}
|
|
238
|
+
} else if (opts.yes) {
|
|
239
|
+
targetAgents = AGENTS.filter((a) => DEFAULT_AGENT_IDS.includes(a.id));
|
|
240
|
+
} else {
|
|
241
|
+
const chosen = await p.multiselect({
|
|
242
|
+
message: "Where do you want to install skills?",
|
|
243
|
+
options: AGENTS.map((a) => ({
|
|
244
|
+
value: a.id,
|
|
245
|
+
label: a.label,
|
|
246
|
+
hint: opts.global ? a.globalPath : `./${a.projectPath}`
|
|
247
|
+
})),
|
|
248
|
+
initialValues: DEFAULT_AGENT_IDS,
|
|
249
|
+
required: true
|
|
250
|
+
});
|
|
251
|
+
if (p.isCancel(chosen)) {
|
|
252
|
+
p.cancel("Cancelled.");
|
|
253
|
+
process.exit(0);
|
|
254
|
+
}
|
|
255
|
+
targetAgents = AGENTS.filter((a) => chosen.includes(a.id));
|
|
256
|
+
}
|
|
215
257
|
let repoPath;
|
|
216
258
|
let tmpDir;
|
|
217
259
|
const isLocal = !repoUrl.startsWith("http") && !repoUrl.startsWith("git@");
|
|
@@ -220,14 +262,14 @@ async function runInstall(source, opts) {
|
|
|
220
262
|
} else {
|
|
221
263
|
tmpDir = fs3.mkdtempSync(path4.join(os2.tmpdir(), "bf-skills-"));
|
|
222
264
|
repoPath = tmpDir;
|
|
223
|
-
const
|
|
224
|
-
|
|
265
|
+
const s = p.spinner();
|
|
266
|
+
s.start("Fetching skills catalog...");
|
|
225
267
|
try {
|
|
226
268
|
await simpleGit().clone(repoUrl, repoPath, ["--depth", "1"]);
|
|
227
|
-
|
|
269
|
+
s.stop("Catalog ready");
|
|
228
270
|
} catch (err) {
|
|
229
|
-
|
|
230
|
-
p.log.error(
|
|
271
|
+
s.stop("Failed to fetch catalog");
|
|
272
|
+
p.log.error(`${err.message}`);
|
|
231
273
|
cleanup(tmpDir);
|
|
232
274
|
process.exit(1);
|
|
233
275
|
}
|
|
@@ -238,7 +280,6 @@ async function runInstall(source, opts) {
|
|
|
238
280
|
cleanup(tmpDir);
|
|
239
281
|
process.exit(1);
|
|
240
282
|
}
|
|
241
|
-
p.log.info(`Found ${allSkills.length} skill${allSkills.length === 1 ? "" : "s"}`);
|
|
242
283
|
let selectedSkills;
|
|
243
284
|
if (opts.skills && opts.skills.length > 0) {
|
|
244
285
|
selectedSkills = [];
|
|
@@ -250,72 +291,50 @@ async function runInstall(source, opts) {
|
|
|
250
291
|
process.exit(1);
|
|
251
292
|
}
|
|
252
293
|
selectedSkills.push(match);
|
|
253
|
-
p.log.step(`Installing ${COLORS.blue}${match.name}${COLORS.reset}`);
|
|
254
294
|
}
|
|
255
295
|
} else if (opts.yes) {
|
|
256
296
|
selectedSkills = allSkills;
|
|
257
297
|
} else {
|
|
258
|
-
const selected = await p.
|
|
259
|
-
message:
|
|
298
|
+
const selected = await p.autocompleteMultiselect({
|
|
299
|
+
message: `Pick skills to install (${allSkills.length} available \u2014 type to search)`,
|
|
260
300
|
options: allSkills.map((s) => ({
|
|
261
301
|
value: s.name,
|
|
262
|
-
label:
|
|
302
|
+
label: s.name,
|
|
303
|
+
hint: s.description
|
|
263
304
|
})),
|
|
264
305
|
required: true
|
|
265
306
|
});
|
|
266
307
|
if (p.isCancel(selected)) {
|
|
267
|
-
p.cancel("
|
|
308
|
+
p.cancel("Cancelled.");
|
|
268
309
|
cleanup(tmpDir);
|
|
269
310
|
process.exit(0);
|
|
270
311
|
}
|
|
271
312
|
selectedSkills = allSkills.filter((s) => selected.includes(s.name));
|
|
272
313
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
314
|
+
const targetLabels = targetAgents.map((a) => {
|
|
315
|
+
const dest = opts.global ? a.globalPath : `./${a.projectPath}`;
|
|
316
|
+
return `${pc.bold(a.label)} ${pc.dim(dest)}`;
|
|
317
|
+
});
|
|
318
|
+
p.note(
|
|
319
|
+
[
|
|
320
|
+
`${pc.bold("Skills:")} ${selectedSkills.map((s) => pc.cyan(s.name)).join(", ")}`,
|
|
321
|
+
`${pc.bold("Install to:")}`,
|
|
322
|
+
...targetLabels.map((t) => ` ${pc.dim("\u2192")} ${t}`)
|
|
323
|
+
].join("\n"),
|
|
324
|
+
"Ready to install"
|
|
325
|
+
);
|
|
326
|
+
await p.tasks(
|
|
327
|
+
selectedSkills.map((skill) => ({
|
|
328
|
+
title: `Installing ${skill.name}`,
|
|
329
|
+
task: async () => {
|
|
330
|
+
const paths = installSkill(skill.dir, skill.name, targetAgents, opts.global);
|
|
331
|
+
return `${skill.name} \u2192 ${paths[0]}`;
|
|
283
332
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
} else if (opts.yes) {
|
|
287
|
-
targetAgents = AGENTS.filter((a) => DEFAULT_AGENT_IDS.includes(a.id));
|
|
288
|
-
} else {
|
|
289
|
-
const chosen = await p.multiselect({
|
|
290
|
-
message: "Install to: (\u2191\u2193 move Space toggle Enter confirm)",
|
|
291
|
-
options: AGENTS.map((a) => ({
|
|
292
|
-
value: a.id,
|
|
293
|
-
label: a.label,
|
|
294
|
-
hint: opts.global ? a.globalPath : path4.join(process.cwd(), a.projectPath)
|
|
295
|
-
})),
|
|
296
|
-
initialValues: DEFAULT_AGENT_IDS,
|
|
297
|
-
required: true
|
|
298
|
-
});
|
|
299
|
-
if (p.isCancel(chosen)) {
|
|
300
|
-
p.cancel("Installation cancelled.");
|
|
301
|
-
cleanup(tmpDir);
|
|
302
|
-
process.exit(0);
|
|
303
|
-
}
|
|
304
|
-
targetAgents = AGENTS.filter((a) => chosen.includes(a.id));
|
|
305
|
-
}
|
|
306
|
-
const spinner2 = p.spinner();
|
|
307
|
-
spinner2.start(`Installing ${selectedSkills.length} skill${selectedSkills.length === 1 ? "" : "s"}...`);
|
|
308
|
-
const results = [];
|
|
309
|
-
for (const skill of selectedSkills) {
|
|
310
|
-
const paths = installSkill(skill.dir, skill.name, targetAgents, opts.global);
|
|
311
|
-
results.push(...paths.map((p4, i) => `${skill.name} \u2192 ${p4}${i > 0 ? pc.dim(" (symlink)") : ""}`));
|
|
312
|
-
}
|
|
313
|
-
spinner2.stop(`Done \u2014 ${selectedSkills.length} skill${selectedSkills.length === 1 ? "" : "s"} installed`);
|
|
314
|
-
for (const line of results) {
|
|
315
|
-
p.log.step(line);
|
|
316
|
-
}
|
|
333
|
+
}))
|
|
334
|
+
);
|
|
317
335
|
p.outro(
|
|
318
|
-
`${pc.
|
|
336
|
+
`${pc.green("\u2713")} ${selectedSkills.length} skill${selectedSkills.length === 1 ? "" : "s"} installed
|
|
337
|
+
${pc.dim("$ npx bf-skills list")} ${pc.dim("$ npx bf-skills remove <name>")}`
|
|
319
338
|
);
|
|
320
339
|
cleanup(tmpDir);
|
|
321
340
|
showFooter();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bf-skills",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "BF Skills installer — Building the Future of Business with AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"prepublishOnly": "npm run build"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@clack/prompts": "^
|
|
18
|
+
"@clack/prompts": "^1.2.0",
|
|
19
19
|
"picocolors": "^1.1.1",
|
|
20
20
|
"simple-git": "^3.27.0",
|
|
21
21
|
"yaml": "^2.7.0"
|