package scaffold import ( "path" "strings" "testing" ) // frontmatter returns the YAML block at the top of a document, or "" if there // is none. Every file here is read by an agent harness that will not load a // document without one. func frontmatter(body string) string { if !strings.HasPrefix(body, "---\n") { return "" } rest := body[len("---\n"):] end := strings.Index(rest, "\n---\n") if end < 0 { return "" } return rest[:end+1] } func field(fm, key string) string { for _, line := range strings.Split(fm, "\n") { if v, ok := strings.CutPrefix(line, key+":"); ok { return strings.TrimSpace(v) } } return "" } // routed reports whether a document is one the harness loads by itself — a // skill, a command, a subagent. Everything under references/ is prose that a // skill names by path and reads in full, so it carries no frontmatter and needs // none. func routed(p string) bool { return !strings.Contains(p, "/references/") } // A routed document with no frontmatter, or with an empty description, is a // document the harness either refuses to load or never routes to. Either way it // is dead weight in the binary, and neither failure shows up until somebody's // project is quietly missing a skill. func TestEveryDocumentIsLoadable(t *testing.T) { files := Files() if len(files) == 0 { t.Fatal("no assets embedded — check the //go:embed directive") } for _, f := range files { if !routed(f.Path) { if frontmatter(f.Body) != "" { t.Errorf("%s: a reference is read by path and needs no frontmatter", f.Path) } continue } fm := frontmatter(f.Body) if fm == "" { t.Errorf("%s: no frontmatter", f.Path) continue } if field(fm, "description") == "" { t.Errorf("%s: no description — nothing will route to it", f.Path) } } } // A skill is addressed by its name, and the harness resolves that name from the // directory. The two disagreeing is a skill that cannot be loaded by the name it // calls itself. func TestSkillNamesMatchTheirDirectories(t *testing.T) { for _, f := range Files() { if !strings.HasPrefix(f.Path, "skills/") || path.Base(f.Path) != "SKILL.md" { continue } dir := path.Base(path.Dir(f.Path)) if got := field(frontmatter(f.Body), "name"); got != dir { t.Errorf("%s: name is %q, directory is %q", f.Path, got, dir) } if !strings.HasPrefix(dir, "kettle-") { t.Errorf("%s: a project skill has no namespace of its own, so the prefix is the whole of it", f.Path) } } } // A command is invoked by an operator who typed it, so it needs no description // to be routed on — but it gets one anyway, because that is what the operator // reads in the command list. What it must NOT carry is a name: a project command // is named by its filename, and a `name:` here would be a second spelling of the // same identity, free to drift. func TestCommandsAreNamedByTheirFilenames(t *testing.T) { found := 0 for _, f := range Files() { if !strings.HasPrefix(f.Path, "commands/") { continue } found++ if got := field(frontmatter(f.Body), "name"); got != "" { t.Errorf("%s: carries name: %q — the filename is the name", f.Path, got) } } if found == 0 { t.Error("no commands embedded") } } // The generated region and the map that declares it are one fact written twice, // and this is the test that keeps them equal. A file that grew a region without // being declared would have it silently ignored; a file declared without one // would fail at splice time, in somebody's project rather than here. func TestDeclaredRegionsAreTheRealOnes(t *testing.T) { const open, close = "", "" seen := map[string]bool{} for _, f := range Files() { has := strings.Contains(f.Body, open) switch { case has && f.Group == "": t.Errorf("%s carries a generated region but is in no group", f.Path) case !has && f.Group != "": t.Errorf("%s is declared for group %q but has no region", f.Path, f.Group) } if has && !strings.Contains(f.Body, close) { t.Errorf("%s opens a region and never closes it", f.Path) } if f.Group != "" { seen[f.Path] = true } } for p := range generated { if !seen[p] { t.Errorf("generated names %s, which is not embedded", p) } } } // One group, one file. Two files claiming the same group would both be written // from the same registry block, and only one of them would be the one anybody // read. func TestEachGroupHasExactlyOneFile(t *testing.T) { for _, g := range Groups() { var paths []string for p, group := range generated { if group == g { paths = append(paths, p) } } if len(paths) != 1 { t.Errorf("group %q is claimed by %v", g, paths) } if PathFor(g) == "" { t.Errorf("PathFor(%q) found nothing", g) } } } // Two calls, one list. Every receipt, every --check diff and every golden test // downstream is built on this holding. func TestFilesAreDeterministic(t *testing.T) { a, b := Files(), Files() if len(a) != len(b) { t.Fatalf("two calls returned %d and %d files", len(a), len(b)) } for i := range a { if a[i] != b[i] { t.Fatalf("call %d differs at %d: %s vs %s", i, i, a[i].Path, b[i].Path) } if i > 0 && a[i-1].Path >= a[i].Path { t.Errorf("not sorted: %s before %s", a[i-1].Path, a[i].Path) } } } // Dirs is what a writer creates before it writes, so a parent that came after // its child would be a mkdir that fails on a cold directory. func TestDirsListsParentsBeforeChildren(t *testing.T) { dirs := Dirs() seen := map[string]bool{} for _, d := range dirs { if parent := path.Dir(d); parent != "." && !seen[parent] { t.Errorf("%s comes before its parent %s", d, parent) } seen[d] = true } for _, f := range Files() { if d := path.Dir(f.Path); d != "." && !seen[d] { t.Errorf("%s lives in %s, which Dirs does not list", f.Path, d) } } } // Nothing authored here may name the plugin it replaced. A path into // `plugins/kettle` is a path that no longer exists, and an operator who follows // one is an operator reading a document that outlived its subject. // // Authored, so the generated region is cut out first: what is between the // markers came from the command registry and is that registry's to get right. // Asserting over it here would fail on a stale embedded block rather than on the // sentence somebody actually wrote. func TestNothingPointsAtTheOldPlugin(t *testing.T) { for _, f := range Files() { body := withoutRegion(f.Body) for _, dead := range []string{"plugins/kettle", "gen skills", "${CLAUDE_PLUGIN_ROOT}"} { if strings.Contains(body, dead) { t.Errorf("%s still mentions %q", f.Path, dead) } } } } func withoutRegion(body string) string { const open, close = "", "" start := strings.Index(body, open) if start < 0 { return body } end := strings.Index(body, close) if end < 0 { return body[:start] } return body[:start] + body[end+len(close):] }