Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit bf3a92349425eb02363a0911c6f073666a921e4e
parent f9c8fce26e3c6fefbdc5ca32af77738de91f9b2d
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed, 30 Sep 2026 09:34:05 -0400

common: doctor's stagit line ends with the render cache — "cache: <path>, <size>" (stat'd; "none yet" when it is not there)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mcommon/bin/doctor.test.ts | 13++++++++++---
Mcommon/bin/doctor.ts | 26++++++++++++++++++++++----
2 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/common/bin/doctor.test.ts b/common/bin/doctor.test.ts @@ -58,6 +58,9 @@ function checkout(): { root: string; bin: string; paths: Paths } { parakeetCliBin: "parakeet-cli", sourceScrubFile: path.join(root, ".config", "source-scrub.txt"), sourceDenylistFile: path.join(root, ".config", "source-denylist.txt"), + // Outside the checkout, as the XDG cache is: the tests that compare the + // checkout's tree before and after never see it. + sourceHistoryCacheDir: path.join(TMP, `${path.basename(root)}-cache`, "archilyzer", "source-history"), } as unknown as Paths; return { root, bin, paths }; } @@ -250,10 +253,11 @@ test("the source publish block: the tools, the operator files by count and mode assert.equal(status(r, id), "info", id); } assert.match(r.checks.find((x) => x.id === "filter-repo")!.detail, /install: `pipx install git-filter-repo`/); - // stagit, beside git-filter-repo: where it is, or not found and how to install it. + // stagit, beside git-filter-repo: where it is, or not found and how to + // install it; then the render cache, where it is and how big. assert.equal( r.checks.find((x) => x.id === "stagit")!.detail, - "not found (PATH, ~/.local/bin) — the source is published without its history pages (/source/git/); install it once: git clone git://git.codemadness.org/stagit && make -C stagit && cp stagit/stagit ~/.local/bin/", + `not found (PATH, ~/.local/bin) — the source is published without its history pages (/source/git/); install it once: git clone git://git.codemadness.org/stagit && make -C stagit && cp stagit/stagit ~/.local/bin/; cache: ${c.paths.sourceHistoryCacheDir}, none yet`, ); const order = r.checks.filter((x) => x.section === "source publish").map((x) => x.id); assert.equal(order.indexOf("stagit"), order.indexOf("filter-repo") + 1, "beside git-filter-repo"); @@ -280,7 +284,10 @@ test("the source publish block: the tools, the operator files by count and mode assert.match(r.checks.find((x) => x.id === "filter-repo")!.detail, /pipx run --spec git-filter-repo==2\.47\.0/); assert.equal(status(r, "gitleaks"), "ok"); assert.equal(status(r, "stagit"), "ok"); - assert.equal(r.checks.find((x) => x.id === "stagit")!.detail, "/opt/stagit/stagit"); + mkdirSync(path.join(c.paths.sourceHistoryCacheDir, "out"), { recursive: true }); + writeFileSync(path.join(c.paths.sourceHistoryCacheDir, "out", "log.html"), Buffer.alloc(3 * 1024 * 1024)); + const withCache = await collectDoctorReport(deps({ filterRepo: null, gitleaks: null, stagit: "/opt/stagit/stagit" })); + assert.equal(withCache.checks.find((x) => x.id === "stagit")!.detail, `/opt/stagit/stagit; cache: ${c.paths.sourceHistoryCacheDir}, 3.0 MB`); assert.equal(status(r, "scrub rules"), "ok"); assert.match(r.checks.find((x) => x.id === "scrub rules")!.detail, /\(2 rules, mode 600\)$/); assert.equal(status(r, "denylist"), "warn"); diff --git a/common/bin/doctor.ts b/common/bin/doctor.ts @@ -307,16 +307,19 @@ export async function collectDoctorReport(deps: DoctorDeps): Promise<DoctorRepor `neither git-filter-repo nor pipx — \`archilyzer build homepage\` refuses; install: \`${src.FILTER_REPO_INSTALL}\``); } // stagit renders the history pages (/source/git/); without it the publish - // goes on without them. A STAGIT_BIN that names nothing is a warning. + // goes on without them. A STAGIT_BIN that names nothing is a warning. The + // line ends with the render cache: where it is and how big (stat'd only). const hist = await import("../publish/sourceHistory"); + const cacheDir = paths.sourceHistoryCacheDir; + const cache = cacheDir ? `; cache: ${cacheDir}, ${await dirSizeText(cacheDir)}` : ""; if (tools.stagit) { - add(SP, "stagit", "ok", tools.stagit); + add(SP, "stagit", "ok", `${tools.stagit}${cache}`); } else if (env.STAGIT_BIN) { add(SP, "stagit", "warn", - `not found: STAGIT_BIN=${env.STAGIT_BIN} names no executable — the source is published without its history pages (/source/git/)`); + `not found: STAGIT_BIN=${env.STAGIT_BIN} names no executable — the source is published without its history pages (/source/git/)${cache}`); } else { add(SP, "stagit", "info", - `not found (PATH, ~/.local/bin) — the source is published without its history pages (/source/git/); install it once: ${hist.STAGIT_INSTALL}`); + `not found (PATH, ~/.local/bin) — the source is published without its history pages (/source/git/); install it once: ${hist.STAGIT_INSTALL}${cache}`); } add(SP, "gitleaks", tools.gitleaks ? "ok" : "info", tools.gitleaks ? `gitleaks ${tools.gitleaks.version}` : "absent — the gate skips the secret scan with a WARNING (the literal audit still runs)"); @@ -554,6 +557,21 @@ async function probeSourceTools(env: NodeJS.ProcessEnv, paths: Paths): Promise<S }; } +// A directory's size, by stat alone ("none yet" when it is not there). +async function dirSizeText(dir: string): Promise<string> { + if (!existsSync(dir)) return "none yet"; + let bytes = 0; + const walk = async (d: string): Promise<void> => { + for (const ent of await readdir(d, { withFileTypes: true }).catch(() => [])) { + const p = path.join(d, ent.name); + if (ent.isDirectory()) await walk(p); + else if (ent.isFile()) bytes += statOrNull(p)?.size ?? 0; + } + }; + await walk(dir); + return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; +} + // In use = something accepts a TCP connection on 127.0.0.1. Never binds. function tcpPortInUse(port: number): Promise<boolean> { return new Promise((resolve) => {