Skip to content

Commit e764bf8

Browse files
authored
fix(checks): suppress name-drift false positives for plugin-namespaced skill names
Extended checkNameDrift to also accept the canonical split structure for plugin-namespaced skill names (prefix:local): dir == prefix and file == local. Adds two new test cases. No behavior change for non-namespaced names.
1 parent cfacc7b commit e764bf8

2 files changed

Lines changed: 40 additions & 14 deletions

File tree

src/checks.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,29 @@ function checkDescriptionLength(v: ValidatedSkill): Diagnostic[] {
129129
function checkNameDrift(v: ValidatedSkill): Diagnostic[] {
130130
const fileBase = basename(v.file).replace(/\.md$/, "");
131131
const dirBase = basename(dirname(v.file));
132-
const expected = v.name.toLowerCase();
133-
if (
134-
fileBase.toLowerCase() !== expected &&
135-
dirBase.toLowerCase() !== expected
136-
) {
137-
return [
138-
{
139-
severity: "warn",
140-
rule: "name-drift",
141-
message: `frontmatter name '${v.name}' does not match filename '${fileBase}' or directory '${dirBase}'`,
142-
file: v.file,
143-
},
144-
];
132+
const nameLower = v.name.toLowerCase();
133+
const fileLower = fileBase.toLowerCase();
134+
const dirLower = dirBase.toLowerCase();
135+
136+
if (fileLower === nameLower || dirLower === nameLower) return [];
137+
138+
// For plugin-namespaced names ("prefix:local"), also accept the
139+
// canonical split structure: dir == prefix, file == local.
140+
const colon = nameLower.indexOf(":");
141+
if (colon !== -1) {
142+
const prefix = nameLower.slice(0, colon);
143+
const local = nameLower.slice(colon + 1);
144+
if (dirLower === prefix && fileLower === local) return [];
145145
}
146-
return [];
146+
147+
return [
148+
{
149+
severity: "warn",
150+
rule: "name-drift",
151+
message: `frontmatter name '${v.name}' does not match filename '${fileBase}' or directory '${dirBase}'`,
152+
file: v.file,
153+
},
154+
];
147155
}
148156

149157
function checkEmptyBody(v: ValidatedSkill): Diagnostic[] {

test/checks.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,22 @@ describe("runChecks", () => {
290290
const ds = runChecks([s], config);
291291
expect(ds.find((d) => d.rule === "name-drift")).toBeUndefined();
292292
});
293+
294+
it("does not flag name-drift for a plugin-namespaced skill in canonical split structure", () => {
295+
const s = mkSkill("/test/github/search.md", {
296+
name: "github:search",
297+
description: "search github repositories for code and issues",
298+
});
299+
const ds = runChecks([s], config);
300+
expect(ds.find((d) => d.rule === "name-drift")).toBeUndefined();
301+
});
302+
303+
it("flags name-drift for a plugin-namespaced skill when dir and file do not match either part", () => {
304+
const s = mkSkill("/test/skills/something-else.md", {
305+
name: "github:search",
306+
description: "search github repositories for code and issues",
307+
});
308+
const ds = runChecks([s], config);
309+
expect(ds.some((d) => d.rule === "name-drift")).toBe(true);
310+
});
293311
});

0 commit comments

Comments
 (0)