Add version control command center#3177
Conversation
- Query open change requests across supported remotes - Surface actionable branch rows only when local branch is behind the MR/PR base - Pass remote repository context to GitHub, GitLab, and Azure DevOps CLIs
…ol-panel-work # Conflicts: # apps/web/src/components/ChatView.tsx # apps/web/src/environmentApi.ts # apps/web/src/environments/runtime/service.threadSubscriptions.test.ts # packages/client-runtime/src/wsRpcClient.ts
- Extract shared source control panel state and API wiring - Move VS Code project scope and subagent parent resolution into runtime helpers - Add tests for presentation state and subagent control resolution
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.
| const defaultCompareRef = | ||
| localBranches.find((ref) => ref.isDefault && !ref.current)?.name ?? | ||
| localBranches.find((ref) => !ref.current)?.name ?? | ||
| null; |
There was a problem hiding this comment.
Wrong compare ref on default branch
Medium Severity
When the checked-out branch is the repository default (for example main), defaultCompareRef skips that branch and picks another local branch instead. Branch details and compare bases for local-only branches then use the wrong ref instead of the repo default.
Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.
| } | ||
| await api.vcs.pullBranch({ cwd, branchName: branch.name, merge: true }); | ||
| await api.vcs.pushBranch({ cwd, branchName: branch.name }); | ||
| }); |
There was a problem hiding this comment.
Merge sync rejects non-current branch
Medium Severity
When a diverged branch row opens smart sync and the user picks merge sync, the panel calls pullBranch with merge: true for that row’s branch. The server only allows merge pull on the checked-out branch, so merge sync fails for any other local branch while force pull and force push can still work.
Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.
| } | ||
| yield* run("vcs.panel.cleanUntrackedFiles", input.cwd, ["clean", "-fd", "--", ...paths]).pipe( | ||
| Effect.asVoid, | ||
| ); |
There was a problem hiding this comment.
Discard hides restore failures
Medium Severity
Unstaged discard runs git restore --worktree for tracked paths, but failures on that step are swallowed. The flow still runs git clean and completes successfully, so the panel can report a successful discard while tracked edits remain on disk.
Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.
| hasConflicts: file.hasConflicts, | ||
| })) | ||
| .toSorted((left, right) => left.path.localeCompare(right.path)); | ||
| } |
There was a problem hiding this comment.
Combined change stats undercount
Low Severity
mergeChangeGroups combines staged and unstaged rows for the same path using Math.max on insertions and deletions. A file with both staged and unstaged edits can show lower +/- totals in the working-tree summary and selection stats than the real combined change.
Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.
| if (weeks === 1) return "last week"; | ||
| if (days < 30) return `${weeks} weeks ago`; | ||
| const months = Math.floor(days / 30); | ||
| if (months < 12) return `${months} month${months === 1 ? "" : "s"} ago`; |
There was a problem hiding this comment.
🟢 Low source-control/SourceControlPanel.tsx:299
When days is 360–364, Math.floor(days / 30) yields 12, which fails the months < 12 guard. The code then falls through to Math.floor(days / 365), which returns 0, producing "0 years ago". Changing the condition to days < 365 avoids the gap between the month and year thresholds.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/source-control/SourceControlPanel.tsx around line 299:
When `days` is 360–364, `Math.floor(days / 30)` yields 12, which fails the `months < 12` guard. The code then falls through to `Math.floor(days / 365)`, which returns 0, producing `"0 years ago"`. Changing the condition to `days < 365` avoids the gap between the month and year thresholds.
Evidence trail:
apps/web/src/components/source-control/SourceControlPanel.tsx lines 292–301 at REVIEWED_COMMIT. The `months < 12` guard on line 299 fails when `Math.floor(days/30)` equals 12 (days 360–364), and `Math.floor(days/365)` on line 300 returns 0, producing the nonsensical string "0 years ago".
| const status = input.statuses?.get(path); | ||
| files.push({ | ||
| path, | ||
| originalPath: status?.originalPath ?? null, |
There was a problem hiding this comment.
🟡 Medium sourceControl/SourceControlPanelService.ts:709
In the line-based format fallback, when renamedPathRaw is present and statuses has no entry for the renamed file, originalPath is set to null instead of pathRaw. This silently drops the original path information that the numstat output already contains. Consider using status?.originalPath ?? (renamedPathRaw ? pathRaw : null) to preserve the original path when the status map misses the entry.
- originalPath: status?.originalPath ?? null,
+ originalPath: status?.originalPath ?? (renamedPathRaw ? pathRaw : null),🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/sourceControl/SourceControlPanelService.ts around line 709:
In the line-based format fallback, when `renamedPathRaw` is present and `statuses` has no entry for the renamed file, `originalPath` is set to `null` instead of `pathRaw`. This silently drops the original path information that the numstat output already contains. Consider using `status?.originalPath ?? (renamedPathRaw ? pathRaw : null)` to preserve the original path when the status map misses the entry.
Evidence trail:
...
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. Diff is too large for automated approval analysis. A human reviewer should evaluate this PR. You can customize Macroscope's approvability policy. Learn more. |


Summary
Adds a Git-backed Version Control surface to the existing right panel. The surface is scoped to the active project/repository, stays server-authoritative for Git operations, and can be opened from draft or existing conversations once repository context is available.
The feature is intentionally a command center rather than a full Git dashboard: it highlights currently actionable work from the working tree, local branches, stashes, and branch state versus configured remotes and open change-request bases.
What Changed
SOURCE_CONTROL.mdto document the shipped Version Control panel behavior, entry points, layout, operations, error handling, and validation expectations.SourceControlPanelServiceon the server for panel snapshots, branch/stash/commit/compare data, selected-file commit and stash flows, discard operations, branch operations, remote operations, and provider-derived PR/MR base checks.VcsStatusBroadcasterto support source-control refresh needs with ref-counted filesystem watching, ignored.git/events, debounce/fingerprint suppression, and gitignore-aware filtering.ActionableandRemotessections, working-tree file selection, inline diffs, branch/stash/commit rows, context menus, and guarded destructive actions.Why
This is an attempt at a version control center for T3 Code. Rather than building a full Git-based dashboard, it acts more as a command center that gives the user information on what is currently actionable based on their working tree and local branches versus existing remotes.
That keeps the surface focused on decisions users can take now: committing or stashing selected work, seeing branches that need sync or publication, inspecting stashes, and noticing when an open PR/MR base has moved ahead.
Validation
pnpm exec vp checkpassed with 0 errors. It reported existing lint warnings in unrelated mobile/web files.pnpm exec vp run typecheckpassed across all 15 configured targets.Proof
Note
High Risk
Large new surface for destructive Git operations (discard, force push/pull, branch delete) and broad server Git/provider integration; mitigated by server-only Git execution, confirmations, and extensive tests.
Overview
Adds a server-authoritative Version Control surface as a new right-panel kind (
source-control), gated by host display preference (hidden by default in VS Code).Backend: Introduces
SourceControlPanelServicewith snapshots, branch/stash/compare/detail loading, selected-file commit/stash/discard, branch/remote/stash mutations, working-tree rename enrichment, and actionable rows from same-name remote forks and open PR/MR base branches (GitHub/GitLab/Azure DevOps/Bitbucket). Provider CLIs now pass--repo/--repositoryderived from remote URL context.VcsStatusBroadcastergains ref-counted local filesystem watches (ignore.git/, debounce,git check-ignore) so status updates without refocus. All panel operations are exposed via newvcs.panel.*WebSocket RPCs inws.ts.Client: Lazy
SourceControlPanelinChatView, picker entry inRightPanelTabs, and thread metadata updates on branch switch (serverthread.meta.updatevs draft context). Desktop context menus support explicitseparatoritems.Docs/tests:
SOURCE_CONTROL.mddescribes behavior; large service and broadcaster test suites plus provider remote-context tests.Reviewed by Cursor Bugbot for commit 4b645ae. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add a Version Control panel to the right sidebar with full Git workflow support
SourceControlPanelServiceon the server with methods for snapshotting repo state, staging/unstaging/discarding files, committing, pulling, pushing, branch management, stash operations, remote management, and diffs.rpc.tsandws.tsto expose these operations, with read vs. operate authorization scopes and automatic git status refresh after mutations.SourceControlPanelReact component (lazy-loaded) mounted in the right panel ofChatView, gated by host display preferences (T3HostBridge) and repository availability.RightPanelTabswith a 'Version Control' surface entry (using aGitBranchicon) that is disabled with an explanation when no Git repo is detected.VcsStatusBroadcasterlocal filesystem watcher with debouncing,.git-directory exclusion, and per-cwd reference counting to trigger live status refreshes.📊 Macroscope summarized 4b645ae. 24 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.