fix(agents): scan nested imports and share document suffixes

This commit is contained in:
4gray committed 2026-09-21 04:21:52 +02:00
1 parent 673d3fd791
commit 47cfc1ba4a
4 files changed
+40 -6

No files matched your search

+4
View File
@@ -4,6 +4,9 @@ import GithubSlugger from 'github-slugger';
import { Marked, Tokenizer } from 'marked';
import { parseFragment } from 'parse5';
export const DOCUMENT_EXTENSION =
/\.(?:md|markdown|mdown|mkd|mdx|txt|json|ya?ml|html?|rst|rest|adoc|asciidoc|pdf|doc[xm]?|dot[xm]?|od[tspgfbm]|ot[tspg]|fod[tspg]|rtf|org|tex|latex)$/iu;
// Inspection only: generated HTML is parsed in memory, never executed or emitted.
const markdownLexer = new Marked({
tokenizer: {
@@ -280,6 +283,7 @@ function isLiteralRepositoryPath(token) {
// This applies to user-defined symbols as well as JavaScript globals.
if (
/^[\p{L}_][\p{L}\p{N}_]*(?:\.[\p{L}_][\p{L}\p{N}_]*)+$/u.test(path) &&
!DOCUMENT_EXTENSION.test(path) &&
!/\.(?:md|mdx|json|jsonc|ya?ml|[cm]?[jt]sx?|html?|css|scss|sass|less|toml|xml|txt|sh|py|sql|svg|png|jpe?g|webp|gif|m3u8?|conf|ini|lock)$/iu.test(
path
)
+3 -4
View File
@@ -10,6 +10,7 @@ import {
} from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import {
DOCUMENT_EXTENSION,
guidanceAnchors as anchors,
guidanceProse,
guidanceStandaloneImports,
@@ -160,9 +161,7 @@ async function packageMentions(rootDir) {
/(?:^|\/)(?:AGENTS|CLAUDE|INSTRUCTIONS|README|LICENSE|LICENCE|NOTICE|COPYING|AUTHORS|CONTRIBUTORS|CHANGELOG)$/u.test(
path
) ||
/\.(?:txt|json|ya?ml|html?|rst|rest|adoc|asciidoc|pdf|doc[xm]?|dot[xm]?|od[tspgfbm]|ot[tspg]|fod[tspg]|rtf|org|tex|latex)$/iu.test(
path
)
DOCUMENT_EXTENSION.test(path)
)
return false;
if (packages.includes(token)) return true;
@@ -213,7 +212,7 @@ export async function validateAgentGuidance({ rootDir }) {
const imports = guidanceStandaloneImports(markdown);
const inlineImports = [];
for (const match of prose.matchAll(
/(?:^|[^\p{L}\p{N}_@])@([^\s]+)/gu
/(?=(?:^|[^\p{L}\p{N}_@])@([^\s]+))/gu
)) {
const token = match[1];
if (isPackageMention(token)) continue;
@@ -1557,3 +1557,32 @@ for (const opening of ['(', '[', '{']) {
);
});
}
test('package prose cannot hide nested guidance import', async (t) => {
assert.ok(
(
await diagnostics(t, {
'package.json': JSON.stringify({
dependencies: { '@angular/core': '*' },
}),
'CLAUDE.md': '@AGENTS.md\n\nUse @angular/core(@INSTRUCTIONS)',
INSTRUCTIONS: 'Guidance',
})
).some((message) => message.includes('additional or inline'))
);
});
for (const extension of ['pdf', 'rst', 'adoc', 'markdown', 'docm', 'latex']) {
test(`bare document literal is checked: ${extension}`, async (t) => {
const name = 'manual.' + extension;
assert.ok(
(await diagnostics(t, { 'AGENTS.md': '`' + name + '`' })).length > 0
);
assert.deepEqual(
await diagnostics(t, {
'AGENTS.md': '`' + name + '`',
[name]: 'Document',
}),
[]
);
});
}