Skip to content

fix(jetbrains): improve session diff rendering - #12862

Merged
kirillk merged 25 commits into
mainfrom
jetbrains-pixel-icons
Aug 5, 2026
Merged

fix(jetbrains): improve session diff rendering#12862
kirillk merged 25 commits into
mainfrom
jetbrains-pixel-icons

Conversation

@kirillk

@kirillk kirillk commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Issue

No linked issue. Fixes user-reported JetBrains session rendering and diff-viewer problems.

Context

This PR collects JetBrains UI fixes for session transcript rendering and diff presentation:

  • Chat transcript turns could appear partially laid out after session load or undo/redo until the tool window was resized.
  • Multi-hunk modified-file diffs opened from "Show turn changes" rendered as raw patch text on an empty left side, making every line look added.
  • Reverted-session diff cards and related UI details needed to preserve/resolve file diff information.
  • Session icons for reasoning/copy actions were sharpened.

Implementation

  • Reconciles cached transcript layout heights across validate-root turn boundaries so settled turns that self-layout can notify the parent layout when their preferred height changes. This makes layout recovery event-source agnostic instead of requiring per-event cache invalidation.
  • Updates patch reconstruction so multi-hunk limited-context diffs concatenate hunk bodies into before/after sides and render as a real side-by-side diff without depending on the VCS module in the split-mode frontend.
  • Wires reverted-session diff data through the JetBrains session model/parser so reopened reverted sessions can show their changed-file list and open associated diffs.
  • Bounds and improves the revert banner file list presentation, including disambiguated paths and absolute tooltip paths.
  • Refines JetBrains SVG assets for reasoning and copy icons.

Tradeoff: multi-hunk patch reconstruction collapses inter-hunk gaps and line numbers restart in the reconstructed side-by-side content. This avoids the client-side VCS dependency and fixes the all-green raw-patch fallback.

Screenshots / Video

Diff render bug for turns

Screen Shot 2026-08-04 at 11 44 03 AM

How to Test

Manual/local verification

Executed by agent:

  • ./gradlew :frontend:test --tests ai.kilocode.client.session.ui.SessionLayoutTest
  • ./gradlew :frontend:test --tests ai.kilocode.client.diff.DiffPatchReconstructTest --tests ai.kilocode.client.diff.KiloDiffEditorContentTest
  • ./gradlew typecheck

Reviewer test steps

  1. Open the JetBrains plugin in a sandbox.
  2. Open an existing session with several transcript turns and confirm no turn/card is cropped after load.
  3. Use undo/redo/revert on a session turn and confirm the transcript relayouts without resizing the tool window.
  4. Open "Show turn changes" for a modified file with multiple diff hunks and confirm it renders as a side-by-side diff instead of raw patch text with all lines added.
  5. Reopen a session whose last message was reverted and confirm the reverted file list/diff card appears.

Blocked checks and substitute verification

  • ./gradlew :frontend:test --tests ai.kilocode.client.session.ui.SessionMessageListPanelTest was run and still fails on the pre-existing unrelated test rollback banner shortens duplicate file names with parents assertion. Substitute verification: the focused SessionLayoutTest, focused diff tests, and typecheck all pass.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Get in Touch

Kilo team internal PR.

Comment thread .changeset/jetbrains-revert-diff-card.md Outdated
@kilo-code-bot

kilo-code-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Incremental review of a3160d7 (9 files, ~32 changed lines since 450b8a2). All four previously reported findings are resolved in this increment:

  • tool: diff tokens now carry the owning message ID (Tool.messageID plumbed from PartDto through SessionModel into EditToolView), so single-edit diffs match the CLI's per-message authoritative snapshot scope. Empty-messageID fallback degrades gracefully to the previous behavior.
  • Revert-banner diffs (revert: tokens) now skip whole-file enrichment and render the CLI's range-scoped hunk patches directly, avoiding whole-session before/after splicing.
  • The reflective revertDto fallback now logs getter mismatches and decode failures instead of silently dropping revert data.
  • The \ No newline at end of file side-specificity limitation is documented in DiffFullReconstruct's KDoc.

