// Covers names ignored in every repo (June, 2026-10-01): a file or folder with that exact name, at // any depth, is gone from every repo at once, stays gone in later saves, and comes back when the // name is taken off the list. import { beforeAll, describe, expect, test } from "bun:test"; import { mkdir, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { openBucket } from "../src/bucket/reader.ts"; import { syncAll } from "../src/bucket/sync.ts"; import { Browser, type Instance, instance } from "./browser.ts"; import { makeRepos } from "./fixture.ts"; describe("names ignored in every repo", () => { let inst: Instance; let browser: Browser; let repos: Awaited>; const status = async (path: string) => `${path} ${(await inst.app.request(path)).status}`; const ignore = (ignored: string) => browser.post("/admin/site", { section: "site", ignored }); const sync = () => syncAll({ bucket: openBucket({ kind: "folder", path: repos.bucketDir }), kepr: inst.kepr, mirrorDir: join(inst.dataDir, "mirror"), }); const gone = ["/app/raw/AGENTS.md", "/app/raw/.agent/notes.md", "/lib/raw/src/AGENTS.md"]; const kept = ["/app/raw/AGENTS.md.bak", "/app/raw/.agents/x.md", "/lib/raw/src/main.ts"]; beforeAll(async () => { repos = await makeRepos(["app", "lib"]); const files: [string, string][] = [ ["app/AGENTS.md", "rules\n"], ["app/AGENTS.md.bak", "old rules\n"], ["app/.agent/notes.md", "notes\n"], ["app/.agents/x.md", "not the same name\n"], ["lib/src/AGENTS.md", "nested rules\n"], ["lib/src/main.ts", "export const a = 1;\n"], ]; for (const [path, text] of files) { const full = join(repos.bucketDir, "..", "work", path); await mkdir(join(full, ".."), { recursive: true }); await writeFile(full, text); } for (const repo of ["app", "lib"]) { repos.koh(repo, "save", "add agent files"); repos.koh(repo, "offer"); } inst = await instance(repos.bucketDir); browser = new Browser(inst.app); await browser.signIn(); for (const repo of ["app", "lib"]) { await browser.post(`/admin/repos/${repo}`, { public: "1", hidden_paths: "" }); } }); test("global hide is linked from repos and precedes the long site editors", async () => { const reposPage = await (await browser.get("/admin/repos")).text(); expect(reposPage).toContain('href="/admin/site#global-hide"'); const site = await (await browser.get("/admin/site")).text(); expect(site).toContain('id="global-hide"'); expect(site.indexOf('name="ignored"')).toBeLessThan(site.indexOf('name="support_page"')); expect(await (await browser.get("/admin/site?section=profile")).text()).not.toContain( 'name="ignored"', ); }); test("refuses anything but a plain name", async () => { for (const name of ["src/AGENTS.md", "..", "a\u0000b", "x".repeat(256)]) { expect((await ignore(name)).status).toBe(400); } expect(await status(gone[0] as string)).toBe(`${gone[0]} 200`); }); test("an ignored name is gone from every repo at any depth, and only that name", async () => { expect((await ignore(".agent\r\nAGENTS.md\n")).status).toBe(303); for (const path of gone) expect(await status(path)).toBe(`${path} 404`); for (const path of kept) expect(await status(path)).toBe(`${path} 200`); expect(await (await browser.get("/admin/site")).text()).toContain( ">.agent\nAGENTS.md", ); }); test("stays ignored in saves that arrive later", async () => { await writeFile(join(repos.bucketDir, "..", "work", "app", "AGENTS.md"), "new rules\n"); repos.koh("app", "save", "change the rules"); repos.koh("app", "offer"); await sync(); expect(await status("/app/raw/AGENTS.md")).toBe("/app/raw/AGENTS.md 404"); expect(await (await inst.app.request("/app")).text()).toContain("change the rules"); }); test("taking a name off the list brings its files back", async () => { expect((await ignore(".agent")).status).toBe(303); expect(await status("/lib/raw/src/AGENTS.md")).toBe("/lib/raw/src/AGENTS.md 200"); expect(await (await inst.app.request("/app/raw/AGENTS.md")).text()).toBe("new rules\n"); expect(await status("/app/raw/.agent/notes.md")).toBe("/app/raw/.agent/notes.md 404"); }); });