Add the content tier: a standalone flake that auto-discovers each skill (a directory containing a SKILL.md, at any depth) and exposes it as an individually addressable derivation built by lib.mkSkill. Directories without a SKILL.md are descended through as cosmetic containers; once a SKILL.md is found, that directory's subfolders are its assets, not further skills. Skill names must be globally unique across the tree — a collision is a hard eval-time error, not a warning. A fixture-driven skill-build check under `nix flake check` exercises the recursive walk, the builder, the SKILL.md-at-$out-root contract, the eval-time name passthru, and the collision error. The repo ships no real skill content yet, so packages.<system> is empty today.
43 lines
1.3 KiB
Nix
43 lines
1.3 KiB
Nix
# Recursive skill discovery: one `{ name; src; }` per skill in a source tree.
|
|
lib: root:
|
|
let
|
|
walk =
|
|
dir:
|
|
let
|
|
subdirs = lib.filterAttrs (_: type: type == "directory") (builtins.readDir dir);
|
|
in
|
|
lib.concatLists (
|
|
lib.mapAttrsToList (
|
|
entryName: _:
|
|
let
|
|
child = dir + "/${entryName}";
|
|
in
|
|
# A directory with a SKILL.md is a skill, and its subdirectories are
|
|
# that skill's assets rather than nested skills, so the walk stops here.
|
|
# A directory without one is a cosmetic container to recurse through.
|
|
if (builtins.readDir child) ? "SKILL.md" then
|
|
[
|
|
{
|
|
name = entryName;
|
|
src = child;
|
|
}
|
|
]
|
|
else
|
|
walk child
|
|
) subdirs
|
|
);
|
|
|
|
found = walk root;
|
|
names = map (s: s.name) found;
|
|
duplicates = lib.unique (lib.filter (n: lib.count (x: x == n) names > 1) names);
|
|
in
|
|
if duplicates != [ ] then
|
|
throw ''
|
|
Skill name collision: ${lib.concatStringsSep ", " duplicates}.
|
|
Two or more skills under ${toString root} resolve to the same name.
|
|
A skill's name is its leaf directory name and must be globally unique
|
|
across the whole tree, independent of the cosmetic folders above it.
|
|
Rename one of the colliding skills.''
|
|
else
|
|
found
|