fix: include numeric .bak files from rotateSessionFile in pruning

This commit is contained in:
Danial Beg 2026-03-15 14:38:00 -07:00
parent 158ab90466
commit 3a0927a33e
2 changed files with 21 additions and 4 deletions

View File

@ -122,6 +122,20 @@ describe("sweepSessionArchiveFiles", () => {
]);
});
it("trims legacy numeric .bak files from rotateSessionFile", async () => {
// rotateSessionFile() creates backups as sessions.json.bak.${Date.now()}.
const baseTs = Date.now();
for (let i = 0; i < 5; i++) {
fs.writeFileSync(path.join(sessionsDir, `sessions.json.bak.${baseTs + i * 1000}`), "");
}
const result = await sweepSessionArchiveFiles({ stateDir: tempDir });
const remaining = fs.readdirSync(sessionsDir).filter((f) => f.startsWith("sessions.json.bak."));
expect(remaining).toHaveLength(3);
expect(result.removed).toBe(2);
});
it("returns zeros when no agent session directories exist", async () => {
mocks.resolveAgentSessionDirs.mockResolvedValue([]);
const result = await sweepSessionArchiveFiles({ stateDir: tempDir });

View File

@ -70,10 +70,13 @@ export async function sweepSessionArchiveFiles(params: {
// name. This mirrors the rotation logic in rotateSessionFile().
const bakByBase = new Map<string, string[]>();
for (const entry of entries) {
// Use parseSessionArchiveTimestamp to validate the file is a genuine
// .bak.* archive — plain indexOf(".bak.") could false-match session
// IDs that contain ".bak." (e.g. "foo.bak.bar.jsonl.deleted.<ts>").
if (parseSessionArchiveTimestamp(entry, "bak") == null) {
// Match genuine .bak.* archives: either ISO-timestamped (from archive
// operations) or numeric (from rotateSessionFile's Date.now() suffix).
// Plain indexOf(".bak.") would false-match session IDs that contain
// ".bak." as a substring (e.g. "foo.bak.bar.jsonl.deleted.<ts>").
const isIsoBak = parseSessionArchiveTimestamp(entry, "bak") != null;
const isNumericBak = /\.bak\.\d+$/.test(entry);
if (!isIsoBak && !isNumericBak) {
continue;
}
const bakIdx = entry.lastIndexOf(".bak.");