From 52733649829f0b135d49f8f6b5ac04241198883b Mon Sep 17 00:00:00 2001 From: "orange.ai" <77816124+orange2ai@users.noreply.github.com> Date: Mon, 25 May 2026 22:28:21 +0800 Subject: [PATCH] Fix live reload after atomic saves --- src/main/index.ts | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index c91af97..542466c 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -27,6 +27,7 @@ interface WindowState { watcher: FSWatcher | null isInternalSave: boolean debounceTimer: ReturnType | null + watchRefreshTimer: ReturnType | null agentState: 'idle' | 'active' | 'cooldown' lastExternalChange: number agentCooldownTimer: ReturnType | null @@ -38,7 +39,7 @@ let pendingFilePaths: string[] = [] function getState(win: BrowserWindow): WindowState { let state = windowStates.get(win.id) if (!state) { - state = { filePath: null, watcher: null, isInternalSave: false, debounceTimer: null, agentState: 'idle', lastExternalChange: 0, agentCooldownTimer: null } + state = { filePath: null, watcher: null, isInternalSave: false, debounceTimer: null, watchRefreshTimer: null, agentState: 'idle', lastExternalChange: 0, agentCooldownTimer: null } windowStates.set(win.id, state) } return state @@ -112,6 +113,10 @@ function stopWatching(state: WindowState): void { clearTimeout(state.agentCooldownTimer) state.agentCooldownTimer = null } + if (state.watchRefreshTimer) { + clearTimeout(state.watchRefreshTimer) + state.watchRefreshTimer = null + } state.agentState = 'idle' state.lastExternalChange = 0 } @@ -148,7 +153,14 @@ function watchFile(win: BrowserWindow, state: WindowState): void { stopWatching(state) const filePath = state.filePath state.watcher = watch(filePath, (eventType) => { - if (eventType !== 'change' || state.isInternalSave) return + if (state.isInternalSave) return + + if (eventType === 'rename') { + refreshWatchedFile(win, state) + return + } + + if (eventType !== 'change') return // Agent activity detection const now = Date.now() @@ -171,6 +183,34 @@ function watchFile(win: BrowserWindow, state: WindowState): void { }) } +function refreshWatchedFile(win: BrowserWindow, state: WindowState): void { + if (!state.filePath) return + if (state.debounceTimer) { + clearTimeout(state.debounceTimer) + state.debounceTimer = null + } + if (state.watchRefreshTimer) { + clearTimeout(state.watchRefreshTimer) + } + + const attemptRefresh = () => { + if (!state.filePath || win.isDestroyed()) return + if (!existsSync(state.filePath)) { + state.watchRefreshTimer = setTimeout(attemptRefresh, 200) + return + } + + watchFile(win, state) + readFile(state.filePath, 'utf-8') + .then((data) => { + if (!win.isDestroyed()) win.webContents.send('file-changed', data) + }) + .catch(() => {}) + } + + state.watchRefreshTimer = setTimeout(attemptRefresh, 150) +} + function loadFileInWindow(win: BrowserWindow, filePath: string): void { readFile(filePath, 'utf-8') .then((data) => {