From 81626fc82725ac105e5149382f46d7fa8cf5bfa3 Mon Sep 17 00:00:00 2001 From: godwiniheuwa Date: Fri, 6 Feb 2026 14:36:15 +0530 Subject: [PATCH] fix(core): ensure directory exists before writing conversation file The writeConversation() method called fs.writeFileSync() without first ensuring the parent directory exists. If the temp directory gets cleaned up after initialization (e.g. by the OS or Conductor process management), subsequent writes crash with ENOENT. Adds fs.mkdirSync with recursive: true before the write call, which is a no-op when the directory already exists. This follows the existing pattern used in promptProvider.ts. Fixes #15398 Co-authored-by: ruintheextinct --- .../src/services/chatRecordingService.test.ts | 32 +++++++++++++++++++ .../core/src/services/chatRecordingService.ts | 2 ++ 2 files changed, 34 insertions(+) diff --git a/packages/core/src/services/chatRecordingService.test.ts b/packages/core/src/services/chatRecordingService.test.ts index 504999a671c..61ba3d32a37 100644 --- a/packages/core/src/services/chatRecordingService.test.ts +++ b/packages/core/src/services/chatRecordingService.test.ts @@ -745,4 +745,36 @@ describe('ChatRecordingService', () => { expect(result[1].functionResponse!.id).toBe(callId); }); }); + + describe('ENOENT (missing directory) handling', () => { + it('should ensure directory exists before writing conversation file', () => { + chatRecordingService.initialize(); + + const mkdirSyncSpy = vi.spyOn(fs, 'mkdirSync'); + const writeFileSyncSpy = vi.spyOn(fs, 'writeFileSync'); + + chatRecordingService.recordMessage({ + type: 'user', + content: 'Hello after dir cleanup', + model: 'gemini-pro', + }); + + // mkdirSync should be called with the parent directory and recursive option + const conversationFile = chatRecordingService.getConversationFilePath()!; + expect(mkdirSyncSpy).toHaveBeenCalledWith( + path.dirname(conversationFile), + { recursive: true }, + ); + + // mkdirSync should be called before writeFileSync + const mkdirCallOrder = mkdirSyncSpy.mock.invocationCallOrder; + const writeCallOrder = writeFileSyncSpy.mock.invocationCallOrder; + const lastMkdir = mkdirCallOrder[mkdirCallOrder.length - 1]; + const lastWrite = writeCallOrder[writeCallOrder.length - 1]; + expect(lastMkdir).toBeLessThan(lastWrite); + + mkdirSyncSpy.mockRestore(); + writeFileSyncSpy.mockRestore(); + }); + }); }); diff --git a/packages/core/src/services/chatRecordingService.ts b/packages/core/src/services/chatRecordingService.ts index bdce4f5f9e4..0b948253538 100644 --- a/packages/core/src/services/chatRecordingService.ts +++ b/packages/core/src/services/chatRecordingService.ts @@ -455,6 +455,8 @@ export class ChatRecordingService { conversation.lastUpdated = new Date().toISOString(); const newContent = JSON.stringify(conversation, null, 2); this.cachedLastConvData = newContent; + // Ensure directory exists before writing (handles cases where temp dir was cleaned) + fs.mkdirSync(path.dirname(this.conversationFile), { recursive: true }); fs.writeFileSync(this.conversationFile, newContent); } } catch (error) {