Skip to content

Comments

feat: show aggregated +/− line counts in FileChangesPanel header#11618

Merged
hannesrudolph merged 7 commits intoRooCodeInc:mainfrom
saneroen:feature/file-changes-panel-totals
Feb 20, 2026
Merged

feat: show aggregated +/− line counts in FileChangesPanel header#11618
hannesrudolph merged 7 commits intoRooCodeInc:mainfrom
saneroen:feature/file-changes-panel-totals

Conversation

@saneroen
Copy link
Contributor

@saneroen saneroen commented Feb 19, 2026

Related GitHub Issue

Closes: #11615

Roo Code Task Context (Optional)

Description

This PR adds aggregated line counts (+/−) in the FileChangesPanel header. The panel header now shows total lines added and removed across all changed files so users can see the scope of changes at a glance.

Implementation:

  • totalStats memo in FileChangesPanel.tsx: Sums diffStats.added and diffStats.removed from all file-change entries.
  • Header totals: Renders +N (green) and -N (red) in the CollapsibleTrigger, right-aligned, using existing chart color tokens.
  • Conditional display: Totals only render when added > 0 or removed > 0.
  • Accessibility: aria-label on the totals container; data-testid for tests.
  • Tests: Extended createFileEditMessage with optional diffStats; added test for aggregated totals in the header; added test that totals are hidden when no diffStats are present.

Test Procedure

  1. Unit tests: Run pnpm exec vitest run -- FileChangesPanel from webview-ui/.
  2. Manual: Start a task, approve file edits. Verify the File Changes panel header shows +X and -Y next to the file count when diffStats are available.
  3. Edge case: When no diffStats are present, totals are hidden; file count still displays.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and updated tests added; FileChangesPanel.spec.tsx includes aggregated totals test.
  • Documentation Impact: No user-facing docs changes required.
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

Screenshot 2026-02-19 at 5 35 50 PM Screenshot 2026-02-19 at 1 23 51 PM

Documentation Updates

  • No documentation updates are required.
  • Yes, documentation updates are required. (Describe or link.)

Additional Notes

  • Totals rely on diffStats from the backend; edits without stats do not contribute to the header.
  • Reuses existing chart color tokens for consistency with per-file stats in CodeAccordian.
  • Diff computation: Previously we concatenated per-edit diffs; now we use createTwoFilesPatch(original, final) when we have both, producing a merged diff with correct final-state line numbers. Falls back to concatenation when originalContent is missing.

Get in Touch

Discord: santy2509

Start a new Roo Code Cloud session on this branch

@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. Enhancement New feature or request labels Feb 19, 2026
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Feb 20, 2026
Copy link
Contributor

@roomote roomote bot left a comment

Choose a reason for hiding this comment

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

PR Review: #11618 -- Aggregated +/- line counts in FileChangesPanel header

Is this PR sound?

No -- this PR has significant scope creep and several issues that need to be addressed before merging.