The SummaryFileDiff schema tightening (omitting before/after alongside patch in packages/opencode/src/snapshot/index.ts) was verified safe: session-level summary writers never populate those fields and no consumer reads them; message-level summaries remain full FileDiff, so JetBrains patch parsing is unaffected.

Files Reviewed (9 files)
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/app/KiloBackendSessionManager.kt
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/model/Message.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/model/SessionModel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/EditToolView.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/model/SessionModelTest.kt
  • packages/opencode/src/snapshot/index.ts
  • packages/opencode/test/kilocode/summary-file-diff.test.ts
Previous Review Summaries (5 snapshots, latest commit 450b8a2)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 450b8a2)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 2

Incremental review of 450b8a2 (one commit since 4c6bcf5): a single-line bun.lock sync of the @kilocode/kilo-jetbrains version (7.4.17 → 7.4.20) to match package.json. The lockfile change is correct and introduces no new issues. No Kotlin sources changed this increment; the four previously reported findings were re-verified against current HEAD (450b8a2) and remain open.

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt 199 tool: diff tokens carry a part ID but the CLI scopes the authoritative snapshot by message ID, so single-edit full diffs never use the per-message snapshot and silently fall back to working-tree reconstruction (re-verified at HEAD)
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt 199 Revert-banner diffs (revert: token unparsed by message()) still enriched with whole-session before/after instead of the rolled-back range (re-verified at HEAD)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/app/KiloBackendSessionManager.kt 355 Reflective revertDto swallows getter mismatches with no logging, silently dropping revert data in repo-CLI dev builds (re-verified at HEAD)
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt 61 \ No newline at end of file marker is side-specific but treated as side-agnostic (re-verified at HEAD)
Files Reviewed (4 files)
  • bun.lock — incremental change this round, no issues
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt - 2 issues
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/app/KiloBackendSessionManager.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt - 1 issue

Previous review (commit 4c6bcf5)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 2

Incremental review of the three commits since f09e628 (session-directory routing for full diffs, tool: message scoping, repo-CLI dev-build fixes, reflective revert-model mapping). Two new findings; the two previous findings were re-verified against current HEAD and remain open.

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt 199 NEW: tool: diff tokens carry a part ID but the CLI scopes the authoritative snapshot by message ID, so single-edit full diffs never use the per-message snapshot and silently fall back to working-tree reconstruction
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt 199 Revert-banner diffs (revert: token unparsed by message()) still enriched with whole-session before/after instead of the rolled-back range (re-verified at HEAD)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/app/KiloBackendSessionManager.kt 355 NEW: reflective revertDto swallows getter mismatches with no logging, silently dropping revert data in repo-CLI dev builds
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt 61 \ No newline at end of file marker is side-specific but treated as side-agnostic (file unchanged this increment; re-verified at HEAD)
Files Reviewed (6 changed files)
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/app/KiloBackendSessionManager.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloSessionRpcApiImpl.kt
  • packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt - 2 issues
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionUi.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/controller/SessionController.kt

Targeted re-verification of prior findings: RevertBanner.kt, DiffFullReconstruct.kt (unchanged since f09e628), CLI scoping in session/summary.ts, token creation in EditToolView.kt.

Previous review (commit f09e628)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1

Incremental review of the whole-file diff pipeline added since bfab19c (CLI DiffFull.detail + Snapshot.diffFile endpoint, JetBrains diffSides enrichment, hunk-gutter line remapping). The three previous findings remain resolved.

Fix these issues in Kilo Cloud

Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt 189 Revert-banner diffs are enriched with whole-session before/after instead of the rolled-back range

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt 61 \ No newline at end of file marker is side-specific but treated as side-agnostic
Files Reviewed (22 files)
  • packages/opencode/src/kilocode/snapshot/diff-full.ts
  • packages/opencode/src/server/routes/instance/httpapi/groups/session.ts
  • packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts
  • packages/opencode/src/session/summary.ts
  • packages/opencode/src/snapshot/index.ts
  • packages/opencode/test/kilocode/diff-full.test.ts
  • packages/opencode/test/session/compaction.test.ts
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/DiffFullReconstruct.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloSessionRpcApiImpl.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/diff/DiffFullReconstructTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/KiloSessionRpcApiImplTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/testing/MockCliServer.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloSessionService.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/DiffBlocks.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/DiffPatchReconstruct.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorKind.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/DiffBlocksTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/DiffPatchReconstructTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeSessionRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloSessionRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/ChatDto.kt

