






















@@ -30,11 +30,14 @@ async function createTempSessionPath() {
3030return { dir, file: path.join(dir, "session.jsonl") };
3131}
323233-function requireBackupPath(result: { backupPath?: string }): string {
34-if (!result.backupPath) {
35-throw new Error("expected session repair backup path");
36-}
37-return result.backupPath;
33+async function expectNoRetainedBackup(
34+file: string,
35+result: { backupPath?: string },
36+): Promise<void> {
37+expect(result.backupPath).toBeUndefined();
38+const siblings = await fs.readdir(path.dirname(file));
39+const leftover = siblings.filter((name) => name.includes(".bak-"));
40+expect(leftover).toEqual([]);
3841}
39424043function requireFirstLogMessage(log: ReturnType<typeof vi.fn>): string {
@@ -60,7 +63,6 @@ describe("repairSessionFileIfNeeded", () => {
6063const result = await repairSessionFileIfNeeded({ sessionFile: file });
6164expect(result.repaired).toBe(true);
6265expect(result.droppedLines).toBe(1);
63-const backupPath = requireBackupPath(result);
64666567const repaired = await fs.readFile(file, "utf-8");
6668const repairedLines = repaired
@@ -69,8 +71,26 @@ describe("repairSessionFileIfNeeded", () => {
6971.map((line) => JSON.parse(line));
7072expect(repairedLines).toEqual([header, message]);
717372-const backup = await fs.readFile(backupPath, "utf-8");
73-expect(backup).toBe(content);
74+await expectNoRetainedBackup(file, result);
75+});
76+77+it("does not accumulate backups across repeated repairs of a persistently corrupted file", async () => {
78+// Regression for #80960: a stuck session with a writer that keeps
79+// appending a malformed line caused every repair invocation to leave a
80+// ~1.8 MB `.bak-<pid>-<ts>` snapshot, accumulating 2,180 files / 2.1 GB
81+// on a single agent over ~25 hours.
82+const { file } = await createTempSessionPath();
83+const { header, message } = buildSessionHeaderAndMessage();
84+const malformedTail = '{"type":"message"';
85+86+for (let i = 0; i < 5; i++) {
87+const content = `${JSON.stringify(header)}\n${JSON.stringify(message)}\n${malformedTail}`;
88+await fs.writeFile(file, content, "utf-8");
89+const result = await repairSessionFileIfNeeded({ sessionFile: file });
90+expect(result.repaired).toBe(true);
91+expect(result.droppedLines).toBe(1);
92+await expectNoRetainedBackup(file, result);
93+}
7494});
75957696it("does not drop CRLF-terminated JSONL lines", async () => {
@@ -151,7 +171,7 @@ describe("repairSessionFileIfNeeded", () => {
151171expect(result.repaired).toBe(true);
152172expect(result.droppedLines).toBe(0);
153173expect(result.rewrittenAssistantMessages).toBe(1);
154-await expect(fs.readFile(requireBackupPath(result), "utf-8")).resolves.toBe(original);
174+await expectNoRetainedBackup(file, result);
155175expect(debug).toHaveBeenCalledTimes(1);
156176const debugMessage = requireFirstLogMessage(debug);
157177expect(debugMessage).toContain("rewrote 1 assistant message(s)");
@@ -528,8 +548,7 @@ describe("repairSessionFileIfNeeded", () => {
528548529549expect(result.repaired).toBe(true);
530550expect(result.insertedToolResults).toBe(1);
531-const backup = await fs.readFile(requireBackupPath(result), "utf-8");
532-expect(backup).toBe(original);
551+await expectNoRetainedBackup(file, result);
533552534553const lines = (await fs.readFile(file, "utf-8")).trimEnd().split("\n");
535554expect(lines).toHaveLength(5);
@@ -773,7 +792,7 @@ describe("repairSessionFileIfNeeded", () => {
773792774793expect(result.repaired).toBe(true);
775794expect(result.droppedLines).toBe(3);
776-await expect(fs.readFile(requireBackupPath(result), "utf-8")).resolves.toBe(`${content}\n`);
795+await expectNoRetainedBackup(file, result);
777796778797const after = await fs.readFile(file, "utf-8");
779798const lines = after.trimEnd().split("\n");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。