fix(agents): require standalone top-level Claude import

This commit is contained in:
4gray committed 2026-09-20 20:20:09 +02:00
1 parent 98e6fd3983
commit 84596ecb41
4 files changed
+28 -3

No files matched your search

+2
View File
@@ -40,6 +40,8 @@ prefix or Markdown link for other ambiguous filenames that resemble code symbols
Multi-part dotfiles are path candidates too. Link paths and fragments are decoded
separately so encoded filename delimiters stay in the filename. Fenced and indented examples
do not count as root guidance imports or satisfy the required Claude import.
The required Claude import must be an unformatted standalone line in a top-level
paragraph; headings, quotes and list items do not satisfy it.
Heading anchors decode HTML character references in text and use `github-slugger`
for GitHub-compatible character filtering and duplicate suffixes. Explicit HTML anchors
use `parse5`, excluding comments, scripts, styles and template contents.
+10
View File
@@ -83,6 +83,16 @@ export function guidanceProse(markdown) {
return markdownLexer.lexer(markdown).map(prose).join('\n');
}
export function guidanceStandaloneImports(markdown) {
return markdownLexer
.lexer(markdown)
.filter((token) => token.type === 'paragraph')
.flatMap((token) => [
...token.raw.matchAll(/^ {0,3}@([^\s]+)[\t ]*$/gmu),
])
.map((match) => match[1]);
}
export function guidanceAnchors(markdown) {
const slugger = new GithubSlugger();
const found = new Set();
+2 -3
View File
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
import {
guidanceAnchors as anchors,
guidanceProse,
guidanceStandaloneImports,
guidanceReferences as references,
} from './agent-guidance-markdown.mjs';
@@ -90,9 +91,7 @@ export async function validateAgentGuidance({ rootDir }) {
`${source}: at most ${maxBytes} UTF-8 bytes allowed (received ${bytes})`
);
const unfenced = guidanceProse(markdown);
const imports = [...unfenced.matchAll(/^\s*@([^\s]+)\s*$/gmu)].map(
(match) => match[1]
);
const imports = guidanceStandaloneImports(markdown);
const prose = unfenced.replace(/`[^`\n]+`/gu, '');
const inlineImports = [...prose.matchAll(/(?:^|[\s(])@([^\s]+)/gu)]
.map((match) => match[1])
@@ -558,3 +558,17 @@ test('GitHub heading slugs remove non-ASCII whitespace', async (t) => {
);
}
});
for (const body of [
'> @AGENTS.md',
'- @AGENTS.md',
'# @AGENTS.md',
'**@AGENTS.md**',
]) {
test(`structured Markdown cannot satisfy Claude import: ${body}`, async (t) => {
assert.match(
(await diagnostics(t, { 'CLAUDE.md': body })).join('\n'),
/standalone @AGENTS.md/
);
});
}