From c9d673d83037167553dcef3947065266743b2d5f Mon Sep 17 00:00:00 2001 From: haoyuren <13851610112@163.com> Date: Sun, 15 Mar 2026 18:21:06 -0500 Subject: Fix file sync for non-active tabs, MCP compile integration, OT resilience - Fix .bib (and other non-active tab) edits disappearing: call otLeaveDoc on tab switch so bridge takes back OT ownership; release .bib pre-loads immediately after reading content for citation autocomplete - Always update lastKnownContent in processDocChange for editor docs to prevent stale state accumulation - Flush pending OT ops in OverleafDocSync.destroy() before tab switch - Add three-way merge in replaceContent to preserve concurrent remote edits - Wire MCP compile to UI: file-based signal between MCP server and Electron main process, with compile animation and PDF refresh in renderer - Add CLSI flush before compile to prevent stale cached results - Add OT error recovery: re-join doc and re-apply disk changes on otUpdateError - Add bridge reconnect handling: reset OtClient on docRejoined for non-editor docs - Add compile concurrency lock to prevent duplicate compiles - removeEditorDoc compares disk vs server content to catch in-flight ops Co-Authored-By: Claude Opus 4.6 --- src/preload/index.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/preload/index.ts') diff --git a/src/preload/index.ts b/src/preload/index.ts index 6bdcdbb..ea330c5 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -160,13 +160,25 @@ const api = { sha1: (text: string): string => createHash('sha1').update(text).digest('hex'), // File sync bridge - onSyncExternalEdit: (cb: (data: { docId: string; content: string }) => void) => { - const handler = (_e: Electron.IpcRendererEvent, data: { docId: string; content: string }) => cb(data) + onSyncExternalEdit: (cb: (data: { docId: string; content: string; baseContent?: string }) => void) => { + const handler = (_e: Electron.IpcRendererEvent, data: { docId: string; content: string; baseContent?: string }) => cb(data) ipcRenderer.on('sync:externalEdit', handler) return () => ipcRenderer.removeListener('sync:externalEdit', handler) }, syncContentChanged: (docId: string, content: string) => ipcRenderer.invoke('sync:contentChanged', docId, content), + + // MCP compile events (Claude Code triggers compile via file signal) + onMcpCompileStarted: (cb: () => void) => { + const handler = () => cb() + ipcRenderer.on('compile:mcpStarted', handler) + return () => ipcRenderer.removeListener('compile:mcpStarted', handler) + }, + onMcpCompileFinished: (cb: (data: { success: boolean; pdfPath: string }) => void) => { + const handler = (_e: Electron.IpcRendererEvent, data: { success: boolean; pdfPath: string }) => cb(data) + ipcRenderer.on('compile:mcpFinished', handler) + return () => ipcRenderer.removeListener('compile:mcpFinished', handler) + }, onSyncNewDoc: (cb: (data: { docId: string | null; relPath: string }) => void) => { const handler = (_e: Electron.IpcRendererEvent, data: { docId: string | null; relPath: string }) => cb(data) ipcRenderer.on('sync:newDoc', handler) -- cgit v1.2.3