You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Files tree does not update for changes made outside the app #4
After #1, the Files tree updates for changes the app makes. Changes made outside the app — touch in a terminal, a file added in Finder, a build writing output — still do not appear until the panel remounts or its 30s staleness window lapses.
Scoping in #2 established that the server-side data is already live. The FileFinder index picks up external creates and deletes on its own in ~100ms with no refresh call. The only missing piece is that the server never learns the index moved, because FileFinder exposes no change callback, so #1's signal is never published.
Full evidence and the rejected alternatives are in the scoping comment on #2. Summary of what that measured on this repo (17,701 entries, populated node_modules, active .git):
external create visible without scanFiles: ~103ms; external delete: ~104ms
getScanProgress().scannedFilesCount never moves — not a usable signal
mixedSearch("", { pageSize: 1 }).totalMatched tracks add/delete exactly, costs ~0.5ms (vs 350ms for a full list)
node_modules / .git write churn: 0/30 samples moved the count; idle repo over 20s: 0 changes
Scope
Publish #1's existing signal when the index changes underneath us, detected by a cheap count poll. No new filesystem watcher, no new ignore list, no rescan.
Implementation sketch
All server-side. Contracts, auth, and the client are untouched — #1 already shipped subscribeProjectEntryChanges and the invalidate line on listEntries.
apps/server/src/workspace/WorkspaceSearchIndex.ts — expose a cheap entryCount() on the service, backed by finder.mixedSearch("", { pageSize: 1 }).totalMatched. pageSize: 1 is load-bearing: it returns the total without materialising the page.
apps/server/src/workspace/WorkspaceEntries.ts — while at least one client is subscribed for a workspace, run a poll fibre at a fixed interval, compare entryCount() to the last observed value, and publish the existing coarse signal on change. Reuse the PubSub keyed by normalised workspace root that Files tree does not update live when files are added or deleted #1 added; do not add a second channel.
Lifetime — the fibre is scoped to the subscription, not to the process. Last unsubscribe stops it. The index's own 15-minute idle TTL is unchanged; an active subscription counts as active use, which is correct.
Suggested interval 1s (0.05% of one core per subscribed workspace). This is the one number worth a maintainer's opinion — 2s halves an already negligible cost and still feels instant for a file tree.
Acceptance criteria
With the Files panel open and untouched, touch test.txt from a terminal makes the file appear in the tree without remounting or reloading.
Deleting that file from a terminal removes it the same way.
With the panel open on a real repo and the workspace idle, no signal is published — verified over at least 20s.
node_modules and .git write churn publishes no signal.
No new filesystem watcher is introduced, and refresh / scanFiles is not called by this change.
Web verified at minimum; mobile and desktop follow through the shared listEntries atom.
Known and accepted gaps
A rename, or a balanced add+delete, leaves the count unchanged and publishes nothing. The 30s client staleness window still catches it; in-app renames still go through refresh. This narrows the gap rather than closing it — say so in the PR body rather than claiming external changes are fully live.
Content-only edits do not move the count. Intended: the tree does not care, and subscribeProjectFileChanges already covers open-file contents.
Problem
After #1, the Files tree updates for changes the app makes. Changes made outside the app —
touchin a terminal, a file added in Finder, a build writing output — still do not appear until the panel remounts or its 30s staleness window lapses.Scoping in #2 established that the server-side data is already live. The
FileFinderindex picks up external creates and deletes on its own in ~100ms with norefreshcall. The only missing piece is that the server never learns the index moved, becauseFileFinderexposes no change callback, so #1's signal is never published.Full evidence and the rejected alternatives are in the scoping comment on #2. Summary of what that measured on this repo (17,701 entries, populated
node_modules, active.git):scanFiles: ~103ms; external delete: ~104msgetScanProgress().scannedFilesCountnever moves — not a usable signalmixedSearch("", { pageSize: 1 }).totalMatchedtracks add/delete exactly, costs ~0.5ms (vs 350ms for a full list)node_modules/.gitwrite churn: 0/30 samples moved the count; idle repo over 20s: 0 changesScope
Publish #1's existing signal when the index changes underneath us, detected by a cheap count poll. No new filesystem watcher, no new ignore list, no rescan.
Implementation sketch
All server-side. Contracts, auth, and the client are untouched — #1 already shipped
subscribeProjectEntryChangesand theinvalidateline onlistEntries.apps/server/src/workspace/WorkspaceSearchIndex.ts— expose a cheapentryCount()on the service, backed byfinder.mixedSearch("", { pageSize: 1 }).totalMatched.pageSize: 1is load-bearing: it returns the total without materialising the page.apps/server/src/workspace/WorkspaceEntries.ts— while at least one client is subscribed for a workspace, run a poll fibre at a fixed interval, compareentryCount()to the last observed value, and publish the existing coarse signal on change. Reuse the PubSub keyed by normalised workspace root that Files tree does not update live when files are added or deleted #1 added; do not add a second channel.Suggested interval 1s (0.05% of one core per subscribed workspace). This is the one number worth a maintainer's opinion — 2s halves an already negligible cost and still feels instant for a file tree.
Acceptance criteria
touch test.txtfrom a terminal makes the file appear in the tree without remounting or reloading.node_modulesand.gitwrite churn publishes no signal.refresh/scanFilesis not called by this change.listEntriesatom.Known and accepted gaps
refresh. This narrows the gap rather than closing it — say so in the PR body rather than claiming external changes are fully live.subscribeProjectFileChangesalready covers open-file contents.Out of scope
enableFsRootScanning/enableHomeDirScanningsettings — both surfaced by Scope: watch the workspace so externally-added files appear in the Files tree #2's scoping, both filed separately.Upstream
The clean fix is a change callback on
FileFinderinstead of a poll. Worth raising with ff-labs; this ticket is the bridge until then.Tests
WorkspaceEntriestest asserting the signal is published when the underlying count changes, and not when it does not.Conventions
Read
docs/internals/code-conventions.mdfirst, and.macroscope/check-run-agents/effect-service-conventions.mdbefore touching server services.Depends on
#1 (landed) — this publishes on the channel that ticket built.