Skip to content

Feature: add inline diff review panel (#609) - #4020

Closed
austinywang wants to merge 23 commits into
mainfrom
issue-609-diff-review-panel
Closed

austinywang wants to merge 23 commits into
mainfrom
issue-609-diff-review-panel

Conversation

@austinywang

@austinywang austinywang commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Closes #609

Summary:

  • Adds a right-sidebar Review mode with a branch/working-tree selector and inline file/hunk diffs.
  • Supports working-tree hunk revert actions and periodic refresh for live agent changes.
  • Extends command palette and right_sidebar CLI mode routing for the Review panel.

Testing:

  • Not run locally per repository policy; CI will run the test suite.

Note

Medium Risk
Introduces git subprocesses and git apply -R hunk revert that mutates the working tree; mistakes or race conditions during refresh could confuse diff state, though changes are user-initiated in a local repo.

Overview
Adds a Review right-sidebar mode that shows inline git diffs for the active workspace, with a Working Tree vs branch comparison picker, file/hunk summaries, and revert hunk on the working tree via git apply.

New SwiftUI stack (DiffReviewStore, DiffReviewGitClient, patch parser, panel UI) loads snapshots asynchronously, refreshes on a timer while visible, and keeps the last good snapshot when later loads fail. Command palette gains Show Sidebar Review; cmux right-sidebar and remote right_sidebar accept review, diff, and code-review aliases (canonical review), with help text split into localized string keys.

Unit tests cover patch parsing, panel content state, and CLI mode normalization.

Reviewed by Cursor Bugbot for commit 63692bf. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds a right‑sidebar Review mode with inline per‑file/hunk diffs, a working‑tree/branch picker, and per‑hunk revert for working‑tree and staged changes. Includes CLI aliases, localized UI, visibility‑aware refresh, and preserves snapshots on transient errors.

  • New Features

    • Review panel with inline diffs, status badges, +/- counts, summary, and target picker; handles untracked/binary/rename/copy with localized UI.
    • Per‑hunk revert for working‑tree and staged hunks via git apply -R; cancellable with progress; refresh pauses during revert.
    • Command palette adds “Show Sidebar Review” (no default shortcut) and uses mode.commandTitle; right‑sidebar CLI adds review/diff/code-review/code_review aliases with localized help and updated focus/availability.
    • Tests cover diff parsing, panel state resolution, CLI routing, and staged hunk revert.
  • Bug Fixes

    • Branch comparisons include working‑tree changes.
    • Preserve the last successful snapshot during transient load failures; harden visibility‑aware refresh and observation lifecycle.
    • Close git pipe writers to prevent hangs; map git root errors to localized messages.

Written for commit 63692bf. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a Review right‑sidebar mode with a Diff Review panel: file/hunk lists, per‑hunk revert, branch/working‑tree targets, loading/error states, and live refresh.
  • CLI / Documentation

    • CLI help and localized strings updated to include new modes and aliases (review, diff, code‑review) and example usage.
  • Platform Integration

    • Git‑backed snapshot loading and hunk revert support for diff review.
  • Tests

    • Added/updated tests for diff parsing, git snapshot errors, panel state resolution, CLI normalization, and command‑palette behavior.

Review Change Stack

@vercel

vercel Bot commented May 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment May 24, 2026 9:09pm
cmux-staging Building Building Preview, Comment May 24, 2026 9:09pm

@coderabbitai

coderabbitai Bot commented May 12, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Diff Review panel surfaced via a new RightSidebarMode .review. Implements diff models, a git client that loads unified diffs, a parser, a MainActor store with live refresh and hunk reverts, a SwiftUI panel, CLI/command wiring, localization, project wiring, and unit tests.

Changes

Diff Review Feature

Layer / File(s) Summary
Data models for Diff Review
Sources/DiffReviewModels.swift
Defines line/hunk/file/snapshot models, diff targets, load phases, and panel content-state resolution.
Unified diff parser
Sources/DiffReviewPatchParser.swift
Parses unified git diff output into per-file headers, hunks, lines, normalized paths, and file status detection (including binary/untracked/rename/copy).
Git integration and process execution
Sources/DiffReviewGitClient.swift
Runs git subprocesses (rev-parse, branch, diff, ls-files), collects tracked/untracked diffs, centralizes Process/stdout-stderr draining, and exposes snapshot load and hunk revert entry points with error mapping.
Store and orchestration
Sources/DiffReviewStore.swift
@MainActor observable store managing directory lifecycle, snapshot loading with stale-result suppression, target selection, guarded hunk reverts, and periodic live-refresh.
Diff Review SwiftUI panel and components
Sources/DiffReviewPanelView.swift
Toolbar (target picker/refresh), summary row, file/hunk sections, per-line rendering, revert actions with progress, and loading/error/empty-state views.
Right-sidebar wiring, focus, tool panel, command palette
Sources/RightSidebarPanelView.swift, Sources/ContentView+RightSidebarCommandPalette.swift, Sources/RightSidebarMode+Availability.swift, Sources/RightSidebarToolPanel.swift, Sources/MainWindowFocusController.swift, Sources/RightSidebarRemoteCommand.swift
Adds .review mode, integrates the panel into the sidebar, updates command-palette IDs/titles, CLI argument parsing/usage strings, focus/tool-panel behavior, and mode availability.
CLI help and localization
CLI/cmux.swift, Resources/Localizable.xcstrings
Updates CLI usage and examples to include review/diff modes and adds localized strings for the review UI and diff-related error/messages.
Project configuration and tests
cmux.xcodeproj/project.pbxproj, cmuxTests/*
Registers new sources/tests in the Xcode project and adds unit tests for patch parsing, snapshot error handling, panel content-state resolution, summary formatting, CLI normalization, and command-palette/focus expectations.

Sequence Diagram(s)

sequenceDiagram
  participant UI as DiffReviewPanelView
  participant Store as DiffReviewStore
  participant Client as DiffReviewGitClient
  participant Parser as DiffReviewPatchParser
  participant Git as /usr/bin/git
  UI->>Store: setDirectory / selectTarget / refresh / revertHunk
  Store->>Client: loadSnapshot(directory, selectedTargetID)
  Client->>Git: git rev-parse / branch / diff / ls-files
  Git-->>Client: stdout/stderr results
  Client->>Parser: parse(diffOutput, untrackedPaths)
  Parser-->>Client: [DiffReviewFile[]]
  Client-->>Store: DiffReviewSnapshot
  Store-->>UI: publish snapshot / phase updates
  UI->>Store: revertHunk(hunk)
  Store->>Client: revertHunk(repositoryRoot, patch)
  Client-->>Store: revert result / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 In the sidebar's hush I nibble lines of change,

hunks unfurl like ribbons soft and bright.
I hop through branches, count each added range,
one gentle revert returns the code to light.
A rabbit cheers: review complete, delight.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error PR introduces Timer-based polling (2s interval) in DiffReviewStore, violating swift-blocking-runtime.md rule treating timers/polling in shipped code as failures by default. Replace Timer polling with file system notifications (FSEvents), workspace callbacks, or explicit refresh triggers rather than 2-second periodic polling.
Cmux Full Internationalization ❌ Error 33 new/changed localization keys have only en/ja translations (2/20 locales), violating requirement for complete translations across all 20 app-supported locales. Add translations for all 20 locales to 30 new diffReview keys and 3 changed CLI keys in Resources/Localizable.xcstrings.
Cmux Architecture Rethink ❌ Error PR introduces polling via Timer and split UI lifecycle ownership across RightSidebarPanelView and DiffReviewPanelView, creating race conditions without single source of truth. Consolidate lifecycle into one owner managing directory/visibility state machine with explicit timer/task invariants, or replace polling with event-driven workspace observation.
Docstring Coverage ⚠️ Warning Docstring coverage is 1.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main feature being added: an inline diff review panel for the right sidebar.
Linked Issues check ✅ Passed The PR successfully implements all primary coding requirements from issue #609: branch/base selector, inline file/hunk diffs, hunk-level revert, and periodic refresh for live updates.
Out of Scope Changes check ✅ Passed All changes are scoped to the Review mode feature: UI components, git operations, CLI wiring, command palette integration, and related test coverage. No unrelated modifications detected.
Cmux Swift Actor Isolation ✅ Passed DiffReviewStore is @MainActor with background work properly detached, all cross-boundary models are Sendable, store safely accessed via SwiftUI @State.
Cmux No Hacky Sleeps ✅ Passed The check applies to TypeScript, JavaScript, shell, and non-Swift build scripts only. This PR contains only Swift source and test files; zero TypeScript/JavaScript/shell changes present.
Cmux Swift Concurrency ✅ Passed PR uses modern async/await and @Observable instead of Combine; no DispatchQueue, completion handlers, or unmanaged Tasks with lifecycle.
Cmux Swift @Concurrent ✅ Passed Static methods are implicitly nonisolated. Task.detached properly crosses actor boundaries without requiring @concurrent annotation on static functions.
Cmux Swift File And Package Boundaries ✅ Passed New files have clear single responsibilities; DiffReviewPanelView (517 lines) is cohesive UI code; no mixed concerns; independently testable with clear extraction path.
Cmux Swift Logging ✅ Passed No prohibited logging patterns detected in production code. Error messages use localized descriptions. Git output safely parsed structurally without logging.
Cmux User-Facing Error Privacy ✅ Passed All user-facing errors use localized, sanitized messages without exposing vendor names, git output, or technical details. stderr is captured internally only, never shown to users.
Cmux Swiftui State Layout ✅ Passed DiffReviewStore uses @Observable (modern pattern), lazy views receive value snapshots/actions not stores, lifecycle in callbacks, no render-time mutations.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds .review right-sidebar mode as an embedded SwiftUI View (DiffReviewPanelView) in the main workspace window's right-sidebar pane, not as a standalone NSWindow/NSPanel/WindowGroup.
Description check ✅ Passed The PR description includes the required Summary and Testing sections with clear details about what changed and how it was tested.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-609-diff-review-panel

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.

@greptile-apps

greptile-apps Bot commented May 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a right-sidebar Review mode that renders inline git diffs (working-tree vs HEAD, or branch vs merge-base) with per-hunk revert, a visibility-aware live-refresh timer, and full CLI/command-palette routing. The implementation is well-structured across dedicated model, parser, git client, store, and view files, and addresses all previous review concerns including concurrent pipe draining, @Observable state ownership, and localized error messages.

  • New DiffReviewGitClient runs git diff/git apply -R in Task.detached with concurrent FileHandle.bytes pipe draining and NSLock-guarded process cancellation; GitProcessCancellation and GitProcessCompletion need @unchecked Sendable to compile cleanly under Swift 6 strict concurrency.
  • All new diffReview.* and cli.rightSidebar.usage.* string-catalog keys carry translations for all 20 supported locales; the existing rightSidebar.remote.error.usage.set key was edited but only has en and ja translations, leaving 18 locales with stale copy.
  • DiffReviewStore is @MainActor @Observable, owned as @State in RightSidebarPanelView, with hunk-revert tasks tracked by ID and cancelled on directory/target/observation teardown.

Confidence Score: 4/5

Safe to merge after fixing two issues: @unchecked Sendable on the two git-process helper classes (Swift 6 compile error), and completing the rightSidebar.remote.error.usage.set translations for all 18 missing locales.

The git client's GitProcessCancellation and GitProcessCompletion classes are captured in @sendable closures without Sendable conformance — a Swift 6 strict-concurrency compile error on a code path exercised on every diff load and hunk revert. Separately, the rightSidebar.remote.error.usage.set catalog entry was updated in this PR but 18 of 20 supported locales remain without an entry, so those users see outdated English fallback text. Both issues are isolated fixes with no architectural impact.

Sources/DiffReviewGitClient.swift (GitProcessCancellation and GitProcessCompletion classes) and Resources/Localizable.xcstrings (rightSidebar.remote.error.usage.set entry).

Important Files Changed

Filename Overview
Sources/DiffReviewGitClient.swift New git subprocess client with concurrent pipe draining via FileHandle.bytes and cancellation via NSLock-guarded helper classes; GitProcessCancellation and GitProcessCompletion are missing @unchecked Sendable despite being captured in @sendable closures (Swift 6 error).
Sources/DiffReviewStore.swift @mainactor @observable store with hunk-revert task tracking, Timer-driven live refresh, and clean lifecycle teardown; all previous threading and lifecycle concerns are resolved.
Sources/DiffReviewPanelView.swift SwiftUI diff review panel; fully localized, visibility-aware observation lifecycle, correct @observable store ownership from parent via @State.
Sources/DiffReviewPatchParser.swift Pure diff patch parser handling renames, copies, binary, untracked, and hunk range extraction; no side effects, well-separated from UI.
Sources/DiffReviewModels.swift Value-model file scoped to data types, load-phase enum, and DiffReviewPanelContentState resolver; single responsibility, well under the 400-line threshold.
Resources/Localizable.xcstrings All new diffReview.* and cli.rightSidebar.usage.* keys carry translations for all 20 supported locales; rightSidebar.remote.error.usage.set was edited but only has en and ja translations, leaving 18 locales without updated copy.
Sources/RightSidebarPanelView.swift Adds .review case to the mode switch, owns DiffReviewStore as @State, and correctly stops observation on mode/visibility changes.
Sources/RightSidebarMode+Availability.swift Registers review/diff/code-review/code_review CLI aliases and marks .review as always available alongside existing modes.

Sequence Diagram

sequenceDiagram
    participant PV as DiffReviewPanelView
    participant S as DiffReviewStore (@MainActor)
    participant GC as DiffReviewGitClient
    participant Git as git process

    PV->>S: setDirectory(path)
    S->>S: refresh() + startLiveRefreshIfNeeded()
    S->>GC: loadSnapshot(directory:selectedTargetID:)
    GC->>Git: git rev-parse / diff / ls-files
    Git-->>GC: stdout + stderr (concurrent FileHandle.bytes)
    GC-->>S: DiffReviewSnapshot
    S->>S: "phase = .loaded, snapshot set"

    Note over S: Timer fires every 2s (allowsLiveRefresh only)
    S->>GC: loadSnapshot() [live refresh]
    GC-->>S: updated DiffReviewSnapshot

    PV->>S: revertHunk(hunk)
    S->>GC: revertHunk(repositoryRoot:patch:)
    GC->>Git: git apply -R -
    Git-->>GC: exit status
    GC-->>S: success / DiffReviewGitError
    S->>S: finishRevert → refresh()

    PV->>S: stopObserving() (onDisappear)
    S->>S: cancel loadTask, cancel revertTasks, stopLiveRefresh()
Loading

Reviews (13): Last reviewed commit: "fix: revert staged diff review hunks" | Re-trigger Greptile

Comment thread Sources/DiffReviewModels.swift Outdated
Comment thread Sources/DiffReviewModels.swift Outdated
Comment thread Sources/DiffReviewModels.swift
Comment thread Sources/RightSidebarPanelView.swift
Comment thread Sources/DiffReviewModels.swift Outdated
Comment thread Sources/RightSidebarPanelView.swift
Comment thread Sources/DiffReviewModels.swift Outdated
Comment thread Sources/DiffReviewPanelView.swift
Comment thread Sources/DiffReviewGitClient.swift
Comment thread Sources/DiffReviewStore.swift Outdated
Comment thread Sources/DiffReviewStore.swift
Comment thread Sources/DiffReviewGitClient.swift Outdated
Comment thread Sources/DiffReviewStore.swift Outdated
Comment thread Sources/DiffReviewStore.swift
Comment thread Sources/DiffReviewStore.swift
Comment thread Sources/DiffReviewPanelView.swift Outdated
Comment thread Sources/DiffReviewPanelView.swift
Comment thread Sources/DiffReviewStore.swift
Comment thread Sources/DiffReviewGitClient.swift Outdated
…-panel

# Conflicts:
#	CLI/cmux.swift
#	cmux.xcodeproj/project.pbxproj
Comment thread Sources/DiffReviewGitClient.swift Outdated
Comment thread Sources/DiffReviewGitClient.swift Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 13163-13167: The three new hardcoded help strings ("set
<files|find|vault|sessions|review|diff|feed|dock>\n                             
Show, switch mode, and focus", "mode                           Print
{\"visible\":bool,\"mode\":string}", and
"files|find|vault|sessions|review|diff|feed|dock\n                              
Alias for show + set + focus") should be routed through localization: replace
each raw literal with String(localized:defaultValue:) (or your project's
localized API) using a distinct key/label and the original English as
defaultValue, and add matching entries to the app’s string catalog; update the
same pattern at the other occurrences referenced (around the other line ranges)
so all user-facing CLI help text is localized.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: aa79c340-d2e5-4ee8-8d92-8cb16ea062ef

📥 Commits

Reviewing files that changed from the base of the PR and between 8627dc9 and e86b0fe.

📒 Files selected for processing (21)
  • CLI/cmux.swift
  • Resources/Localizable.xcstrings
  • Sources/ContentView+RightSidebarCommandPalette.swift
  • Sources/DiffReviewGitClient.swift
  • Sources/DiffReviewModels.swift
  • Sources/DiffReviewPanelView.swift
  • Sources/DiffReviewPatchParser.swift
  • Sources/DiffReviewStore.swift
  • Sources/MainWindowFocusController.swift
  • Sources/RightSidebarMode+Availability.swift
  • Sources/RightSidebarPanelView.swift
  • Sources/RightSidebarRemoteCommand.swift
  • Sources/RightSidebarToolPanel.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/DiffReviewPanelContentStateTests.swift
  • cmuxTests/DiffReviewPatchParserTests.swift
  • cmuxTests/FileExplorerStateModePersistenceTests.swift
  • cmuxTests/RightSidebarCommandPaletteTests.swift
  • cmuxTests/ShortcutAndCommandPaletteTests.swift
  • cmuxTests/TerminalControllerSocketSecurityTests.swift

Comment thread CLI/cmux.swift Outdated
Comment thread Sources/DiffReviewStore.swift
Comment thread Sources/DiffReviewPanelView.swift
Comment thread Sources/DiffReviewModels.swift
Comment thread CLI/cmux.swift
Comment thread Sources/DiffReviewModels.swift
Comment thread Sources/DiffReviewStore.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Sources/DiffReviewGitClient.swift (2)

215-218: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Prefer throwing write(contentsOf:) for robust error handling.

The non-throwing write(_:) silently fails on errors (e.g., broken pipe if the process terminates early). Using write(contentsOf:) surfaces failures so they can propagate as commandFailed(.generic).

♻️ Suggested fix
-                        inputPipe.fileHandleForWriting.write(Data(standardInput.utf8))
+                        try inputPipe.fileHandleForWriting.write(contentsOf: Data(standardInput.utf8))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/DiffReviewGitClient.swift` around lines 215 - 218, Replace the
non-throwing write(Data(_:) ) with the throwing write(contentsOf:) so write
failures (e.g., broken pipe) propagate instead of being silently ignored: when
writing the String standardInput to inputPipe?.fileHandleForWriting use the
throwing API (try fileHandleForWriting.write(contentsOf:
Data(standardInput.utf8))) and let the surrounding function propagate the error
(or catch and map to commandFailed(.generic)) before closing the file handle;
update the code paths referencing standardInput and inputPipe to perform the
write with try and proper error propagation.

141-149: 🧹 Nitpick | 🔵 Trivial | 🏗️ Heavy lift

Consider bounded concurrency for untracked file diffs.

Sequential process spawning for up to 100 untracked files may be slow due to fork/exec overhead per file. Using TaskGroup with bounded concurrency (e.g., 8-10 concurrent processes) would reduce latency significantly while avoiding resource exhaustion.

♻️ Suggested approach using TaskGroup
-        var untrackedOutputs: [String] = []
-        for path in untrackedPaths.prefix(100) {
-            if let output = try? await runGit(
-                in: repositoryRoot,
-                arguments: ["diff", "--no-ext-diff", "--no-color", "--unified=3", "--no-index", "--", "/dev/null", path],
-                acceptedStatuses: [0, 1]
-            ).stdout {
-                untrackedOutputs.append(output)
-            }
-        }
+        let pathsToProcess = Array(untrackedPaths.prefix(100))
+        let untrackedOutputs: [String] = await withTaskGroup(of: (Int, String?).self) { group in
+            for (index, path) in pathsToProcess.enumerated() {
+                group.addTask {
+                    let output = try? await runGit(
+                        in: repositoryRoot,
+                        arguments: ["diff", "--no-ext-diff", "--no-color", "--unified=3", "--no-index", "--", "/dev/null", path],
+                        acceptedStatuses: [0, 1]
+                    ).stdout
+                    return (index, output)
+                }
+            }
+            var results = [(Int, String)]()
+            for await (index, output) in group {
+                if let output { results.append((index, output)) }
+            }
+            return results.sorted { $0.0 < $1.0 }.map(\.1)
+        }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/DiffReviewGitClient.swift` around lines 141 - 149, The loop that
calls runGit for each path in untrackedPaths (up to 100) should be parallelized
with bounded concurrency to avoid sequential fork/exec overhead: replace the for
loop with a withTaskGroup (or TaskGroup) that launches up to N concurrent child
tasks (suggest N = 8) which each call runGit(in: repositoryRoot, arguments: ...,
acceptedStatuses: [0,1]) for a single path; have each task return its stdout (or
nil on failure) and then collect results after awaiting the group, appending
non-nil outputs to untrackedOutputs (do not mutate shared untrackedOutputs
inside tasks—collect into a local array from the group's returned values or use
an actor/lock if you must mutate concurrently). Ensure you still respect the
prefix(100) limit on untrackedPaths and preserve the same arguments and status
handling used by runGit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/DiffReviewPanelContentStateTests.swift`:
- Around line 90-114: Add two tests that exercise plural forms for the summary
formatter: create testSummaryFormatterUsesPluralFileLabelForZeroFiles and
testSummaryFormatterUsesPluralFileLabelForMultipleFiles that build
DiffReviewSnapshot instances (empty files array for zero, and two DiffReviewFile
entries for multiple) and call
DiffReviewSummaryFormatter.summaryText(snapshot:); assert the returned summary
contains "0 files" and "2 files" respectively to verify the ICU-style .other
plural branch alongside the existing testSummaryFormatterUsesSingularFileLabel.

---

Outside diff comments:
In `@Sources/DiffReviewGitClient.swift`:
- Around line 215-218: Replace the non-throwing write(Data(_:) ) with the
throwing write(contentsOf:) so write failures (e.g., broken pipe) propagate
instead of being silently ignored: when writing the String standardInput to
inputPipe?.fileHandleForWriting use the throwing API (try
fileHandleForWriting.write(contentsOf: Data(standardInput.utf8))) and let the
surrounding function propagate the error (or catch and map to
commandFailed(.generic)) before closing the file handle; update the code paths
referencing standardInput and inputPipe to perform the write with try and proper
error propagation.
- Around line 141-149: The loop that calls runGit for each path in
untrackedPaths (up to 100) should be parallelized with bounded concurrency to
avoid sequential fork/exec overhead: replace the for loop with a withTaskGroup
(or TaskGroup) that launches up to N concurrent child tasks (suggest N = 8)
which each call runGit(in: repositoryRoot, arguments: ..., acceptedStatuses:
[0,1]) for a single path; have each task return its stdout (or nil on failure)
and then collect results after awaiting the group, appending non-nil outputs to
untrackedOutputs (do not mutate shared untrackedOutputs inside tasks—collect
into a local array from the group's returned values or use an actor/lock if you
must mutate concurrently). Ensure you still respect the prefix(100) limit on
untrackedPaths and preserve the same arguments and status handling used by
runGit.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f1ec20d6-11b5-4365-a702-d3a8c8640dda

📥 Commits

Reviewing files that changed from the base of the PR and between 10bbd40 and 1785656.

📒 Files selected for processing (4)
  • Resources/Localizable.xcstrings
  • Sources/DiffReviewGitClient.swift
  • Sources/DiffReviewPanelView.swift
  • cmuxTests/DiffReviewPanelContentStateTests.swift

Comment thread cmuxTests/DiffReviewPanelContentStateTests.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/DiffReviewGitClient.swift (1)

247-253: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider reading pipe data in chunks instead of byte-by-byte.

Iterating FileHandle.bytes appends one byte at a time, which incurs per-byte overhead. For large diffs (multi-MB in active repos), this can noticeably slow snapshot loading. Reading in chunks (e.g., via availableData or read(upToCount:) in a loop) would be more efficient.

♻️ Suggested chunk-based reading
-    private static func readData(from handle: FileHandle) async throws -> Data {
-        var data = Data()
-        for try await byte in handle.bytes {
-            data.append(byte)
-        }
-        return data
-    }
+    private static func readData(from handle: FileHandle) async throws -> Data {
+        try await withCheckedThrowingContinuation { continuation in
+            DispatchQueue.global(qos: .utility).async {
+                do {
+                    let data = try handle.readToEnd() ?? Data()
+                    continuation.resume(returning: data)
+                } catch {
+                    continuation.resume(throwing: error)
+                }
+            }
+        }
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/DiffReviewGitClient.swift` around lines 247 - 253, The
readData(from:) function currently iterates FileHandle.bytes and appends one
byte at a time (per-byte overhead); change it to read in chunks instead by
looping on FileHandle.read(upToCount:) or FileHandle.availableData until EOF and
append each Data chunk to the accumulator to improve performance for large
diffs; update the method readData(from handle: FileHandle) to perform chunked
reads and return the combined Data (preserve async/throws semantics and close
the handle where appropriate).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Sources/DiffReviewGitClient.swift`:
- Around line 247-253: The readData(from:) function currently iterates
FileHandle.bytes and appends one byte at a time (per-byte overhead); change it
to read in chunks instead by looping on FileHandle.read(upToCount:) or
FileHandle.availableData until EOF and append each Data chunk to the accumulator
to improve performance for large diffs; update the method readData(from handle:
FileHandle) to perform chunked reads and return the combined Data (preserve
async/throws semantics and close the handle where appropriate).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f372efbb-80dc-45d2-9e38-44501bcea958

📥 Commits

Reviewing files that changed from the base of the PR and between 1785656 and e28f5d0.

📒 Files selected for processing (1)
  • Sources/DiffReviewGitClient.swift

Comment thread Sources/DiffReviewGitClient.swift
Comment thread Sources/DiffReviewGitClient.swift
Comment thread Sources/DiffReviewPanelView.swift Outdated
Comment thread Sources/DiffReviewStore.swift Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 and found 1 potential issue.

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 39fd20d. Configure here.

Comment thread Sources/DiffReviewGitClient.swift
@austinywang

Copy link
Copy Markdown
Contributor Author

Closing for now; not actively working on this. Branch issue-609-diff-review-panel is preserved if we pick it back up.

This branch was successfully deployed

1 active deployment
Preview – cmux — 63692bff Deployed May 24, 2026 by vercel[bot]
Sign up for free to 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.

Feature: Add inline diff / code review panel for reviewing agent-generated changes

1 participant