bf-skills 1.0.0 → 1.0.1
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 +77 -58
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -80,6 +80,7 @@ function copyDir(src, dest) {
|
|
|
80
80
|
fs2.mkdirSync(dest, { recursive: true });
|
|
81
81
|
const entries = fs2.readdirSync(src, { withFileTypes: true });
|
|
82
82
|
for (const entry of entries) {
|
|
83
|
+
if (entry.name === ".git" || entry.name === ".DS_Store") continue;
|
|
83
84
|
const srcPath = path2.join(src, entry.name);
|
|
84
85
|
const destPath = path2.join(dest, entry.name);
|
|
85
86
|
if (entry.isDirectory()) {
|
|
@@ -89,46 +90,70 @@ function copyDir(src, dest) {
|
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
fs2.mkdirSync(basePath, { recursive: true });
|
|
96
|
-
if (fs2.existsSync(destDir)) {
|
|
97
|
-
fs2.rmSync(destDir, { recursive: true, force: true });
|
|
93
|
+
function removePath(p4) {
|
|
94
|
+
if (fs2.existsSync(p4)) {
|
|
95
|
+
fs2.rmSync(p4, { recursive: true, force: true });
|
|
98
96
|
}
|
|
99
|
-
copyDir(skill.dir, destDir);
|
|
100
|
-
return destDir;
|
|
101
97
|
}
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
fs2.
|
|
107
|
-
|
|
98
|
+
function installSkill(skillDir, skillName, agents, isGlobal) {
|
|
99
|
+
if (agents.length === 0) throw new Error("No install targets selected");
|
|
100
|
+
const resolvePath = (agent) => isGlobal ? path2.join(agent.globalPath, skillName) : path2.join(process.cwd(), agent.projectPath, skillName);
|
|
101
|
+
const primaryDest = resolvePath(agents[0]);
|
|
102
|
+
fs2.mkdirSync(path2.dirname(primaryDest), { recursive: true });
|
|
103
|
+
removePath(primaryDest);
|
|
104
|
+
copyDir(skillDir, primaryDest);
|
|
105
|
+
const installed = [primaryDest];
|
|
106
|
+
for (const agent of agents.slice(1)) {
|
|
107
|
+
const dest = resolvePath(agent);
|
|
108
|
+
fs2.mkdirSync(path2.dirname(dest), { recursive: true });
|
|
109
|
+
removePath(dest);
|
|
110
|
+
const rel = path2.relative(path2.dirname(dest), primaryDest);
|
|
111
|
+
fs2.symlinkSync(rel, dest);
|
|
112
|
+
installed.push(dest);
|
|
113
|
+
}
|
|
114
|
+
return installed;
|
|
108
115
|
}
|
|
109
|
-
function
|
|
110
|
-
const
|
|
116
|
+
function removeSkill(name, agents, isGlobal) {
|
|
117
|
+
const removed = [];
|
|
118
|
+
for (const agent of agents) {
|
|
119
|
+
const p4 = isGlobal ? path2.join(agent.globalPath, name) : path2.join(process.cwd(), agent.projectPath, name);
|
|
120
|
+
if (fs2.existsSync(p4)) {
|
|
121
|
+
fs2.rmSync(p4, { recursive: true, force: true });
|
|
122
|
+
removed.push(p4);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return removed;
|
|
126
|
+
}
|
|
127
|
+
function listInstalledSkills(agent, isGlobal) {
|
|
128
|
+
const basePath = isGlobal ? agent.globalPath : path2.join(process.cwd(), agent.projectPath);
|
|
111
129
|
if (!fs2.existsSync(basePath)) return [];
|
|
112
|
-
return fs2.readdirSync(basePath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
130
|
+
return fs2.readdirSync(basePath, { withFileTypes: true }).filter((e) => e.isDirectory() || e.isSymbolicLink()).map((e) => e.name);
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
// src/lib/agents.ts
|
|
116
134
|
import os from "os";
|
|
117
135
|
import path3 from "path";
|
|
118
136
|
var AGENTS = [
|
|
137
|
+
{
|
|
138
|
+
id: "general",
|
|
139
|
+
label: ".agents/skills (general agents)",
|
|
140
|
+
projectPath: ".agents/skills",
|
|
141
|
+
globalPath: path3.join(os.homedir(), ".agents", "skills")
|
|
142
|
+
},
|
|
119
143
|
{
|
|
120
144
|
id: "claude-code",
|
|
121
|
-
label: "Claude Code",
|
|
145
|
+
label: ".claude/skills (Claude Code)",
|
|
122
146
|
projectPath: ".claude/skills",
|
|
123
147
|
globalPath: path3.join(os.homedir(), ".claude", "skills")
|
|
124
148
|
},
|
|
125
149
|
{
|
|
126
|
-
id: "
|
|
127
|
-
label: "
|
|
128
|
-
projectPath: "
|
|
129
|
-
globalPath: path3.join(os.homedir(), "
|
|
150
|
+
id: "root",
|
|
151
|
+
label: "skills/ (root folder)",
|
|
152
|
+
projectPath: "skills",
|
|
153
|
+
globalPath: path3.join(os.homedir(), "skills")
|
|
130
154
|
}
|
|
131
155
|
];
|
|
156
|
+
var DEFAULT_AGENT_IDS = ["general", "claude-code"];
|
|
132
157
|
function getAgentById(id) {
|
|
133
158
|
return AGENTS.find((a) => a.id === id);
|
|
134
159
|
}
|
|
@@ -231,11 +256,10 @@ async function runInstall(source, opts) {
|
|
|
231
256
|
selectedSkills = allSkills;
|
|
232
257
|
} else {
|
|
233
258
|
const selected = await p.multiselect({
|
|
234
|
-
message: "Select skills to install (
|
|
259
|
+
message: "Select skills to install (\u2191\u2193 move Space toggle Enter confirm)",
|
|
235
260
|
options: allSkills.map((s) => ({
|
|
236
261
|
value: s.name,
|
|
237
|
-
label: pc.bold(s.name.padEnd(
|
|
238
|
-
hint: s.description
|
|
262
|
+
label: pc.bold(s.name.padEnd(32)) + pc.dim(s.description)
|
|
239
263
|
})),
|
|
240
264
|
required: true
|
|
241
265
|
});
|
|
@@ -248,50 +272,50 @@ async function runInstall(source, opts) {
|
|
|
248
272
|
}
|
|
249
273
|
let targetAgents;
|
|
250
274
|
if (opts.agent) {
|
|
251
|
-
if (opts.agent === "
|
|
275
|
+
if (opts.agent === "all") {
|
|
252
276
|
targetAgents = [...AGENTS];
|
|
253
277
|
} else {
|
|
254
278
|
const found = getAgentById(opts.agent);
|
|
255
279
|
if (!found) {
|
|
256
|
-
p.log.error(`Unknown agent "${opts.agent}". Use: claude-code,
|
|
280
|
+
p.log.error(`Unknown agent "${opts.agent}". Use: general, claude-code, root, or all`);
|
|
257
281
|
cleanup(tmpDir);
|
|
258
282
|
process.exit(1);
|
|
259
283
|
}
|
|
260
284
|
targetAgents = [found];
|
|
261
285
|
}
|
|
262
286
|
} else if (opts.yes) {
|
|
263
|
-
targetAgents =
|
|
287
|
+
targetAgents = AGENTS.filter((a) => DEFAULT_AGENT_IDS.includes(a.id));
|
|
264
288
|
} else {
|
|
265
|
-
const
|
|
266
|
-
message: "Install to:",
|
|
267
|
-
options:
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
|
272
298
|
});
|
|
273
|
-
if (p.isCancel(
|
|
299
|
+
if (p.isCancel(chosen)) {
|
|
274
300
|
p.cancel("Installation cancelled.");
|
|
275
301
|
cleanup(tmpDir);
|
|
276
302
|
process.exit(0);
|
|
277
303
|
}
|
|
278
|
-
targetAgents =
|
|
304
|
+
targetAgents = AGENTS.filter((a) => chosen.includes(a.id));
|
|
279
305
|
}
|
|
280
306
|
const spinner2 = p.spinner();
|
|
281
307
|
spinner2.start(`Installing ${selectedSkills.length} skill${selectedSkills.length === 1 ? "" : "s"}...`);
|
|
282
|
-
const
|
|
308
|
+
const results = [];
|
|
283
309
|
for (const skill of selectedSkills) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
installed.push(`${skill.name} \u2192 ${dest}`);
|
|
287
|
-
}
|
|
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)") : ""}`));
|
|
288
312
|
}
|
|
289
313
|
spinner2.stop(`Done \u2014 ${selectedSkills.length} skill${selectedSkills.length === 1 ? "" : "s"} installed`);
|
|
290
|
-
for (const line of
|
|
314
|
+
for (const line of results) {
|
|
291
315
|
p.log.step(line);
|
|
292
316
|
}
|
|
293
317
|
p.outro(
|
|
294
|
-
`${pc.dim("$ npx bf-skills list")}
|
|
318
|
+
`${pc.dim("$ npx bf-skills list")} ${pc.dim("$ npx bf-skills remove <name>")}`
|
|
295
319
|
);
|
|
296
320
|
cleanup(tmpDir);
|
|
297
321
|
showFooter();
|
|
@@ -311,11 +335,11 @@ function runList(opts) {
|
|
|
311
335
|
let total = 0;
|
|
312
336
|
for (const agent of AGENTS) {
|
|
313
337
|
const skills = listInstalledSkills(agent, opts.global);
|
|
314
|
-
const
|
|
338
|
+
const basePath = opts.global ? agent.globalPath : `./${agent.projectPath}`;
|
|
315
339
|
if (skills.length === 0) {
|
|
316
|
-
p2.log.info(`${pc2.bold(agent.label)} ${pc2.dim(
|
|
340
|
+
p2.log.info(`${pc2.bold(agent.label)} ${pc2.dim(basePath)} \u2014 no skills installed`);
|
|
317
341
|
} else {
|
|
318
|
-
p2.log.step(`${pc2.bold(agent.label)} ${pc2.dim(
|
|
342
|
+
p2.log.step(`${pc2.bold(agent.label)} ${pc2.dim(basePath)}`);
|
|
319
343
|
for (const name of skills) {
|
|
320
344
|
console.log(` ${pc2.dim("\u2022")} ${name}`);
|
|
321
345
|
}
|
|
@@ -332,19 +356,14 @@ import pc3 from "picocolors";
|
|
|
332
356
|
function runRemove(name, opts) {
|
|
333
357
|
showLogo();
|
|
334
358
|
p3.intro(`${pc3.bold("bf-skills remove")}`);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (didRemove) {
|
|
339
|
-
const pathLabel = opts.global ? agent.globalPath : `./${agent.projectPath}`;
|
|
340
|
-
p3.log.step(`Removed ${pc3.bold(name)} from ${pc3.dim(pathLabel)}`);
|
|
341
|
-
removed = true;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
if (!removed) {
|
|
345
|
-
p3.log.error(`Skill "${name}" not found in any agent skills directory.`);
|
|
359
|
+
const removed = removeSkill(name, AGENTS, opts.global);
|
|
360
|
+
if (removed.length === 0) {
|
|
361
|
+
p3.log.error(`Skill "${name}" not found in any target directory.`);
|
|
346
362
|
p3.outro("Nothing removed.");
|
|
347
363
|
} else {
|
|
364
|
+
for (const p_ of removed) {
|
|
365
|
+
p3.log.step(`Removed ${pc3.bold(name)} from ${pc3.dim(p_)}`);
|
|
366
|
+
}
|
|
348
367
|
p3.outro(`Done \u2014 ${pc3.bold(name)} removed`);
|
|
349
368
|
}
|
|
350
369
|
showFooter();
|