Skip to content

Commit f771aea

Browse files
committed
fix(hooks): rotation falls back to truncate-in-place on Windows
The Rust agent flagged this real concern: on Windows, the tailer's open `File` handle can keep `fs.renameSync(out → out.1)` from succeeding. First time the producer tries to rotate while the inspector is tailing, the rename throws — and our previous catch-all swallowed the error so the file would just keep growing. Try rename first (preserves history in .1 on POSIX). If rename fails (Windows file lock), truncate-in-place to 0 bytes. The inspector's tail mode already handles truncation-as-rotation via the `metadata.len() < read_offset` check, so the consumer side is unchanged. Tradeoff: on Windows we lose the .1 archive across rotations, but events keep flowing — that's the right priority.
1 parent 6e16997 commit f771aea

1 file changed

Lines changed: 12 additions & 1 deletion

File tree

scripts/hooks/claude-code-emit.mjs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,23 @@ function rotateIfLarge() {
8383
const st = fs.statSync(outPath);
8484
if (st.size <= MAX_BYTES) return;
8585
const backup = `${outPath}.1`;
86+
// Try rename-swap first (preserves history in .1). On Windows, this
87+
// fails while the inspector has the file open for tailing. Fall back
88+
// to truncate-in-place — the tailer's `metadata.len() < read_offset`
89+
// detection treats truncation as rotation, so the consumer side is
90+
// unchanged. We lose the .1 archive in the truncate path; acceptable
91+
// tradeoff vs. dropping events because rename was blocked.
8692
try {
8793
fs.unlinkSync(backup);
8894
} catch {
8995
/* fine if missing */
9096
}
91-
fs.renameSync(outPath, backup);
97+
try {
98+
fs.renameSync(outPath, backup);
99+
} catch {
100+
// Rename blocked (most likely Windows + open handle). Truncate.
101+
fs.truncateSync(outPath, 0);
102+
}
92103
} catch {
93104
/* file doesn't exist yet — nothing to rotate */
94105
}

0 commit comments

Comments
 (0)