Description
The review panel in the desktop app (and any environment with OPENCODE_EXPERIMENTAL_FILEWATCHER=true) flickers/rerenders every few seconds during active development. Each rerender clears the current diff state momentarily before refetching, making the panel unusable.
Root cause
Two bugs compound each other:
Backend (packages/opencode/src/file/watcher.ts): The parcel/watcher callback was shared across both subscriptions (worktree dir and git dir). Events from all paths were published as file.watcher.updated without being filtered through FileIgnore.match() after receipt. This means build artifacts like out/renderer/index.js, .turbo/ lock files, etc. all fired watcher events even though they match the ignore patterns.
Frontend (packages/app/src/pages/session.tsx): The file.watcher.updated listener only skipped paths starting with the relative string .git/. In git worktrees (and on Windows), the git dir lives at an absolute path like /path/to/.git/worktrees/<branch>/HEAD, so those events slipped through and triggered spurious refreshVcs() calls.
Steps to reproduce
- Run
electron-vite dev (or any build tool that writes output to a directory not in .gitignore at the OS level — note: FileIgnore ignores out/ but the filter was not applied on incoming events)
- Open a session in the desktop app
- Open the Review tab
- Observe the diff panel repeatedly clearing and reloading every few seconds
Or: use a git worktree and observe the same flicker driven by absolute .git/worktrees/…/HEAD paths.
OpenCode version
1.4.0
OS
macOS (also reproducible on Linux worktrees and Windows due to path separator issue)
Fix
- Move the parcel/watcher callback inside
subscribe() so each subscription filters independently
- Non-git subscriptions now run incoming paths through
FileIgnore.match() before publishing
- Git-dir subscription only allows
HEAD through (the only event that signals a branch/commit change)
- Frontend listener normalizes separators and checks both
path.startsWith(".git/") and path.includes("/.git/") to handle worktree absolute paths
Description
The review panel in the desktop app (and any environment with
OPENCODE_EXPERIMENTAL_FILEWATCHER=true) flickers/rerenders every few seconds during active development. Each rerender clears the current diff state momentarily before refetching, making the panel unusable.Root cause
Two bugs compound each other:
Backend (
packages/opencode/src/file/watcher.ts): The parcel/watcher callback was shared across both subscriptions (worktree dir and git dir). Events from all paths were published asfile.watcher.updatedwithout being filtered throughFileIgnore.match()after receipt. This means build artifacts likeout/renderer/index.js,.turbo/lock files, etc. all fired watcher events even though they match the ignore patterns.Frontend (
packages/app/src/pages/session.tsx): Thefile.watcher.updatedlistener only skipped paths starting with the relative string.git/. In git worktrees (and on Windows), the git dir lives at an absolute path like/path/to/.git/worktrees/<branch>/HEAD, so those events slipped through and triggered spuriousrefreshVcs()calls.Steps to reproduce
electron-vite dev(or any build tool that writes output to a directory not in.gitignoreat the OS level — note:FileIgnoreignoresout/but the filter was not applied on incoming events)Or: use a git worktree and observe the same flicker driven by absolute
.git/worktrees/…/HEADpaths.OpenCode version
1.4.0
OS
macOS (also reproducible on Linux worktrees and Windows due to path separator issue)
Fix
subscribe()so each subscription filters independentlyFileIgnore.match()before publishingHEADthrough (the only event that signals a branch/commit change)path.startsWith(".git/")andpath.includes("/.git/")to handle worktree absolute paths