Skip to content

feat(git-diff): rebuild Source Control window for VSCode parity + AI integration roadmap#50

Merged
erdembas merged 3 commits intomainfrom
feature/37-git-diff
Apr 24, 2026
Merged

feat(git-diff): rebuild Source Control window for VSCode parity + AI integration roadmap#50
erdembas merged 3 commits intomainfrom
feature/37-git-diff

Conversation

@erdembas
Copy link
Copy Markdown
Owner

Closes #37.

Summary

This PR delivers a fullscreen, VSCode-parity Source Control window for RunHQ and plans the next chapter (OpenAI-compatible AI assistant) on top of it. Two commits, two concerns, one goal: make day-to-day Git work in RunHQ feel like a real dev tool, and lay the runway for AI surfaces that fit into the flow instead of bolting a chat box on the side.

The initial diff viewer landed as 8ae019a feat(git-diff): add git diff viewer …. Everything else here is the polish, structure, and roadmap that turns it from "works" into "lives there".

What changed

feat(git-diff): rebuild Source Control window for VSCode parity (f42b045)

  • Tabs reshuffledCommit (now also owns the file browser the old Changes tab had — they were 90% the same data), Branches (promoted out of being a sub-mode), History, Graph. Less duplication, clearer purpose per tab.
  • Commit panel got file search, tree/list toggle, expand/collapse all, status legend, hover-to-stage, and a right-click context menu per file: Open / Reveal / Copy Path / Copy Relative / Stage / Unstage / Discard. Discard is gated behind ConfirmDialog; untracked deletes require typing delete before the button enables — destructive ops are never one mis-click away.
  • New discard_file core op auto-routes tracked paths through git checkout HEAD -- (after a defensive git reset HEAD -- to drop staged hunks first) and untracked paths through git clean -f -d --. Exposed as git_discard_file IPC + ipc.gitDiscardFile. 53 Rust unit tests still green.
  • BranchPicker (new shadcn-style component) replaces every native <select> across GraphPanel, HistoryPanel, and BranchesPanel. Portal-rendered, auto-flipping, type-ahead search, keyboard nav (↑/↓/↵/Esc), grouping. One component, four tabs, consistent UX.
  • Graph commit search — type a substring (subject / author / email / hash / refs) and non-matching commits dim to ~30% opacity instead of being filtered out. Lane topology never reshuffles, so spatial memory holds. Live matched / total counter in the header.
  • Layered Esc in DiffViewer — first defers to any open overlay (role="alertdialog" | "menu" | "dialog" | "listbox"), so reflexive Esc dismisses popovers / context menus / branch pickers first. Only when nothing nested is open does it pop a close-confirm before tearing the window down. Saves users from nuking a half-typed commit message because they reflex-pressed Esc to close a tooltip. The titlebar X still closes immediately — a deliberate click is a deliberate close.
  • Full-file diff context (-U100000) so reviewers see the whole file, not just hunks. Toggleable via store.
  • Status serialization fix — Rust FileDiffStatus was serializing as CamelCase but the frontend expected lowercase, so the M/A/D/R/C/U letters silently never rendered. Added #[serde(rename_all = \"lowercase\")]. Status letters and icons now actually show up.
  • Color consistency — every panel surface unified to bg-surface-raised, inputs to bg-surface. No more opacity-stacked muted layers fighting each other across tabs.
  • Material Icon Theme integration via @iconify/react + @iconify-json/material-icon-theme for file-type icons. Resizable sidebars (320–600px) with localStorage persistence.

docs(roadmap): plan OpenAI-compatible AI integration (Phase 6–8) (4a43935)

A new section in ROADMAP.md for a BYOK, OpenAI-API-compatible AI layer — provider-agnostic by design (OpenAI, Azure, OpenRouter, Together, Groq, DeepSeek, Mistral, Ollama, LM Studio, llama.cpp), so users keep their own keys and we never become a billing relay or a data hop.

