skilldrop-cli 0.11.7 → 0.11.8
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/README.md +4 -1
- package/bin/skilldrop.js +137 -1
- package/package.json +1 -1
- package/packs.json +6 -0
package/README.md
CHANGED
|
@@ -424,6 +424,9 @@ npx skilldrop-cli install --pack dev-team --project # .claude/skills — als
|
|
|
424
424
|
npx skilldrop-cli install prfaq --ide cursor # + writes .cursor/rules/prfaq.mdc
|
|
425
425
|
npx skilldrop-cli install --pack sre-oncall --ide kiro # .kiro/skills — Kiro IDE + Kiro CLI, discovered natively
|
|
426
426
|
npx skilldrop-cli install adr-generator --dest .agents/skills # Codex + Copilot CLI (see below)
|
|
427
|
+
npx skilldrop-cli loops # the five loops, their stages and gates
|
|
428
|
+
npx skilldrop-cli install --loop build # a loop + every stage skill it sequences (RFC-0028)
|
|
429
|
+
npx skilldrop-cli install --loop --pack sre-oncall # every loop that pack declares
|
|
427
430
|
npx skilldrop-cli agents # the reviewer subagents
|
|
428
431
|
npx skilldrop-cli install --agent devils-advocate # -> ~/.claude/agents/ (RFC-0012)
|
|
429
432
|
npx skilldrop-cli install --panel review # the whole review fleet: 3 subagents + the pre-merge-review orchestrator (RFC-0020)
|
|
@@ -432,7 +435,7 @@ npx skilldrop-cli list | skilldrop info <skill> | skilldrop packs | skilldrop un
|
|
|
432
435
|
npx skilldrop-cli list --json # machine-readable: list/info/packs/agents/outdated (RFC-0021)
|
|
433
436
|
```
|
|
434
437
|
|
|
435
|
-
`--with-related` also pulls each skill's companions. From a clone (or before the package is published): `node bin/skilldrop.js <same args>`. Scope and design: [RFC-0002](docs/rfcs/0002-skilldrop-cli.md), full command surface in [`docs/designs/skilldrop-cli-design.md`](docs/designs/skilldrop-cli-design.md).
|
|
438
|
+
`--loop` installs a loop as an invokable skill (its `LOOP.md` is already `SKILL.md`-shaped) plus the skills its stages name — add `--no-skills` for the loop alone, which still runs because each stage degrades through its declared `fallback`. `--with-related` also pulls each skill's companions. From a clone (or before the package is published): `node bin/skilldrop.js <same args>`. Scope and design: [RFC-0002](docs/rfcs/0002-skilldrop-cli.md), full command surface in [`docs/designs/skilldrop-cli-design.md`](docs/designs/skilldrop-cli-design.md).
|
|
436
439
|
|
|
437
440
|
### Or: the Claude Code plugin marketplace
|
|
438
441
|
|
package/bin/skilldrop.js
CHANGED
|
@@ -37,16 +37,20 @@ Usage:
|
|
|
37
37
|
skilldrop info <skill> [--from <src>] description, related, packs, deps
|
|
38
38
|
skilldrop packs [--from <src>] role-based packs
|
|
39
39
|
skilldrop agents [--from <src>] reviewer subagents in a catalog
|
|
40
|
+
skilldrop loops [--from <src>] loops — sequenced stages over skills (RFC-0028)
|
|
40
41
|
skilldrop install <skill...> install skills (default: Claude Code, user scope)
|
|
41
42
|
skilldrop install --pack <name> install a whole pack
|
|
42
43
|
skilldrop install --all install every skill in the catalog
|
|
43
44
|
skilldrop install --agent <name...> install reviewer subagents (RFC-0012)
|
|
45
|
+
skilldrop install --loop <name...> install loops + the stage skills they sequence
|
|
46
|
+
(--no-skills for the loop alone) (RFC-0028)
|
|
44
47
|
skilldrop install --panel review install the review panel — the 3 reviewer subagents +
|
|
45
48
|
the pre-merge-review orchestrator that fires them (RFC-0020)
|
|
46
49
|
skilldrop update re-copy installed skills whose version changed
|
|
47
50
|
skilldrop outdated show installed vs current versions, change nothing
|
|
48
51
|
skilldrop uninstall <skill...> remove skills (and wiring files this tool wrote)
|
|
49
52
|
skilldrop uninstall --agent <name...> remove subagents
|
|
53
|
+
skilldrop uninstall --loop <name...> remove loops (stage skills are left in place)
|
|
50
54
|
skilldrop validate [--from <src>] structural check of a catalog (for catalog authors)
|
|
51
55
|
skilldrop scan [<skill...>] [--from <src>] supply-chain scan — flag network/exec/credential
|
|
52
56
|
patterns in scripts and injection-shaped instructions
|
|
@@ -740,6 +744,7 @@ function installPanel(args) {
|
|
|
740
744
|
|
|
741
745
|
function install(args) {
|
|
742
746
|
if (args.flags.panel) return installPanel(args);
|
|
747
|
+
if (args.flags.loop) return installLoops(args);
|
|
743
748
|
if (args.flags.agent) return installAgents(args);
|
|
744
749
|
const cat = resolveCatalog(args.flags.from);
|
|
745
750
|
let names = expandNames(args, cat);
|
|
@@ -846,6 +851,7 @@ function outdated(args) {
|
|
|
846
851
|
|
|
847
852
|
function uninstall(args) {
|
|
848
853
|
if (args.flags.agent) return uninstallAgents(args);
|
|
854
|
+
if (args.flags.loop) return uninstallLoops(args);
|
|
849
855
|
if (!args._.length) die("pass skill names to uninstall");
|
|
850
856
|
const { dest, ide } = target(args.flags);
|
|
851
857
|
const l = ledger(dest);
|
|
@@ -881,6 +887,136 @@ function listAgents(args) {
|
|
|
881
887
|
console.log(`\n${names.length} agent(s). Install one: skilldrop install --agent <name>`);
|
|
882
888
|
}
|
|
883
889
|
|
|
890
|
+
/* Loops (RFC-0028): an ordered sequence of stages over existing skills, with a gate between
|
|
891
|
+
them. LOOP.md's frontmatter is already SKILL.md's shape (name + description), so a loop
|
|
892
|
+
projects into the target's skill directory as <name>/SKILL.md and becomes invokable exactly
|
|
893
|
+
like a skill. loop.json travels beside it so stages, gates and cap stay machine-readable
|
|
894
|
+
after install. A loop never contains a skill — installing one also installs the skills its
|
|
895
|
+
stages name, unless --no-skills. Optional in a catalog. */
|
|
896
|
+
function loopsIn(cat) {
|
|
897
|
+
if (cat.shape === "apm") return [];
|
|
898
|
+
const d = path.join(cat.dir, "loops");
|
|
899
|
+
if (!fs.existsSync(d)) return [];
|
|
900
|
+
return fs.readdirSync(d).filter((x) => fs.existsSync(path.join(d, x, "loop.json"))).sort();
|
|
901
|
+
}
|
|
902
|
+
function loopDir(cat, n) { return path.join(cat.dir, "loops", n); }
|
|
903
|
+
function loopSpec(cat, n) { return readJSON(path.join(loopDir(cat, n), "loop.json")); }
|
|
904
|
+
|
|
905
|
+
function loopSkills(cat, n) {
|
|
906
|
+
const seen = [];
|
|
907
|
+
for (const st of loopSpec(cat, n).stages || [])
|
|
908
|
+
for (const sk of st.skills || [])
|
|
909
|
+
if (sk !== "*" && !seen.includes(sk)) seen.push(sk);
|
|
910
|
+
return seen;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
function checkLoop(cat, n) {
|
|
914
|
+
const problems = [];
|
|
915
|
+
if (!fs.existsSync(path.join(loopDir(cat, n), "LOOP.md"))) problems.push("no LOOP.md — it is the entrypoint");
|
|
916
|
+
let spec;
|
|
917
|
+
try { spec = loopSpec(cat, n); } catch (e) { return problems.concat("loop.json is missing or unparseable"); }
|
|
918
|
+
if (spec.name !== n) problems.push(`loop.json name '${spec.name}' != folder '${n}'`);
|
|
919
|
+
if (!Array.isArray(spec.stages) || !spec.stages.length) problems.push("no stages — a loop with none sequences nothing");
|
|
920
|
+
for (const sk of loopSkills(cat, n))
|
|
921
|
+
if (!skillExists(cat, sk)) problems.push(`stage names skill '${sk}', which is not in this catalog`);
|
|
922
|
+
return problems;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function listLoops(args) {
|
|
926
|
+
const cat = resolveCatalog(args.flags.from);
|
|
927
|
+
const names = loopsIn(cat);
|
|
928
|
+
if (args.flags.json)
|
|
929
|
+
return emitJSON({
|
|
930
|
+
catalog: cat.source, count: names.length,
|
|
931
|
+
loops: names.map((n) => {
|
|
932
|
+
const sp = loopSpec(cat, n);
|
|
933
|
+
return { name: n, kind: sp.kind, cap: sp.cap ?? 3, description: sp.description,
|
|
934
|
+
stages: (sp.stages || []).map((st) => ({ id: st.id, type: st.type, skills: st.skills,
|
|
935
|
+
gate: st.gate ? { id: st.gate.id, kind: st.gate.kind } : null })) };
|
|
936
|
+
}),
|
|
937
|
+
});
|
|
938
|
+
if (!names.length) return console.log(`catalog '${cat.source}' ships no loops.`);
|
|
939
|
+
for (const n of names) {
|
|
940
|
+
const sp = loopSpec(cat, n);
|
|
941
|
+
const gates = (sp.stages || []).filter((st) => st.gate).map((st) => `${st.gate.id}:${st.gate.kind}`);
|
|
942
|
+
console.log(`${n} [${sp.kind}, cap ${sp.cap ?? 3}]`);
|
|
943
|
+
console.log(` ${(sp.stages || []).map((st) => st.id).join(" -> ")}`);
|
|
944
|
+
console.log(` gates: ${gates.join(", ") || "none"}`);
|
|
945
|
+
}
|
|
946
|
+
console.log(`\n${names.length} loop(s). Install one: skilldrop install --loop <name>`);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
function installLoops(args) {
|
|
950
|
+
const cat = resolveCatalog(args.flags.from);
|
|
951
|
+
const available = loopsIn(cat);
|
|
952
|
+
if (!available.length) die(`catalog '${cat.source}' ships no loops`);
|
|
953
|
+
let names = args._.slice();
|
|
954
|
+
if (!names.length && args.flags.pack) {
|
|
955
|
+
const ps = packsOf(cat);
|
|
956
|
+
if (!ps) die(`catalog '${cat.source}' has no packs.json`);
|
|
957
|
+
const pk = ps[args.flags.pack];
|
|
958
|
+
if (!pk) die(`unknown pack '${args.flags.pack}' in catalog '${cat.source}'`);
|
|
959
|
+
names = (pk.loops || []).slice();
|
|
960
|
+
if (!names.length) die(`pack '${args.flags.pack}' declares no loops`);
|
|
961
|
+
}
|
|
962
|
+
if (!names.length && args.flags.all) names = available.slice();
|
|
963
|
+
if (!names.length) die("nothing to install — pass loop names, --pack <name>, or --all");
|
|
964
|
+
for (const n of names) if (!available.includes(n)) die(`unknown loop '${n}' in catalog '${cat.source}'`);
|
|
965
|
+
|
|
966
|
+
let bad = 0;
|
|
967
|
+
for (const n of names) {
|
|
968
|
+
const problems = checkLoop(cat, n);
|
|
969
|
+
for (const pr of problems) console.error(`refused ${n}: ${pr}`);
|
|
970
|
+
if (problems.length) bad++;
|
|
971
|
+
}
|
|
972
|
+
if (bad) die(`${bad} loop(s) failed the structural check — nothing was installed`);
|
|
973
|
+
|
|
974
|
+
const { dest, ide } = target(args.flags);
|
|
975
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
976
|
+
const l = ledger(dest);
|
|
977
|
+
const notes = [];
|
|
978
|
+
for (const n of names) {
|
|
979
|
+
const sp = loopSpec(cat, n);
|
|
980
|
+
const out = path.join(dest, n);
|
|
981
|
+
fs.mkdirSync(out, { recursive: true });
|
|
982
|
+
fs.copyFileSync(path.join(loopDir(cat, n), "LOOP.md"), path.join(out, "SKILL.md"));
|
|
983
|
+
fs.copyFileSync(path.join(loopDir(cat, n), "loop.json"), path.join(out, "loop.json"));
|
|
984
|
+
const note = writeWiring(ide, dest, n, sp.description);
|
|
985
|
+
if (note) notes.push(note);
|
|
986
|
+
l.data[n] = { version: sp.version || null, source: cat.source, loop: true };
|
|
987
|
+
console.log(`installed loop ${n} -> ${out}`);
|
|
988
|
+
}
|
|
989
|
+
saveLedger(l);
|
|
990
|
+
|
|
991
|
+
const wanted = [];
|
|
992
|
+
for (const n of names) for (const sk of loopSkills(cat, n)) if (!wanted.includes(sk)) wanted.push(sk);
|
|
993
|
+
if (args.flags["no-skills"]) {
|
|
994
|
+
console.log(`\n${names.length} loop(s) installed (${ide}). Skipped ${wanted.length} stage skill(s) (--no-skills).`);
|
|
995
|
+
console.log(`A loop whose stage skills are absent still runs — each stage degrades via its declared fallback.`);
|
|
996
|
+
} else if (wanted.length) {
|
|
997
|
+
console.log(`\nInstalling ${wanted.length} stage skill(s) the loop sequences.\n`);
|
|
998
|
+
const flags = Object.assign({}, args.flags);
|
|
999
|
+
delete flags.loop; delete flags.pack; delete flags.all;
|
|
1000
|
+
install({ _: wanted, flags });
|
|
1001
|
+
}
|
|
1002
|
+
if (notes.length) console.log(`\n${notes.join("\n")}`);
|
|
1003
|
+
console.log(`\nRun a loop by name — e.g. "run the ${names[0]} loop on this". Its SKILL.md is the script; honour each gate and the cap.`);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
function uninstallLoops(args) {
|
|
1007
|
+
if (!args._.length) die("pass loop names to uninstall");
|
|
1008
|
+
const { dest, ide } = target(args.flags);
|
|
1009
|
+
const l = ledger(dest);
|
|
1010
|
+
for (const n of args._) {
|
|
1011
|
+
fs.rmSync(path.join(dest, n), { recursive: true, force: true });
|
|
1012
|
+
const w = wiringPath(ide, dest, n);
|
|
1013
|
+
if (w) fs.rmSync(w, { force: true });
|
|
1014
|
+
delete l.data[n];
|
|
1015
|
+
console.log(`removed loop ${n} from ${dest} (stage skills left in place)`);
|
|
1016
|
+
}
|
|
1017
|
+
saveLedger(l);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
884
1020
|
function installAgents(args) {
|
|
885
1021
|
const cat = resolveCatalog(args.flags.from);
|
|
886
1022
|
const available = agentsIn(cat);
|
|
@@ -1019,7 +1155,7 @@ function validateCmd(args) {
|
|
|
1019
1155
|
|
|
1020
1156
|
const args = parseArgs(process.argv.slice(2));
|
|
1021
1157
|
const cmd = args._.shift();
|
|
1022
|
-
const commands = { list, info, packs: listPacks, agents: listAgents, install, update, outdated, uninstall, validate: validateCmd, scan };
|
|
1158
|
+
const commands = { list, info, packs: listPacks, agents: listAgents, loops: listLoops, install, update, outdated, uninstall, validate: validateCmd, scan };
|
|
1023
1159
|
if (!cmd || cmd === "help" || args.flags.help) console.log(HELP);
|
|
1024
1160
|
else if (commands[cmd]) commands[cmd](args);
|
|
1025
1161
|
else die(`unknown command '${cmd}' — run: skilldrop help`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skilldrop-cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
4
4
|
"description": "Portable AI-agent skills for the deliverables knowledge workers ship \u2014 diagrams, ADRs, PRDs, runbooks, decks, reviews \u2014 installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Sanjay Ananthanarayan",
|
package/packs.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"packs": {
|
|
5
5
|
"solution-architect": {
|
|
6
6
|
"description": "Design-phase artifacts: diagrams, decision records, design docs, contracts, schemas, threat models, and the reviews that gate them.",
|
|
7
|
+
"loops": ["design", "ship-a-draft"],
|
|
7
8
|
"skills": [
|
|
8
9
|
"brief-intake",
|
|
9
10
|
"architecture-diagrams",
|
|
@@ -26,6 +27,7 @@
|
|
|
26
27
|
},
|
|
27
28
|
"product-manager": {
|
|
28
29
|
"description": "Direction to requirements: PR/FAQs, strategy frameworks, OKRs, PRDs, journey maps, story splitting, and success measurement.",
|
|
30
|
+
"loops": ["discover", "ship-a-draft"],
|
|
29
31
|
"skills": [
|
|
30
32
|
"brief-intake",
|
|
31
33
|
"prfaq",
|
|
@@ -44,6 +46,7 @@
|
|
|
44
46
|
},
|
|
45
47
|
"dev-team": {
|
|
46
48
|
"description": "Build-and-ship loop: story implementation with adversarial review, test plans, triage, migrations, release notes, agent-policy files, and code-quality gates.",
|
|
49
|
+
"loops": ["build", "ship-a-draft"],
|
|
47
50
|
"skills": [
|
|
48
51
|
"agents-md-generator",
|
|
49
52
|
"user-story-splitter",
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
},
|
|
64
67
|
"sre-oncall": {
|
|
65
68
|
"description": "Operate the service: runbooks, observability design, incident communications, postmortems, and capacity/cost models.",
|
|
69
|
+
"loops": ["operate"],
|
|
66
70
|
"skills": [
|
|
67
71
|
"runbook-generator",
|
|
68
72
|
"observability-plan",
|
|
@@ -73,6 +77,7 @@
|
|
|
73
77
|
},
|
|
74
78
|
"stakeholder-comms": {
|
|
75
79
|
"description": "Non-technical audiences: audience profiling, deck outlines and real .pptx decks, exec summaries, decision logs, and guides.",
|
|
80
|
+
"loops": ["ship-a-draft"],
|
|
76
81
|
"skills": [
|
|
77
82
|
"brief-intake",
|
|
78
83
|
"audience-profile",
|
|
@@ -87,6 +92,7 @@
|
|
|
87
92
|
},
|
|
88
93
|
"ai-engineering": {
|
|
89
94
|
"description": "Adopt and build AI systems: readiness assessment, use-case triage, rollout and acceptable-use policy, plus agent loop design, subagent orchestration, spend budgets, agent security review, eval harnesses, AI-usage reporting, and the data contracts AI pipelines depend on.",
|
|
95
|
+
"loops": ["design", "build"],
|
|
90
96
|
"skills": [
|
|
91
97
|
"agent-loop-design",
|
|
92
98
|
"subagent-design",
|