Repository navigation
Conversation
…l call Every finished shell or edit tool rescans the project listing (a shell tool twice), and each scan stored a fresh array and notified everyone, so every mounted composer of that checkout, hidden tabs included, rebuilt its mention index even though nothing on disk had changed. On a 15,000-file root with 23 sessions open that was about a second of main thread per tool call. - An unchanged rescan keeps the previous array and notifies no one; the last listing per checkout survives invalidation so it can be compared. - Composers with the same listing and notes share one mention index. - A composer in an inactive tab lets go of the listing until shown again.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
What changed
loadProjectFileskeeps the previous array when a rescan returns the same listing (same paths andisDir, in order) and doesn't notify subscribers. The last listing per checkout is kept throughinvalidateProjectFiles(cwd)(bounded atCACHE_LIMIT * 2) so the comparison still works after the cache entry is dropped; a fullinvalidateProjectFiles()clears it.sharedMentionIndex(files, extras)infileMentions.ts: composers holding the same listing (and the same notes) share oneMentionIndex(aWeakMapkeyed by the listing array, at most 4 note sets per listing) instead of each building its own.enabled === false) stops holding the project listing and picks it up from the cache again when shown.Why
When a shell tool finishes,
nudgeOpenEditorsinApp.tsxcallsnudgeWorkspace(cwd)twice (immediately and 150 ms later), and a finished edit tool calls it once. Each call runsinvalidateProjectFiles(cwd)+notifyDirsChanged(), which rescans the checkout. Every scan stored a fresh array and callednotifyProjectFilesChanged(), so every mountedComposerfor that checkout, hidden tabs included, got a newfilesarray and re-ranbuildMentionIndexin its ownuseMemo, even though nothing on disk had changed.buildMentionIndexis linear in the listing but not cheap: about 16 ms for 15,000 paths in Node (below), and about 50 ms in a real window on a 15,000-file multi-repo root. With 23 sessions open on that root, every agent tool call cost about 1.1 s of main thread, enough to break an IME composition or swallow a click. A heap snapshot of that window also held about 170,000 file entries, mostly the per-composer copies kept by hidden tabs.UI
No visual change.
@suggestions behave the same; a hidden tab's composer reloads its listing from the cache when shown.Validation
main:fileIndex.test.ts› "keeps the same array and stays quiet when a rescan finds nothing new" (thetoBeidentity check fails onmain)fileMentions.test.ts› "sharedMentionIndex builds once per listing and extras, matching a direct build"buildMentionIndex: ~16 mssharedMentionIndex): ~16 msnpm run check:web: vitest (5365 passed, 13 skipped) andtsc --noEmit. No Rust changes.Checklist
npm run check(check:web; no Rust files changed)Summary by CodeRabbit