fix(bin): route remaining Windows-reachable mkdirSync sites through mkdirpSync

Sweep follow-up to #2641's lib/fs-utils.ts helper: bun on Windows throws EEXIST from a recursive mkdir on an existing dir, so every unguarded recursive mkdirSync on a Windows-reachable path is a latent crash. Converted: bin/gstack-decision-log (unguarded, runs on every decision log — the second call on any machine hits the pre-existing projects dir), bin/gstack-evidence logsDir + ledger dir sites, and bin/gstack-redact-prepush's skip-log site (already try-wrapped, so its failure mode was a silent skip-log loss rather than a crash — the fix makes the log survive). The ~15 remaining gbrain/mac-lane sites are deliberately left alone.

Regression: fs-utils.test.ts drives gstack-decision-log twice, the second run under the bun-Windows EEXIST preload fixture — the pre-sweep code exits 1 with EEXIST there; verified red against v1.68.3.0.
This commit is contained in:
Garry Tan
2026-08-22 01:59:16 +00:00
parent 790c42505a
commit 361dfebcbe
4 changed files with 40 additions and 6 deletions
+4 -3
View File
@@ -34,7 +34,8 @@
* in the ledger; it cannot prove that an expected lane ever ran.
*/
import { mkdirSync, openSync, writeSync, closeSync, readdirSync, statSync, unlinkSync, chmodSync, readFileSync } from "fs";
import { openSync, writeSync, closeSync, readdirSync, statSync, unlinkSync, chmodSync, readFileSync } from "fs";
import { mkdirpSync } from "../lib/fs-utils";
import { join, dirname } from "path";
import { spawnSync } from "child_process";
import { appendJsonl, readJsonl } from "../lib/jsonl-store";
@@ -137,7 +138,7 @@ function pruneOldLogs(logsDir: string): void {
/** Exclusive-open a collision-safe log file. Returns undefined on failure. */
function openLog(logsDir: string, label: string, cmdSha: string): { fd: number; path: string } | undefined {
try {
mkdirSync(logsDir, { recursive: true });
mkdirpSync(logsDir);
pruneOldLogs(logsDir);
const ts = new Date().toISOString().replace(/[:.]/g, "-");
const base = `${ts}-${label}-${process.pid}-${cmdSha.slice(0, 8)}`;
@@ -266,7 +267,7 @@ async function cmdRun(argv: string[]): Promise<number> {
let paths: ReturnType<typeof ledgerPath> | undefined;
try {
paths = ledgerPath();
mkdirSync(paths.dir, { recursive: true });
mkdirpSync(paths.dir);
} catch (e: any) {
warn(`ledger setup failed (${e?.message ?? e}) — result will not be recorded`);
}