tenseleyflow/claudex / 8378ba8

Browse files

perf: skip rescan on modified file events (only added/removed)

Authored by espadonne
SHA
8378ba8b222c08e3960c93dbee51bf559d47a7a6
Parents
b612367
Tree
6551633

1 changed file

StatusFile+-
M src/lib/store/sessions.ts 14 9
src/lib/store/sessions.tsmodified
@@ -445,15 +445,20 @@ export const useSessionStore = create<SessionStore>((set, get) => ({
445445
   async subscribeToChanges() {
446446
     if (watcherAttached) return;
447447
     watcherAttached = true;
448
-    await onSessionsChanged(() => {
449
-      // 2s debounce is a compromise between feeling responsive when
450
-      // the user finishes a claude turn in the real CLI outside
451
-      // claudex (so we eventually pick up the new session on disk)
452
-      // and avoiding a rescan storm while PTYs are actively
453
-      // writing. The Rust side also suppresses file-watcher events
454
-      // for sessions owned by a live PTY, so this mostly fires for
455
-      // out-of-band changes (external claude runs, git operations,
456
-      // archive pruning).
448
+    await onSessionsChanged((ev) => {
449
+      // ONLY rescan on structural changes (new session file appears,
450
+      // session file disappears). Message-count ticks from active
451
+      // writes fire as `modified` events and previously caused a
452
+      // periodic ~300ms main-thread stall every few seconds —
453
+      // Rust walks every session on disk, serializes a ~1-2 MB
454
+      // Project[] payload, the frontend deserializes on the main
455
+      // thread, and React reconciles the whole sidebar. That
456
+      // full storm ran every ~2s any time an external claude
457
+      // process (observer sessions, background runs) was writing
458
+      // to disk, producing the "periodic mouse-move beachball"
459
+      // signature. Added/Removed still trigger a rescan because
460
+      // the sidebar needs to show new sessions as they appear.
461
+      if (ev.kind === "modified") return;
457462
       if (pendingRescan) clearTimeout(pendingRescan);
458463
       pendingRescan = setTimeout(() => {
459464
         pendingRescan = null;