diff --git a/.changeset/lucky-pugs-repeat.md b/.changeset/lucky-pugs-repeat.md new file mode 100644 index 0000000..7a1071b --- /dev/null +++ b/.changeset/lucky-pugs-repeat.md @@ -0,0 +1,5 @@ +--- +"@neuledge/context": patch +--- + +Only skip repo-meta filenames (`security`, `license`, `changelog`, `contributing`, …) at the scan root, not at every depth. A documentation page that happens to share one of those names was being dropped silently: `context add` on the forgejo docs lost `docs/admin/actions/security.md`, the only source in the repo for `container.valid_volumes`, and reported success. `docker/docs` and `excalidraw/excalidraw` lose pages to the same rule. diff --git a/packages/context/src/git.test.ts b/packages/context/src/git.test.ts index 925b4fd..2f567c6 100644 --- a/packages/context/src/git.test.ts +++ b/packages/context/src/git.test.ts @@ -1,9 +1,13 @@ -import { describe, expect, it } from "vitest"; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { findLatestStableVersion, isMissingRefError, isTransientGitError, parseMonorepoTag, + readLocalDocsFiles, } from "./git.js"; describe("isTransientGitError", () => { @@ -189,3 +193,42 @@ describe("findLatestStableVersion", () => { }); }); }); + +describe("readLocalDocsFiles — repo-meta filenames", () => { + let dir: string; + + beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "ctx-localdocs-")); + }); + + afterEach(() => { + rmSync(dir, { recursive: true, force: true }); + }); + + const write = (rel: string, body: string): void => { + const full = join(dir, rel); + mkdirSync(join(full, ".."), { recursive: true }); + writeFileSync(full, body); + }; + + it("skips repo-meta files at the scan root", () => { + write("security.md", "# Security policy\n\nReport issues to us.\n"); + write("license.md", "# License\n\nMIT.\n"); + write("guide.md", "# Guide\n\nContent.\n"); + + const paths = readLocalDocsFiles(dir).map((f) => f.path); + + expect(paths).toEqual(["guide.md"]); + }); + + it("keeps a documentation page that merely shares a repo-meta filename", () => { + write( + "admin/actions/security.md", + "# Securing Actions\n\nThe default value of valid_volumes is an empty array.\n", + ); + + const paths = readLocalDocsFiles(dir).map((f) => f.path); + + expect(paths).toEqual(["admin/actions/security.md"]); + }); +}); diff --git a/packages/context/src/git.ts b/packages/context/src/git.ts index fa764d1..bc58be9 100755 --- a/packages/context/src/git.ts +++ b/packages/context/src/git.ts @@ -474,7 +474,11 @@ function findMarkdownFiles( const matchingExt = DOCUMENTATION_EXTENSIONS.find((ext) => lowerName.endsWith(ext), ); - if (matchingExt) { + // Only at the scan root: these names mean repo housekeeping there, but + // deeper in a docs tree they are ordinary pages — forgejo's + // docs/admin/actions/security.md documents Actions security, and was + // being dropped as if it were a SECURITY.md policy file. + if (matchingExt && basePath === "") { const baseName = lowerName.slice(0, -matchingExt.length); if (IGNORED_FILES.has(baseName)) continue; }