Previous review (commit bfab19c)

Status: No Issues Found | Recommendation: Merge

All three previous findings are resolved in the new commits: RevertBanner.absolute() now falls back to the original relative path when no session directory is known (fixing both the misleading IDE-CWD tooltip and the failing duplicate-names test, whose relative-tooltip expectations now hold), and the five patch changesets were grouped into one concise user-facing changeset. The incremental diff introduces no new issues — the tooltip-only call site of absolute() makes the relative fallback safe.

Files Reviewed (7 files)
  • .changeset/jetbrains-revert-diff-card.md
  • .changeset/bright-reasoning-icon.md (deleted)
  • .changeset/jetbrains-multihunk-diff-viewer.md (deleted)
  • .changeset/jetbrains-reverted-session-diff-list.md (deleted)
  • .changeset/smooth-copy-icon.md (deleted)
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/RevertBanner.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/SessionMessageListPanelTest.kt

Previous review (commit 6414e64)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 1
SUGGESTION 1

The JetBrains session/diff fixes are well-structured: unified-diff parsing lives in the backend, DTOs carry defaults for RPC compatibility, threading follows the EDT/coroutine rules, the layout reconcile converges instead of looping, and the new tests exercise real implementation. No memory leaks found — the row cache is pruned on update and no new listeners or subscriptions outlive their scope. The one blocker is that the PR ships a test it introduced (test rollback banner shortens duplicate file names with parents) in a knowingly failing state; the PR description calls it pre-existing and unrelated, but it does not exist on the base branch and is broken by this PR's own absolute-tooltip change.

Fix these issues in Kilo Cloud

Issue Details (click to expand)

CRITICAL

File Line Issue
packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/SessionMessageListPanelTest.kt 1161 Failing tooltip test was added by this PR (not pre-existing); commit 5's absolute tooltips broke commit 3's relative-path expectation

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/RevertBanner.kt 201 absolute() falls back to Path.toAbsolutePath() (IDE process CWD) when no session directory is known, producing misleading tooltips

SUGGESTION

File Line Issue
.changeset/jetbrains-revert-diff-card.md 5 Five related patch changesets could be grouped into one per repo guidance
Files Reviewed (44 files)
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/SessionMessageListPanelTest.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/RevertBanner.kt - 1 issue
  • .changeset/jetbrains-revert-diff-card.md - 1 issue
  • .changeset/bright-reasoning-icon.md
  • .changeset/jetbrains-multihunk-diff-viewer.md
  • .changeset/jetbrains-reverted-session-diff-list.md
  • .changeset/smooth-copy-icon.md
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDataParser.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDataParserTest.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/DiffPatchReconstruct.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/controller/SessionController.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/SessionLayout.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/SessionMessageListPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/base/BaseQuestionView.kt
  • packages/kilo-jetbrains/frontend/src/main/resources/icons/copy.svg + copy_dark.svg
  • packages/kilo-jetbrains/frontend/src/main/resources/icons/views/brain.svg + brain_dark.svg
  • packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties + 18 locale variants
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/DiffPatchReconstructTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/KiloDiffEditorContentTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/controller/RevertDiffLoadingTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/SessionLayoutTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/base/BaseQuestionViewTest.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/SessionDto.kt

Reviewed by kimi-k3 · Input: 155.1K · Output: 15.8K · Cached: 1.1M

Review guidance: REVIEW.md from base branch main

kirillk added 6 commits August 4, 2026 12:52
Add on-demand full-content diff loading for the JetBrains diff editor
tab while keeping inline turn cards hunk-bounded. Adds a full/file query
path to the CLI session diff endpoint and a diffFile RPC that matches the
requested path so multi-file turns are not collapsed to a single entry.
Roll back the CLI diff full/file server changes and rebuild whole-file
diffs entirely in the JetBrains plugin: the backend reads the working-tree
file and reverse-applies the existing hunk patch to recover the full before
side, falling back to the hunk view when the tree has drifted. Works against
any pinned CLI with no server change.
…back

