From d3fd788654f0b26489f331ce35f469e6a1894727 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Thu, 1 Oct 2026 12:55:37 -0700 Subject: [PATCH 01/52] feat(native-chat): keep composer drafts across restarts --- .../native-chat-composer-drop-scope.test.tsx | 48 ++-- .../native-chat-composer-scope-cache.ts | 14 +- .../native-chat/native-chat-draft-cache.ts | 213 +++++++++++++---- .../native-chat-draft-persistence.test.ts | 215 +++++++++++++++++ .../native-chat/native-chat-draft-storage.ts | 217 ++++++++++++++++++ ...structured-send-composition-clear.test.tsx | 30 ++- ...session-withdrawn-message-restore.test.tsx | 29 +-- ...agent-session-withdrawn-message-restore.ts | 15 +- ...-native-chat-composer-attachments.test.tsx | 16 +- .../use-native-chat-composer-attachments.ts | 78 ++----- ...tructured-agent-session-queued-messages.ts | 4 +- 11 files changed, 706 insertions(+), 173 deletions(-) create mode 100644 src/renderer/src/components/native-chat/native-chat-draft-persistence.test.ts create mode 100644 src/renderer/src/components/native-chat/native-chat-draft-storage.ts diff --git a/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx b/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx index 508a7c20e5ea..ffda9656a7e3 100644 --- a/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx +++ b/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx @@ -14,10 +14,10 @@ import { useComposerDropListener } from '../../hooks/composer-state/composer-dro import type { NativeFileDropPayload } from '../../../../shared/native-file-drop' import { useNativeChatFileAttachmentActions } from './use-native-chat-file-attachment-actions' import { - clearNativeChatAttachmentCacheForTests, - readNativeChatAttachmentCache, - useNativeChatComposerAttachments -} from './use-native-chat-composer-attachments' + clearNativeChatDraftCacheForTests, + readNativeChatDraftAttachments +} from './native-chat-draft-cache' +import { useNativeChatComposerAttachments } from './use-native-chat-composer-attachments' const electron = vi.hoisted(() => ({ on: vi.fn(), @@ -163,7 +163,7 @@ describe('native chat composer drop scoping', () => { cleanup() resetLocalImageSrcStateForTests() vi.unstubAllGlobals() - clearNativeChatAttachmentCacheForTests() + clearNativeChatDraftCacheForTests() electron.send.mockClear() }) @@ -181,7 +181,7 @@ describe('native chat composer drop scoping', () => { reason: 'unresolved-paths', target: 'rejected' }) - expect(readNativeChatAttachmentCache('chat-a')).toEqual([]) + expect(readNativeChatDraftAttachments('chat-a')).toEqual([]) }) it('notices an OS drop whose every path fails authorization', async () => { @@ -194,7 +194,7 @@ describe('native chat composer drop scoping', () => { expect(view.container.querySelector('[data-notice="chat-a"]')?.textContent).toBe( "Couldn't read the dropped files." ) - expect(readNativeChatAttachmentCache('chat-a')).toEqual([]) + expect(readNativeChatDraftAttachments('chat-a')).toEqual([]) }) it('notices an OS drop whose owner changes during authorization', async () => { @@ -209,7 +209,7 @@ describe('native chat composer drop scoping', () => { expect(view.container.querySelector('[data-notice="chat-a"]')?.textContent).toBe( 'This workspace changed hosts while attaching — drop the files again.' ) - expect(readNativeChatAttachmentCache('chat-a')).toEqual([]) + expect(readNativeChatDraftAttachments('chat-a')).toEqual([]) }) it('attaches only to the dropped pane and leaves a hidden pane clean on remount', async () => { @@ -219,8 +219,8 @@ describe('native chat composer drop scoping', () => {