Headline pieces:

  • Foundations — Provider Profiles with per-feature model routing, OS-keychain credential storage, streaming-first via Tauri channels with cancellation, token/cost telemetry with monthly soft/hard limits, privacy switches (per-project AI off, local-only network mode, pre-flight secret redaction with a "preview before send" panel), offline-tolerant degradation.
  • AI Surfaces (in dependency order) — Commit Message Generator (Phase 6 quick-win, rides on the Source Control window in this very PR) → Branch Name Suggester → Diff Explainer → Log Triage → PR Description / Release Notes → Code Review on Diff (suggestions only) → Project Q&A chat with auto-injected context + slash commands (/explain, /test, /diff, /run — never auto-execute) → Cross-Project Q&A backed by the existing dashboard data → Smart Auto-Tagging → Health-Check Policy Advisor.
  • Operational Surfaces — editable prompt library (no black-box prompts), local SQLite per-project conversation history, "Preview Before Send" disclosure, function calling/tools later behind explicit consent.
  • Technical Notes — headless runhq-core::ai module (Provider trait + OpenAICompatible impl), typed AIEvent stream (Delta / Tool / Done { usage }), static model registry for context windows + per-1k pricing, failure budget (30s timeout, 2-retry exponential backoff, per-profile circuit breaker), no background calls without explicit user action.

Implementation order updated:

Phase Features
Phase 6 AI Foundations + Commit Messages
Phase 7 AI Diff & Log Triage, PR Drafting
Phase 8 AI Project & Cross-Project Q&A

Marked Git Diff Viewer as ~~shipped~~ in the existing phase table.

Why two commits

  • feat is reviewable as a single Source Control deliverable — open the window, click around, all of it works without touching the roadmap.
  • docs is a planning artifact reviewable on its own merits — no risk of "approve the code, oh and also approve the AI plan I didn't notice".

Test plan

  • Open a project with a dirty working tree → click the Source Control toggle → window opens fullscreen.
  • Commit tab: tree + list toggles work; file search filters live; expand/collapse all behave; status legend renders M/A/D/R/C/U with colors.
  • Right-click a tracked modified file → context menu shows Open / Reveal / Copy Path / Copy Relative / Stage / Unstage / Discard. Discard pops ConfirmDialog. Confirming reverts the file.
  • Right-click an untracked file → Discard label reads "Delete from disk", button is disabled until you type delete. Confirming removes the file via git clean -f -d --.
  • Branches tab: both base and head selectors are the new BranchPicker (portal popover, type-ahead search, keyboard nav with ↑/↓/↵/Esc, groups for local/remote).
  • History tab: branch filter is BranchePicker; commit search filters live.
  • Graph tab: branch filter is BranchPicker; commit search dims non-matches (graph topology unchanged); matched / total count visible.
  • Esc behavior — open the diff window, open any popover/menu/branch picker → press Esc → only the overlay closes, window stays. Press Esc again with nothing open → close-confirm dialog appears. Click the titlebar X → closes immediately, no confirm.
  • Diff display — full-file context renders (not just hunks); no diff --git / index preamble lines leak into Monaco.
  • Theme switch — flip light/dark while the diff viewer is open; Monaco + panels follow without reload.
  • Backendcargo test -p runhq-core ⇒ 53 passing (verified locally).

Made with Cursor

