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 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.7",
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",