ignored.test.ts

3.6 KB · raw

1// Covers names ignored in every repo (June, 2026-10-01): a file or folder with that exact name, at2// any depth, is gone from every repo at once, stays gone in later saves, and comes back when the3// name is taken off the list.45import { beforeAll, describe, expect, test } from "bun:test";6import { mkdir, writeFile } from "node:fs/promises";7import { join } from "node:path";8import { openBucket } from "../src/bucket/reader.ts";9import { syncAll } from "../src/bucket/sync.ts";10import { Browser, type Instance, instance } from "./browser.ts";11import { makeRepos } from "./fixture.ts";1213describe("names ignored in every repo", () => {14	let inst: Instance;15	let browser: Browser;16	let repos: Awaited<ReturnType<typeof makeRepos>>;17	const status = async (path: string) => `${path} ${(await inst.app.request(path)).status}`;18	const ignore = (ignored: string) => browser.post("/admin/site", { section: "site", ignored });19	const sync = () =>20		syncAll({21			bucket: openBucket({ kind: "folder", path: repos.bucketDir }),22			kepr: inst.kepr,23			mirrorDir: join(inst.dataDir, "mirror"),24		});25	const gone = ["/app/raw/AGENTS.md", "/app/raw/.agent/notes.md", "/lib/raw/src/AGENTS.md"];26	const kept = ["/app/raw/AGENTS.md.bak", "/app/raw/.agents/x.md", "/lib/raw/src/main.ts"];2728	beforeAll(async () => {29		repos = await makeRepos(["app", "lib"]);30		const files: [string, string][] = [31			["app/AGENTS.md", "rules\n"],32			["app/AGENTS.md.bak", "old rules\n"],33			["app/.agent/notes.md", "notes\n"],34			["app/.agents/x.md", "not the same name\n"],35			["lib/src/AGENTS.md", "nested rules\n"],36			["lib/src/main.ts", "export const a = 1;\n"],37		];38		for (const [path, text] of files) {39			const full = join(repos.bucketDir, "..", "work", path);40			await mkdir(join(full, ".."), { recursive: true });41			await writeFile(full, text);42		}43		for (const repo of ["app", "lib"]) {44			repos.koh(repo, "save", "add agent files");45			repos.koh(repo, "offer");46		}47		inst = await instance(repos.bucketDir);48		browser = new Browser(inst.app);49		await browser.signIn();50		for (const repo of ["app", "lib"]) {51			await browser.post(`/admin/repos/${repo}`, { public: "1", hidden_paths: "" });52		}53	});5455	test("refuses anything but a plain name", async () => {56		for (const name of ["src/AGENTS.md", "..", "a\u0000b", "x".repeat(256)]) {57			expect((await ignore(name)).status).toBe(400);58		}59		expect(await status(gone[0] as string)).toBe(`${gone[0]} 200`);60	});6162	test("an ignored name is gone from every repo at any depth, and only that name", async () => {63		expect((await ignore(".agent\r\nAGENTS.md\n")).status).toBe(303);64		for (const path of gone) expect(await status(path)).toBe(`${path} 404`);65		for (const path of kept) expect(await status(path)).toBe(`${path} 200`);66		expect(await (await browser.get("/admin/site")).text()).toContain(67			">.agent\nAGENTS.md</textarea>",68		);69	});7071	test("stays ignored in saves that arrive later", async () => {72		await writeFile(join(repos.bucketDir, "..", "work", "app", "AGENTS.md"), "new rules\n");73		repos.koh("app", "save", "change the rules");74		repos.koh("app", "offer");75		await sync();76		expect(await status("/app/raw/AGENTS.md")).toBe("/app/raw/AGENTS.md 404");77		expect(await (await inst.app.request("/app")).text()).toContain("change the rules");78	});7980	test("taking a name off the list brings its files back", async () => {81		expect((await ignore(".agent")).status).toBe(303);82		expect(await status("/lib/raw/src/AGENTS.md")).toBe("/lib/raw/src/AGENTS.md 200");83		expect(await (await inst.app.request("/app/raw/AGENTS.md")).text()).toBe("new rules\n");84		expect(await status("/app/raw/.agent/notes.md")).toBe("/app/raw/.agent/notes.md 404");85	});86});