The diff editor tab now shows whole-file diffs (with collapsible unchanged
regions) for modified files, while inline session cards stay hunk-bounded.

diffSides resolves full before/after with a safe precedence:
1. Authoritative: query the CLI's snapshot diff (full=true&file=...), which
   reads the exact turn's before/after from snapshot commits via git show and
   is correct even for historical/reverted turns.
2. Fallback: reverse-apply the hunk patch onto the working-tree file locally,
   so it works against the current pinned CLI until the new one is released.
3. Hunk view: if neither yields full content (drift/binary/added/deleted),
   render the existing patch.

The CLI change is minimal and additive: full-content logic lives in the
kilo-owned diff-full.ts (DiffFull.detail); shared files only gain thin
kilocode_change hooks (FileDiff before/after, Snapshot.diffFile, the summary
full/file branch, and the diff query fields).
When the diff editor tab falls back to reconstructing sides from the hunk
patch, the content is just the concatenated hunk bodies, so IntelliJ numbered
the gutter from 1 instead of the real file positions.

DiffPatchReconstruct now records, in lockstep with the content it builds, the
0-based source-file line for each reconstructed document line (following the
@@ headers and jumping across elided inter-hunk gaps). diffRequest attaches
these via the public DiffUserDataKeysEx.LINE_NUMBER_CONVERTOR so the gutter
matches the file, mirroring what the inline card already shows. Full
authoritative content is untouched since it already starts at line 1.
The binary branch returned an object without before/after while the normal
branch included them, so the result was a union and callers could not read
before/after without narrowing (the diff-full test failed typecheck). Return
before/after as undefined for binary files so the shape is uniform; JSON still
omits the undefined keys, so serialized output is unchanged.
kirillk added 4 commits August 4, 2026 18:51
# Conflicts:
#	packages/opencode/src/snapshot/index.ts
…e edits

Two correctness fixes for the diff editor's full-file view plus diagnostics:

- Open inline/turn/edit diffs against the session's own directory
  (SessionController.sessionDirectory) instead of the active workspace
  directory, so authoritative snapshot lookup and local reconstruction
  resolve against the repo where the session actually ran.
- Scope single Edit/Patch diffs to their message: message() now parses the
  "tool:<sessionId>:<messageId>" token in addition to "turn:", so the
  authoritative snapshot query is scoped to that edit. A single edit's
  intermediate state cannot be rebuilt from the final working tree, so it
  requires the authoritative per-message snapshot.

Also adds a dev-only working-tree resolver: when kilo.dev.worktree.root is
set, resolve() re-roots a stored diff's file path onto the running worktree by
matching the longest existing path suffix, so cross-worktree dev sessions can
still reconstruct locally. In production resolve() returns the direct path only.
Adds info logging around diffSides/authoritative/detail to make full-vs-hunk
decisions observable.
- Add a revertDto overload for the regenerated GlobalSessionRevert model so
  the backend compiles against the post-merge OpenAPI client.
- Resolve the bun executable from BUN_BINARY/BUN, PATH, ~/.bun/bin, and common
  Homebrew locations in GenerateOpenApiSpecTask, so IDE-launched Gradle (which
  runs with a stripped PATH) can generate the OpenAPI spec in repo-CLI mode.
Pinned CLI generation exposes GlobalSession.revert as SessionRevert, while the
local repo CLI client can generate a separate GlobalSessionRevert model. Avoid
importing the repo-only type so pinned builds keep compiling, while still
mapping the regenerated repo-CLI shape through reflective getters when present.
@kirillk
kirillk merged commit 2a5cfdf into main Aug 5, 2026
31 checks passed
@kirillk
kirillk deleted the jetbrains-pixel-icons branch August 5, 2026 17:41
LudwigSolutionsAI pushed a commit to LudwigSolutionsAI/kilocode that referenced this pull request Aug 6, 2026
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
fix(jetbrains): improve session diff rendering
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.

2 participants