erdembas added 3 commits April 24, 2026 19:03
…ison (#37)

- Add diff functions to git.rs: diff, diff_staged, diff_file, diff_file_staged, diff_branches, diff_all_raw, diff_staged_raw
- Add DiffSummary, FileDiff, FileDiffStatus types
- Add IPC commands for all diff operations
- Add DiffViewer component: file sidebar with staged/unstaged sections, inline diff with syntax coloring
- Add store state for diff viewer
- Add 5 new unit tests for diff operations
The diff viewer that shipped in #37 was functional but felt nothing
like a real source-control surface. This pass turns it into a proper
fullscreen Git workbench: multi-tab layout, modern combobox dropdowns,
context menus with safe destructive ops, layered Esc handling, and a
consistent visual language with the rest of the app.

Highlights
- Tabs reshuffled: Commit (merged with the old Changes browser),
  Branches (promoted from a sub-mode), History, Graph. The 90%
  overlap between Changes and Commit is gone, branch comparison gets
  its own home.
- Commit panel: file search, tree/list toggle, expand/collapse all,
  status legend, hover-to-stage actions, and right-click context menu
  per file (Open / Reveal / Copy Path / Copy Relative / Stage / Unstage
  / Discard). Discard is gated behind ConfirmDialog; untracked deletes
  require typing 'delete' to confirm.
- New 'discard_file' core op auto-routes tracked paths through
  'git checkout HEAD --' (after a defensive index reset) and untracked
  paths through 'git clean -f -d --'. Exposed as 'git_discard_file'
  IPC + 'ipc.gitDiscardFile' on the frontend.
- Branch pickers: every native <select> replaced with a shadcn-style
  BranchPicker (portal, auto-flip, type-ahead search, keyboard nav,
  groups). One component, four tabs, consistent UX.
- Graph: client-side commit search (subject / author / email / hash /
  refs) that dims non-matches instead of filtering, so lane topology
  never reshuffles. History panel got the same search treatment.
- Layered Esc in DiffViewer: defers to any open overlay (alertdialog /
  menu / dialog / listbox) so reflexive Esc dismisses popovers first;
  with nothing nested open, pops a close-confirm instead of nuking
  the window and losing typed commit messages. The X button still
  closes immediately because that's a deliberate click.
- Diffs render in full-file context (-U100000) so reviewers see the
  whole file, not just hunks. Toggle preserved via store.
- Fixed FileDiffStatus serialization mismatch (Rust enum was
  CamelCase, frontend expected lowercase) — status letters/icons now
  actually render.
- Color consistency: panel surfaces unified to bg-surface-raised,
  inputs to bg-surface, no more opacity-stacked muted backgrounds.
- Material Icon Theme integration via @iconify-json for file-type
  icons. Resizable sidebars (320–600px) with localStorage persistence.

Made-with: Cursor
Adds a dedicated section to the roadmap outlining a BYOK,
OpenAI-API-compatible AI layer for RunHQ. Provider-agnostic by design
(OpenAI, Azure, OpenRouter, Together, Groq, DeepSeek, Mistral,
Ollama, LM Studio, llama.cpp) so users keep their own keys and we
never become a billing relay.

Foundations
- Provider Profiles with per-feature model routing.
- OS-keychain credential storage (never plaintext, never synced).
- Streaming-first via Tauri channels with explicit cancellation.
- Token + cost telemetry, monthly soft/hard limits.
- Privacy switches: per-project AI off, local-only network mode,
  pre-flight secret redaction with a 'preview before send' panel.
- Offline-tolerant: AI failures degrade silently, never block flows.

AI Surfaces (in dependency order)
- Commit Message Generator (the first surface to ship — rides on the
  Source Control window already in this branch).
- Branch Name Suggester from issue titles.
- Diff Explainer in the diff viewer.
- Log Triage in LogPanel ('Explain error', 'Suggest fix').
- PR Description + Release Notes from branch / commit ranges.
- Code Review on Diff (suggestions only, never blocking).
- Project Q&A chat with auto-injected context + slash commands
  (/explain, /test, /diff, /run — never auto-execute).
- Cross-Project Q&A backed by the Cross-Project Dashboard data.
- Smart Auto-Tagging on import; Health-Check Policy Advisor.

Operational Surfaces
- Editable prompt library (no black-box prompts).
- Local SQLite per-project conversation history, wipe-able.
- 'Preview Before Send' disclosure with model + redacted prompt.
- Function calling/tools left for later behind explicit consent.

Technical Notes
- Headless 'runhq-core::ai' module with Provider trait +
  OpenAICompatible impl; Tauri shell only does IPC.
- Typed AIEvent stream (Delta / Tool / Done { usage }).
- Static model registry for context windows + per-1k pricing.
- Failure budget: 30s timeout, 2-retry exponential backoff,
  per-profile circuit breaker.
- No background calls without user action — every request traceable.

Implementation Order updated: Phase 6 (Foundations + Commit
Messages), Phase 7 (Diff & Log Triage, PR Drafting), Phase 8
(Project & Cross-Project Q&A). Marked Git Diff Viewer as shipped in
the existing phase table.

Made-with: Cursor
@github-actions github-actions Bot added size/size/XL documentation Improvements or additions to documentation dependencies rust frontend and removed size/size/XL labels Apr 24, 2026
@erdembas erdembas enabled auto-merge (rebase) April 24, 2026 22:55
@erdembas erdembas merged commit 1a4dfb3 into main Apr 24, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies documentation Improvements or additions to documentation frontend rust

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Roadmap: Git Diff Viewer

1 participant