mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 04:26:16 -08:00
fix(agents): handle fenced imports and encoded paths
This commit is contained in:
1 parent
46d7f58a6c
commit
1206f0d255
4 files changed
+62
-7
No files matched your search
@@ -37,6 +37,9 @@ Write generic filenames as prose; commands, templates, globs, URLs, package
|
||||
aliases and dotted code symbols are excluded. Bare dotted names with conventional
|
||||
file suffixes (such as .md, .json or .ts) are treated as filenames. Use a `./`
|
||||
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 examples
|
||||
do not count as root guidance imports or satisfy the required Claude import.
|
||||
Heading anchors are derived from parsed text, not HTML sanitization. The Nx test
|
||||
hash includes `marked` so dependency changes invalidate parser coverage.
|
||||
It cannot prove semantic equivalence; review changed contracts as well.
|
||||
|
||||
@@ -83,7 +83,7 @@ function isLiteralRepositoryPath(token) {
|
||||
return false;
|
||||
return (
|
||||
path.includes('/') ||
|
||||
/^(?:\.[\p{L}\p{N}_-]+|[\p{L}\p{N}_-][\p{L}\p{N}_.-]*\.[\p{L}][\p{L}\p{N}_-]*)$/u.test(
|
||||
/^(?:\.[\p{L}\p{N}_-][\p{L}\p{N}_.-]*|[\p{L}\p{N}_-][\p{L}\p{N}_.-]*\.[\p{L}][\p{L}\p{N}_-]*)$/u.test(
|
||||
path
|
||||
)
|
||||
);
|
||||
|
||||
@@ -50,14 +50,17 @@ async function validateReference(
|
||||
if (unresolvedReference !== undefined)
|
||||
return `${source}: unresolved Markdown reference "${unresolvedReference}"`;
|
||||
if (/^(?:[a-z][a-z\d+.-]*:|\/\/)/iu.test(target)) return;
|
||||
let decoded;
|
||||
let path;
|
||||
let anchor;
|
||||
try {
|
||||
decoded = decodeURIComponent(target);
|
||||
const hash = target.indexOf('#');
|
||||
const pathAndQuery = hash < 0 ? target : target.slice(0, hash);
|
||||
path = decodeURIComponent(pathAndQuery.split('?')[0]);
|
||||
anchor =
|
||||
hash < 0 ? undefined : decodeURIComponent(target.slice(hash + 1));
|
||||
} catch {
|
||||
return `${source}: malformed local link: ${target}`;
|
||||
}
|
||||
const [pathAndQuery, anchor] = decoded.split('#');
|
||||
const path = pathAndQuery.split('?')[0];
|
||||
const absolute = path
|
||||
? resolve(literal ? rootDir : dirname(resolve(rootDir, source)), path)
|
||||
: resolve(rootDir, source);
|
||||
@@ -106,10 +109,11 @@ export async function validateAgentGuidance({ rootDir }) {
|
||||
diagnostics.push(
|
||||
`${source}: at most ${maxBytes} UTF-8 bytes allowed (received ${bytes})`
|
||||
);
|
||||
const imports = [...markdown.matchAll(/^\s*@([^\s]+)\s*$/gmu)].map(
|
||||
const unfenced = withoutFences(markdown);
|
||||
const imports = [...unfenced.matchAll(/^\s*@([^\s]+)\s*$/gmu)].map(
|
||||
(match) => match[1]
|
||||
);
|
||||
const prose = withoutFences(markdown).replace(/`[^`\n]+`/gu, '');
|
||||
const prose = unfenced.replace(/`[^`\n]+`/gu, '');
|
||||
const inlineImports = [...prose.matchAll(/(?:^|[\s(])@([^\s]+)/gu)]
|
||||
.map((match) => match[1])
|
||||
.filter(
|
||||
|
||||
@@ -172,6 +172,8 @@ for (const path of [
|
||||
'missing.scss',
|
||||
'custom.config-format',
|
||||
'.custom-config',
|
||||
'.env.local',
|
||||
'.eslintrc.json',
|
||||
'arbitrary/directory',
|
||||
]) {
|
||||
test(`checks generic literal repository path ${path}`, async (t) => {
|
||||
@@ -406,3 +408,49 @@ test('explicit HTML anchors work but anchors in code examples do not', async (t)
|
||||
});
|
||||
assert.match(errors.join('\n'), /missing anchor/);
|
||||
});
|
||||
|
||||
for (const source of ['AGENTS.md', 'CLAUDE.md']) {
|
||||
test(`${source}: fenced decorators are not root imports`, async (t) => {
|
||||
const prefix = source === 'CLAUDE.md' ? '@AGENTS.md\n' : '';
|
||||
assert.deepEqual(
|
||||
await diagnostics(t, {
|
||||
[source]:
|
||||
prefix + '```ts\n@Injectable()\n@docs/missing.md\n```\n',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
});
|
||||
}
|
||||
test('a fenced import cannot satisfy the required CLAUDE import', async (t) => {
|
||||
assert.match(
|
||||
(
|
||||
await diagnostics(t, {
|
||||
'CLAUDE.md': '```text\n@AGENTS.md\n```\n',
|
||||
})
|
||||
).join('\n'),
|
||||
/standalone @AGENTS.md/
|
||||
);
|
||||
});
|
||||
for (const [encoded, filename] of [
|
||||
['guide%23one.md', 'guide#one.md'],
|
||||
['guide%3Fone.md', 'guide?one.md'],
|
||||
]) {
|
||||
test(`encoded filename delimiters stay in path: ${encoded}`, async (t) => {
|
||||
assert.deepEqual(
|
||||
await diagnostics(t, {
|
||||
'AGENTS.md': `[Doc](docs/${encoded}?view=1#hello%2Dworld)`,
|
||||
[`docs/${filename}`]: '# Hello World\n',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
assert.match(
|
||||
(
|
||||
await diagnostics(t, {
|
||||
'AGENTS.md': `[Doc](docs/${encoded}#missing)`,
|
||||
[`docs/${filename}`]: '# Hello World\n',
|
||||
})
|
||||
).join('\n'),
|
||||
/missing anchor/
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user