summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhaoyuren <13851610112@163.com>2026-03-15 15:02:15 -0500
committerhaoyuren <13851610112@163.com>2026-03-15 15:02:15 -0500
commit72b38fed1d75fcb3420beeeeefd3dc2fc442e64b (patch)
tree5dfc2bdaf49f9ac99d2789c7ee7d75defdd95e28
parentd1cde0fa291046b3e9768a4efd2f6c62b20748d6 (diff)
Fix sync race condition: external edits overwritten by remote ops
When Claude Code writes to disk, a debounce timer is set. If a remote Overleaf op arrives during the debounce, onEditorContentChanged would write the remote content back to disk, overwriting Claude Code's edit. Fix: skip disk write and lastKnownContent update in onEditorContentChanged when a debounce is pending (external disk change waiting to be processed). Also increase writesInProgress guard to 800ms to exceed chokidar's 500ms polling interval. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
-rw-r--r--src/main/fileSyncBridge.ts14
1 files changed, 12 insertions, 2 deletions
diff --git a/src/main/fileSyncBridge.ts b/src/main/fileSyncBridge.ts
index 7d7274a..73f3e70 100644
--- a/src/main/fileSyncBridge.ts
+++ b/src/main/fileSyncBridge.ts
@@ -509,8 +509,10 @@ export class FileSyncBridge {
if (this.editorDocs.has(docId)) {
// Doc is open in editor → send to renderer via IPC
+ // Don't update lastKnownContent here — let the renderer confirm via syncContentChanged.
+ // This prevents race conditions where remote OT ops overwrite lastKnownContent
+ // before the disk change is fully processed through the editor's OT pipeline.
bridgeLog(`[FileSyncBridge] → sending sync:externalEdit to renderer for ${relPath}`)
- this.lastKnownContent.set(relPath, newContent)
this.mainWindow.webContents.send('sync:externalEdit', { docId, content: newContent })
} else {
// Doc NOT open in editor → bridge handles OT directly
@@ -723,6 +725,14 @@ export class FileSyncBridge {
const relPath = this.docPathMap[docId]
if (!relPath) return
+ // If there's a pending debounce for this file, an external tool (e.g. Claude Code)
+ // just wrote to disk and the change hasn't been processed yet. Don't overwrite the
+ // disk file or update lastKnownContent — let processDocChange handle it.
+ if (this.debounceTimers.has(relPath)) {
+ bridgeLog(`[FileSyncBridge] onEditorContentChanged: skipping ${relPath} (pending disk change)`)
+ return
+ }
+
// Update last known content
this.lastKnownContent.set(relPath, content)
@@ -778,7 +788,7 @@ export class FileSyncBridge {
setTimeout(() => {
this.writesInProgress.delete(relPath)
- }, 150)
+ }, 800) // Must exceed chokidar polling interval (500ms)
}
private async deleteFromDisk(relPath: string): Promise<void> {