From eb130693975f6d27b8eee4d99f93565e9daf7f28 Mon Sep 17 00:00:00 2001 From: Michael Powers Date: Wed, 13 May 2026 13:33:38 +0000 Subject: [PATCH] fix: linter skipping skills-only plugins Branch-Creation-Time: 2026-05-13T13:12:22+0000 --- pkg/codingcontext/context.go | 1 + pkg/codingcontext/lint_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pkg/codingcontext/context.go b/pkg/codingcontext/context.go index 68dd9127..47a7ba4b 100644 --- a/pkg/codingcontext/context.go +++ b/pkg/codingcontext/context.go @@ -1054,6 +1054,7 @@ func (cc *Context) loadSkillEntry(skillFile string, lenient bool) error { if cc.lintCollector != nil { cc.lintCollector.recordFile(skillFile, LoadedFileKindSkill) + cc.lintCollector.recordFrontmatterValues(frontmatter.BaseFrontMatter) } matches, reason := cc.includes.MatchesIncludes(frontmatter.BaseFrontMatter, cc.includeByDefault) diff --git a/pkg/codingcontext/lint_test.go b/pkg/codingcontext/lint_test.go index 8355a5d2..82299673 100644 --- a/pkg/codingcontext/lint_test.go +++ b/pkg/codingcontext/lint_test.go @@ -269,3 +269,34 @@ func TestLint_Command_Tracked(t *testing.T) { t.Errorf("expected command file in LoadedFiles, got %+v", result.LoadedFiles) } } + +// TestLint_SelectorMatched_FromSkillFrontmatter verifies that frontmatter keys +// declared in SKILL.md files contribute to the selector-coverage 'seen' map. +// Regression test: previously loadSkillEntry recorded the file but not its +// frontmatter values, so a selector key declared only in skill frontmatter +// (e.g. a plugin whose only converted output is a SKILL.md) would falsely +// trigger 'selector matched no discovered files'. +func TestLint_SelectorMatched_FromSkillFrontmatter(t *testing.T) { + t.Parallel() + dir := lintTestDir(t) + + createTask(t, dir, "task1", "", "Do stuff.") + createSkill(t, dir, ".agents/skills/myskill", + "---\nname: myskill\ndescription: A skill that declares a custom selector key.\ncategory: alpha\n---\nbody") + + cc := New( + WithSearchPaths(dir), + WithSelectors(map[string]map[string]bool{ + "category": {"alpha": true}, + }), + ) + + result, err := cc.Lint(context.Background(), "task1") + if err != nil { + t.Fatalf("Lint() returned error: %v", err) + } + + if hasLintError(result, LintErrorKindSelectorNoMatch, "category=alpha") { + t.Errorf("skill frontmatter should satisfy selector coverage, got errors: %+v", result.Errors) + } +}