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:
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) => {