Skip to content

Replace polling with real-time git change notifications via file system watcher - #12

Merged
roulpriya merged 2 commits into
mainfrom
add-git-watcher
Apr 30, 2026
Merged

Replace polling with real-time git change notifications via file system watcher#12
roulpriya merged 2 commits into
mainfrom
add-git-watcher

Conversation

@recrsn

@recrsnrecrsn commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Real-time git monitoring added: branch and workspace changes now emit live branch and diff updates over websockets.
    • Agent-specific diffs are delivered as live updates and surfaced in the UI store.
  • Performance Improvements

    • Removed periodic 5-second polling for branch and diff data; replaced by event-driven updates for lower load and faster UX.

@coderabbitai

coderabbitaiBot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8026c016-3e3e-44d1-9fe4-f43038db87e9

📥 Commits

Reviewing files that changed from the base of the PR and between 602fdd7 and 271cef4.

📒 Files selected for processing (1)
  • src/backend/services/GitWatcher.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/backend/services/GitWatcher.ts

📝 Walkthrough

Walkthrough

The PR adds a GitWatcher service that monitors a repository's .git and worktrees, computes branch and diff information, and broadcasts branch-updated and diff-updated events over the session WebSocket. The backend starts the watcher on startup (after seeding/reading remote config), and remote routes (/detect, /clone) and the OrchestratorService start/stop per-agent worktree watches. Frontend state/store gains currentBranch and agentDiffs, receives the new WS events, and components derive UI state from the store instead of polling.

Sequence Diagram

sequenceDiagram
participant Startup as Backend Startup
participant RemoteRoutes as /detect & /clone
participant Orch as OrchestratorService
participant GitWatcher as GitWatcher Service
participant FS as File System
participant GWM as GitWorktreeManager
participant WS as WebSocket Broadcast
participant Store as Frontend Store
participant UI as Frontend Components
Startup->>GitWatcher: start(localPath, broadcastNotification)
RemoteRoutes->>GitWatcher: start(localPath, broadcastNotification)
Orch->>GitWatcher: watchWorktree(agentId, worktreePath, baseBranch)
GitWatcher->>FS: fs.watch(.git, worktree paths)
rect rgba(100, 150, 255, 0.5)
Note over FS,GWM: user pushes, switches branch, or worktree changes
FS->>GitWatcher: filesystem event (debounced)
GitWatcher->>GWM: compute branch / getDiff(agentId)
GWM-->>GitWatcher: DiffResult / branch
GitWatcher->>WS: emit branch-updated / diff-updated
end
rect rgba(150, 200, 100, 0.5)
WS->>Store: receive event -> setCurrentBranch / setAgentDiff
Store-->>UI: state updated
UI->>UI: re-render using store state
end
Loading

Possibly related PRs

Poem

🐇 I nibble logs and watch the tree,

Branches whisper, diffs sing to me.
No more polling, I hop and cheer,
Events arrive — the view is clear.
Tiny paws, a rabbit's glance, realtime dance!


Review rate limit: 2/3 reviews remaining, refill in 20 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/backend/services/GitWatcher.ts (1)

130-132: 💤 Low value

Consider caching the GitWorktreeManager instance.

A new GitWorktreeManager is instantiated on every call to git(). Since localPath doesn't change between start() calls, caching the instance would reduce object allocations during frequent git operations.

♻️ Suggested refactor
+ private gitManager: GitWorktreeManager | null = null;+
start(localPath: string, broadcast: BroadcastFn): void {
this.stop();
this.localPath = localPath;
this.broadcast = broadcast;
+ this.gitManager = new GitWorktreeManager(localPath);
// ...
}
private git(): GitWorktreeManager | null {
- return this.localPath ? new GitWorktreeManager(this.localPath) : null;+ return this.gitManager;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/backend/services/GitWatcher.ts` around lines 130 - 132, The git() method
currently instantiates a new GitWorktreeManager on every call; change it to
cache the instance in a private property (e.g. private gitManager?:
GitWorktreeManager) and lazily initialize it inside git(): if gitManager exists
return it, otherwise set gitManager = new GitWorktreeManager(this.localPath) and
return it; ensure initialization guards against null localPath (return null if
no localPath) and consider resetting gitManager if localPath can ever change
(start() uses localPath so caching is safe if it is immutable).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/backend/services/GitWatcher.ts`:
- Around line 61-65: unwatchWorktree currently deletes the timer entry from
debounceTimers without cancelling the scheduled timeout, so pending debounce
handlers (e.g. pushDiff) can still run; update unwatchWorktree to first retrieve
the timer from this.debounceTimers (key `diff:${agentId}`), call clearTimeout on
it if present, then delete the map entry and proceed to close and delete the
watcher; this ensures any pending debounce is cancelled before removal.
---
Nitpick comments:
In `@src/backend/services/GitWatcher.ts`:
- Around line 130-132: The git() method currently instantiates a new
GitWorktreeManager on every call; change it to cache the instance in a private
property (e.g. private gitManager?: GitWorktreeManager) and lazily initialize it
inside git(): if gitManager exists return it, otherwise set gitManager = new
GitWorktreeManager(this.localPath) and return it; ensure initialization guards
against null localPath (return null if no localPath) and consider resetting
gitManager if localPath can ever change (start() uses localPath so caching is
safe if it is immutable).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71ada691-a54d-4dbc-ba76-0bb1cfd5a44f

📥 Commits

Reviewing files that changed from the base of the PR and between 436b9fd and 602fdd7.

📒 Files selected for processing (8)
  • src/backend/main.ts
  • src/backend/routes/remote.ts
  • src/backend/services/GitWatcher.ts
  • src/backend/services/OrchestratorService.ts
  • src/frontend/components/AgentDetailPanel.tsx
  • src/frontend/components/RemoteBar.tsx
  • src/frontend/hooks/useSessionSocket.tsx
  • src/frontend/store/store.ts

Comment threadsrc/backend/services/GitWatcher.ts
@roulpriya
roulpriya merged commit 3b1b190 into mainApr 30, 2026
2 checks passed
@roulpriya
roulpriya deleted the add-git-watcher branch April 30, 2026 16:13
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@recrsn@roulpriya