11import assert from "node:assert/strict" ;
2- import { execFile } from "node:child_process" ;
3- import { lstat , readFile , readlink } from "node:fs/promises" ;
42import { resolve } from "node:path" ;
53import { test } from "node:test" ;
6- import { promisify } from "node:util" ;
74import {
85 analyse ,
96 CODEX_SKILLS ,
7+ codeSpans ,
108 parse ,
119 references ,
1210 type Snapshot ,
11+ scan ,
1312 type TrackedFile ,
1413 withoutCode ,
1514} from "./check-agent-instructions.ts" ;
@@ -27,6 +26,7 @@ function only(failures: readonly string[]): string {
2726
2827/** A symlink to `target`, as an override value. */
2928const symlinkTo = ( target : string ) : { readonly target : string } => ( { target } ) ;
29+ const markdownSpans = ( markdown : string ) : readonly string [ ] => codeSpans ( markdown , "markdown" ) ;
3030
3131type Override = string | { readonly target : string } | { readonly kind : "opaque" } | null ;
3232
@@ -57,27 +57,8 @@ await test("the wired checkout passes", () => {
5757 assert . deepEqual ( analyse ( snapshot ( ) ) , [ ] ) ;
5858} ) ;
5959
60- /**
61- * The repository itself. `pnpm run check` runs the CLI over the real tree, but only ever over the
62- * content of the day; this pins it.
63- */
6460await test ( "the repository this gate ships in passes it" , async ( ) => {
65- const { stdout } = await promisify ( execFile ) (
66- "git" ,
67- [ "ls-files" , "-z" , "--cached" , "--others" , "--exclude-standard" ] ,
68- { cwd : REPO_ROOT , maxBuffer : 64 * 1024 * 1024 } ,
69- ) ;
70- const files : TrackedFile [ ] = [ ] ;
71- for ( const path of [ ...new Set ( stdout . split ( "\0" ) . filter ( Boolean ) ) ] . toSorted ( ) ) {
72- const stats = await lstat ( resolve ( REPO_ROOT , path ) ) . catch ( ( ) => undefined ) ;
73- if ( stats === undefined ) continue ;
74- if ( stats . isSymbolicLink ( ) ) {
75- files . push ( { path, kind : "symlink" , target : await readlink ( resolve ( REPO_ROOT , path ) ) } ) ;
76- } else if ( path . endsWith ( ".md" ) || path === "opencode.json" ) {
77- files . push ( { path, kind : "text" , content : await readFile ( resolve ( REPO_ROOT , path ) , "utf8" ) } ) ;
78- } else files . push ( { path, kind : "opaque" } ) ;
79- }
80- assert . deepEqual ( analyse ( { files } , CODEX_SKILLS ) , [ ] ) ;
61+ assert . deepEqual ( analyse ( await scan ( REPO_ROOT ) , CODEX_SKILLS ) , [ ] ) ;
8162} ) ;
8263
8364await test ( "a nested AGENTS.md with no CLAUDE.md beside it is unreachable in Claude Code" , ( ) => {
@@ -200,6 +181,158 @@ await test("code is not prose: a reference inside a span, a fence or a comment i
200181 assert . deepEqual ( references ( "```sh\nx\n```\n\n@AGENTS.md\n" ) , [ "AGENTS.md" ] ) ;
201182} ) ;
202183
184+ await test ( "the markdown scanner extracts code spans, not fences or comments" , ( ) => {
185+ assert . deepEqual ( markdownSpans ( "Use `scripts/check.ts` and ``a ` b``." ) , [
186+ "scripts/check.ts" ,
187+ "a ` b" ,
188+ ] ) ;
189+ assert . deepEqual ( markdownSpans ( "A `line\nwrap` is one span." ) , [ "line wrap" ] ) ;
190+ assert . deepEqual ( markdownSpans ( "A `CRLF\r\nwrap` is one span." ) , [ "CRLF wrap" ] ) ;
191+ assert . deepEqual ( markdownSpans ( "A `CR\rwrap` is one span." ) , [ "CR wrap" ] ) ;
192+ assert . deepEqual ( markdownSpans ( "` padded ` and ` `" ) , [ "padded" , " " ] ) ;
193+ assert . deepEqual ( markdownSpans ( "<!-- `hidden.md` -->\n```md\n`fenced.md`\n```\n`shown.md`" ) , [
194+ "shown.md" ,
195+ ] ) ;
196+ assert . deepEqual ( markdownSpans ( "\\`escaped.md\\`\n\n `indented.md`" ) , [ ] ) ;
197+ assert . deepEqual ( markdownSpans ( "`a <!-- literal --> span`" ) , [ "a <!-- literal --> span" ] ) ;
198+ assert . deepEqual ( markdownSpans ( "> ```md\n> `quoted.md`\n> ```\n`shown.md`" ) , [ "shown.md" ] ) ;
199+ assert . deepEqual ( codeSpans ( "<Tabs>\n<TabItem>\nUse `inside.md`\n</TabItem>\n</Tabs>" , "mdx" ) , [
200+ "inside.md" ,
201+ ] ) ;
202+ assert . deepEqual ( markdownSpans ( "`not closed``" ) , [ ] ) ;
203+ assert . deepEqual (
204+ markdownSpans ( "```md\n`hidden.md`\n``` not a close\n`still-hidden.md`\n```" ) ,
205+ [ ] ,
206+ ) ;
207+ assert . deepEqual ( markdownSpans ( "```md\n<!--\n```\n`shown.md`" ) , [ "shown.md" ] ) ;
208+ assert . deepEqual ( markdownSpans ( "<!--\n```md\n-->\n`shown.md`" ) , [ "shown.md" ] ) ;
209+ } ) ;
210+
211+ await test ( "contributor docs reject missing repository paths and npm packages" , ( ) => {
212+ const failures = analyse (
213+ snapshot ( {
214+ "package.json" : JSON . stringify ( { dependencies : { react : "19.0.0" } } ) ,
215+ "scripts/existing.ts" : { kind : "opaque" } ,
216+ "docs/contributor/setup.md" :
217+ "Use `scripts/existing.ts`, `react`, `scripts/missing.ts`, `missing-plugin`, and `@missing/package`.\n" ,
218+ } ) ,
219+ ) ;
220+ assert . equal ( failures . length , 3 , failures . join ( "\n" ) ) ;
221+ assert . match ( failures [ 0 ] ?? "" , / s c r i p t s \/ m i s s i n g \. t s / ) ;
222+ assert . match ( failures [ 1 ] ?? "" , / m i s s i n g - p l u g i n / ) ;
223+ assert . match ( failures [ 2 ] ?? "" , / @ m i s s i n g \/ p a c k a g e / ) ;
224+ } ) ;
225+
226+ await test ( "an intentional non-checkout path is allowed only in the document that owns it" , ( ) => {
227+ assert . deepEqual (
228+ analyse (
229+ snapshot ( {
230+ "server/existing.ts" : { kind : "opaque" } ,
231+ "docs/contributor/local-development.mdx" : "Create `server/.env`.\n" ,
232+ } ) ,
233+ ) ,
234+ [ ] ,
235+ ) ;
236+ assert . match (
237+ only (
238+ analyse (
239+ snapshot ( {
240+ "server/existing.ts" : { kind : "opaque" } ,
241+ "docs/contributor/setup.md" : "Create `server/.env`.\n" ,
242+ } ) ,
243+ ) ,
244+ ) ,
245+ / s e r v e r \/ .e n v / ,
246+ ) ;
247+ } ) ;
248+
249+ await test ( "a unique shorthand directory resolves independently of its descendant count" , ( ) => {
250+ assert . deepEqual (
251+ analyse (
252+ snapshot ( {
253+ "webapp/src/features/a.ts" : { kind : "opaque" } ,
254+ "webapp/src/features/b.ts" : { kind : "opaque" } ,
255+ "docs/contributor/setup.md" : "Use `src/features/`.\n" ,
256+ } ) ,
257+ ) ,
258+ [ ] ,
259+ ) ;
260+ } ) ;
261+
262+ await test ( "an invalid contributor MDX document is reported with its path" , ( ) => {
263+ assert . throws (
264+ ( ) => analyse ( snapshot ( { "docs/contributor/broken.mdx" : "<Component/ name>" } ) ) ,
265+ / d o c s \/ c o n t r i b u t o r \/ b r o k e n \. m d x : / ,
266+ ) ;
267+ } ) ;
268+
269+ await test ( "path claims cannot escape through a typo, basename, or unrelated suffix match" , ( ) => {
270+ for ( const claim of [ "scrips/missing.ts" , "missing.md" , "./config.md" ] ) {
271+ const failure = only (
272+ analyse (
273+ snapshot ( {
274+ "other/config.md" : "# Unrelated\n" ,
275+ "docs/contributor/setup.md" : `Use \`${ claim } \`.\n` ,
276+ } ) ,
277+ ) ,
278+ ) ;
279+ assert . ok ( failure . includes ( claim ) , claim ) ;
280+ }
281+ assert . deepEqual (
282+ analyse (
283+ snapshot ( {
284+ "docs/shared.md" : { kind : "opaque" } ,
285+ "docs/contributor/local.md" : { kind : "opaque" } ,
286+ "webapp/src/config.ts" : { kind : "opaque" } ,
287+ "docs/contributor/setup.md" : "Use `src/config.ts`, `./local.md`, and `../shared.md`.\n" ,
288+ } ) ,
289+ ) ,
290+ [ ] ,
291+ ) ;
292+ assert . match (
293+ only (
294+ analyse (
295+ snapshot ( {
296+ "server/src/config.ts" : { kind : "opaque" } ,
297+ "webapp/src/config.ts" : { kind : "opaque" } ,
298+ "docs/contributor/setup.md" : "Use `src/config.ts`.\n" ,
299+ } ) ,
300+ ) ,
301+ ) ,
302+ / s r c \/ c o n f i g \. t s / ,
303+ ) ;
304+ } ) ;
305+
306+ await test ( "the contributor claim scope is root Markdown and contributor Markdown or MDX only" , ( ) => {
307+ for ( const path of [ "README.md" , "docs/contributor/setup.md" , "docs/contributor/setup.mdx" ] ) {
308+ assert . match ( only ( analyse ( snapshot ( { [ path ] : "Use `missing.md`.\n" } ) ) ) , / m i s s i n g \. m d / , path ) ;
309+ }
310+ for ( const path of [ "README.mdx" , "docs/reader/setup.md" ] ) {
311+ assert . deepEqual ( analyse ( snapshot ( { [ path ] : "Use `missing.md`.\n" } ) ) , [ ] , path ) ;
312+ }
313+ } ) ;
314+
315+ await test ( "every package.json declaration field satisfies a contributor package claim" , ( ) => {
316+ const manifest = {
317+ name : "workspace-package" ,
318+ dependencies : { dependency : "1" } ,
319+ devDependencies : { "dev-package" : "1" } ,
320+ optionalDependencies : { "optional-package" : "1" } ,
321+ peerDependencies : { "peer-package" : "1" } ,
322+ } ;
323+ assert . deepEqual (
324+ analyse (
325+ snapshot ( {
326+ "package.json" : JSON . stringify ( manifest ) ,
327+ "docs/contributor/setup.md" :
328+ "`workspace-package` `dependency` `dev-package` `optional-package` `peer-package`\n" ,
329+ } ) ,
330+ ) ,
331+ [ ] ,
332+ ) ;
333+ assert . throws ( ( ) => analyse ( snapshot ( { "package.json" : "{broken" } ) ) , SyntaxError ) ;
334+ } ) ;
335+
203336await test ( "a code span split by the line wrap does not swallow the import after it" , ( ) => {
204337 assert . deepEqual (
205338 references ( "the `<form>` is the level: `flex\nmin-h-0 flex-col`, then @AGENTS.md" ) ,
0 commit comments