From 363d390f3f0b766934e6fc5a36369df3e09e54d6 Mon Sep 17 00:00:00 2001 From: Jeremy Levartovsky Date: Sun, 30 Aug 2026 09:22:26 +1000 Subject: [PATCH 1/2] fix(context): only skip repo-meta filenames at the scan root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `IGNORED_FILES` is matched by basename at every depth, so any documentation page that happens to be named `security.md`, `license.md`, `changelog.md`, `contributing.md` or `history.md` is dropped as if it were repo housekeeping. Measured on codeberg.org/forgejo/docs with @neuledge/context 1.2.3: 138 markdown files under `docs/`, 135 reach the builder. The two lost files are `docs/admin/actions/security.md` and `docs/user/actions/security.md` — real documentation about securing Forgejo Actions, and the only source in the repo for `container.valid_volumes`. `context add` prints "Found 135 markdown files" and exits 0, so nothing signals the loss; a later query for `valid_volumes` simply returns nothing. Other repos hit by the same rule: docker/docs loses `content/manuals/extensions/extensions-sdk/architecture/security.md`, two `history.md` pages and two `changelog.md` API references; excalidraw/excalidraw loses `dev-docs/docs/introduction/contributing.mdx`. Restricting the check to `basePath === ""` keeps the original intent — those names mean repo housekeeping at the top of a tree — while leaving nested pages alone. Two tests cover both halves. --- packages/context/src/git.test.ts | 45 +++++++++++++++++++++++++++++++- packages/context/src/git.ts | 6 ++++- 2 files changed, 49 insertions(+), 2 deletions(-) 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; } From a24d887ba53ad3b73f5f278a026da781c96db87d Mon Sep 17 00:00:00 2001 From: Jeremy Levartovsky Date: Sun, 30 Aug 2026 12:59:00 +1000 Subject: [PATCH 2/2] Add a changeset for the IGNORED_FILES fix --- .changeset/lucky-pugs-repeat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lucky-pugs-repeat.md 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.