fix(server): detect file changes inside untracked directories on refresh - #1739
Merged
Merged
Conversation
git status --porcelain collapses untracked directories into a single "?? dir/" line, so adding or removing a file inside an already-untracked directory never moved the dirty-set fingerprint. file.refresh returned null, no files.changed broadcast fired, and cached file autocomplete stayed stale across attention refreshes. Fingerprint with --untracked-files=all so untracked directories expand to per-file entries, matching the granularity list() already uses via git ls-files --others --exclude-standard. Ignore rules are unchanged. Adds real-git regression coverage for add, remove, nested dirs, staging, unchanged sets, ignored files, and repo config overrides, plus a consumer invalidation test for files.changed on the web client. Closes #1735 Generated with [Devin](https://devin.ai)
chuks-qua
added a commit
that referenced
this pull request
Sep 22, 2026
Combines with #1739's --untracked-files=all status flag: refresh now runs `status --porcelain --untracked-files=all -z` so untracked directories expand per file and paths arrive unquoted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
file.refreshfingerprintedgit status --porcelain, which collapses untracked directories into a single?? dir/line. Adding or removing a file inside an already-untracked directory never moved the dirty-set fingerprint, sofiles.changednever broadcast and cached@file autocomplete stayed stale across attention refreshes.The refresh now runs
git status --porcelain --untracked-files=all, expanding untracked directories to per-file entries — the same granularityfile.listalready uses viagit ls-files --others --exclude-standard. Ignore rules, the bounded single-status-call design, and per-scope baselines are unchanged.Verified end to end on the live worktree runtime: public WS
file.refreshbaseline → external write ofverify1735/alpha.tsinside a new untracked dir →files.changed{changedPaths:["verify1735/alpha.ts"]}push (removal too). In the real web app, reopening the@picker after an external write shows the new file without a restart (screenshots attached).Why
Closes #1735. Users directing agents hit stale file autocomplete when an agent or external tool creates files inside a new directory; the cached list silently missed them even after reopening the picker.
UI Changes
Behavioral fix with UI evidence attached: before, the
@picker lacksverify1735-ui/beta.ts; after an external write plus one attention refresh, the reopened picker lists it.Review Notes
audit-untracked-file-refresh.test.ts) uses real git against temp repos: add, remove, nested dirs, unchanged set, ignored files, staging (?? f→A fintentionally stays silent, matching single-file staging), andstatus.showUntrackedFiles=nooverride. Red-before/green-after confirmed against the audit's pinned reproduction.ws-eventstests pin the consumer side:files.changedclears the autocomplete cache and bumps the diff revision for both thread and workspace scopes.execFile's 1 MiBmaxBuffercan makerefreshreturnnullon repos with huge unignored untracked trees.list()shares the exposure; not introduced here.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.