Skip to content

Add version control command center#3177

Open
Quicksaver wants to merge 11 commits into
pingdotgg:mainfrom
Quicksaver:split/version-control-panel-work
Open

Add version control command center#3177
Quicksaver wants to merge 11 commits into
pingdotgg:mainfrom
Quicksaver:split/version-control-panel-work

Conversation

@Quicksaver

@Quicksaver Quicksaver commented Jun 19, 2026

Copy link
Copy Markdown

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

  • Added SOURCE_CONTROL.md to document the shipped Version Control panel behavior, entry points, layout, operations, error handling, and validation expectations.
  • Added SourceControlPanelService on 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.
  • Extended GitHub, GitLab, Azure DevOps, and Bitbucket provider plumbing so the panel can detect actionable branches relative to open PR/MR base branches.
  • Updated VcsStatusBroadcaster to support source-control refresh needs with ref-counted filesystem watching, ignored .git/ events, debounce/fingerprint suppression, and gitignore-aware filtering.
  • Added the React Version Control panel UI in the right panel with Actionable and Remotes sections, working-tree file selection, inline diffs, branch/stash/commit rows, context menus, and guarded destructive actions.
  • Added client presentation state and workspace-scope helpers so source-control UI state is tied to the active thread/project context and works after the connection-runtime updates.
  • Extended shared RPC, IPC, Git, settings, and VCS contracts for the new source-control snapshot and operation protocol.
  • Added desktop menu wiring and host display preferences for enabling the shared panel by runtime host, with VS Code defaulting to hidden so it does not compete with native Source Control.
  • Added focused tests for provider change-request base detection, source-control service behavior, VCS broadcaster behavior, source-control panel state, and workspace scope resolution.

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 check passed with 0 errors. It reported existing lint warnings in unrelated mobile/web files.
  • pnpm exec vp run typecheck passed across all 15 configured targets.

Proof

Screenshot 2026-06-16 at 19 26 39

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 SourceControlPanelService with 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 / --repository derived from remote URL context. VcsStatusBroadcaster gains ref-counted local filesystem watches (ignore .git/, debounce, git check-ignore) so status updates without refocus. All panel operations are exposed via new vcs.panel.* WebSocket RPCs in ws.ts.

Client: Lazy SourceControlPanel in ChatView, picker entry in RightPanelTabs, and thread metadata updates on branch switch (server thread.meta.update vs draft context). Desktop context menus support explicit separator items.

Docs/tests: SOURCE_CONTROL.md describes 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

  • Introduces SourceControlPanelService on the server with methods for snapshotting repo state, staging/unstaging/discarding files, committing, pulling, pushing, branch management, stash operations, remote management, and diffs.
  • Adds ~30 new WebSocket RPC methods in rpc.ts and ws.ts to expose these operations, with read vs. operate authorization scopes and automatic git status refresh after mutations.
  • Adds a SourceControlPanel React component (lazy-loaded) mounted in the right panel of ChatView, gated by host display preferences (T3HostBridge) and repository availability.
  • Extends RightPanelTabs with a 'Version Control' surface entry (using a GitBranch icon) that is disabled with an explanation when no Git repo is detected.
  • Adds VcsStatusBroadcaster local filesystem watcher with debouncing, .git-directory exclusion, and per-cwd reference counting to trigger live status refreshes.
  • Adds GitHub, GitLab, and Azure DevOps source control providers that scope PR/MR listings to the repository and project derived from the remote URL context.
  • Changes the default automatic Git fetch interval from 30 seconds to 5 minutes.
  • Risk: the fetch interval change is a behavioral default that affects all users without explicit configuration.
📊 Macroscope summarized 4b645ae. 24 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted

🗂️ Filtered Issues

No issues evaluated.

- 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
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ef5b9de5-07d8-47c4-84b2-a06bce9a86e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

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

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jun 19, 2026

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using high effort and found 4 potential issues.

Fix All in Cursor

❌ 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;

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.

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.

Fix in Cursor Fix in Web

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 });
});

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.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.

}
yield* run("vcs.panel.cleanUntrackedFiles", input.cwd, ["clean", "-fd", "--", ...paths]).pipe(
Effect.asVoid,
);

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.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4b645ae. Configure here.

hasConflicts: file.hasConflicts,
}))
.toSorted((left, right) => left.path.localeCompare(right.path));
}

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.

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.

Fix in Cursor Fix in Web

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`;

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.

🟢 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,

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.

🟡 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:
...

@macroscopeapp

macroscopeapp Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant