fix(agents): reject empty media and ignore URL at-signs

This commit is contained in:
4gray committed 2026-09-21 02:44:36 +02:00
1 parent 6558245e12
commit a7150d1e72
3 files changed
+25 -2

No files matched your search

+2 -1
View File
@@ -60,13 +60,14 @@ as Markdown links, including decoded attributes and fragment validation.
URL attributes remove ASCII tabs/newlines throughout and discard surrounding
ASCII control/space characters before resolution.
Iframe/embed sources and object data attributes are document references and retain Markdown-target anchor checks.
Image and media references must resolve to files, not directories.
Image and media references require nonempty targets that resolve to files, not directories.
Image references check file existence without interpreting image fragments as
Markdown headings; document links keep anchor checks even when sharing a target.
HTML video, audio, source and track `src` assets and video posters use the same
existence checks as images. Entity decoding uses full HTML text/attribute rules,
including references whose semicolon may be omitted.
Inline guidance imports are rejected after punctuation as well as whitespace.
At-signs inside external URLs are excluded from the import scan.
Extensionless inline candidates are also imports when they resolve to repository files,
checking the full filename before prefixes at ASCII/Unicode prose separators.
Declared scoped dependencies, scope wildcards and matching TypeScript path aliases
+5 -1
View File
@@ -41,6 +41,7 @@ async function validateReference(
if (unresolvedReference !== undefined)
return `${source}: unresolved Markdown reference "${unresolvedReference}"`;
if (/^(?:[a-z][a-z\d+.-]*:|\/\/)/iu.test(target)) return;
if (image && !target) return `${source}: empty media target`;
let path;
let anchor;
try {
@@ -184,7 +185,10 @@ export async function validateAgentGuidance({ rootDir }) {
diagnostics.push(
`${source}: at most ${maxBytes} UTF-8 bytes allowed (received ${bytes})`
);
const prose = guidanceProse(markdown);
const prose = guidanceProse(markdown).replace(
/(?:\b[a-z][a-z\d+.-]*:\/\/|\/\/)[^\s]+/giu,
' '
);
const imports = guidanceStandaloneImports(markdown);
const inlineImports = [];
for (const match of prose.matchAll(
@@ -1381,3 +1381,21 @@ for (const entity of ['	', '
', '
']) {
);
});
}
for (const markup of ['![logo]()', '<img src="">', '<video src=" "></video>']) {
test(`empty media references are rejected: ${markup}`, async (t) => {
assert.ok((await diagnostics(t, { 'AGENTS.md': markup })).length > 0);
});
}
for (const url of [
'https://example.com/@docs/guide',
'https://example.com/user?next=@docs/guide',
'//example.com/@docs/guide',
]) {
test(`external URL at-sign is not an import: ${url}`, async (t) => {
assert.deepEqual(
await diagnostics(t, { 'AGENTS.md': 'Visit ' + url }),
[]
);
});
}