The linked issue (#11615) requests one thing: "The File Changes panel header should show total lines added and removed across all changed files." The aggregated totals feature is well-implemented and accounts for roughly 30% of this PR. However, the remaining 70% introduces an entirely separate feature -- merged diff computation -- that reads the current file from disk at expand time and recomputes a single unified diff using createTwoFilesPatch. This second feature is never mentioned in the issue, was not requested, and introduces new backend infrastructure (readFileContent message handler, fileContent response type, originalContent plumbing through tools).


Findings

P0 (Critical) -- Path Traversal in readFileContent Handler

The new readFileContent handler in webviewMessageHandler.ts reads arbitrary files from the filesystem:

const absPath = path.isAbsolute(relPath) ? relPath : path.join(getCurrentCwd(), relPath)
const content = await fs.readFile(absPath, "utf-8")

There is no path validation or sandboxing. A crafted message from the webview could read any file the extension process has access to (e.g., ../../.ssh/id_rsa, /etc/passwd). While the webview content is extension-controlled, this still expands the attack surface unnecessarily. Other existing handlers like openFile have the same pattern, but they open files in the editor (user-visible). Silently returning file contents to the webview is a different risk profile. At minimum, this needs workspace-boundary validation.

P1 (High) -- Scope Creep: Merged Diff Feature Bundled With Header Totals

This PR bundles two distinct features:

  1. Aggregated +/- totals in the header (what the issue asks for)
  2. Merged diff display using originalContent + live file reads (not requested)

The merged diff feature touches 5 files beyond what the totals feature requires:

  • Adds originalContent to ClineSayTool type
  • Adds originalContent passthrough in ApplyDiffTool.ts and ApplyPatchTool.ts
  • Adds readFileContent / fileContent message types to ExtensionMessage and WebviewMessage
  • Adds readFileContent handler in webviewMessageHandler.ts
  • Adds file-fetching state management and createTwoFilesPatch logic in FileChangesPanel.tsx
  • Adds originalContent to FileChangeEntry interface

These should be separate PRs. The merged diff feature needs its own issue, design discussion, and review cycle.

P1 (High) -- Inconsistent originalContent Coverage Across Tools

originalContent is only added to ApplyDiffTool and ApplyPatchTool, but not to WriteToFileTool, SearchReplaceTool, EditTool, or EditFileTool -- all of which also emit tool: "appliedDiff" messages. This means the merged diff feature will silently fall back to concatenated diffs for edits made by those tools, creating an inconsistent and confusing user experience. Users will see merged diffs for some file edits and concatenated diffs for others with no indication of why.

P1 (High) -- No Tests for New Backend or Merged Diff Logic

  • The readFileContent handler has zero test coverage. This is a new message type that reads from the filesystem.
  • The merged diff computation in FileChangesPanel.tsx (the createTwoFilesPatch path, the useEffect for requesting file content, the message listener) has no test coverage.
  • The only new tests cover the aggregated totals feature, which is the simpler part of the PR.

P2 (Medium) -- Duplicated Path Normalization

The lookupPath logic (path.startsWith("./") ? path.slice(2) : path) appears in two separate locations within FileChangesPanel.tsx (the useEffect for requesting content and the render function). This should be extracted to a helper to avoid drift between the two.

P2 (Medium) -- Missing Error Handling for createTwoFilesPatch

If createTwoFilesPatch throws (e.g., due to encoding issues or unexpected content), the entire FileChangesPanel render will crash. This call should be wrapped in a try/catch that falls back to the concatenated diff display.

P3 (Low) -- hasMergedDiff Condition May Suppress Valid Empty-File Diffs

The condition finalContent !== "" means if a file was edited down to empty content, the merged diff will not render -- it will fall back to concatenated diffs. This is a minor edge case but worth noting.


Recommendation

Split this PR into two:

  1. PR A (header totals): The totalStats memo, the header rendering with +N/-N, and the corresponding tests. This is clean, well-tested, and directly addresses #11615.
  2. PR B (merged diff display): The originalContent plumbing, readFileContent handler, fileContent message type, and createTwoFilesPatch logic. This needs its own issue, consistent coverage across all edit tools, path validation, error handling, and test coverage.

Copy link
Collaborator

@hannesrudolph hannesrudolph left a comment

Choose a reason for hiding this comment

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

Hannes: Disregard the scope creep / feature split feedback above, the merged diff addition is acceptable to bundle here. However, please fix the P0 path traversal vulnerability in readFileContent before we merge!

saneroen and others added 5 commits February 19, 2026 20:46
…-platform compatibility

The isPathOutsideWorkspace mock used hardcoded Unix-style path comparisons
(/mock/workspace with forward slashes), which fails on Windows where
path.resolve() produces paths with drive letters (C:\mock\workspace\...).

Replace manual string normalization with path.resolve() and path.sep so the
mock behaves correctly on both Windows and Unix.
Copy link
Collaborator

@hannesrudolph hannesrudolph left a comment

Choose a reason for hiding this comment

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

Tests are fully green.

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 20, 2026
@hannesrudolph hannesrudolph merged commit 5db2062 into RooCodeInc:main Feb 20, 2026
13 of 15 checks passed
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ENHANCEMENT] Show aggregated line counts in File Changes panel header

3 participants