@@ -43,18 +43,29 @@ export function maxCodeBlockLines(content: string): number {
4343 return max
4444}
4545
46- // True when the doc references a backing `scripts/**.mts` (the deferral target
47- // a thin skill/command should point to). Scans the markdown content, not a
48- // shell command line.
46+ // True when the doc references a backing `.mts` in ANY of the fleet's deferral
47+ // conventions: a `scripts/**.mts` path, a co-located `.claude/skills/**.mts`, or
48+ // a relative co-located `lib/**.mts` / `run.mts` the skill invokes (the dominant
49+ // skill-backing shape). Scans the markdown content, not a shell command line.
4950export function referencesScript ( content : string ) : boolean {
50- return / \b s c r i p t s \/ [ ^ \s ) ' " ] * \. m t s \b / . test ( content )
51+ return / (?: \b s c r i p t s \/ [ ^ \s ) ' " ] * \. m t s | \. c l a u d e \/ s k i l l s \/ [ ^ \s ) ' " ] * \. m t s | \b l i b \/ [ ^ \s ) ' " ] * \. m t s | \b r u n \. m t s ) \b / . test (
52+ content ,
53+ )
54+ }
55+
56+ // A `user-invocable: false` skill is a REFERENCE/doc — its fenced blocks are
57+ // examples, not an operation with logic to extract — so the thin-wrapper rule
58+ // doesn't apply and a large example block is not a smell.
59+ export function isReferenceSkill ( content : string ) : boolean {
60+ return / ^ u s e r - i n v o c a b l e : \s * f a l s e \b / m. test ( content )
5161}
5262
5363export const hook = defineHook ( {
5464 check : editGuard ( ( filePath , content ) => {
5565 if (
5666 ! content ||
5767 ! isSkillOrCommandDoc ( filePath ) ||
68+ isReferenceSkill ( content ) ||
5869 maxCodeBlockLines ( content ) <= HEAVY_LINES ||
5970 referencesScript ( content )
6071 ) {
@@ -66,10 +77,11 @@ export const hook = defineHook({
6677 '' ,
6778 ` File: ${ filePath } ` ,
6879 '' ,
69- ` A fenced code block over ${ HEAVY_LINES } lines with no backing` ,
70- ' `scripts/**.mts` reference — inline logic in a skill/command is' ,
71- ' untested, unlinted, and not reusable. Move it to a script and invoke' ,
72- ' that from the markdown so the skill stays a thin wrapper.' ,
80+ ` A fenced code block over ${ HEAVY_LINES } lines with no backing \`.mts\`` ,
81+ ' reference (`scripts/**.mts`, a co-located `lib/*.mts`, or `run.mts`) —' ,
82+ ' inline logic in a skill/command is untested, unlinted, and not' ,
83+ ' reusable. Move it to a script and invoke that from the markdown so the' ,
84+ ' skill stays a thin wrapper.' ,
7385 ] . join ( '\n' ) ,
7486 )
7587 } ) ,
0 commit comments